From 7977f4640dc53c8226dc6be969775acedee7c78b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 07:27:22 -0700 Subject: [PATCH 001/165] new class: SpatiallyNestable --- libraries/shared/src/SpatiallyNestable.cpp | 37 +++++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 47 ++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 libraries/shared/src/SpatiallyNestable.cpp create mode 100644 libraries/shared/src/SpatiallyNestable.h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp new file mode 100644 index 0000000000..5e14f398ea --- /dev/null +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -0,0 +1,37 @@ +// +// SpatiallyNestable.cpp +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SpatiallyNestable.h" + +SpatiallyNestable::SpatiallyNestable() : + _transform() { +} + + +const glm::vec3& SpatiallyNestable::getPosition() const { + return _transform.getTranslation(); +} + +void SpatiallyNestable::setPosition(const glm::vec3& position) { + _transform.setTranslation(position); +} + +const glm::quat& SpatiallyNestable::getOrientation() const { + return _transform.getRotation(); +} + +void SpatiallyNestable::setOrientation(const glm::quat& orientation) { + _transform.setRotation(orientation); +} + +const Transform& SpatiallyNestable::getTransform() const { + return _transform; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h new file mode 100644 index 0000000000..dd57f27477 --- /dev/null +++ b/libraries/shared/src/SpatiallyNestable.h @@ -0,0 +1,47 @@ +// +// SpatiallyNestable.h +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SpatiallyNestable_h +#define hifi_SpatiallyNestable_h + +#include + +#include "Transform.h" + + +class SpatiallyNestable; +typedef std::weak_ptr SpatiallyNestableWeakPointer; +typedef std::shared_ptr SpatiallyNestablePointer; + +class SpatiallyNestable { + +public: + SpatiallyNestable(); + virtual ~SpatiallyNestable() { } + + virtual const glm::vec3& getPosition() const; + virtual void setPosition(const glm::vec3& position); + virtual const glm::quat& getOrientation() const; + virtual void setOrientation(const glm::quat& orientation); + virtual const Transform& getTransform() const; + +protected: + Transform _transform; + + QUuid _parentID; // what is this thing's transform relative to? + int _parentJointIndex; // which joint of the parent is this relative to? + + SpatiallyNestableWeakPointer _parent; + QVector _children; +}; + + +#endif // hifi_SpatiallyNestable_h From 275e77d29e2a258eed2ea286398107bb983ed660 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 07:51:00 -0700 Subject: [PATCH 002/165] remove old-style avatar referentials --- interface/src/Menu.cpp | 6 +- interface/src/avatar/Avatar.cpp | 28 ---- interface/src/avatar/ModelReferential.cpp | 192 ---------------------- interface/src/avatar/ModelReferential.h | 48 ------ interface/src/avatar/MyAvatar.cpp | 31 ---- interface/src/avatar/MyAvatar.h | 4 - libraries/avatars/src/AvatarData.cpp | 79 +++------ libraries/avatars/src/AvatarData.h | 10 +- libraries/avatars/src/Referential.cpp | 109 ------------ libraries/avatars/src/Referential.h | 73 -------- libraries/entities/src/EntityItem.cpp | 12 -- libraries/entities/src/EntityItem.h | 33 +--- 12 files changed, 31 insertions(+), 594 deletions(-) delete mode 100644 interface/src/avatar/ModelReferential.cpp delete mode 100644 interface/src/avatar/ModelReferential.h delete mode 100644 libraries/avatars/src/Referential.cpp delete mode 100644 libraries/avatars/src/Referential.h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 008694717f..c6f5bace3a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -369,9 +369,9 @@ Menu::Menu() { auto& atpMigrator = ATPAssetMigrator::getInstance(); atpMigrator.setDialogParent(this); - QAction* assetMigration = addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::AssetMigration, - 0, &atpMigrator, - SLOT(loadEntityServerFile())); + /*QAction* assetMigration =*/ addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::AssetMigration, + 0, &atpMigrator, + SLOT(loadEntityServerFile())); MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9f4e7ee3cf..432149d907 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -38,7 +38,6 @@ #include "Hand.h" #include "Head.h" #include "Menu.h" -#include "ModelReferential.h" #include "Physics.h" #include "Recorder.h" #include "Util.h" @@ -150,30 +149,6 @@ float Avatar::getLODDistance() const { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - // update the avatar's position according to its referential - if (_referential) { - if (_referential->hasExtraData()) { - EntityTreePointer tree = qApp->getEntities()->getTree(); - switch (_referential->type()) { - case Referential::MODEL: - _referential = new ModelReferential(_referential, - tree, - this); - break; - case Referential::JOINT: - _referential = new JointReferential(_referential, - tree, - this); - break; - default: - qCDebug(interfaceapp) << "[WARNING] Avatar::simulate(): Unknown referential type."; - break; - } - } - - _referential->update(); - } - if (_scale != _targetScale) { setScale(_targetScale); } @@ -329,9 +304,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); - } auto& batch = *renderArgs->_batch; diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp deleted file mode 100644 index 18c5e36e7a..0000000000 --- a/interface/src/avatar/ModelReferential.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// -// ModelReferential.cpp -// -// -// Created by Clement on 7/30/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include - -#include "InterfaceLogging.h" -#include "ModelReferential.h" - -ModelReferential::ModelReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : - Referential(MODEL, avatar), - _tree(tree) -{ - _translation = referential->getTranslation(); - _rotation = referential->getRotation(); - unpackExtraData(reinterpret_cast(referential->getExtraData().data()), - referential->getExtraData().size()); - - if (!isValid()) { - qCDebug(interfaceapp) << "ModelReferential::copyConstructor(): Not Valid"; - return; - } - - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (item != NULL) { - _lastRefDimension = item->getDimensions(); - _refRotation = item->getRotation(); - _refPosition = item->getPosition(); - update(); - } -} - -ModelReferential::ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : - Referential(MODEL, avatar), - _entityID(entityID), - _tree(tree) -{ - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (!isValid() || item == NULL) { - qCDebug(interfaceapp) << "ModelReferential::constructor(): Not Valid"; - _isValid = false; - return; - } - - _lastRefDimension = item->getDimensions(); - _refRotation = item->getRotation(); - _refPosition = item->getPosition(); - - glm::quat refInvRot = glm::inverse(_refRotation); - _rotation = refInvRot * _avatar->getOrientation(); - _translation = refInvRot * (avatar->getPosition() - _refPosition); -} - -void ModelReferential::update() { - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (!isValid() || item == NULL || _avatar == NULL) { - return; - } - - bool somethingChanged = false; - if (item->getDimensions() != _lastRefDimension) { - glm::vec3 oldDimension = _lastRefDimension; - _lastRefDimension = item->getDimensions(); - _translation *= _lastRefDimension / oldDimension; - somethingChanged = true; - } - if (item->getRotation() != _refRotation) { - _refRotation = item->getRotation(); - _avatar->setOrientation(_refRotation * _rotation, true); - somethingChanged = true; - } - if (item->getPosition() != _refPosition || somethingChanged) { - _refPosition = item->getPosition(); - _avatar->setPosition(_refPosition + _refRotation * _translation, true); - } -} - -int ModelReferential::packExtraData(unsigned char* destinationBuffer) const { - QByteArray encodedEntityID = _entityID.toRfc4122(); - memcpy(destinationBuffer, encodedEntityID.constData(), encodedEntityID.size()); - return encodedEntityID.size(); -} - -int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { - QByteArray encodedEntityID((const char*)sourceBuffer, NUM_BYTES_RFC4122_UUID); - _entityID = QUuid::fromRfc4122(encodedEntityID); - return NUM_BYTES_RFC4122_UUID; -} - -JointReferential::JointReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : - ModelReferential(referential, tree, avatar) -{ - _type = JOINT; - if (!isValid()) { - qCDebug(interfaceapp) << "JointReferential::copyConstructor(): Not Valid"; - return; - } - - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (isValid() && model != NULL && _jointIndex < (uint32_t)(model->getJointStateCount())) { - _lastRefDimension = item->getDimensions(); - model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - } - update(); -} - -JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : - ModelReferential(entityID, tree, avatar), - _jointIndex(jointIndex) -{ - _type = JOINT; - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) { - qCDebug(interfaceapp) << "JointReferential::constructor(): Not Valid"; - _isValid = false; - return; - } - - _lastRefDimension = item->getDimensions(); - model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - - glm::quat refInvRot = glm::inverse(_refRotation); - _rotation = refInvRot * _avatar->getOrientation(); - // BUG! _refPosition is in domain units, but avatar is in meters - _translation = refInvRot * (avatar->getPosition() - _refPosition); -} - -void JointReferential::update() { - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) { - return; - } - - bool somethingChanged = false; - if (item->getDimensions() != _lastRefDimension) { - glm::vec3 oldDimension = _lastRefDimension; - _lastRefDimension = item->getDimensions(); - _translation *= _lastRefDimension / oldDimension; - somethingChanged = true; - } - if (item->getRotation() != _refRotation) { - model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - _avatar->setOrientation(_refRotation * _rotation, true); - somethingChanged = true; - } - if (item->getPosition() != _refPosition || somethingChanged) { - model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - _avatar->setPosition(_refPosition + _refRotation * _translation, true); - } -} - -const Model* JointReferential::getModel(EntityItemPointer item) { - EntityItemFBXService* fbxService = _tree->getFBXService(); - if (item != NULL && fbxService != NULL) { - return fbxService->getModelForEntityItem(item); - } - return NULL; -} - -int JointReferential::packExtraData(unsigned char* destinationBuffer) const { - unsigned char* startPosition = destinationBuffer; - destinationBuffer += ModelReferential::packExtraData(destinationBuffer); - - memcpy(destinationBuffer, &_jointIndex, sizeof(_jointIndex)); - destinationBuffer += sizeof(_jointIndex); - - return destinationBuffer - startPosition; -} - -int JointReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { - const unsigned char* startPosition = sourceBuffer; - sourceBuffer += ModelReferential::unpackExtraData(sourceBuffer, size); - - memcpy(&_jointIndex, sourceBuffer, sizeof(_jointIndex)); - sourceBuffer += sizeof(_jointIndex); - - return sourceBuffer - startPosition; -} diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h deleted file mode 100644 index 810db4b8e5..0000000000 --- a/interface/src/avatar/ModelReferential.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// ModelReferential.h -// -// -// Created by Clement on 7/30/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ModelReferential_h -#define hifi_ModelReferential_h - -#include - -class EntityTree; -class Model; - -class ModelReferential : public Referential { -public: - ModelReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); - ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); - virtual void update(); - -protected: - virtual int packExtraData(unsigned char* destinationBuffer) const; - virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); - - QUuid _entityID; - EntityTreePointer _tree; -}; - -class JointReferential : public ModelReferential { -public: - JointReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); - JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); - virtual void update(); - -protected: - const Model* getModel(EntityItemPointer item); - virtual int packExtraData(unsigned char* destinationBuffer) const; - virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); - - uint32_t _jointIndex; -}; - -#endif // hifi_ModelReferential_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5920543dca..3f6a6a1e77 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -43,7 +43,6 @@ #include "AvatarManager.h" #include "Environment.h" #include "Menu.h" -#include "ModelReferential.h" #include "MyAvatar.h" #include "Physics.h" #include "Recorder.h" @@ -209,10 +208,6 @@ void MyAvatar::update(float deltaTime) { _goToPending = false; } - if (_referential) { - _referential->update(); - } - Head* head = getHead(); head->relaxLean(deltaTime); updateFromTrackers(deltaTime); @@ -540,32 +535,6 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } } -void MyAvatar::clearReferential() { - changeReferential(NULL); -} - -bool MyAvatar::setModelReferential(const QUuid& id) { - EntityTreePointer tree = qApp->getEntities()->getTree(); - changeReferential(new ModelReferential(id, tree, this)); - if (_referential->isValid()) { - return true; - } else { - changeReferential(NULL); - return false; - } -} - -bool MyAvatar::setJointReferential(const QUuid& id, int jointIndex) { - EntityTreePointer tree = qApp->getEntities()->getTree(); - changeReferential(new JointReferential(jointIndex, id, tree, this)); - if (!_referential->isValid()) { - return true; - } else { - changeReferential(NULL); - return false; - } -} - bool MyAvatar::isRecording() { if (!_recorder) { return false; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7347419fee..0c3b415177 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -199,10 +199,6 @@ public slots: Q_INVOKABLE void updateMotionBehaviorFromMenu(); - void clearReferential(); - bool setModelReferential(const QUuid& id); - bool setJointReferential(const QUuid& id, int jointIndex); - bool isRecording(); qint64 recorderElapsed(); void startRecording(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a698c6f374..a4d506a748 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -40,7 +40,6 @@ AvatarData::AvatarData() : _sessionUUID(), _position(0.0f), _handPosition(0.0f), - _referential(NULL), _bodyYaw(-90.0f), _bodyPitch(0.0f), _bodyRoll(0.0f), @@ -68,7 +67,6 @@ AvatarData::AvatarData() : AvatarData::~AvatarData() { delete _headData; delete _handData; - delete _referential; } // We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized. @@ -82,40 +80,29 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { } const glm::vec3& AvatarData::getPosition() const { - if (_referential) { - _referential->update(); - } return _position; } -void AvatarData::setPosition(const glm::vec3 position, bool overideReferential) { - if (!_referential || overideReferential) { - _position = position; - } +void AvatarData::setPosition(const glm::vec3 position) { + _position = position; } glm::quat AvatarData::getOrientation() const { - if (_referential) { - _referential->update(); - } - return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); } -void AvatarData::setOrientation(const glm::quat& orientation, bool overideReferential) { - if (!_referential || overideReferential) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; - } +void AvatarData::setOrientation(const glm::quat& orientation) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); + _bodyPitch = eulerAngles.x; + _bodyYaw = eulerAngles.y; + _bodyRoll = eulerAngles.z; } // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - setPosition(position, true); - setOrientation(orientation, true); + setPosition(position); + setOrientation(orientation); avatarLock.unlock(); } void AvatarData::startCapture() { @@ -145,31 +132,25 @@ void AvatarData::endRenderRun() { void AvatarData::startRender() { glm::vec3 pos = getPosition(); glm::quat rot = getOrientation(); - setPosition(_nextPosition, true); - setOrientation(_nextOrientation, true); + setPosition(_nextPosition); + setOrientation(_nextOrientation); updateAttitude(); _nextPosition = pos; _nextOrientation = rot; } void AvatarData::endRender() { - setPosition(_nextPosition, true); - setOrientation(_nextOrientation, true); + setPosition(_nextPosition); + setOrientation(_nextOrientation); updateAttitude(); _nextAllowed = true; } float AvatarData::getTargetScale() const { - if (_referential) { - _referential->update(); - } - return _targetScale; } void AvatarData::setTargetScale(float targetScale, bool overideReferential) { - if (!_referential || overideReferential) { - _targetScale = targetScale; - } + _targetScale = targetScale; } void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { @@ -246,14 +227,14 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); } // referential state - if (_referential != NULL && _referential->isValid()) { - setAtBit(bitItems, HAS_REFERENTIAL); + if (false) { + setAtBit(bitItems, HAS_REFERENTIAL); // XXX leaving this for later use } *destinationBuffer++ = bitItems; - // Add referential - if (_referential != NULL && _referential->isValid()) { - destinationBuffer += _referential->packReferential(destinationBuffer); + // XXX leaving this for later use + if (false) { + // destinationBuffer += _referential->packReferential(destinationBuffer); } // If it is connected, pack up the data @@ -572,21 +553,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->_isEyeTrackerConnected = oneAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); - // Referential + // XXX leaving this for later use Referential if (hasReferential) { - Referential* ref = new Referential(sourceBuffer, this); - if (_referential == NULL || - ref->version() != _referential->version()) { - changeReferential(ref); - } else { - delete ref; - } - _referential->update(); - } else if (_referential != NULL) { - changeReferential(NULL); } - if (_headData->_isFaceTrackerConnected) { float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); @@ -779,10 +749,6 @@ int AvatarData::getReceiveRate() const { return lrint(1.0f / _averageBytesReceived.getEventDeltaAverage()); } -bool AvatarData::hasReferential() { - return _referential != NULL; -} - bool AvatarData::isPlaying() { return _player && _player->isPlaying(); } @@ -946,11 +912,6 @@ void AvatarData::stopPlaying() { } } -void AvatarData::changeReferential(Referential* ref) { - delete _referential; - _referential = ref; -} - void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) { if (index == -1) { return; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 3abd63bf63..8f5416e4fd 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -57,7 +57,6 @@ typedef unsigned long long quint64; #include "PathUtils.h" #include "Player.h" #include "Recorder.h" -#include "Referential.h" using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; @@ -174,7 +173,7 @@ public: const QUuid& getSessionUUID() const { return _sessionUUID; } const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3 position, bool overideReferential = false); + virtual void setPosition(const glm::vec3 position); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -199,7 +198,7 @@ public: void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } glm::quat getOrientation() const; - virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false); + virtual void setOrientation(const glm::quat& orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. @@ -319,7 +318,6 @@ public: void setOwningAvatarMixer(const QWeakPointer& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; } const AABox& getLocalAABox() const { return _localAABox; } - const Referential* getReferential() const { return _referential; } int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); } int getAverageBytesReceivedPerSecond() const; @@ -339,7 +337,6 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; } - bool hasReferential(); bool isPlaying(); bool isPaused(); @@ -369,8 +366,6 @@ protected: glm::vec3 _position = START_LOCATION; glm::vec3 _handPosition; - Referential* _referential; - // Body rotation float _bodyYaw; // degrees float _bodyPitch; // degrees @@ -421,7 +416,6 @@ protected: /// Loads the joint indices, names from the FST file (if any) virtual void updateJointMappings(); - void changeReferential(Referential* ref); glm::vec3 _velocity; glm::vec3 _targetVelocity; diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp deleted file mode 100644 index 0683580093..0000000000 --- a/libraries/avatars/src/Referential.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// -// Referential.cpp -// -// -// Created by Clement on 7/30/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "AvatarData.h" -#include "AvatarLogging.h" -#include "Referential.h" - -Referential::Referential(Type type, AvatarData* avatar) : - _type(type), - _version(0), - _isValid(true), - _avatar(avatar) -{ - if (_avatar == NULL) { - _isValid = false; - return; - } - if (_avatar->hasReferential()) { - _version = _avatar->getReferential()->version() + 1; - } -} - -Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) : - _isValid(false), - _avatar(avatar) -{ - // Since we can't return how many byte have been read - // We take a reference to the pointer as argument and increment the pointer ouself. - sourceBuffer += unpackReferential(sourceBuffer); - // The actual unpacking to the right referential type happens in Avatar::simulate() - // If subclassed, make sure to add a case there to unpack the new referential type correctly -} - -Referential::~Referential() { -} - -int Referential::packReferential(unsigned char* destinationBuffer) const { - const unsigned char* startPosition = destinationBuffer; - destinationBuffer += pack(destinationBuffer); - - unsigned char* sizePosition = destinationBuffer++; // Save a spot for the extra data size - char size = packExtraData(destinationBuffer); - *sizePosition = size; // write extra data size in saved spot here - destinationBuffer += size; - return destinationBuffer - startPosition; -} - -int Referential::unpackReferential(const unsigned char* sourceBuffer) { - const unsigned char* startPosition = sourceBuffer; - sourceBuffer += unpack(sourceBuffer); - char expectedSize = *sourceBuffer++; - char bytesRead = unpackExtraData(sourceBuffer, expectedSize); - _isValid = (bytesRead == expectedSize); - if (!_isValid) { - // Will occur if the new instance unpacking is of the wrong type - qCDebug(avatars) << "[ERROR] Referential extra data overflow"; - } - sourceBuffer += expectedSize; - return sourceBuffer - startPosition; -} - -int Referential::pack(unsigned char* destinationBuffer) const { - unsigned char* startPosition = destinationBuffer; - *destinationBuffer++ = (unsigned char)_type; - memcpy(destinationBuffer, &_version, sizeof(_version)); - destinationBuffer += sizeof(_version); - - destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0); - destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation); - return destinationBuffer - startPosition; -} - -int Referential::unpack(const unsigned char* sourceBuffer) { - const unsigned char* startPosition = sourceBuffer; - _type = (Type)*sourceBuffer++; - if (_type < 0 || _type >= NUM_TYPES) { - _type = UNKNOWN; - } - memcpy(&_version, sourceBuffer, sizeof(_version)); - sourceBuffer += sizeof(_version); - - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); - return sourceBuffer - startPosition; -} - -int Referential::packExtraData(unsigned char *destinationBuffer) const { - // Since we can't interpret that data, just store it in a buffer for later use. - memcpy(destinationBuffer, _extraDataBuffer.data(), _extraDataBuffer.size()); - return _extraDataBuffer.size(); -} - - -int Referential::unpackExtraData(const unsigned char* sourceBuffer, int size) { - _extraDataBuffer.clear(); - _extraDataBuffer.append(reinterpret_cast(sourceBuffer), size); - return size; -} - diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h deleted file mode 100644 index 70edecda62..0000000000 --- a/libraries/avatars/src/Referential.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// Referential.h -// -// -// Created by Clement on 7/30/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Referential_h -#define hifi_Referential_h - -#include -#include - -class AvatarData; - -/// Stores and enforce the relative position of an avatar to a given referential (ie. model, joint, ...) -class Referential { -public: - enum Type { - UNKNOWN, - MODEL, - JOINT, - AVATAR, - - NUM_TYPES - }; - - Referential(const unsigned char*& sourceBuffer, AvatarData* avatar); - virtual ~Referential(); - - Type type() const { return _type; } - quint8 version() const { return _version; } - bool isValid() const { return _isValid; } - bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); } - - glm::vec3 getTranslation() const { return _translation; } - glm::quat getRotation() const { return _rotation; } - QByteArray getExtraData() const { return _extraDataBuffer; } - - virtual void update() {} - int packReferential(unsigned char* destinationBuffer) const; - int unpackReferential(const unsigned char* sourceBuffer); - -protected: - Referential(Type type, AvatarData* avatar); - - // packs the base class data - int pack(unsigned char* destinationBuffer) const; - int unpack(const unsigned char* sourceBuffer); - // virtual functions that pack fthe extra data of subclasses (needs to be reimplemented in subclass) - virtual int packExtraData(unsigned char* destinationBuffer) const; - virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); - - Type _type; - quint8 _version; - bool _isValid; - AvatarData* _avatar; - QByteArray _extraDataBuffer; - - glm::vec3 _refPosition; // position of object in world-frame - glm::quat _refRotation; // rotation of object in world-frame - glm::vec3 _lastRefDimension; // dimension of object when _translation was last computed - - glm::vec3 _translation; // offset of avatar in object local-frame - glm::quat _rotation; // rotation of avatar in object local-frame -}; - - -#endif // hifi_Referential_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5b262b273b..d58c26e72c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -46,7 +46,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _lastEditedFromRemoteInRemoteTime(0), _created(UNKNOWN_CREATED_TIME), _changedOnServer(0), - _transform(), _glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL), _localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA), _density(ENTITY_ITEM_DEFAULT_DENSITY), @@ -1516,7 +1515,6 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act } bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPointer action) { - assertLocked(); assert(action); assert(simulation); auto actionOwnerEntity = action->getOwnerEntity().lock(); @@ -1570,7 +1568,6 @@ bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionI } bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) { - assertWriteLocked(); _previouslyDeletedActions.insert(actionID, usecTimestampNow()); if (_objectActions.contains(actionID)) { if (!simulation) { @@ -1615,7 +1612,6 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { void EntityItem::deserializeActions() { - assertUnlocked(); withWriteLock([&] { deserializeActionsInternal(); }); @@ -1623,8 +1619,6 @@ void EntityItem::deserializeActions() { void EntityItem::deserializeActionsInternal() { - assertWriteLocked(); - quint64 now = usecTimestampNow(); if (!_element) { @@ -1704,7 +1698,6 @@ void EntityItem::deserializeActionsInternal() { } void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { - assertLocked(); foreach(QUuid actionID, _actionsToRemove) { removeActionInternal(actionID, simulation); } @@ -1712,14 +1705,12 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { - assertUnlocked(); withWriteLock([&] { setActionDataInternal(actionData); }); } void EntityItem::setActionDataInternal(QByteArray actionData) { - assertWriteLocked(); if (_allActionsDataCache != actionData) { _allActionsDataCache = actionData; deserializeActionsInternal(); @@ -1728,8 +1719,6 @@ void EntityItem::setActionDataInternal(QByteArray actionData) { } void EntityItem::serializeActions(bool& success, QByteArray& result) const { - assertLocked(); - if (_objectActions.size() == 0) { success = true; result.clear(); @@ -1771,7 +1760,6 @@ const QByteArray EntityItem::getActionDataInternal() const { const QByteArray EntityItem::getActionData() const { QByteArray result; - assertUnlocked(); withReadLock([&] { result = getActionDataInternal(); }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f438e3f28b..e85112d4ef 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "EntityItemID.h" #include "EntityItemPropertiesDefaults.h" @@ -71,31 +72,10 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" -//#if DEBUG -// #define assertLocked() assert(isLocked()) -//#else -// #define assertLocked() -//#endif -// -//#if DEBUG -// #define assertWriteLocked() assert(isWriteLocked()) -//#else -// #define assertWriteLocked() -//#endif -// -//#if DEBUG -// #define assertUnlocked() assert(isUnlocked()) -//#else -// #define assertUnlocked() -//#endif -#define assertLocked() -#define assertUnlocked() -#define assertWriteLocked() - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem : public std::enable_shared_from_this, public ReadWriteLockable { +class EntityItem : public std::enable_shared_from_this, public SpatiallyNestable, public ReadWriteLockable { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -208,11 +188,11 @@ public: inline void setTransform(const Transform& transform) { _transform = transform; requiresRecalcBoxes(); } /// Position in meters (-TREE_SCALE - TREE_SCALE) - inline const glm::vec3& getPosition() const { return _transform.getTranslation(); } - inline void setPosition(const glm::vec3& value) { _transform.setTranslation(value); requiresRecalcBoxes(); } + virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } + virtual void setPosition(const glm::vec3& value) { SpatiallyNestable::setPosition(value); requiresRecalcBoxes(); } - inline const glm::quat& getRotation() const { return _transform.getRotation(); } - inline void setRotation(const glm::quat& rotation) { _transform.setRotation(rotation); requiresRecalcBoxes(); } + virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + virtual void setRotation(const glm::quat& rotation) { SpatiallyNestable::setOrientation(rotation); requiresRecalcBoxes(); } inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } @@ -428,7 +408,6 @@ protected: quint64 _created; quint64 _changedOnServer; - Transform _transform; mutable AABox _cachedAABox; mutable AACube _maxAACube; mutable AACube _minAACube; From 37923e81bbc26db526fd0fe59a7d39faffe18911 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 08:18:10 -0700 Subject: [PATCH 003/165] make SpatiallyNestable::_transform private --- libraries/entities/src/EntityItem.cpp | 8 ++++---- libraries/entities/src/EntityItem.h | 5 ++--- libraries/shared/src/SpatiallyNestable.cpp | 12 ++++++++++++ libraries/shared/src/SpatiallyNestable.h | 18 +++++++++++++++--- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d58c26e72c..3c3f7fd0f1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -79,9 +79,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulated(false) { // explicitly set transform parts to set dirty flags used by batch rendering - _transform.setTranslation(ENTITY_ITEM_DEFAULT_POSITION); - _transform.setRotation(ENTITY_ITEM_DEFAULT_ROTATION); - _transform.setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); + setPosition(ENTITY_ITEM_DEFAULT_POSITION); + setRotation(ENTITY_ITEM_DEFAULT_ROTATION); + setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; @@ -1176,7 +1176,7 @@ void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } - _transform.setScale(value); + setScale(value); requiresRecalcBoxes(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e85112d4ef..4d56b92171 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -184,8 +184,7 @@ public: const Transform getTransformToCenter() const; void setTranformToCenter(const Transform& transform); - inline const Transform& getTransform() const { return _transform; } - inline void setTransform(const Transform& transform) { _transform = transform; requiresRecalcBoxes(); } + virtual void setTransform(const Transform& transform) { SpatiallyNestable::setTransform(transform); requiresRecalcBoxes(); } /// Position in meters (-TREE_SCALE - TREE_SCALE) virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } @@ -204,7 +203,7 @@ public: void setDescription(QString value) { _description = value; } /// Dimensions in meters (0.0 - TREE_SCALE) - inline const glm::vec3& getDimensions() const { return _transform.getScale(); } + inline const glm::vec3& getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); float getGlowLevel() const { return _glowLevel; } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 5e14f398ea..a3e427caa8 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -35,3 +35,15 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) { const Transform& SpatiallyNestable::getTransform() const { return _transform; } + +void SpatiallyNestable::setTransform(const Transform& transform) { + _transform = transform; +} + +const glm::vec3& SpatiallyNestable::getScale() const { + return _transform.getScale(); +} + +void SpatiallyNestable::setScale(const glm::vec3& scale) { + _transform.setScale(scale); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index dd57f27477..294450a980 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -27,20 +27,32 @@ public: SpatiallyNestable(); virtual ~SpatiallyNestable() { } + // world frame + virtual const Transform& getTransform() const; + virtual void setTransform(const Transform& transform); + virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); + virtual const glm::quat& getOrientation() const; virtual void setOrientation(const glm::quat& orientation); - virtual const Transform& getTransform() const; + + virtual const glm::vec3& getScale() const; + virtual void setScale(const glm::vec3& scale); + + // model frame + // ... + protected: - Transform _transform; - QUuid _parentID; // what is this thing's transform relative to? int _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestableWeakPointer _parent; QVector _children; + +private: + Transform _transform; }; From a78f2a95777603a0764da4cc7bca92ba973d652c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 09:48:46 -0700 Subject: [PATCH 004/165] have avatar make use of SpatiallyNestable --- interface/src/Application.cpp | 4 +- interface/src/avatar/Avatar.cpp | 74 +++++++++---------- interface/src/avatar/Avatar.h | 5 +- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/Hand.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 29 ++++---- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 70 +++++++++++------- libraries/avatars/src/AvatarData.h | 29 +++----- 11 files changed, 112 insertions(+), 109 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b6be53876..9b5b83492c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1136,7 +1136,7 @@ void Application::paintGL() { * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); @@ -1144,7 +1144,7 @@ void Application::paintGL() { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 432149d907..92493ab23f 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -90,7 +90,6 @@ Avatar::Avatar(RigPointer rig) : _angularAcceleration(0.0f), _lastOrientation(), _leanScale(0.5f), - _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), _initialized(false), @@ -100,6 +99,7 @@ Avatar::Avatar(RigPointer rig) : // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); + setAvatarScale(1.0f); // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); _handData = static_cast(new Hand(this)); @@ -124,12 +124,12 @@ void Avatar::init() { glm::vec3 Avatar::getChestPosition() const { // for now, let's just assume that the "chest" is halfway between the root and the neck glm::vec3 neckPosition; - return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position; + return _skeletonModel.getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition(); } glm::vec3 Avatar::getNeckPosition() const { glm::vec3 neckPosition; - return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : _position; + return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : getPosition(); } @@ -143,14 +143,14 @@ AABox Avatar::getBounds() const { float Avatar::getLODDistance() const { return DependencyManager::get()->getAvatarLODDistanceMultiplier() * - glm::distance(qApp->getCamera()->getPosition(), _position) / _scale; + glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale(); } void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (_scale != _targetScale) { - setScale(_targetScale); + if (getAvatarScale() != _targetScale) { + setAvatarScale(_targetScale); } // update the billboard render flag @@ -165,7 +165,7 @@ void Avatar::simulate(float deltaTime) { // simple frustum check float boundingRadius = getBillboardSize(); - bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(_position, boundingRadius) != + bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(getPosition(), boundingRadius) != ViewFrustum::OUTSIDE; { @@ -189,11 +189,11 @@ void Avatar::simulate(float deltaTime) { } { PerformanceTimer perfTimer("head"); - glm::vec3 headPosition = _position; + glm::vec3 headPosition = getPosition(); _skeletonModel.getHeadPosition(headPosition); Head* head = getHead(); head->setPosition(headPosition); - head->setScale(_scale); + head->setScale(getAvatarScale()); head->simulate(deltaTime, false, _shouldRenderBillboard); } } @@ -226,7 +226,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) { glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); glm::vec3 myEyePosition = getHead()->getEyePosition(); - return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getScale()); + return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale()); } void Avatar::slamPosition(const glm::vec3& newPosition) { @@ -237,7 +237,7 @@ void Avatar::slamPosition(const glm::vec3& newPosition) { } void Avatar::applyPositionDelta(const glm::vec3& delta) { - _position += delta; + setPosition(getPosition() + delta); _positionDeltaAccumulator += delta; } @@ -307,7 +307,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { auto& batch = *renderArgs->_batch; - if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { + if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); @@ -405,7 +405,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; const float LIGHT_CUTOFF = glm::radians(80.0f); - float distance = BASE_LIGHT_DISTANCE * _scale; + float distance = BASE_LIGHT_DISTANCE * getAvatarScale(); glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f); glm::quat orientation = getOrientation(); foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { @@ -435,7 +435,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { static const float INDICATOR_OFFSET = 0.22f; static const float INDICATOR_RADIUS = 0.03f; static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + INDICATOR_OFFSET, _position.z); + glm::vec3 position = glm::vec3(getPosition().x, getDisplayNamePosition().y + INDICATOR_OFFSET, getPosition().z); Transform transform; transform.setTranslation(position); transform.postScale(INDICATOR_RADIUS); @@ -467,7 +467,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); @@ -477,7 +477,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } @@ -507,7 +507,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { Transform transform; - transform.setTranslation(_position); + transform.setTranslation(getPosition()); transform.setScale(height); transform.postScale(sphereRadius); DependencyManager::get()->renderSolidSphereInstance(batch, @@ -610,9 +610,9 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { - model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); + model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale()); model->setRotation(jointRotation * attachment.rotation); - model->setScaleToFit(true, _scale * attachment.scale, true); // hack to force rescale + model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale model->setSnapModelToCenter(false); // hack to force resnap model->setSnapModelToCenter(true); model->simulate(deltaTime); @@ -639,14 +639,14 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } // rotate about vertical to face the camera glm::quat rotation = getOrientation(); - glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - _position); + glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - getPosition()); rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f)); // compute the size from the billboard camera parameters and scale float size = getBillboardSize(); Transform transform; - transform.setTranslation(_position); + transform.setTranslation(getPosition()); transform.setRotation(rotation); transform.setScale(size); @@ -663,7 +663,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } float Avatar::getBillboardSize() const { - return _scale * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); } #ifdef DEBUG @@ -700,7 +700,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const { DEBUG_VALUE("_position =", _position); DEBUG_VALUE("billboardSize =", billboardSize); - namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION); + namePosition = getPosition() + bodyUpDirection * (billboardSize * HEAD_PROPORTION); } if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) { @@ -803,7 +803,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co } void Avatar::setSkeletonOffset(const glm::vec3& offset) { - const float MAX_OFFSET_LENGTH = _scale * 0.5f; + const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f; float offsetLength = glm::length(offset); if (offsetLength > MAX_OFFSET_LENGTH) { _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; @@ -816,7 +816,7 @@ glm::vec3 Avatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return _position + getOrientation() * FLIP * _skeletonOffset; + return getPosition() + getOrientation() * FLIP * _skeletonOffset; } QVector Avatar::getJointRotations() const { @@ -941,7 +941,7 @@ void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = _position + _scale * (positionToScale - _position); + positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition()); } void Avatar::setFaceModelURL(const QUrl& faceModelURL) { @@ -981,7 +981,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { for (int i = 0; i < attachmentData.size(); i++) { _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); _attachmentModels[i]->setSnapModelToCenter(true); - _attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale); + _attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale); } } @@ -1000,12 +1000,12 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { } // change in position implies movement - glm::vec3 oldPosition = _position; + glm::vec3 oldPosition = getPosition(); int bytesRead = AvatarData::parseDataFromBuffer(buffer); const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } @@ -1068,12 +1068,12 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g } } -void Avatar::setScale(float scale) { - _scale = scale; - - if (_targetScale * (1.0f - RESCALING_TOLERANCE) < _scale && - _scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { - _scale = _targetScale; +void Avatar::setAvatarScale(float scale) { + if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale && + scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { + setScale(glm::vec3(_targetScale)); + } else { + setScale(glm::vec3(scale)); } } @@ -1088,7 +1088,7 @@ float Avatar::getHeadHeight() const { // HACK: We have a really odd case when fading out for some models where this value explodes float result = extents.maximum.y - extents.minimum.y; - if (result >= 0.0f && result < 100.0f * _scale ) { + if (result >= 0.0f && result < 100.0f * getAvatarScale() ) { return result; } } @@ -1096,7 +1096,7 @@ float Avatar::getHeadHeight() const { extents = _skeletonModel.getMeshExtents(); glm::vec3 neckPosition; if (!extents.isEmpty() && extents.isValid() && _skeletonModel.getNeckPosition(neckPosition)) { - return extents.maximum.y / 2.0f - neckPosition.y + _position.y; + return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y; } const float DEFAULT_HEAD_HEIGHT = 0.25f; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 9a46a145c2..2b7d27b2e3 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -103,7 +103,7 @@ public: const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } const QVector& getAttachmentModels() const { return _attachmentModels; } glm::vec3 getChestPosition() const; - float getScale() const { return _scale; } + float getAvatarScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } Hand* getHand() { return static_cast(_handData); } @@ -207,7 +207,6 @@ protected: glm::quat _lastOrientation; float _leanScale; - float _scale; glm::vec3 _worldUpDirection; float _stringLength; bool _moving; ///< set when position is changing @@ -219,7 +218,7 @@ protected: glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void setScale(float scale); + void setAvatarScale(float scale); void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 5f0ac435e0..f42cdc200b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -151,7 +151,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->startUpdate(); - avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); if (avatar->getTargetScale() < MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 0eeb7222b6..a8d09aff69 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -43,7 +43,7 @@ void Hand::simulate(float deltaTime, bool isMine) { void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { float avatarScale = 1.0f; if (_owningAvatar) { - avatarScale = _owningAvatar->getScale(); + avatarScale = _owningAvatar->getAvatarScale(); } const float alpha = 1.0f; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3f6a6a1e77..8b9d89eeaa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -129,11 +129,11 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { CameraMode mode = qApp->getCamera()->getMode(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer - glm::vec3 oldPosition = _position; - _position = getSkeletonPosition(); + glm::vec3 oldPosition = getPosition(); + setPosition(getSkeletonPosition()); QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll); // copy the correct position back - _position = oldPosition; + setPosition(oldPosition); return array; } return AvatarData::toByteArray(cullSmallChanges, sendAll); @@ -228,9 +228,9 @@ void MyAvatar::simulate(float deltaTime) { _player->play(); } - if (_scale != _targetScale) { - float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; - setScale(scale); + if (getAvatarScale() != _targetScale) { + float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale; + setAvatarScale(scale); } { @@ -277,10 +277,10 @@ void MyAvatar::simulate(float deltaTime) { Head* head = getHead(); glm::vec3 headPosition; if (!_skeletonModel.getHeadPosition(headPosition)) { - headPosition = _position; + headPosition = getPosition(); } head->setPosition(headPosition); - head->setScale(_scale); + head->setScale(getAvatarScale()); head->simulate(deltaTime, true); } @@ -846,7 +846,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setScale(_scale); + setAvatarScale(getAvatarScale()); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); @@ -992,7 +992,8 @@ void MyAvatar::updateLookAtTargetAvatar() { bool isCurrentTarget = avatar->getIsLookAtTarget(); float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); avatar->setIsLookAtTarget(false); - if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getScale())) { + if (!avatar->isMyAvatar() && avatar->isInitialized() && + (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) { float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; @@ -1228,7 +1229,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return _position + getOrientation() * FLIP * _skeletonOffset; + return getPosition() + getOrientation() * FLIP * _skeletonOffset; } return Avatar::getPosition(); } @@ -1464,7 +1465,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * _scale); + return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1618,11 +1619,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (isHovering) { // we're flying --> complex acceleration curve with high max speed float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = _scale * MAX_KEYBOARD_MOTOR_SPEED; + float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = _scale * MAX_BOOST_SPEED; + const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED; if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 4e5dd0da0c..c6164978ef 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -416,7 +416,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){ result = position + direction * t; return true; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4ba248c76c..3a222ce15a 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -189,7 +189,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); - ui.avatarScaleSpin->setValue(myAvatar->getScale()); + ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale()); ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 02d432ea81..1b1c48c3ca 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { glm::vec3 myAvatarPosition = avatar->getPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getScale(); + float myAvatarScale = avatar->getAvatarScale(); Transform transform = Transform(); transform.setTranslation(myAvatarPosition); transform.setRotation(glm::angleAxis(angle, axis)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a4d506a748..6f4c89abe7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -38,11 +38,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); AvatarData::AvatarData() : _sessionUUID(), - _position(0.0f), _handPosition(0.0f), - _bodyYaw(-90.0f), - _bodyPitch(0.0f), - _bodyRoll(0.0f), _targetScale(1.0f), _handState(0), _keyState(NO_KEY_DOWN), @@ -61,7 +57,9 @@ AvatarData::AvatarData() : _targetVelocity(0.0f), _localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE) { - + setBodyPitch(0.0f); + setBodyYaw(-90.0f); + setBodyRoll(0.0f); } AvatarData::~AvatarData() { @@ -79,23 +77,37 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { return _defaultFullAvatarModelUrl; } -const glm::vec3& AvatarData::getPosition() const { - return _position; +float AvatarData::getBodyYaw() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.y; } -void AvatarData::setPosition(const glm::vec3 position) { - _position = position; +void AvatarData::setBodyYaw(float bodyYaw) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.y = bodyYaw; + setOrientation(glm::quat(glm::radians(eulerAngles))); } -glm::quat AvatarData::getOrientation() const { - return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); +float AvatarData::getBodyPitch() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.x; } -void AvatarData::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; +void AvatarData::setBodyPitch(float bodyPitch) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.x = bodyPitch; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyRoll() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.z; +} + +void AvatarData::setBodyRoll(float bodyRoll) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.z = bodyRoll; + setOrientation(glm::quat(glm::radians(eulerAngles))); } // There are a number of possible strategies for this set of tools through endRender, below. @@ -162,12 +174,12 @@ void AvatarData::setClampedTargetScale(float targetScale, bool overideReferentia } glm::vec3 AvatarData::getHandPosition() const { - return getOrientation() * _handPosition + _position; + return getOrientation() * _handPosition + getPosition(); } void AvatarData::setHandPosition(const glm::vec3& handPosition) { // store relative to position/orientation - _handPosition = glm::inverse(getOrientation()) * (handPosition - _position); + _handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition()); } QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { @@ -188,13 +200,14 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; - memcpy(destinationBuffer, &_position, sizeof(_position)); - destinationBuffer += sizeof(_position); + const glm::vec3& position = getPosition(); + memcpy(destinationBuffer, &position, sizeof(position)); + destinationBuffer += sizeof(position); - // Body rotation (NOTE: This needs to become a quaternion to save two bytes) - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyYaw); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyPitch); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll); + // Body rotation + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyYaw()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyPitch()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyRoll()); // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); @@ -487,11 +500,12 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } return maxAvailableSize; } - if (_bodyYaw != yaw || _bodyPitch != pitch || _bodyRoll != roll) { + + // TODO is this safe? will the floats not exactly match? + if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; - _bodyYaw = yaw; - _bodyPitch = pitch; - _bodyRoll = roll; + glm::vec3 eulerAngles(pitch, yaw, roll); + setOrientation(glm::quat(glm::radians(eulerAngles))); } // scale diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8f5416e4fd..a7d216be6d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -50,6 +50,7 @@ typedef unsigned long long quint64; #include #include #include +#include #include "AABox.h" #include "HandData.h" @@ -134,7 +135,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject { +class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -172,9 +173,6 @@ public: const QUuid& getSessionUUID() const { return _sessionUUID; } - const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3 position); - glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -189,16 +187,13 @@ public: /// \return number of bytes parsed virtual int parseDataFromBuffer(const QByteArray& buffer); - // Body Rotation (degrees) - float getBodyYaw() const { return _bodyYaw; } - void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; } - float getBodyPitch() const { return _bodyPitch; } - void setBodyPitch(float bodyPitch) { _bodyPitch = bodyPitch; } - float getBodyRoll() const { return _bodyRoll; } - void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } - - glm::quat getOrientation() const; - virtual void setOrientation(const glm::quat& orientation); + // Body Rotation (degrees) + float getBodyYaw() const; + void setBodyYaw(float bodyYaw); + float getBodyPitch() const; + void setBodyPitch(float bodyPitch); + float getBodyRoll() const; + void setBodyRoll(float bodyRoll); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. @@ -363,13 +358,7 @@ public slots: protected: QUuid _sessionUUID; - glm::vec3 _position = START_LOCATION; glm::vec3 _handPosition; - - // Body rotation - float _bodyYaw; // degrees - float _bodyPitch; // degrees - float _bodyRoll; // degrees glm::vec3 _nextPosition {}; glm::quat _nextOrientation {}; From bc99ef778cb16c94fb48875e30eb5940db6238ae Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 20 Oct 2015 12:04:29 -0700 Subject: [PATCH 005/165] change how render engine is told about model position changes --- interface/src/Application.cpp | 140 +++++++++--------- interface/src/avatar/Avatar.cpp | 44 +++--- interface/src/avatar/Avatar.h | 3 + interface/src/avatar/AvatarManager.cpp | 26 ++-- interface/src/avatar/AvatarUpdate.cpp | 10 +- libraries/avatars/src/AvatarData.cpp | 58 ++------ libraries/avatars/src/AvatarData.h | 22 +-- .../render-utils/src/MeshPartPayload.cpp | 22 ++- libraries/render-utils/src/MeshPartPayload.h | 10 +- libraries/render-utils/src/Model.cpp | 62 +++++--- libraries/render-utils/src/Model.h | 11 +- 11 files changed, 213 insertions(+), 195 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b5b83492c..cab189e7a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1086,75 +1086,77 @@ void Application::paintGL() { { PerformanceTimer perfTimer("CameraUpdates"); - auto myAvatar = getMyAvatar(); - - myAvatar->startCapture(); - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); - cameraMenuChanged(); - } - - // The render mode is default or mirror if the camera is in mirror mode, assigned further below - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - - // Always use the default eye position, not the actual head eye position. - // Using the latter will cause the camera to wobble with idle animations, - // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - if (isHMDMode()) { - mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); + myAvatar->withReadLock([&] { + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, + myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, + !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); + cameraMenuChanged(); } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); - auto worldBoomOffset = myAvatar->getOrientation() * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); - _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); - } else { - _myCamera.setRotation(myAvatar->getHead()->getOrientation()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() - * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + + // The render mode is default or mirror if the camera is in mirror mode, assigned further below + renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; + + // Always use the default eye position, not the actual head eye position. + // Using the latter will cause the camera to wobble with idle animations, + // or with changes from the face tracker + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + if (isHMDMode()) { + mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setPosition(extractTranslation(camMat)); + _myCamera.setRotation(glm::quat_cast(camMat)); } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getOrientation() - * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); } + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + if (isHMDMode()) { + auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); + auto worldBoomOffset = myAvatar->getOrientation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); + _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); + } else { + _myCamera.setRotation(myAvatar->getHead()->getOrientation()); + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getOrientation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } + } + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + (myAvatar->getOrientation() * + glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + } else { + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + } + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); - glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); - } else { - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + // Update camera position + if (!isHMDMode()) { + _myCamera.update(1.0f / _fps); } - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - } - // Update camera position - if (!isHMDMode()) { - _myCamera.update(1.0f / _fps); - } - myAvatar->endCapture(); + }); } // Primary rendering pass @@ -3386,9 +3388,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering. // Then we can move this logic into the Avatar::simulate call. auto myAvatar = getMyAvatar(); - myAvatar->startRender(); - myAvatar->preRender(renderArgs); - myAvatar->endRender(); + myAvatar->withReadLock([&] { + myAvatar->preRender(renderArgs); + }); activeRenderingThread = QThread::currentThread(); @@ -3502,9 +3504,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _renderEngine->setRenderContext(renderContext); // Before the deferred pass, let's try to use the render engine - myAvatar->startRenderRun(); - _renderEngine->run(); - myAvatar->endRenderRun(); + myAvatar->withReadLock([&] { + _renderEngine->run(); + }); auto engineRC = _renderEngine->getRenderContext(); sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 92493ab23f..c70c1a5501 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -303,8 +303,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr_batch; if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) { @@ -375,7 +373,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { - endRender(); return; } @@ -529,7 +526,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { renderDisplayName(batch, frustum, textPosition); } } - endRender(); } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { @@ -993,23 +989,25 @@ void Avatar::setBillboard(const QByteArray& billboard) { } int Avatar::parseDataFromBuffer(const QByteArray& buffer) { - startUpdate(); - if (!_initialized) { - // now that we have data for this Avatar we are go for init - init(); - } + int bytesRead; - // change in position implies movement - glm::vec3 oldPosition = getPosition(); + withWriteLock([&] { + if (!_initialized) { + // now that we have data for this Avatar we are go for init + init(); + } - int bytesRead = AvatarData::parseDataFromBuffer(buffer); + // change in position implies movement + glm::vec3 oldPosition = getPosition(); - const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; - if (_moving && _motionState) { - _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); - } - endUpdate(); + bytesRead = AvatarData::parseDataFromBuffer(buffer); + + const float MOVE_DISTANCE_THRESHOLD = 0.001f; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; + if (_moving && _motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); + } + }); return bytesRead; } @@ -1201,3 +1199,13 @@ glm::quat Avatar::getRightPalmRotation() { getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); return rightRotation; } + +void Avatar::setPosition(const glm::vec3& position) { + AvatarData::setPosition(position); + updateAttitude(); +} + +void Avatar::setOrientation(const glm::quat& orientation) { + AvatarData::setOrientation(orientation); + updateAttitude(); +} diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2b7d27b2e3..2366e79c5b 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -174,6 +174,9 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); + public slots: glm::vec3 getLeftPalmPosition(); glm::vec3 getLeftPalmVelocity(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index f42cdc200b..16e136f9d1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -129,9 +129,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { _avatarFades.push_back(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); } else { - avatar->startUpdate(); - avatar->simulate(deltaTime); - avatar->endUpdate(); + avatar->withWriteLock([&] { + avatar->simulate(deltaTime); + }); ++avatarIterator; } } @@ -150,16 +150,16 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); - avatar->startUpdate(); - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); - if (avatar->getTargetScale() < MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, pendingChanges); - fadingIterator = _avatarFades.erase(fadingIterator); - } else { - avatar->simulate(deltaTime); - ++fadingIterator; - } - avatar->endUpdate(); + avatar->withWriteLock([&] { + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); + if (avatar->getTargetScale() < MIN_FADE_SCALE) { + avatar->removeFromScene(*fadingIterator, scene, pendingChanges); + fadingIterator = _avatarFades.erase(fadingIterator); + } else { + avatar->simulate(deltaTime); + ++fadingIterator; + } + }); } scene->enqueuePendingChanges(pendingChanges); } diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index acdb251950..a32948f598 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -56,11 +56,11 @@ bool AvatarUpdate::process() { //gets current lookat data, removes missing avatars, etc. manager->updateOtherAvatars(deltaSeconds); - myAvatar->startUpdate(); - qApp->updateMyAvatarLookAtPosition(); - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - manager->updateMyAvatar(deltaSeconds); - myAvatar->endUpdate(); + myAvatar->withWriteLock([&] { + qApp->updateMyAvatarLookAtPosition(); + // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + manager->updateMyAvatar(deltaSeconds); + }); if (!isThreaded()) { return true; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6f4c89abe7..9b2967cf5d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -110,51 +110,25 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } +void AvatarData::setPosition(const glm::vec3& position) { + withWriteLock([&] { + SpatiallyNestable::setPosition(position); + }); +} + +void AvatarData::setOrientation(const glm::quat& orientation) { + withWriteLock([&] { + SpatiallyNestable::setOrientation(orientation); + }); +} + // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { - avatarLock.lock(); - setPosition(position); - setOrientation(orientation); - avatarLock.unlock(); -} -void AvatarData::startCapture() { - avatarLock.lock(); - assert(_nextAllowed); - _nextAllowed = false; - _nextPosition = getPosition(); - _nextOrientation = getOrientation(); -} -void AvatarData::endCapture() { - avatarLock.unlock(); -} -void AvatarData::startUpdate() { - avatarLock.lock(); -} -void AvatarData::endUpdate() { - avatarLock.unlock(); -} -void AvatarData::startRenderRun() { - // I'd like to get rid of this and just (un)lock at (end-)startRender. - // But somehow that causes judder in rotations. - avatarLock.lock(); -} -void AvatarData::endRenderRun() { - avatarLock.unlock(); -} -void AvatarData::startRender() { - glm::vec3 pos = getPosition(); - glm::quat rot = getOrientation(); - setPosition(_nextPosition); - setOrientation(_nextOrientation); + withWriteLock([&] { + SpatiallyNestable::setPosition(position); + SpatiallyNestable::setOrientation(orientation); + }); updateAttitude(); - _nextPosition = pos; - _nextOrientation = rot; -} -void AvatarData::endRender() { - setPosition(_nextPosition); - setOrientation(_nextOrientation); - updateAttitude(); - _nextAllowed = true; } float AvatarData::getTargetScale() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a7d216be6d..9f8224caf8 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -44,13 +44,13 @@ typedef unsigned long long quint64; #include #include #include -#include #include #include #include #include #include +#include #include "AABox.h" #include "HandData.h" @@ -59,6 +59,7 @@ typedef unsigned long long quint64; #include "Player.h" #include "Recorder.h" + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -135,7 +136,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject, public SpatiallyNestable { +class AvatarData : public QObject, public ReadWriteLockable, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -195,15 +196,10 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); + void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. - void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. - void endCapture(); - void startUpdate(); // start/end of update iteration - void endUpdate(); - void startRender(); // start/end of rendering of this object - void startRenderRun(); // start/end of entire scene. - void endRenderRun(); - void endRender(); virtual void updateAttitude() {} // Tell skeleton mesh about changes glm::quat getHeadOrientation() const { return _headData->getOrientation(); } @@ -360,10 +356,6 @@ protected: QUuid _sessionUUID; glm::vec3 _handPosition; - glm::vec3 _nextPosition {}; - glm::quat _nextOrientation {}; - bool _nextAllowed {true}; - // Body scale float _targetScale; @@ -413,8 +405,6 @@ protected: SimpleMovingAverage _averageBytesReceived; - QMutex avatarLock; // Name is redundant, but it aids searches. - private: static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 80327b7e54..294bf015e0 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -39,9 +39,14 @@ namespace render { using namespace render; -MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : - model(model), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) -{ +MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, + glm::vec3 position, glm::quat orientation) : + model(model), + meshIndex(meshIndex), + partIndex(partIndex), + _shapeID(shapeIndex), + _modelPosition(position), + _modelOrientation(orientation) { initCache(); } @@ -66,6 +71,11 @@ void MeshPartPayload::initCache() { } +void MeshPartPayload::updateModelLocation(glm::vec3 position, glm::quat orientation) { + _modelPosition = position; + _modelOrientation = orientation; +} + render::ItemKey MeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -91,7 +101,7 @@ render::ItemKey MeshPartPayload::getKey() const { render::Item::Bound MeshPartPayload::getBound() const { // NOTE: we can't cache this bounds because we need to handle the case of a moving // entity or mesh part. - return model->getPartBounds(meshIndex, partIndex); + return model->getPartBounds(meshIndex, partIndex, _modelPosition, _modelOrientation); } void MeshPartPayload::drawCall(gpu::Batch& batch) const { @@ -222,7 +232,7 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati transform = Transform(state.clusterMatrices[0]); } } - transform.preTranslate(model->_translation); + transform.preTranslate(_modelPosition); batch.setModelTransform(transform); } @@ -247,7 +257,7 @@ void MeshPartPayload::render(RenderArgs* args) const { } // Back to model to update the cluster matrices right now - model->updateClusterMatrices(); + model->updateClusterMatrices(_modelPosition, _modelOrientation); const FBXMesh& mesh = geometry.meshes.at(meshIndex); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 51e577e7c7..b29d9510d1 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -24,7 +24,7 @@ class Model; class MeshPartPayload { public: - MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); + MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, glm::vec3 position, glm::quat orientation); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; @@ -33,7 +33,11 @@ public: int meshIndex; int partIndex; int _shapeID; - + glm::vec3 _modelPosition; + glm::quat _modelOrientation; + + void updateModelLocation(glm::vec3 position, glm::quat orientation); + // Render Item interface render::ItemKey getKey() const; render::Item::Bound getBound() const; @@ -63,4 +67,4 @@ namespace render { template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); } -#endif // hifi_MeshPartPayload_h \ No newline at end of file +#endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 38f5ffdabe..9c3b8adc17 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -73,13 +73,16 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; + void Model::setTranslation(const glm::vec3& translation) { _translation = translation; + enqueueLocationChange(); } - + void Model::setRotation(const glm::quat& rotation) { _rotation = rotation; -} + enqueueLocationChange(); +} void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); @@ -107,6 +110,20 @@ void Model::setOffset(const glm::vec3& offset) { _snappedToRegistrationPoint = false; } +void Model::enqueueLocationChange() { + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + render::PendingChanges pendingChanges; + foreach (auto itemID, _renderItems.keys()) { + pendingChanges.updateItem(itemID, [=](MeshPartPayload& data) { + data.updateModelLocation(_translation, _rotation); + data.model->_needsUpdateClusterMatrices = true; + }); + } + + scene->enqueuePendingChanges(pendingChanges); +} + QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; for (int i = 0; i < geometry.joints.size(); ++i) { @@ -378,7 +395,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { _calculatedMeshPartBoxes.clear(); for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); - Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); + Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation); _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); @@ -659,7 +676,8 @@ Extents Model::getUnscaledMeshExtents() const { return scaledExtents; } -Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { +Extents Model::calculateScaledOffsetExtents(const Extents& extents, + glm::vec3 modelPosition, glm::quat modelOrientation) const { // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); @@ -667,17 +685,17 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), ((maximum + _offset) * _scale) }; - Extents rotatedExtents = scaledOffsetExtents.getRotated(_rotation); + Extents rotatedExtents = scaledOffsetExtents.getRotated(modelOrientation); - Extents translatedExtents = { rotatedExtents.minimum + _translation, - rotatedExtents.maximum + _translation }; + Extents translatedExtents = { rotatedExtents.minimum + modelPosition, + rotatedExtents.maximum + modelPosition }; return translatedExtents; } /// Returns the world space equivalent of some box in model space. -AABox Model::calculateScaledOffsetAABox(const AABox& box) const { - return AABox(calculateScaledOffsetExtents(Extents(box))); +AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const { + return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation)); } glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { @@ -971,7 +989,7 @@ void Model::simulateInternal(float deltaTime) { glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; updateRig(deltaTime, parentTransform); } -void Model::updateClusterMatrices() { +void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation) { PerformanceTimer perfTimer("Model::updateClusterMatrices"); if (!_needsUpdateClusterMatrices) { @@ -985,7 +1003,7 @@ void Model::updateClusterMatrices() { glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig->getJointTransform(geometry.neckJointIndex) * zeroScale; - glm::mat4 modelToWorld = glm::mat4_cast(_rotation); + glm::mat4 modelToWorld = glm::mat4_cast(modelOrientation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -1007,16 +1025,21 @@ void Model::updateClusterMatrices() { // Once computed the cluster matrices, update the buffer(s) if (mesh.clusters.size() > 1) { if (!state.clusterBuffer) { - state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.clusterMatrices.constData()); + state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); } else { - state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.clusterMatrices.constData()); + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); } if (!_cauterizeBoneSet.empty() && (state.cauterizedClusterMatrices.size() > 1)) { if (!state.cauterizedClusterBuffer) { - state.cauterizedClusterBuffer = std::make_shared(state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); + state.cauterizedClusterBuffer = + std::make_shared(state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); } else { - state.cauterizedClusterBuffer->setSubData(0, state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); + state.cauterizedClusterBuffer->setSubData(0, state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); } } } @@ -1109,7 +1132,7 @@ void Model::deleteGeometry() { _blendedBlendshapeCoefficients.clear(); } -AABox Model::getPartBounds(int meshIndex, int partIndex) { +AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation) { if (!_geometry || !_geometry->isLoaded()) { return AABox(); @@ -1120,7 +1143,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { bool isSkinned = state.clusterMatrices.size() > 1; if (isSkinned) { // if we're skinned return the entire mesh extents because we can't know for sure our clusters don't move us - return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents); + return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents, modelPosition, modelOrientation); } } if (_geometry->getFBXGeometry().meshes.size() > meshIndex) { @@ -1138,7 +1161,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { // // If we not skinned use the bounds of the subMesh for all it's parts const FBXMesh& mesh = _geometry->getFBXGeometry().meshes.at(meshIndex); - return calculateScaledOffsetExtents(mesh.meshExtents); + return calculateScaledOffsetExtents(mesh.meshExtents, modelPosition, modelOrientation); } return AABox(); } @@ -1164,7 +1187,7 @@ void Model::segregateMeshGroups() { // Create the render payloads int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { - _renderItemsSet << std::make_shared(this, i, partIndex, shapeID); + _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, _translation, _rotation); shapeID++; } } @@ -1184,6 +1207,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { _renderItems.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); pendingChanges.updateItem(item, [&](MeshPartPayload& data) { + data.updateModelLocation(_translation, _rotation); data.model->_needsUpdateClusterMatrices = true; }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e3a9ce9ac3..68468642da 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -86,7 +86,8 @@ public: bool isVisible() const { return _isVisible; } - AABox getPartBounds(int meshIndex, int partIndex); + void updateRenderItems(); + AABox getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation); bool maybeStartBlender(); @@ -109,7 +110,7 @@ public: bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } virtual void simulate(float deltaTime, bool fullUpdate = true); - void updateClusterMatrices(); + void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation); /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } @@ -183,6 +184,8 @@ public: void setScale(const glm::vec3& scale); const glm::vec3& getScale() const { return _scale; } + void enqueueLocationChange(); + /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to @@ -210,10 +213,10 @@ protected: Extents getUnscaledMeshExtents() const; /// Returns the scaled equivalent of some extents in model space. - Extents calculateScaledOffsetExtents(const Extents& extents) const; + Extents calculateScaledOffsetExtents(const Extents& extents, glm::vec3 modelPosition, glm::quat modelOrientation) const; /// Returns the world space equivalent of some box in model space. - AABox calculateScaledOffsetAABox(const AABox& box) const; + AABox calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const; /// Returns the scaled equivalent of a point in model space. glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; From 264b65813211eee445b936994494a406844ebd14 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 11:05:48 -0700 Subject: [PATCH 006/165] hook up entities and avatars to SpatialParentFinder --- .../src/entities/AssignmentParentFinder.cpp | 22 +++++ .../src/entities/AssignmentParentFinder.h | 34 +++++++ .../src/entities/EntityServer.cpp | 5 + interface/src/Application.cpp | 4 + interface/src/InterfaceParentFinder.cpp | 35 +++++++ interface/src/InterfaceParentFinder.h | 27 ++++++ libraries/entities/src/EntityItem.cpp | 13 ++- libraries/entities/src/EntityItem.h | 4 - libraries/shared/src/SpatialParentFinder.h | 39 ++++++++ libraries/shared/src/SpatiallyNestable.cpp | 96 +++++++++++++++++-- libraries/shared/src/SpatiallyNestable.h | 37 +++++-- 11 files changed, 296 insertions(+), 20 deletions(-) create mode 100644 assignment-client/src/entities/AssignmentParentFinder.cpp create mode 100644 assignment-client/src/entities/AssignmentParentFinder.h create mode 100644 interface/src/InterfaceParentFinder.cpp create mode 100644 interface/src/InterfaceParentFinder.h create mode 100644 libraries/shared/src/SpatialParentFinder.h diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp new file mode 100644 index 0000000000..6a66aa3f73 --- /dev/null +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -0,0 +1,22 @@ +// +// AssignmentParentFinder.cpp +// assignment-client/src/ +// +// Created by Seth Alves on 2015-10-22 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AssignmentParentFinder.h" + +SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const { + assert(false); + SpatiallyNestableWeakPointer parent; + // search entities + _tree->withReadLock([&] { + parent = _tree->findEntityByEntityItemID(parentID); + }); + return parent; +} diff --git a/assignment-client/src/entities/AssignmentParentFinder.h b/assignment-client/src/entities/AssignmentParentFinder.h new file mode 100644 index 0000000000..4d2e080443 --- /dev/null +++ b/assignment-client/src/entities/AssignmentParentFinder.h @@ -0,0 +1,34 @@ +// +// AssignmentParentFinder.h +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AssignmentParentFinder_h +#define hifi_AssignmentParentFinder_h + +#include +#include + +#include +#include + +// This interface is used to turn a QUuid into a pointer to a "parent" -- something that children can +// be spatially relative to. At this point, this means either an EntityItem or an Avatar. + +class AssignmentParentFinder : public SpatialParentFinder { +public: + AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { } + virtual ~AssignmentParentFinder() { } + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; + +protected: + EntityTreePointer _tree; +}; + +#endif // hifi_AssignmentParentFinder_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index f2a4c2664a..5c9b120a3a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -16,6 +16,7 @@ #include "EntityServer.h" #include "EntityServerConsts.h" #include "EntityNodeData.h" +#include "AssignmentParentFinder.h" const char* MODEL_SERVER_NAME = "Entity"; const char* MODEL_SERVER_LOGGING_TARGET_NAME = "entity-server"; @@ -60,6 +61,10 @@ OctreePointer EntityServer::createTree() { tree->setSimulation(simpleSimulation); _entitySimulation = simpleSimulation; } + + DependencyManager::registerInheritance(); + DependencyManager::set(tree); + return tree; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cab189e7a0..1a02cf912e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -136,6 +136,8 @@ #include "ui/Stats.h" #include "ui/UpdateDialog.h" #include "Util.h" +#include "InterfaceParentFinder.h" + // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -286,6 +288,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); + DependencyManager::registerInheritance(); Setting::init(); @@ -327,6 +330,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); return true; } diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp new file mode 100644 index 0000000000..f8604b15d3 --- /dev/null +++ b/interface/src/InterfaceParentFinder.cpp @@ -0,0 +1,35 @@ +// +// InterfaceParentFinder.cpp +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include + +#include "InterfaceParentFinder.h" + +SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { + SpatiallyNestableWeakPointer parent; + + // search entities + EntityTreeRenderer* treeRenderer = qApp->getEntities(); + EntityTreePointer tree = treeRenderer->getTree(); + tree->withReadLock([&] { + parent = tree->findEntityByEntityItemID(parentID); + }); + if (!parent.expired()) { + return parent; + } + + // search avatars + QSharedPointer avatarManager = DependencyManager::get(); + return avatarManager->getAvatarBySessionID(parentID); +} diff --git a/interface/src/InterfaceParentFinder.h b/interface/src/InterfaceParentFinder.h new file mode 100644 index 0000000000..c8e8d4ed9f --- /dev/null +++ b/interface/src/InterfaceParentFinder.h @@ -0,0 +1,27 @@ +// +// InterfaceParentFinder.h +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_InterfaceParentFinder_h +#define hifi_InterfaceParentFinder_h + +#include +#include + +#include + +class InterfaceParentFinder : public SpatialParentFinder { +public: + InterfaceParentFinder() { } + virtual ~InterfaceParentFinder() { } + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; +}; + +#endif // hifi_InterfaceParentFinder_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c2e6a90ca8..0a47a004fd 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -37,8 +37,8 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : + SpatiallyNestable(entityItemID), _type(EntityTypes::Unknown), - _id(entityItemID), _lastSimulated(0), _lastUpdated(0), _lastEdited(0), @@ -1723,6 +1723,9 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionData to " << actionData.size() << "bytes."; + } withWriteLock([&] { setActionDataInternal(actionData); }); @@ -1730,8 +1733,16 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { if (_allActionsDataCache != actionData) { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionDataInternal to " << actionData.size() << "bytes."; + } + _allActionsDataCache = actionData; deserializeActionsInternal(); + } else { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionDataInternal NOT setting to " << actionData.size() << "bytes."; + } } checkWaitingToRemove(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 185d052bbd..79fe438c39 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -89,9 +89,6 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); - // ID and EntityItemID related methods - const QUuid& getID() const { return _id; } - void setID(const QUuid& id) { _id = id; } EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity @@ -399,7 +396,6 @@ protected: static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; - QUuid _id; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, // and physics changes quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h new file mode 100644 index 0000000000..9cadbaf8ce --- /dev/null +++ b/libraries/shared/src/SpatialParentFinder.h @@ -0,0 +1,39 @@ +// +// SpatialParentFinder.h +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SpatialParentFinder_h +#define hifi_SpatialParentFinder_h + +#include + +#include "DependencyManager.h" + +class SpatiallyNestable; +using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestablePointer = std::shared_ptr; +class SpatialParentFinder; +using SpatialParentFinderPointer = std::shared_ptr; +class SpatialParentFinder : public Dependency { + + + +// This interface is used to turn a QUuid into a pointer to a "parent" -- something that children can +// be spatially relative to. At this point, this means either an EntityItem or an Avatar. + + +public: + SpatialParentFinder() { } + virtual ~SpatialParentFinder() { } + + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const = 0; +}; + +#endif // hifi_SpatialParentFinder_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a3e427caa8..4cdf61061c 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -9,35 +9,84 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DependencyManager.h" #include "SpatiallyNestable.h" -SpatiallyNestable::SpatiallyNestable() : - _transform() { +Transform SpatiallyNestable::getParentTransform() const { + Transform result; + SpatiallyNestablePointer parent = getParentPointer(); + if (parent) { + Transform parentTransform = parent->getTransform(); + result = parentTransform.setScale(1.0f); + } + return result; } +SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { + SpatiallyNestablePointer parent = _parent.lock(); + + if (!parent && _parentID.isNull()) { + // no parent + return nullptr; + } + + if (parent && parent->getID() == _parentID) { + // parent pointer is up-to-date + return parent; + } + + if (parent && _parentID.isNull()) { + // we have a parent pointer but our _parentID is null + _parent.reset(); + return nullptr; + } + + // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing + QSharedPointer parentFinder = DependencyManager::get(); + _parent = parentFinder->find(_parentID); + return _parent.lock(); +} const glm::vec3& SpatiallyNestable::getPosition() const { - return _transform.getTranslation(); + Transform parentTransformDescaled = getParentTransform(); + glm::mat4 parentMat; + parentTransformDescaled.getMatrix(parentMat); + glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); + _absolutePositionCache = glm::vec3(absPos); + return _absolutePositionCache; } void SpatiallyNestable::setPosition(const glm::vec3& position) { - _transform.setTranslation(position); + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); } const glm::quat& SpatiallyNestable::getOrientation() const { - return _transform.getRotation(); + Transform parentTransformDescaled = getParentTransform(); + _absoluteRotationCache = parentTransformDescaled.getRotation() * getLocalOrientation(); + return _absoluteRotationCache; } void SpatiallyNestable::setOrientation(const glm::quat& orientation) { - _transform.setRotation(orientation); + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); } const Transform& SpatiallyNestable::getTransform() const { - return _transform; + Transform parentTransform = getParentTransform(); + Transform::mult(_worldTransformCache, parentTransform, _transform); + return _worldTransformCache; } void SpatiallyNestable::setTransform(const Transform& transform) { - _transform = transform; + Transform parentTransform = getParentTransform(); + Transform::inverseMult(_transform, parentTransform, transform); } const glm::vec3& SpatiallyNestable::getScale() const { @@ -47,3 +96,34 @@ const glm::vec3& SpatiallyNestable::getScale() const { void SpatiallyNestable::setScale(const glm::vec3& scale) { _transform.setScale(scale); } + +const Transform& SpatiallyNestable::getLocalTransform() const { + return _transform; +} + +void SpatiallyNestable::setLocalTransform(const Transform& transform) { +} + +const glm::vec3& SpatiallyNestable::getLocalPosition() const { + return _transform.getTranslation(); +} + +void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { + _transform.setTranslation(position); +} + +const glm::quat& SpatiallyNestable::getLocalOrientation() const { + return _transform.getRotation(); +} + +void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { + _transform.setRotation(orientation); +} + +const glm::vec3& SpatiallyNestable::getLocalScale() const { + return _transform.getScale(); +} + +void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { + _transform.setScale(scale); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 294450a980..e3d3b8dc0d 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -15,22 +15,29 @@ #include #include "Transform.h" +#include "SpatialParentFinder.h" class SpatiallyNestable; -typedef std::weak_ptr SpatiallyNestableWeakPointer; -typedef std::shared_ptr SpatiallyNestablePointer; +using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestablePointer = std::shared_ptr; class SpatiallyNestable { public: - SpatiallyNestable(); + SpatiallyNestable() : _transform() { } + SpatiallyNestable(QUuid id) : _id(id), _transform() { } virtual ~SpatiallyNestable() { } + const QUuid& getID() const { return _id; } + void setID(const QUuid& id) { _id = id; } + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); + Transform getParentTransform() const; + virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); @@ -40,19 +47,35 @@ public: virtual const glm::vec3& getScale() const; virtual void setScale(const glm::vec3& scale); - // model frame - // ... + // object's parent's frame + virtual const Transform& getLocalTransform() const; + virtual void setLocalTransform(const Transform& transform); + virtual const glm::vec3& getLocalPosition() const; + virtual void setLocalPosition(const glm::vec3& position); + + virtual const glm::quat& getLocalOrientation() const; + virtual void setLocalOrientation(const glm::quat& orientation); + + virtual const glm::vec3& getLocalScale() const; + virtual void setLocalScale(const glm::vec3& scale); protected: + QUuid _id; QUuid _parentID; // what is this thing's transform relative to? int _parentJointIndex; // which joint of the parent is this relative to? - SpatiallyNestableWeakPointer _parent; + mutable SpatiallyNestableWeakPointer _parent; QVector _children; private: - Transform _transform; + Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. + SpatiallyNestablePointer getParentPointer() const; + + // these are so we can return by reference + mutable glm::vec3 _absolutePositionCache; + mutable glm::quat _absoluteRotationCache; + mutable Transform _worldTransformCache; }; From 778dc8dc15ddb1831d33c05350fbbc07c0bf62b9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 11:52:56 -0700 Subject: [PATCH 007/165] add parentID and parentJointIndex EntityItemProperties --- libraries/entities/src/EntityItem.cpp | 12 +++++++++++- libraries/entities/src/EntityItemProperties.cpp | 17 +++++++++++++++-- libraries/entities/src/EntityItemProperties.h | 5 +++++ .../entities/src/EntityItemPropertiesMacros.h | 2 ++ libraries/entities/src/EntityPropertyFlags.h | 3 +++ libraries/networking/src/udt/PacketHeaders.cpp | 3 ++- libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 2 ++ libraries/shared/src/SpatiallyNestable.h | 16 +++++++++++----- 9 files changed, 52 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0a47a004fd..c3c0204aee 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -134,6 +134,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; requestedProperties += PROP_ACTION_DATA; + requestedProperties += PROP_PARENT_ID; + requestedProperties += PROP_PARENT_JOINT_INDEX; return requestedProperties; } @@ -268,7 +270,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData()); - + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, getParentID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -715,6 +718,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef overwriteLocalData = oldOverwrite; } + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1062,6 +1068,8 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); properties._defaultSettings = false; @@ -1124,6 +1132,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); if (somethingChanged) { uint64_t now = usecTimestampNow(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 19c8f779b4..6755149944 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -261,6 +261,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); CHECK_PROPERTY_CHANGE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); changedProperties += _animation.getChangedProperties(); changedProperties += _atmosphere.getChangedProperties(); @@ -467,6 +469,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable } + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -591,6 +596,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(yPNeighborID, EntityItemID, setYPNeighborID); COPY_PROPERTY_FROM_QSCRIPTVALUE(zPNeighborID, EntityItemID, setZPNeighborID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); + _lastEdited = usecTimestampNow(); } @@ -906,7 +914,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); - + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); if (properties.getType() == EntityTypes::Web) { APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); @@ -1191,7 +1200,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); if (properties.getType() == EntityTypes::Web) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); @@ -1446,6 +1456,9 @@ void EntityItemProperties::markAllChanged() { _xPNeighborIDChanged = true; _yPNeighborIDChanged = true; _zPNeighborIDChanged = true; + + _parentIDChanged = true; + _parentJointIndexChanged = true; } /// The maximum bounding cube for the entity, independent of it's rotation. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 2227644484..1851e69dd2 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -191,6 +191,8 @@ public: DEFINE_PROPERTY_REF(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); + DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); + DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); static QString getBackgroundModeString(BackgroundMode mode); @@ -389,6 +391,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, YPNeighborID, yPNeighborID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZPNeighborID, zPNeighborID, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentID, parentID, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentJointIndex, parentJointIndex, ""); + properties.getAnimation().debugDump(); properties.getAtmosphere().debugDump(); properties.getSkybox().debugDump(); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index b3299b6fe6..ca6bbbbbb8 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -104,6 +104,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, quint16 v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { return QScriptValue((qsreal)v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); } @@ -179,6 +180,7 @@ inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isVal // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range. return v.toString().toUInt(&isValid); } +inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index d70a5c9616..f0087b4803 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -149,6 +149,9 @@ enum EntityPropertyList { PROP_ANIMATION_HOLD, PROP_ANIMATION_START_AUTOMATICALLY, + PROP_PARENT_ID, + PROP_PARENT_JOINT_INDEX, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 3c1d33deaf..ca2d03ca2b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,9 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP; + return VERSION_ENTITIES_HAVE_PARENTS; case PacketType::AvatarData: case PacketType::BulkAvatarData: + return 17; default: return 16; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3654d5b5fa..5f2cbf0193 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -143,5 +143,6 @@ const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 43; const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44; const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45; const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; +const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 47; #endif // hifi_PacketHeaders_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4cdf61061c..870c96a784 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -12,6 +12,8 @@ #include "DependencyManager.h" #include "SpatiallyNestable.h" +// TODO -- make use of parent joint index + Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e3d3b8dc0d..c8bb7c2808 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -25,18 +25,24 @@ using SpatiallyNestablePointer = std::shared_ptr; class SpatiallyNestable { public: - SpatiallyNestable() : _transform() { } + SpatiallyNestable() : _transform() { } // XXX get rid of this one? SpatiallyNestable(QUuid id) : _id(id), _transform() { } virtual ~SpatiallyNestable() { } - const QUuid& getID() const { return _id; } - void setID(const QUuid& id) { _id = id; } + virtual const QUuid& getID() const { return _id; } + virtual void setID(const QUuid& id) { _id = id; } + + virtual const QUuid& getParentID() const { return _parentID; } + virtual void setParentID(const QUuid& parentID) { _parentID = parentID; } + + virtual quint16 getParentJointIndex() const { return _parentJointIndex; } + virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); - Transform getParentTransform() const; + virtual Transform getParentTransform() const; virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); @@ -63,7 +69,7 @@ public: protected: QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - int _parentJointIndex; // which joint of the parent is this relative to? + quint16 _parentJointIndex; // which joint of the parent is this relative to? mutable SpatiallyNestableWeakPointer _parent; QVector _children; From f6fe503c515d636bf4ddc0f66b58c111576a6e03 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 13:44:04 -0700 Subject: [PATCH 008/165] pass avatar parent information through avatar-mixer --- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 29 ++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 16e136f9d1..3d13ef5d02 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -151,7 +151,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->withWriteLock([&] { - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); if (avatar->getTargetScale() < MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9b2967cf5d..9a6c4b0180 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -135,15 +135,15 @@ float AvatarData::getTargetScale() const { return _targetScale; } -void AvatarData::setTargetScale(float targetScale, bool overideReferential) { +void AvatarData::setTargetScale(float targetScale) { _targetScale = targetScale; } -void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { +void AvatarData::setClampedTargetScale(float targetScale) { targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - setTargetScale(targetScale, overideReferential); + setTargetScale(targetScale); qCDebug(avatars) << "Changed scale to " << _targetScale; } @@ -214,14 +214,18 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); } // referential state - if (false) { - setAtBit(bitItems, HAS_REFERENTIAL); // XXX leaving this for later use + SpatiallyNestablePointer parent = getParentPointer(); + if (parent) { + setAtBit(bitItems, HAS_REFERENTIAL); } *destinationBuffer++ = bitItems; - // XXX leaving this for later use - if (false) { - // destinationBuffer += _referential->packReferential(destinationBuffer); + if (parent) { + QByteArray referentialAsBytes = parent->getID().toRfc4122(); + memcpy(destinationBuffer, referentialAsBytes.data(), referentialAsBytes.size()); + destinationBuffer += referentialAsBytes.size(); + memcpy(destinationBuffer, &_parentJointIndex, sizeof(_parentJointIndex)); + destinationBuffer += sizeof(_parentJointIndex); } // If it is connected, pack up the data @@ -541,8 +545,15 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->_isEyeTrackerConnected = oneAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); - // XXX leaving this for later use Referential if (hasReferential) { + const int sizeOfPackedUuid = 16; + QByteArray referentialAsBytes((const char*)sourceBuffer, sizeOfPackedUuid); + _parentID = QUuid::fromRfc4122(referentialAsBytes); + sourceBuffer += sizeOfPackedUuid; + memcpy(&_parentJointIndex, sourceBuffer, sizeof(_parentJointIndex)); + sourceBuffer += sizeof(_parentJointIndex); + } else { + _parentID = QUuid(); } if (_headData->_isFaceTrackerConnected) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9f8224caf8..4f826eafde 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -223,8 +223,8 @@ public: // Scale float getTargetScale() const; - void setTargetScale(float targetScale, bool overideReferential = false); - void setClampedTargetScale(float targetScale, bool overideReferential = false); + void setTargetScale(float targetScale); + void setClampedTargetScale(float targetScale); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index c8bb7c2808..930b096450 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -70,13 +70,13 @@ protected: QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? + SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; QVector _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. - SpatiallyNestablePointer getParentPointer() const; // these are so we can return by reference mutable glm::vec3 _absolutePositionCache; From d86d69aeba4b72f69d2d0d3f626801bfa4ee0fb6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 15:36:03 -0700 Subject: [PATCH 009/165] keep track of children. use local position and orientation on the wire. --- assignment-client/src/avatars/AvatarMixer.cpp | 4 +-- .../src/entities/AssignmentParentFinder.cpp | 5 +-- interface/src/InterfaceParentFinder.cpp | 4 +-- libraries/avatars/src/AvatarData.cpp | 13 +++---- .../RenderableParticleEffectEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 12 +++---- libraries/entities/src/EntityItem.h | 4 ++- libraries/shared/src/SpatiallyNestable.cpp | 34 ++++++++++++++++--- libraries/shared/src/SpatiallyNestable.h | 13 ++++--- 10 files changed, 61 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 833b53b729..7124bb368c 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -155,7 +155,7 @@ void AvatarMixer::broadcastAvatarData() { ++_sumListeners; AvatarData& avatar = nodeData->getAvatar(); - glm::vec3 myPosition = avatar.getPosition(); + glm::vec3 myPosition = avatar.getLocalPosition(); // XXX should be world position // reset the internal state for correct random number distribution distribution.reset(); @@ -248,7 +248,7 @@ void AvatarMixer::broadcastAvatarData() { // The full rate distance is the distance at which EVERY update will be sent for this avatar // at twice the full rate distance, there will be a 50% chance of sending this avatar's update - glm::vec3 otherPosition = otherAvatar.getPosition(); + glm::vec3 otherPosition = otherAvatar.getLocalPosition(); // XXX should be world position float distanceToAvatar = glm::length(myPosition - otherPosition); // potentially update the max full rate distance for this frame diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index 6a66aa3f73..3e6fc2ed38 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -12,11 +12,8 @@ #include "AssignmentParentFinder.h" SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const { - assert(false); SpatiallyNestableWeakPointer parent; // search entities - _tree->withReadLock([&] { - parent = _tree->findEntityByEntityItemID(parentID); - }); + parent = _tree->findEntityByEntityItemID(parentID); return parent; } diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index f8604b15d3..1703ffc5d1 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -22,9 +22,7 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { // search entities EntityTreeRenderer* treeRenderer = qApp->getEntities(); EntityTreePointer tree = treeRenderer->getTree(); - tree->withReadLock([&] { - parent = tree->findEntityByEntityItemID(parentID); - }); + parent = tree->findEntityByEntityItemID(parentID); if (!parent.expired()) { return parent; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9a6c4b0180..fc9d9c75a7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -174,14 +174,15 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; - const glm::vec3& position = getPosition(); + const glm::vec3& position = getLocalPosition(); memcpy(destinationBuffer, &position, sizeof(position)); destinationBuffer += sizeof(position); // Body rotation - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyYaw()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyPitch()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyRoll()); + glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation())); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.x); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.z); // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); @@ -465,7 +466,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } return maxAvailableSize; } - setPosition(position); + setLocalPosition(position); // rotation (NOTE: This needs to become a quaternion to save two bytes) float yaw, pitch, roll; @@ -483,7 +484,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; glm::vec3 eulerAngles(pitch, yaw, roll); - setOrientation(glm::quat(glm::radians(eulerAngles))); + setLocalOrientation(glm::quat(glm::radians(eulerAngles))); } // scale diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a7bdffc020..a0bb582d58 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -134,7 +134,8 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) { - auto particlePayload = std::shared_ptr(new ParticlePayload(shared_from_this())); + auto particlePayload = + std::shared_ptr(new ParticlePayload(getThisPointer())); particlePayload->setPipeline(_untexturedPipeline); _renderItemId = scene->allocateID(); auto renderData = ParticlePayload::Pointer(particlePayload); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd5a9a6b4a..3ce3717dfb 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -547,7 +547,7 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, render::PendingChanges& pendingChanges) { _myItem = scene->allocateID(); - auto renderItem = std::make_shared(shared_from_this()); + auto renderItem = std::make_shared(getThisPointer()); auto renderData = PolyVoxPayload::Pointer(renderItem); auto renderPayload = std::make_shared(renderData); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c3c0204aee..f8e191cde1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -242,7 +242,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // PROP_CUSTOM_PROPERTIES_INCLUDED, APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); - APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition()); + APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); @@ -1038,7 +1038,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper properties._type = getType(); COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPosition); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); @@ -1078,7 +1078,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const { // a TerseUpdate includes the transform and its derivatives - properties._position = getPosition(); + properties._position = getLocalPosition(); properties._velocity = _velocity; properties._rotation = getRotation(); properties._angularVelocity = _angularVelocity; @@ -1313,10 +1313,10 @@ void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } - auto delta = glm::distance(getPosition(), value); + auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { _dirtyFlags |= Simulation::DIRTY_POSITION; - setPosition(value); + setLocalPosition(value); if (delta > ACTIVATION_POSITION_DELTA) { _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; } @@ -1685,7 +1685,7 @@ void EntityItem::deserializeActionsInternal() { action->locallyAddedButNotYetReceived = false; } else { auto actionFactory = DependencyManager::get(); - EntityItemPointer entity = shared_from_this(); + EntityItemPointer entity = getThisPointer(); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { entity->addActionInternal(simulation, action); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 79fe438c39..7d6de20a5c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -75,7 +75,7 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem : public std::enable_shared_from_this, public SpatiallyNestable, public ReadWriteLockable { +class EntityItem : public SpatiallyNestable, public ReadWriteLockable { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -89,6 +89,8 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); + inline EntityItemPointer getThisPointer() { return std::static_pointer_cast(shared_from_this()); } + EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 870c96a784..b3723cf3b7 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -34,19 +34,43 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date + if (!_parentKnowsMe) { + parent->beParentOfChild(shared_from_this()); + _parentKnowsMe = true; + } return parent; } - if (parent && _parentID.isNull()) { - // we have a parent pointer but our _parentID is null + if (parent) { + // we have a parent pointer but our _parentID doesn't indicate this parent. + parent->forgetChild(shared_from_this()); + _parentKnowsMe = false; _parent.reset(); - return nullptr; } // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); - _parent = parentFinder->find(_parentID); - return _parent.lock(); + _parent = parentFinder->find(_parentID); + parent = _parent.lock(); + if (parent) { + parent->beParentOfChild(shared_from_this()); + _parentKnowsMe = true; + } + return parent; +} + +void SpatiallyNestable::beParentOfChild(SpatiallyNestableConstPointer newChild) const { + _children[newChild->getID()] = newChild; +} + +void SpatiallyNestable::forgetChild(SpatiallyNestableConstPointer newChild) const { + _children.remove(newChild->getID()); +} + + +void SpatiallyNestable::setParentID(const QUuid& parentID) { + _parentID = parentID; + _parentKnowsMe = false; } const glm::vec3& SpatiallyNestable::getPosition() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 930b096450..7ba5493340 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -20,9 +20,11 @@ class SpatiallyNestable; using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestableWeakConstPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; +using SpatiallyNestableConstPointer = std::shared_ptr; -class SpatiallyNestable { +class SpatiallyNestable : public std::enable_shared_from_this { public: SpatiallyNestable() : _transform() { } // XXX get rid of this one? @@ -33,7 +35,7 @@ public: virtual void setID(const QUuid& id) { _id = id; } virtual const QUuid& getParentID() const { return _parentID; } - virtual void setParentID(const QUuid& parentID) { _parentID = parentID; } + virtual void setParentID(const QUuid& parentID); virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } @@ -71,9 +73,11 @@ protected: QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; - mutable SpatiallyNestableWeakPointer _parent; - QVector _children; + + virtual void beParentOfChild(SpatiallyNestableConstPointer newChild) const; + virtual void forgetChild(SpatiallyNestableConstPointer newChild) const; + mutable QHash _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. @@ -82,6 +86,7 @@ private: mutable glm::vec3 _absolutePositionCache; mutable glm::quat _absoluteRotationCache; mutable Transform _worldTransformCache; + mutable bool _parentKnowsMe = false; }; From 7b08d047b19598784cfa03c67d67329a6351724a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 16:59:56 -0700 Subject: [PATCH 010/165] when EntityTree::updateEntityWithElement is called on an entity, call it on all the children of that entity --- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 5 +- .../src/BoundingBoxRelatedProperties.cpp | 83 ++++++++++++++ .../src/BoundingBoxRelatedProperties.h | 30 ++++++ libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 33 +++++- libraries/entities/src/EntityTypes.h | 4 +- .../entities/src/UpdateEntityOperator.cpp | 101 ++++-------------- libraries/entities/src/UpdateEntityOperator.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 24 ++++- libraries/shared/src/SpatiallyNestable.h | 28 +++-- 11 files changed, 213 insertions(+), 105 deletions(-) create mode 100644 libraries/entities/src/BoundingBoxRelatedProperties.cpp create mode 100644 libraries/entities/src/BoundingBoxRelatedProperties.h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fc9d9c75a7..a1db573d8d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -37,7 +37,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f); const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); AvatarData::AvatarData() : - _sessionUUID(), + SpatiallyNestable(NestableTypes::Avatar, QUuid()), _handPosition(0.0f), _targetScale(1.0f), _handState(0), diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 4f826eafde..8a0a9ac38a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -172,7 +172,7 @@ public: virtual bool isMyAvatar() const { return false; } - const QUuid& getSessionUUID() const { return _sessionUUID; } + const QUuid& getSessionUUID() const { return getID(); } glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -327,7 +327,7 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); - void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; } + void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); } bool isPlaying(); bool isPaused(); @@ -353,7 +353,6 @@ public slots: void stopPlaying(); protected: - QUuid _sessionUUID; glm::vec3 _handPosition; // Body scale diff --git a/libraries/entities/src/BoundingBoxRelatedProperties.cpp b/libraries/entities/src/BoundingBoxRelatedProperties.cpp new file mode 100644 index 0000000000..e9ee302300 --- /dev/null +++ b/libraries/entities/src/BoundingBoxRelatedProperties.cpp @@ -0,0 +1,83 @@ +// +// BoundingBoxRelatedProperties.cpp +// libraries/entities/src +// +// Created by Seth Alves on 2015-9-24 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityItemProperties.h" +#include "BoundingBoxRelatedProperties.h" +#include "EntityTree.h" + +BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity) : + position(entity->getPosition()), + rotation(entity->getRotation()), + registrationPoint(entity->getRegistrationPoint()), + dimensions(entity->getDimensions()), + parentID(entity->getParentID()) { +} + +BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity, + const EntityItemProperties& propertiesWithUpdates) : + BoundingBoxRelatedProperties(entity) { + + if (propertiesWithUpdates.parentIDChanged()) { + parentID = propertiesWithUpdates.getParentID(); + } + + bool parentFound = false; + if (parentID != UNKNOWN_ENTITY_ID) { + EntityTreePointer tree = entity->getTree(); + EntityItemPointer parentZone = tree->findEntityByID(parentID); + if (parentZone) { + parentFound = true; + glm::vec3 localPosition = propertiesWithUpdates.containsPositionChange() ? + propertiesWithUpdates.getPosition() : + entity->getLocalPosition(); + + glm::quat localRotation = propertiesWithUpdates.rotationChanged() ? + propertiesWithUpdates.getRotation() : + entity->getLocalOrientation(); + + const Transform parentTransform = parentZone->getTransformToCenter(); + Transform parentDescaled(parentTransform.getRotation(), glm::vec3(1.0f), parentTransform.getTranslation()); + + Transform localTransform(localRotation, glm::vec3(1.0f), localPosition); + Transform result; + Transform::mult(result, parentDescaled, localTransform); + position = result.getTranslation(); + rotation = result.getRotation(); + } + } + + if (!parentFound) { + if (propertiesWithUpdates.containsPositionChange()) { + position = propertiesWithUpdates.getPosition(); + } + if (propertiesWithUpdates.rotationChanged()) { + rotation = propertiesWithUpdates.getRotation(); + } + } + + if (propertiesWithUpdates.registrationPointChanged()) { + registrationPoint = propertiesWithUpdates.getRegistrationPoint(); + } + + if (propertiesWithUpdates.dimensionsChanged()) { + dimensions = propertiesWithUpdates.getDimensions(); + } +} + +AACube BoundingBoxRelatedProperties::getMaximumAACube() const { + // see EntityItem::getMaximumAACube for comments which explain the following. + glm::vec3 scaledRegistrationPoint = (dimensions * registrationPoint); + glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - registrationPoint)); + glm::vec3 furthestExtentFromRegistration = glm::max(scaledRegistrationPoint, registrationRemainder); + float radius = glm::length(furthestExtentFromRegistration); + glm::vec3 minimumCorner = position - glm::vec3(radius, radius, radius); + return AACube(minimumCorner, radius * 2.0f); +} diff --git a/libraries/entities/src/BoundingBoxRelatedProperties.h b/libraries/entities/src/BoundingBoxRelatedProperties.h new file mode 100644 index 0000000000..811c885fd2 --- /dev/null +++ b/libraries/entities/src/BoundingBoxRelatedProperties.h @@ -0,0 +1,30 @@ +// +// BoundingBoxRelatedProperties.h +// libraries/entities/src +// +// Created by Seth Alves on 2015-9-24 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityItem.h" + +#ifndef hifi_BoundingBoxRelatedProperties_h +#define hifi_BoundingBoxRelatedProperties_h + +class BoundingBoxRelatedProperties { + public: + BoundingBoxRelatedProperties(EntityItemPointer entity); + BoundingBoxRelatedProperties(EntityItemPointer entity, const EntityItemProperties& propertiesWithUpdates); + AACube getMaximumAACube() const; + + glm::vec3 position; + glm::quat rotation; + glm::vec3 registrationPoint; + glm::vec3 dimensions; + EntityItemID parentID; +}; + +#endif // hifi_BoundingBoxRelatedProperties_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f8e191cde1..46d5635fc5 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -37,7 +37,7 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : - SpatiallyNestable(entityItemID), + SpatiallyNestable(NestableTypes::Entity, entityItemID), _type(EntityTypes::Unknown), _lastSimulated(0), _lastUpdated(0), diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 24c13ae28e..257e3e0ed2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -143,8 +143,11 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (!wantsLocked) { EntityItemProperties tempProperties; tempProperties.setLocked(wantsLocked); - UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, tempProperties); + + BoundingBoxRelatedProperties newBBRelProperties(entity, tempProperties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties); recurseTreeWithOperator(&theOperator); + entity->setProperties(tempProperties); _isDirty = true; } } @@ -205,8 +208,34 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI quint64 entityScriptTimestampBefore = entity->getScriptTimestamp(); QString collisionSoundURLBefore = entity->getCollisionSoundURL(); uint32_t preFlags = entity->getDirtyFlags(); - UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties); + + BoundingBoxRelatedProperties newBBRelProperties(entity, properties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties); recurseTreeWithOperator(&theOperator); + entity->setProperties(properties); + + // if the entity has children, run UpdateEntityOperator on them. If the children have children, recurse + QQueue toProcess; + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + + while (!toProcess.empty()) { + EntityItemPointer childEntity = std::static_pointer_cast(toProcess.dequeue()); + BoundingBoxRelatedProperties newChildBBRelProperties(childEntity); + UpdateEntityOperator theChildOperator(getThisPointer(), + childEntity->getElement(), + childEntity, newChildBBRelProperties); + recurseTreeWithOperator(&theChildOperator); + foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { + if (childChild && childChild->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(childChild); + } + } + } + _isDirty = true; uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 30b6edbc07..3536327d18 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -20,8 +20,8 @@ #include // for RenderArgs class EntityItem; -typedef std::shared_ptr EntityItemPointer; -typedef std::weak_ptr EntityItemWeakPointer; +using EntityItemPointer = std::shared_ptr; +using EntityItemWeakPointer = std::weak_ptr; inline uint qHash(const EntityItemPointer& a, uint seed) { return qHash(a.get(), seed); diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 617663f48a..4acc386333 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -14,12 +14,12 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, EntityItemPointer existingEntity, - const EntityItemProperties& properties) : + const BoundingBoxRelatedProperties& newProperties) : _tree(tree), _existingEntity(existingEntity), _containingElement(containingElement), _containingElementCube(containingElement->getAACube()), - _properties(properties), + _newProperties(newProperties), _entityItemID(existingEntity->getEntityItemID()), _foundOld(false), _foundNew(false), @@ -44,83 +44,32 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, _oldEntityCube = _existingEntity->getMaximumAACube(); _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds - // If the old properties doesn't contain the properties required to calculate a bounding box, - // get them from the existing entity. Registration point is required to correctly calculate - // the bounding box. - if (!_properties.registrationPointChanged()) { - _properties.setRegistrationPoint(_existingEntity->getRegistrationPoint()); - } - - // If the new properties has position OR dimension changes, but not both, we need to - // get the old property value and set it in our properties in order for our bounds - // calculations to work. - if (_properties.containsPositionChange() && !_properties.containsDimensionsChange()) { - glm::vec3 oldDimensions= _existingEntity->getDimensions(); - _properties.setDimensions(oldDimensions); - - if (_wantDebug) { - qCDebug(entities) << " ** setting properties dimensions - had position change, no dimension change **"; - } - - } - if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) { - glm::vec3 oldPosition= _existingEntity->getPosition(); - _properties.setPosition(oldPosition); - - if (_wantDebug) { - qCDebug(entities) << " ** setting properties position - had dimensions change, no position change **"; - } - } - - // If our new properties don't have bounds details (no change to position, etc) or if this containing element would - // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will + // If our new properties don't have bounds details (no change to position, etc) or if this containing element would + // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will // be the same for both parts of the update - bool oldElementBestFit = _containingElement->bestFitBounds(_properties); - - // if we don't have bounds properties, then use our old clamped box to determine best fit - if (!_properties.containsBoundsProperties()) { - oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox); + bool oldElementBestFit = _containingElement->bestFitBounds(newProperties.getMaximumAACube()); - if (_wantDebug) { - qCDebug(entities) << " ** old Element best fit - no dimensions change, no position change **"; - } - - } - // For some reason we've seen a case where the original containing element isn't a best fit for the old properties // in this case we want to move it, even if the properties haven't changed. - if (!_properties.containsBoundsProperties() && !oldElementBestFit) { + if (!oldElementBestFit) { _newEntityCube = _oldEntityCube; _removeOld = true; // our properties are going to move us, so remember this for later processing if (_wantDebug) { qCDebug(entities) << " **** UNUSUAL CASE **** no changes, but not best fit... consider it a move.... **"; } - - - } else if (!_properties.containsBoundsProperties() || oldElementBestFit) { + } else { _foundOld = true; _newEntityCube = _oldEntityCube; _dontMove = true; if (_wantDebug) { - qCDebug(entities) << " **** TYPICAL NO MOVE CASE ****"; - qCDebug(entities) << " _properties.containsBoundsProperties():" << _properties.containsBoundsProperties(); - qCDebug(entities) << " oldElementBestFit:" << oldElementBestFit; - } - - } else { - _newEntityCube = _properties.getMaximumAACube(); - _removeOld = true; // our properties are going to move us, so remember this for later processing - - if (_wantDebug) { - qCDebug(entities) << " **** TYPICAL MOVE CASE ****"; + qCDebug(entities) << " **** TYPICAL NO MOVE CASE **** oldElementBestFit:" << oldElementBestFit; } } _newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds - if (_wantDebug) { qCDebug(entities) << " _entityItemID:" << _entityItemID; qCDebug(entities) << " _containingElementCube:" << _containingElementCube; @@ -176,7 +125,7 @@ bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - + // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if // and of the following are true: @@ -185,7 +134,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { // // Note: it's often the case that the branch in question contains both the old entity // and the new entity. - + bool keepSearching = false; // assume we don't need to search any more bool subtreeContainsOld = subTreeContainsOldEntity(element); @@ -257,7 +206,8 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { qCDebug(entities) << " NEW TREE CASE...."; qCDebug(entities) << " entityTreeElement=" << entityTreeElement.get(); qCDebug(entities) << " _containingElement=" << _containingElement.get(); - qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox); + qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" + << entityTreeElement->bestFitBounds(_newEntityBox); } // If this element is the best fit for the new entity properties, then add/or update it @@ -270,16 +220,9 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { EntityTreeElementPointer oldElement = _existingEntity->getElement(); // if we are the existing containing element, then we can just do the update of the entity properties if (entityTreeElement == oldElement) { - if (_wantDebug) { qCDebug(entities) << " *** This is the same OLD ELEMENT ***"; } - - // set the entity properties and mark our element as changed. - _existingEntity->setProperties(_properties); - if (_wantDebug) { - qCDebug(entities) << " *** set properties ***"; - } } else { // otherwise, this is an add case. if (oldElement) { @@ -290,11 +233,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { } entityTreeElement->addEntityItem(_existingEntity); _tree->setContainingElement(_entityItemID, entityTreeElement); - - _existingEntity->setProperties(_properties); // still need to update the properties! - if (_wantDebug) { - qCDebug(entities) << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; - } } _foundNew = true; // we found the new element _removeOld = false; // and it has already been removed from the old @@ -308,7 +246,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { qCDebug(entities) << "--------------------------------------------------"; } - return keepSearching; // if we haven't yet found it, keep looking } @@ -329,9 +266,9 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) { } // It's not OK to prune if we have the potential of deleting the original containig element. - // because if we prune the containing element then new might end up reallocating the same memory later + // because if we prune the containing element then new might end up reallocating the same memory later // and that will confuse our logic. - // + // // it's ok to prune if: // 1) we're not removing the old // 2) we are removing the old, but this subtree doesn't contain the old @@ -340,17 +277,17 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves } - + return keepSearching; // if we haven't yet found it, keep looking } -OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { +OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { // If we're getting called, it's because there was no child element at this index while recursing. // We only care if this happens while still searching for the new entity location. - // Check to see if + // Check to see if if (!_foundNew) { float childElementScale = element->getScale() / 2.0f; // all of our children will be half our scale - + // Note: because the entity's bounds might have been clamped to the domain. We want to check if the // bounds of the clamped box would fit in our child elements. It may be the case that the actual // bounds of the element would hang outside of the child elements cells. @@ -365,5 +302,5 @@ OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPo } } } - return NULL; + return NULL; } diff --git a/libraries/entities/src/UpdateEntityOperator.h b/libraries/entities/src/UpdateEntityOperator.h index 46322997f7..aac442d415 100644 --- a/libraries/entities/src/UpdateEntityOperator.h +++ b/libraries/entities/src/UpdateEntityOperator.h @@ -12,6 +12,7 @@ #ifndef hifi_UpdateEntityOperator_h #define hifi_UpdateEntityOperator_h +#include "BoundingBoxRelatedProperties.h" #include "EntitiesLogging.h" #include "EntityItem.h" #include "EntityItemProperties.h" @@ -21,7 +22,8 @@ class UpdateEntityOperator : public RecurseOctreeOperator { public: UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, - EntityItemPointer existingEntity, const EntityItemProperties& properties); + EntityItemPointer existingEntity, const BoundingBoxRelatedProperties& newProperties); + ~UpdateEntityOperator(); virtual bool preRecursion(OctreeElementPointer element); @@ -32,7 +34,7 @@ private: EntityItemPointer _existingEntity; EntityTreeElementPointer _containingElement; AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element - EntityItemProperties _properties; + BoundingBoxRelatedProperties _newProperties; EntityItemID _entityItemID; bool _foundOld; bool _foundNew; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index b3723cf3b7..a813a37bfe 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,10 +32,13 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); + SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! + if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date if (!_parentKnowsMe) { - parent->beParentOfChild(shared_from_this()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } return parent; @@ -43,7 +46,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(shared_from_this()); + parent->forgetChild(thisPointer); _parentKnowsMe = false; _parent.reset(); } @@ -53,17 +56,17 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { _parent = parentFinder->find(_parentID); parent = _parent.lock(); if (parent) { - parent->beParentOfChild(shared_from_this()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } return parent; } -void SpatiallyNestable::beParentOfChild(SpatiallyNestableConstPointer newChild) const { +void SpatiallyNestable::beParentOfChild(SpatiallyNestablePointer newChild) const { _children[newChild->getID()] = newChild; } -void SpatiallyNestable::forgetChild(SpatiallyNestableConstPointer newChild) const { +void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { _children.remove(newChild->getID()); } @@ -153,3 +156,14 @@ const glm::vec3& SpatiallyNestable::getLocalScale() const { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { _transform.setScale(scale); } + +QList SpatiallyNestable::getChildren() const { + QList children; + foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + SpatiallyNestablePointer child = childWP.lock(); + if (child) { + children << child; + } + } + return children; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 7ba5493340..e0ee5bdb74 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -24,11 +24,21 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr using SpatiallyNestablePointer = std::shared_ptr; using SpatiallyNestableConstPointer = std::shared_ptr; -class SpatiallyNestable : public std::enable_shared_from_this { - +class NestableTypes { public: - SpatiallyNestable() : _transform() { } // XXX get rid of this one? - SpatiallyNestable(QUuid id) : _id(id), _transform() { } + using NestableType = enum NestableType_t { + Entity, + Avatar + }; +}; + +class SpatiallyNestable : public std::enable_shared_from_this { +public: + // SpatiallyNestable() : _transform() { } // XXX get rid of this one? + SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : + _nestableType(nestableType), + _id(id), + _transform() { } virtual ~SpatiallyNestable() { } virtual const QUuid& getID() const { return _id; } @@ -68,16 +78,20 @@ public: virtual const glm::vec3& getLocalScale() const; virtual void setLocalScale(const glm::vec3& scale); + QList getChildren() const; + NestableTypes::NestableType getNestableType() const { return _nestableType; } + protected: + NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; - virtual void beParentOfChild(SpatiallyNestableConstPointer newChild) const; - virtual void forgetChild(SpatiallyNestableConstPointer newChild) const; - mutable QHash _children; + virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; + virtual void forgetChild(SpatiallyNestablePointer newChild) const; + mutable QHash _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From bf290c35be4ce5ff2c188d601785ad26ee27f24e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 09:46:57 -0700 Subject: [PATCH 011/165] when an entity gets a physics flag set, set the same flag in any children --- libraries/entities/src/EntityItem.cpp | 47 +++++++++++++++++++++------ libraries/entities/src/EntityItem.h | 2 ++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 46d5635fc5..7c9f3139df 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1309,17 +1309,40 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } +bool EntityItem::forSelfAndEachChildEntity(std::function actor) { + bool result = true; + QQueue toProcess; + toProcess.enqueue(shared_from_this()); + + while (!toProcess.empty()) { + EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); + + result &= actor(entity); + + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + } + + return result; +} + void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_POSITION; setLocalPosition(value); - if (delta > ACTIVATION_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->_dirtyFlags |= Simulation::DIRTY_POSITION; + if (delta > ACTIVATION_POSITION_DELTA) { + entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + return true; + }); } } @@ -1342,12 +1365,16 @@ void EntityItem::updateRotation(const glm::quat& rotation) { setRotation(rotation); auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); - if (alignmentDot < IGNORE_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_ROTATION; - } - if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + if (alignmentDot < IGNORE_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; + } + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + return true; + }); } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7d6de20a5c..6e03e52679 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -396,6 +396,8 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); + bool forSelfAndEachChildEntity(std::function actor); + static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, From 22af5b27abe9012e2d1cfa6fb6ef69b2377603fb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 12:55:48 -0700 Subject: [PATCH 012/165] avoid shared_from_this while constructing --- libraries/avatars/src/AvatarData.cpp | 1 + libraries/entities/src/EntityItem.cpp | 1 + libraries/shared/src/SpatiallyNestable.cpp | 5 +++++ libraries/shared/src/SpatiallyNestable.h | 2 ++ 4 files changed, 9 insertions(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1db573d8d..7f0f758b87 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -60,6 +60,7 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); + _constructing = false; } AvatarData::~AvatarData() { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7c9f3139df..fd4a4b298c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,6 +85,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; + _constructing = false; } EntityItem::~EntityItem() { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a813a37bfe..9d1220c214 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,6 +32,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } + if (_constructing) { + // we can't use shared_from_this yet, so stop here. + return nullptr; + } + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e0ee5bdb74..108da796a0 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -82,6 +82,8 @@ public: NestableTypes::NestableType getNestableType() const { return _nestableType; } protected: + bool _constructing = true; + NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? From 61269c3ce837b30cfcd389849832045a9d55e05f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 13:52:50 -0700 Subject: [PATCH 013/165] fix up entity constructors so that setProperties isn't called during the constructor --- libraries/avatars/src/AvatarData.cpp | 1 - .../src/RenderableBoxEntityItem.cpp | 4 +++- .../src/RenderableBoxEntityItem.h | 5 +--- .../src/RenderableLightEntityItem.cpp | 4 +++- .../src/RenderableLightEntityItem.h | 5 +--- .../src/RenderableLineEntityItem.cpp | 4 +++- .../src/RenderableLineEntityItem.h | 5 ++-- .../src/RenderableModelEntityItem.cpp | 13 ++++++----- .../src/RenderableModelEntityItem.h | 2 +- .../RenderableParticleEffectEntityItem.cpp | 12 ++++++---- .../src/RenderableParticleEffectEntityItem.h | 2 +- .../src/RenderablePolyLineEntityItem.cpp | 10 ++++---- .../src/RenderablePolyLineEntityItem.h | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 9 ++++---- .../src/RenderablePolyVoxEntityItem.h | 3 +-- .../src/RenderableSphereEntityItem.cpp | 4 +++- .../src/RenderableSphereEntityItem.h | 5 +--- .../src/RenderableTextEntityItem.cpp | 4 +++- .../src/RenderableTextEntityItem.h | 5 +--- .../src/RenderableWebEntityItem.cpp | 8 ++++--- .../src/RenderableWebEntityItem.h | 3 +-- .../src/RenderableZoneEntityItem.cpp | 4 +++- .../src/RenderableZoneEntityItem.h | 8 +++---- libraries/entities/src/BoxEntityItem.cpp | 10 ++++---- libraries/entities/src/BoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 1 - libraries/entities/src/LightEntityItem.cpp | 13 ++++------- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.cpp | 12 ++++------ libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 8 +++---- libraries/entities/src/ModelEntityItem.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 11 ++++----- .../entities/src/ParticleEffectEntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 23 +++++++++---------- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 7 +++--- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/SphereEntityItem.cpp | 10 ++++---- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 9 ++++---- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 9 ++++---- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 10 ++++---- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 5 ---- libraries/shared/src/SpatiallyNestable.h | 2 -- 48 files changed, 127 insertions(+), 147 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7f0f758b87..a1db573d8d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -60,7 +60,6 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); - _constructing = false; } AvatarData::~AvatarData() { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 077f28350b..702b691342 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -25,7 +25,9 @@ #include "../render-utils/simple_frag.h" EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableBoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableBoxEntityItem::setUserData(const QString& value) { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.h b/libraries/entities-renderer/src/RenderableBoxEntityItem.h index 838022c7d4..9addfd813a 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.h @@ -20,10 +20,7 @@ class RenderableBoxEntityItem : public BoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableBoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - BoxEntityItem(entityItemID, properties) - { } + RenderableBoxEntityItem(const EntityItemID& entityItemID) : BoxEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual void setUserData(const QString& value); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index b0cc0462c6..5b8891d1f2 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -20,7 +20,9 @@ #include "RenderableLightEntityItem.h" EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableLightEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableLightEntityItem::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index ecf24eaec7..aac1a4a998 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -18,10 +18,7 @@ class RenderableLightEntityItem : public LightEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - LightEntityItem(entityItemID, properties) - { } + RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 3735690c33..1c9c50af55 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -20,7 +20,9 @@ #include "RenderableLineEntityItem.h" EntityItemPointer RenderableLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableLineEntityItem::updateGeometry() { diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.h b/libraries/entities-renderer/src/RenderableLineEntityItem.h index 09f98ca364..058cab2c4b 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.h @@ -20,9 +20,8 @@ class RenderableLineEntityItem : public LineEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - LineEntityItem(entityItemID, properties), + RenderableLineEntityItem(const EntityItemID& entityItemID) : + LineEntityItem(entityItemID), _lineVerticesID(GeometryCache::UNKNOWN_ID) { } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e604bdb925..d2f16de936 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -24,13 +24,14 @@ #include "RenderableModelEntityItem.h" EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) }; + entity->setProperties(properties); + return entity; } -RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, - const EntityItemProperties& properties) : - ModelEntityItem(entityItemID, properties), - _dimensionsInitialized(properties.getDimensionsInitialized()) -{ + +RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) : + ModelEntityItem(entityItemID), + _dimensionsInitialized(dimensionsInitialized) { } RenderableModelEntityItem::~RenderableModelEntityItem() { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4dc1cced48..77c7f71ae9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -25,7 +25,7 @@ class RenderableModelEntityItem : public ModelEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized); virtual ~RenderableModelEntityItem(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a0bb582d58..0ce6b49a5c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -117,13 +117,15 @@ namespace render { gpu::PipelinePointer RenderableParticleEffectEntityItem::_texturedPipeline; gpu::PipelinePointer RenderableParticleEffectEntityItem::_untexturedPipeline; -EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); +EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, + const EntityItemProperties& properties) { + EntityItemPointer entity{ new RenderableParticleEffectEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ParticleEffectEntityItem(entityItemID, properties) { - +RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) : + ParticleEffectEntityItem(entityItemID) { // lazy creation of particle system pipeline if (!_untexturedPipeline && !_texturedPipeline) { createPipelines(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 5d69d19026..5ff6c3ff92 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -19,7 +19,7 @@ class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { friend class ParticlePayload; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableParticleEffectEntityItem(const EntityItemID& entityItemID); virtual void update(const quint64& now) override; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 572b24e99f..c5f5e9d55a 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -23,15 +23,15 @@ #include "paintStroke_frag.h" - EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties)); + EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -PolyLineEntityItem(entityItemID, properties) { +RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID) : + PolyLineEntityItem(entityItemID) { _numVertices = 0; - } gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 59bf416d7a..f803e4c520 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -25,7 +25,7 @@ class RenderablePolyLineEntityItem : public PolyLineEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); static void createPipeline(); - RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderablePolyLineEntityItem(const EntityItemID& entityItemID); virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 3ce3717dfb..d9f1832339 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -49,12 +49,13 @@ gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderablePolyVoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, - const EntityItemProperties& properties) : - PolyVoxEntityItem(entityItemID, properties), +RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID) : + PolyVoxEntityItem(entityItemID), _mesh(new model::Mesh()), _meshDirty(true), _xTexture(nullptr), diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ef44ba5ab0..4068b09e13 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -45,8 +45,7 @@ namespace render { class RenderablePolyVoxEntityItem : public PolyVoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderablePolyVoxEntityItem(const EntityItemID& entityItemID); virtual ~RenderablePolyVoxEntityItem(); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 246cd2fea7..705a9a4d26 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -30,7 +30,9 @@ static const float SPHERE_ENTITY_SCALE = 0.5f; EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableSphereEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableSphereEntityItem::setUserData(const QString& value) { diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.h b/libraries/entities-renderer/src/RenderableSphereEntityItem.h index 293ae79029..737bee3134 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.h +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.h @@ -20,10 +20,7 @@ class RenderableSphereEntityItem : public SphereEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableSphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - SphereEntityItem(entityItemID, properties) - { } + RenderableSphereEntityItem(const EntityItemID& entityItemID) : SphereEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual void setUserData(const QString& value); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index d87f89ba41..bdf3b5b97c 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -22,7 +22,9 @@ #include "GLMHelpers.h" EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableTextEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableTextEntityItem::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index de1d745875..149df946f7 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -22,10 +22,7 @@ const int FIXED_FONT_POINT_SIZE = 40; class RenderableTextEntityItem : public TextEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableTextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - TextEntityItem(entityItemID, properties) - { } + RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { } ~RenderableTextEntityItem() { delete _textRenderer; } virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 84707aca3b..943de1aa76 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -31,11 +31,13 @@ const float DPI = 30.47f; const float METERS_TO_INCHES = 39.3701f; EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableWebEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - WebEntityItem(entityItemID, properties) { +RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) : + WebEntityItem(entityItemID) { qDebug() << "Created web entity " << getID(); } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 63418a890f..2266401b5d 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -22,8 +22,7 @@ class QObject; class RenderableWebEntityItem : public WebEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableWebEntityItem(const EntityItemID& entityItemID); ~RenderableWebEntityItem(); virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ff56bef46b..7dfefb9097 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -24,7 +24,9 @@ static const float SPHERE_ENTITY_SCALE = 0.5f; EntityItemPointer RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableZoneEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } template diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 92de136df6..36555dbc45 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -21,10 +21,10 @@ class RenderableZoneEntityItem : public ZoneEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ZoneEntityItem(entityItemID, properties), - _model(NULL), - _needsInitialSimulation(true) + RenderableZoneEntityItem(const EntityItemID& entityItemID) : + ZoneEntityItem(entityItemID), + _model(NULL), + _needsInitialSimulation(true) { } virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 70d5ba0c4f..061c5b3854 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -21,15 +21,13 @@ #include "EntityTreeElement.h" EntityItemPointer BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new BoxEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new BoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Box; - setProperties(properties); } EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 6c1b5b2312..351feb7e54 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -18,7 +18,7 @@ class BoxEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + BoxEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fd4a4b298c..7c9f3139df 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,7 +85,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; - _constructing = false; } EntityItem::~EntityItem() { diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index fd3f674c5e..ac56fc9c1f 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -24,23 +24,20 @@ bool LightEntityItem::_lightsArePickable = false; EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new LightEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new LightEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Light; - + // default property values _color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0; _intensity = 1.0f; _exponent = 0.0f; _cutoff = PI; - - setProperties(properties); } void LightEntityItem::setDimensions(const glm::vec3& value) { diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 9f8d340852..103c462809 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -18,7 +18,7 @@ class LightEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + LightEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index e03d3a7a96..d48780845f 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -26,20 +26,18 @@ const int LineEntityItem::MAX_POINTS_PER_LINE = 70; EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new LineEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new LineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) , +LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) : + EntityItem(entityItemID), _lineWidth(DEFAULT_LINE_WIDTH), _pointsChanged(true), _points(QVector(0)) { _type = EntityTypes::Line; - setProperties(properties); - - } EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index b20587637f..4d63562cf7 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -18,7 +18,7 @@ class LineEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + LineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b4adde7467..eefe873b74 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -25,17 +25,17 @@ const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ModelEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) +ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _animationProperties.associateWithAnimationLoop(&_animationLoop); _animationLoop.setResetOnRunning(false); _type = EntityTypes::Model; - setProperties(properties); _jointMappingCompleted = false; _lastKnownCurrentFrame = -1; _color[0] = _color[1] = _color[2] = 0; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e8ffcab3e7..8a49759921 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -21,7 +21,7 @@ class ModelEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ModelEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index ddd79375b3..1cd53c87f4 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -97,11 +97,13 @@ const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ParticleEffectEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _lastSimulated(usecTimestampNow()), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), @@ -121,12 +123,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _particleMaxBound(glm::vec3(1.0f, 1.0f, 1.0f)), - _particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) -{ - + _particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) { _type = EntityTypes::ParticleEffect; setColor(DEFAULT_COLOR); - setProperties(properties); } ParticleEffectEntityItem::~ParticleEffectEntityItem() { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 029d65cfc0..be2204a321 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -20,7 +20,7 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ParticleEffectEntityItem(const EntityItemID& entityItemID); virtual ~ParticleEffectEntityItem(); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index f1be431ce8..82ee0e1269 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -26,22 +26,21 @@ const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 70; EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result{ new PolyLineEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity{ new PolyLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -EntityItem(entityItemID), -_lineWidth(DEFAULT_LINE_WIDTH), -_pointsChanged(true), -_points(QVector(0.0f)), -_vertices(QVector(0.0f)), -_normals(QVector(0.0f)), -_strokeWidths(QVector(0.0f)) +PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : + EntityItem(entityItemID), + _lineWidth(DEFAULT_LINE_WIDTH), + _pointsChanged(true), + _points(QVector(0.0f)), + _vertices(QVector(0.0f)), + _normals(QVector(0.0f)), + _strokeWidths(QVector(0.0f)) { _type = EntityTypes::PolyLine; - _created = properties.getCreated(); - setProperties(properties); } EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 86a1dfb6e0..9608bd9b44 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -18,7 +18,7 @@ class PolyLineEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + PolyLineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 403d0bb1bc..9b85938a78 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -32,7 +32,9 @@ const QString PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL = QString(""); const QString PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL = QString(""); EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new PolyVoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } QByteArray PolyVoxEntityItem::makeEmptyVoxelData(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) { @@ -49,7 +51,7 @@ QByteArray PolyVoxEntityItem::makeEmptyVoxelData(quint16 voxelXSize, quint16 vox return newVoxelData; } -PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE), _voxelData(PolyVoxEntityItem::DEFAULT_VOXEL_DATA), @@ -59,7 +61,6 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent _yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL), _zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) { _type = EntityTypes::PolyVox; - setProperties(properties); } void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 9070ad250f..13e541d298 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -18,7 +18,7 @@ class PolyVoxEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + PolyVoxEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 26177f89de..841b70aa56 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -24,16 +24,14 @@ #include "SphereEntityItem.h" EntityItemPointer SphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new SphereEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new SphereEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Sphere; - setProperties(properties); _volumeMultiplier *= PI / 6.0f; } diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index e1e31d4839..941d5a167c 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -18,7 +18,7 @@ class SphereEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + SphereEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 49d3c13d80..893329d1ce 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -30,14 +30,13 @@ const xColor TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; const bool TextEntityItem::DEFAULT_FACE_CAMERA = false; EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new TextEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Text; - setProperties(properties); } const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index d205e9d01e..1caceee085 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -18,7 +18,7 @@ class TextEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + TextEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 56f8357c8f..5f113f1de4 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -23,14 +23,13 @@ const QString WebEntityItem::DEFAULT_SOURCE_URL("http://www.google.com"); EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new WebEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -WebEntityItem::WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Web; - setProperties(properties); } const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 425d89de76..8e9d924cde 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -17,7 +17,7 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + WebEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 3147af35e8..bc74c47e54 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -31,12 +31,12 @@ const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX; const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = ""; EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ZoneEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Zone; _keyLightColor[RED_INDEX] = DEFAULT_KEYLIGHT_COLOR.red; @@ -50,8 +50,6 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL; _backgroundMode = BACKGROUND_MODE_INHERIT; - - setProperties(properties); } diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index e7f2e03981..8a1f8022fc 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -24,7 +24,7 @@ class ZoneEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ZoneEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 9d1220c214..a813a37bfe 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,11 +32,6 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } - if (_constructing) { - // we can't use shared_from_this yet, so stop here. - return nullptr; - } - SpatiallyNestableConstPointer constThisPointer = shared_from_this(); SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 108da796a0..e0ee5bdb74 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -82,8 +82,6 @@ public: NestableTypes::NestableType getNestableType() const { return _nestableType; } protected: - bool _constructing = true; - NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? From f3c61a823e1064d7bfec23f6f56a3605875fb617 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 16:58:09 -0700 Subject: [PATCH 014/165] try harder to get children flags right when something moves. added worldToLocal methods --- libraries/entities/src/EntityItem.cpp | 99 ++++++++++++++------- libraries/entities/src/EntityItem.h | 21 ++--- libraries/physics/src/EntityMotionState.cpp | 4 +- libraries/shared/src/SpatiallyNestable.cpp | 31 +++++++ libraries/shared/src/SpatiallyNestable.h | 9 +- 5 files changed, 114 insertions(+), 50 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7c9f3139df..2dee8a9d44 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -79,8 +79,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulated(false) { // explicitly set transform parts to set dirty flags used by batch rendering - setPosition(ENTITY_ITEM_DEFAULT_POSITION); - setRotation(ENTITY_ITEM_DEFAULT_ROTATION); setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -1309,24 +1307,19 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -bool EntityItem::forSelfAndEachChildEntity(std::function actor) { - bool result = true; +void EntityItem::forSelfAndEachChildEntity(std::function actor) { QQueue toProcess; toProcess.enqueue(shared_from_this()); while (!toProcess.empty()) { EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - - result &= actor(entity); - + actor(entity); foreach (SpatiallyNestablePointer child, entity->getChildren()) { if (child && child->getNestableType() == NestableTypes::Entity) { toProcess.enqueue(child); } } } - - return result; } void EntityItem::updatePosition(const glm::vec3& value) { @@ -1336,16 +1329,76 @@ void EntityItem::updatePosition(const glm::vec3& value) { auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { setLocalPosition(value); + if (delta > ACTIVATION_POSITION_DELTA) { + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } forSelfAndEachChildEntity([&](EntityItemPointer entity) { entity->_dirtyFlags |= Simulation::DIRTY_POSITION; - if (delta > ACTIVATION_POSITION_DELTA) { - entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } - return true; }); } } +void EntityItem::setTransform(const Transform& transform) { + SpatiallyNestable::setTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalTransform(const Transform& transform) { + SpatiallyNestable::setLocalTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalPosition(const glm::vec3& position) { + SpatiallyNestable::setLocalPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::updateRotation(const glm::quat& rotation) { + if (shouldSuppressLocationEdits()) { + return; + } + if (getRotation() != rotation) { + auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); + setRotation(rotation); + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + if (alignmentDot < IGNORE_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; + } + entity->requiresRecalcBoxes(); + }); + } +} + +void EntityItem::setRotation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalRotation(const glm::quat& orientation) { + SpatiallyNestable::setLocalOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { @@ -1357,26 +1410,6 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } } -void EntityItem::updateRotation(const glm::quat& rotation) { - if (shouldSuppressLocationEdits()) { - return; - } - if (getRotation() != rotation) { - setRotation(rotation); - - auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); - - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - if (alignmentDot < IGNORE_ALIGNMENT_DOT) { - entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; - } - if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { - entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } - return true; - }); - } -} void EntityItem::updateMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 6e03e52679..ffcf24854d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -183,15 +183,6 @@ public: const Transform getTransformToCenter() const; void setTranformToCenter(const Transform& transform); - virtual void setTransform(const Transform& transform) { SpatiallyNestable::setTransform(transform); requiresRecalcBoxes(); } - - /// Position in meters (-TREE_SCALE - TREE_SCALE) - virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } - virtual void setPosition(const glm::vec3& value) { SpatiallyNestable::setPosition(value); requiresRecalcBoxes(); } - - virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setRotation(const glm::quat& rotation) { SpatiallyNestable::setOrientation(rotation); requiresRecalcBoxes(); } - inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } // Hyperlink related getters and setters @@ -330,6 +321,16 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } + virtual void setTransform(const Transform& transform); + virtual void setLocalTransform(const Transform& transform); + // virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } + virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + + virtual void setPosition(const glm::vec3& position); + virtual void setLocalPosition(const glm::vec3& position); + virtual void setRotation(const glm::quat& orientation); + virtual void setLocalRotation(const glm::quat& orientation); + // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); void updateDimensions(const glm::vec3& value); @@ -396,7 +397,7 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - bool forSelfAndEachChildEntity(std::function actor); + void forSelfAndEachChildEntity(std::function actor); static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6832b8daff..98d0bb245e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -445,8 +445,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q EntityItemProperties properties; // explicitly set the properties that changed so that they will be packed - properties.setPosition(_serverPosition); - properties.setRotation(_serverRotation); + properties.setPosition(_entity->worldToLocal(_serverPosition)); + properties.setRotation(_entity->worldToLocal(_serverRotation)); properties.setVelocity(_serverVelocity); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a813a37bfe..300d9a5728 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -14,6 +14,16 @@ // TODO -- make use of parent joint index + +SpatiallyNestable::SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : + _nestableType(nestableType), + _id(id), + _transform() { + // set flags in _transform + _transform.setTranslation(glm::vec3(0.0f)); + _transform.setRotation(glm::quat()); +} + Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); @@ -76,6 +86,26 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { _parentKnowsMe = false; } +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform result; + Transform::inverseMult(result, parentTransform, myWorldTransform); + return result.getTranslation(); +} + +glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform result; + Transform::inverseMult(result, parentTransform, myWorldTransform); + return result.getRotation(); +} + const glm::vec3& SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; @@ -131,6 +161,7 @@ const Transform& SpatiallyNestable::getLocalTransform() const { } void SpatiallyNestable::setLocalTransform(const Transform& transform) { + _transform = transform; } const glm::vec3& SpatiallyNestable::getLocalPosition() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e0ee5bdb74..986a282891 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -34,11 +34,7 @@ public: class SpatiallyNestable : public std::enable_shared_from_this { public: - // SpatiallyNestable() : _transform() { } // XXX get rid of this one? - SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : - _nestableType(nestableType), - _id(id), - _transform() { } + SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id); virtual ~SpatiallyNestable() { } virtual const QUuid& getID() const { return _id; } @@ -50,6 +46,9 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } + glm::vec3 worldToLocal(const glm::vec3& position); + glm::quat worldToLocal(const glm::quat& orientation); + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); From f60b1d9bd7c7f64fc9a23ca958667906c0d7d47a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 13:50:35 -0800 Subject: [PATCH 015/165] unmangle merge --- libraries/entities/src/EntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ba82bc230d..a4f4ed6512 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1861,7 +1861,6 @@ const QByteArray EntityItem::getActionDataInternal() const { const QByteArray EntityItem::getActionData() const { QByteArray result; - assertUnlocked(); if (_actionDataDirty) { withWriteLock([&] { From 60824a1fb013dc3a2eb839aef5272d8456a7b670 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 16:07:28 -0800 Subject: [PATCH 016/165] back out some off-brand changes. add parentChanged call --- interface/src/Application.cpp | 142 ++++++++++----------- interface/src/avatar/Avatar.cpp | 32 ++--- interface/src/avatar/AvatarManager.cpp | 26 ++-- interface/src/avatar/AvatarUpdate.cpp | 11 +- libraries/avatars/src/AvatarData.cpp | 55 ++++++-- libraries/avatars/src/AvatarData.h | 18 ++- libraries/entities/src/EntityItem.cpp | 11 -- libraries/shared/src/SpatiallyNestable.cpp | 14 +- libraries/shared/src/SpatiallyNestable.h | 2 + 9 files changed, 178 insertions(+), 133 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e1ba4a8163..e9c2e0ccb1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1128,77 +1128,75 @@ void Application::paintGL() { { PerformanceTimer perfTimer("CameraUpdates"); + auto myAvatar = getMyAvatar(); - myAvatar->withReadLock([&] { - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, - myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, - !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); - cameraMenuChanged(); - } + + myAvatar->startCapture(); + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); + cameraMenuChanged(); + } - // The render mode is default or mirror if the camera is in mirror mode, assigned further below - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; + // The render mode is default or mirror if the camera is in mirror mode, assigned further below + renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - // Always use the default eye position, not the actual head eye position. - // Using the latter will cause the camera to wobble with idle animations, - // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - if (isHMDMode()) { - mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); - } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); - auto worldBoomOffset = myAvatar->getOrientation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); - _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); - } else { - _myCamera.setRotation(myAvatar->getHead()->getOrientation()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getOrientation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); - } - } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); - glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (myAvatar->getOrientation() * - glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); - } else { - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); - } - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + // Always use the default eye position, not the actual head eye position. + // Using the latter will cause the camera to wobble with idle animations, + // or with changes from the face tracker + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + if (isHMDMode()) { + mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setPosition(extractTranslation(camMat)); + _myCamera.setRotation(glm::quat_cast(camMat)); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); } - // Update camera position - if (!isHMDMode()) { - _myCamera.update(1.0f / _fps); + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + if (isHMDMode()) { + auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); + auto worldBoomOffset = myAvatar->getOrientation() * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); + _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); + } else { + _myCamera.setRotation(myAvatar->getHead()->getOrientation()); + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() + * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getOrientation() + * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } } - }); + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + } else { + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + } + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + } + // Update camera position + if (!isHMDMode()) { + _myCamera.update(1.0f / _fps); + } + myAvatar->endCapture(); } // Primary rendering pass @@ -3454,9 +3452,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering. // Then we can move this logic into the Avatar::simulate call. auto myAvatar = getMyAvatar(); - myAvatar->withReadLock([&] { - myAvatar->preRender(renderArgs); - }); + myAvatar->startRender(); + myAvatar->preRender(renderArgs); + myAvatar->endRender(); activeRenderingThread = QThread::currentThread(); @@ -3570,9 +3568,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _renderEngine->setRenderContext(renderContext); // Before the deferred pass, let's try to use the render engine - myAvatar->withReadLock([&] { - _renderEngine->run(); - }); + myAvatar->startRenderRun(); + _renderEngine->run(); + myAvatar->endRenderRun(); auto engineRC = _renderEngine->getRenderContext(); sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4ffa1ffc7c..b6a6ae001d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -377,6 +377,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { + endRender(); return; } @@ -535,6 +536,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { renderDisplayName(batch, frustum, textPosition); } } + endRender(); } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { @@ -1011,25 +1013,23 @@ void Avatar::setBillboard(const QByteArray& billboard) { } int Avatar::parseDataFromBuffer(const QByteArray& buffer) { - int bytesRead; + startUpdate(); + if (!_initialized) { + // now that we have data for this Avatar we are go for init + init(); + } - withWriteLock([&] { - if (!_initialized) { - // now that we have data for this Avatar we are go for init - init(); - } + // change in position implies movement + glm::vec3 oldPosition = getPosition(); - // change in position implies movement - glm::vec3 oldPosition = getPosition(); + int bytesRead = AvatarData::parseDataFromBuffer(buffer); - bytesRead = AvatarData::parseDataFromBuffer(buffer); - - const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; - if (_moving && _motionState) { - _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); - } - }); + const float MOVE_DISTANCE_THRESHOLD = 0.001f; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; + if (_moving && _motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); + } + endUpdate(); return bytesRead; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e9f4c63532..551891cbfa 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -133,9 +133,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { QWriteLocker locker(&_hashLock); avatarIterator = _avatarHash.erase(avatarIterator); } else { - avatar->withWriteLock([&] { - avatar->simulate(deltaTime); - }); + avatar->startUpdate(); + avatar->simulate(deltaTime); + avatar->endUpdate(); ++avatarIterator; } } @@ -154,16 +154,16 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); - avatar->withWriteLock([&] { - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); - if (avatar->getTargetScale() < MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, pendingChanges); - fadingIterator = _avatarFades.erase(fadingIterator); - } else { - avatar->simulate(deltaTime); - ++fadingIterator; - } - }); + avatar->startUpdate(); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); + if (avatar->getTargetScale() < MIN_FADE_SCALE) { + avatar->removeFromScene(*fadingIterator, scene, pendingChanges); + fadingIterator = _avatarFades.erase(fadingIterator); + } else { + avatar->simulate(deltaTime); + ++fadingIterator; + } + avatar->endUpdate(); } scene->enqueuePendingChanges(pendingChanges); } diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index a32948f598..cae593ff85 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -56,11 +56,12 @@ bool AvatarUpdate::process() { //gets current lookat data, removes missing avatars, etc. manager->updateOtherAvatars(deltaSeconds); - myAvatar->withWriteLock([&] { - qApp->updateMyAvatarLookAtPosition(); - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - manager->updateMyAvatar(deltaSeconds); - }); + myAvatar->startUpdate(); + qApp->updateMyAvatarLookAtPosition(); + // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + manager->updateMyAvatar(deltaSeconds); + myAvatar->endUpdate(); + if (!isThreaded()) { return true; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1db573d8d..a06b3448ea 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -111,25 +111,60 @@ void AvatarData::setBodyRoll(float bodyRoll) { } void AvatarData::setPosition(const glm::vec3& position) { - withWriteLock([&] { - SpatiallyNestable::setPosition(position); - }); + SpatiallyNestable::setPosition(position); } void AvatarData::setOrientation(const glm::quat& orientation) { - withWriteLock([&] { - SpatiallyNestable::setOrientation(orientation); - }); + SpatiallyNestable::setOrientation(orientation); } // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { - withWriteLock([&] { - SpatiallyNestable::setPosition(position); - SpatiallyNestable::setOrientation(orientation); - }); + avatarLock.lock(); + SpatiallyNestable::setPosition(position); + SpatiallyNestable::setOrientation(orientation); + avatarLock.unlock(); updateAttitude(); } +void AvatarData::startCapture() { + avatarLock.lock(); + assert(_nextAllowed); + _nextAllowed = false; + _nextPosition = getPosition(); + _nextOrientation = getOrientation(); +} +void AvatarData::endCapture() { + avatarLock.unlock(); +} +void AvatarData::startUpdate() { + avatarLock.lock(); +} +void AvatarData::endUpdate() { + avatarLock.unlock(); +} +void AvatarData::startRenderRun() { + // I'd like to get rid of this and just (un)lock at (end-)startRender. + // But somehow that causes judder in rotations. + avatarLock.lock(); +} +void AvatarData::endRenderRun() { + avatarLock.unlock(); +} +void AvatarData::startRender() { + glm::vec3 pos = getPosition(); + glm::quat rot = getOrientation(); + setPosition(_nextPosition); + setOrientation(_nextOrientation); + updateAttitude(); + _nextPosition = pos; + _nextOrientation = rot; +} +void AvatarData::endRender() { + setPosition(_nextPosition); + setOrientation(_nextOrientation); + updateAttitude(); + _nextAllowed = true; +} float AvatarData::getTargetScale() const { return _targetScale; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8a0a9ac38a..2e3257554d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -44,13 +44,13 @@ typedef unsigned long long quint64; #include #include #include +#include #include #include #include #include #include -#include #include "AABox.h" #include "HandData.h" @@ -136,7 +136,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject, public ReadWriteLockable, public SpatiallyNestable { +class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -200,6 +200,14 @@ public: virtual void setOrientation(const glm::quat& orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. + void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. + void endCapture(); + void startUpdate(); // start/end of update iteration + void endUpdate(); + void startRender(); // start/end of rendering of this object + void startRenderRun(); // start/end of entire scene. + void endRenderRun(); + void endRender(); virtual void updateAttitude() {} // Tell skeleton mesh about changes glm::quat getHeadOrientation() const { return _headData->getOrientation(); } @@ -355,6 +363,10 @@ public slots: protected: glm::vec3 _handPosition; + glm::vec3 _nextPosition {}; + glm::quat _nextOrientation {}; + bool _nextAllowed {true}; + // Body scale float _targetScale; @@ -404,6 +416,8 @@ protected: SimpleMovingAverage _averageBytesReceived; + QMutex avatarLock; // Name is redundant, but it aids searches. + private: static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a4f4ed6512..0227aa23a1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1795,9 +1795,6 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionData to " << actionData.size() << "bytes."; - } withWriteLock([&] { setActionDataInternal(actionData); }); @@ -1805,16 +1802,8 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { if (_allActionsDataCache != actionData) { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionDataInternal to " << actionData.size() << "bytes."; - } - _allActionsDataCache = actionData; deserializeActionsInternal(); - } else { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionDataInternal NOT setting to " << actionData.size() << "bytes."; - } } checkWaitingToRemove(); } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 300d9a5728..f8b1d0dd54 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -61,7 +61,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { _parent.reset(); } - // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing + // we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); _parent = parentFinder->find(_parentID); parent = _parent.lock(); @@ -69,6 +69,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } + + if (parent || _parentID.isNull()) { + parentChanged(); + } + return parent; } @@ -80,10 +85,11 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { _children.remove(newChild->getID()); } - void SpatiallyNestable::setParentID(const QUuid& parentID) { - _parentID = parentID; - _parentKnowsMe = false; + if (_parentID != parentID) { + _parentID = parentID; + _parentKnowsMe = false; + } } glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 986a282891..82e6c3d788 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,6 +92,8 @@ protected: virtual void forgetChild(SpatiallyNestablePointer newChild) const; mutable QHash _children; + virtual void parentChanged() const {} // called when parent pointer is updated + private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From fbaa86426c1359966f6308589c0f9ff91c8cf9e1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 16:52:46 -0800 Subject: [PATCH 017/165] re-remove the _nextPosition stuff --- interface/src/avatar/AvatarUpdate.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 13 ------------- libraries/avatars/src/AvatarData.h | 4 ---- 3 files changed, 18 deletions(-) diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index cae593ff85..acdb251950 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -62,7 +62,6 @@ bool AvatarUpdate::process() { manager->updateMyAvatar(deltaSeconds); myAvatar->endUpdate(); - if (!isThreaded()) { return true; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a06b3448ea..63e20b55b5 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -128,10 +128,6 @@ void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { } void AvatarData::startCapture() { avatarLock.lock(); - assert(_nextAllowed); - _nextAllowed = false; - _nextPosition = getPosition(); - _nextOrientation = getOrientation(); } void AvatarData::endCapture() { avatarLock.unlock(); @@ -151,19 +147,10 @@ void AvatarData::endRenderRun() { avatarLock.unlock(); } void AvatarData::startRender() { - glm::vec3 pos = getPosition(); - glm::quat rot = getOrientation(); - setPosition(_nextPosition); - setOrientation(_nextOrientation); updateAttitude(); - _nextPosition = pos; - _nextOrientation = rot; } void AvatarData::endRender() { - setPosition(_nextPosition); - setOrientation(_nextOrientation); updateAttitude(); - _nextAllowed = true; } float AvatarData::getTargetScale() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 2e3257554d..952017aa77 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -363,10 +363,6 @@ public slots: protected: glm::vec3 _handPosition; - glm::vec3 _nextPosition {}; - glm::quat _nextOrientation {}; - bool _nextAllowed {true}; - // Body scale float _targetScale; From 9b3708ea66a9ebd2cdf6e910039eb4b443776688 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 09:27:57 -0800 Subject: [PATCH 018/165] use parentChanged to recalculate entity bounding boxes --- libraries/entities/src/EntityItem.cpp | 6 ++++++ libraries/entities/src/EntityItem.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 2 +- libraries/shared/src/SpatiallyNestable.h | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0227aa23a1..5394631459 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1324,6 +1324,12 @@ void EntityItem::forSelfAndEachChildEntity(std::functionrequiresRecalcBoxes(); + }); +} + void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ffcf24854d..6692886127 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -398,6 +398,7 @@ protected: void setActionDataInternal(QByteArray actionData); void forSelfAndEachChildEntity(std::function actor); + virtual void parentChanged(); static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index f8b1d0dd54..1d058b56df 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -71,7 +71,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { } if (parent || _parentID.isNull()) { - parentChanged(); + thisPointer->parentChanged(); } return parent; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 82e6c3d788..6550eb721e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,7 +92,7 @@ protected: virtual void forgetChild(SpatiallyNestablePointer newChild) const; mutable QHash _children; - virtual void parentChanged() const {} // called when parent pointer is updated + virtual void parentChanged() {} // called when parent pointer is updated private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From 3154b9d75f5e9762abb39b894240836caa182c40 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 16:21:02 -0800 Subject: [PATCH 019/165] don't set release velocity --- examples/controllers/handControllerGrab.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 2d82896e26..4cce546840 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -895,9 +895,9 @@ function MyController(hand) { // the action will tend to quickly bring an object's velocity to zero. now that // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(this.grabbedEntity, { - velocity: this.grabbedVelocity - }); + // Entities.editEntity(this.grabbedEntity, { + // velocity: this.grabbedVelocity + // }); this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; From 7cb8adb0905c92d2c8e4b3c1a8a847fd7896ffaa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 16:26:30 -0800 Subject: [PATCH 020/165] get rid of code that computes release velocity --- examples/controllers/handControllerGrab.js | 29 +--------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4cce546840..e6381e8770 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -178,12 +178,11 @@ function MyController(hand) { this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. - this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity this.state = STATE_OFF; this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; - + this.offsetPosition = { x: 0.0, y: 0.0, z: 0.0 }; this.offsetRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; @@ -587,7 +586,6 @@ function MyController(hand) { var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters var now = Date.now(); var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - this.computeReleaseVelocity(deltaPosition, deltaTime, false); this.currentObjectPosition = newObjectPosition; this.currentObjectTime = now; @@ -707,7 +705,6 @@ function MyController(hand) { var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - this.computeReleaseVelocity(deltaPosition, deltaTime, true); this.currentHandControllerTipPosition = handControllerPosition; this.currentObjectTime = now; @@ -859,23 +856,6 @@ function MyController(hand) { Entities.callEntityMethod(entityID, "stopTouch"); }; - this.computeReleaseVelocity = function(deltaPosition, deltaTime, useMultiplier) { - if (deltaTime > 0.0 && !vec3equal(deltaPosition, ZERO_VEC)) { - var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); - // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger - // value would otherwise give the held object time to slow down. - if (this.triggerSqueezed()) { - this.grabbedVelocity = - Vec3.sum(Vec3.multiply(this.grabbedVelocity, (1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)), - Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)); - } - - if (useMultiplier) { - this.grabbedVelocity = Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER); - } - } - }; - this.release = function() { if(this.hand !== disabledHand){ @@ -893,13 +873,6 @@ function MyController(hand) { this.deactivateEntity(this.grabbedEntity); - // the action will tend to quickly bring an object's velocity to zero. now that - // the action is gone, set the objects velocity to something the holder might expect. - // Entities.editEntity(this.grabbedEntity, { - // velocity: this.grabbedVelocity - // }); - - this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; this.actionID = null; this.setState(STATE_OFF); From 4ffaa7db8e573ee941b4b60b9ec0217151eea852 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 13:59:37 -0800 Subject: [PATCH 021/165] don't attempt to grab particles or zones --- examples/controllers/handControllerGrab.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e6381e8770..b0721de119 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -451,6 +451,14 @@ function MyController(hand) { continue; } + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { continue; } From 0f214555c13a73823ac3fc680186bc5a12dcfe74 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 09:13:03 -0800 Subject: [PATCH 022/165] New algorithmic stereo reverb --- libraries/audio/src/AudioReverb.cpp | 1965 +++++++++++++++++++++++++++ libraries/audio/src/AudioReverb.h | 76 ++ 2 files changed, 2041 insertions(+) create mode 100644 libraries/audio/src/AudioReverb.cpp create mode 100644 libraries/audio/src/AudioReverb.h diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp new file mode 100644 index 0000000000..3f28a9c00d --- /dev/null +++ b/libraries/audio/src/AudioReverb.cpp @@ -0,0 +1,1965 @@ +// +// AudioReverb.cpp +// libraries/audio/src +// +// Created by Ken Cooke on 10/11/15. +// Copyright 2015 High Fidelity, Inc. +// + +#include +#include +#include + +#include "AudioReverb.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4351) // new behavior: elements of array will be default initialized + +#include +inline static int MULHI(int a, int b) { + long long c = __emul(a, b); + return ((int*)&c)[1]; +} +#else + +#define MULHI(a,b) (int)(((long long)(a) * (b)) >> 32) + +#endif // _MSC_VER + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static const float M_PHI = 0.6180339887f; // maximum allpass diffusion + +static const double M_PI = 3.14159265358979323846; +static const double M_SQRT2 = 1.41421356237309504880; + +static const double FIXQ31 = 2147483648.0; +static const double FIXQ32 = 4294967296.0; + +// Round an integer to the next power-of-two, at compile time. +// VS2013 does not support constexpr so macros are used instead. +#define SETBITS0(x) (x) +#define SETBITS1(x) (SETBITS0(x) | (SETBITS0(x) >> 1)) +#define SETBITS2(x) (SETBITS1(x) | (SETBITS1(x) >> 2)) +#define SETBITS3(x) (SETBITS2(x) | (SETBITS2(x) >> 4)) +#define SETBITS4(x) (SETBITS3(x) | (SETBITS3(x) >> 8)) +#define SETBITS5(x) (SETBITS4(x) | (SETBITS4(x) >> 16)) +#define NEXTPOW2(x) (SETBITS5((x) - 1) + 1) + +// +// Allpass delay modulation +// +static const int MOD_INTBITS = 4; +static const int MOD_FRACBITS = 31 - MOD_INTBITS; +static const uint32_t MOD_FRACMASK = (1 << MOD_FRACBITS) - 1; +static const float QMOD_TO_FLOAT = 1.0f / (1 << MOD_FRACBITS); + +// +// Reverb delay values, defined for sampleRate=48000 roomSize=100% density=100% +// +// max path should already be prime, to prevent getPrime(NEXTPOW2(N)) > NEXTPOW2(N) +// +static const int M_PD0 = 16000; // max predelay = 333ms + +static const int M_AP0 = 83; +static const int M_AP1 = 211; +static const int M_AP2 = 311; +static const int M_AP3 = 97; +static const int M_AP4 = 223; +static const int M_AP5 = 293; + +static const int M_MT0 = 1017; +static const int M_MT1 = 4077; +static const int M_MT2 = 2039; +static const int M_MT3 = 1017; +static const int M_MT4 = 2593; +static const int M_MT5 = 2039; + +static const int M_MT1_2 = 600; +static const int M_MT4_2 = 600; +static const int M_MT1_MAX = MAX(M_MT1, M_MT1_2); +static const int M_MT4_MAX = MAX(M_MT4, M_MT4_2); + +static const int M_AP6 = 817; +static const int M_AP7 = 513; +static const int M_AP8 = 765; +static const int M_AP9 = 465; +static const int M_AP10 = 3021; +static const int M_AP11 = 2121; +static const int M_AP12 = 1705; +static const int M_AP13 = 1081; +static const int M_AP14 = 3313; +static const int M_AP15 = 2205; +static const int M_AP16 = 1773; +static const int M_AP17 = 981; + +static const int M_AP7_MAX = M_AP7 + (1 << MOD_INTBITS) + 1; // include max excursion +static const int M_AP9_MAX = M_AP9 + (1 << MOD_INTBITS) + 1; + +static const int M_MT6 = 6863; +static const int M_MT7 = 7639; +static const int M_MT8 = 3019; +static const int M_MT9 = 2875; + +static const int M_LD0 = 8000; // max late delay = 166ms +static const int M_MT6_MAX = MAX(M_MT6, M_LD0); +static const int M_MT7_MAX = MAX(M_MT7, M_LD0); +static const int M_MT8_MAX = MAX(M_MT8, M_LD0); +static const int M_MT9_MAX = MAX(M_MT9, M_LD0); + +static const int M_AP18 = 131; +static const int M_AP19 = 113; +static const int M_AP20 = 107; +static const int M_AP21 = 127; + +// +// Filter design tools using analog-matched response. +// All filter types approximate the s-plane response, including cutoff > Nyquist. +// + +static float dBToGain(float dB) { + return powf(10.0f, dB * (1/20.0f)); +} + +static double dBToGain(double dB) { + return pow(10.0, dB * (1/20.0)); +} + +// Returns the gain of analog (s-plane) peak-filter evaluated at w +static double analogPeak(double w0, double G, double Q, double w) { + double w0sq, wsq, Gsq, Qsq; + double num, den; + + w0sq = w0 * w0; + wsq = w * w; + Gsq = G * G; + Qsq = Q * Q; + + num = Qsq * (wsq - w0sq) * (wsq - w0sq) + wsq * w0sq * Gsq; + den = Qsq * (wsq - w0sq) * (wsq - w0sq) + wsq * w0sq; + + return sqrt(num / den); +} + +// Returns the gain of analog (s-plane) shelf evaluated at w +// non-resonant Q = sqrt(0.5) so 1/Q^2 = 2.0 +static double analogShelf(double w0, double G, double resonance, int isHigh, double w) { + double w0sq, wsq, Qrsq; + double num, den; + + resonance = MIN(MAX(resonance, 0.0), 1.0); + Qrsq = 2.0 * pow(G, 1.0 - resonance); // resonant 1/Q^2 + + w0sq = w0 * w0; + wsq = w * w; + + if (isHigh) { + num = (G*wsq - w0sq) * (G*wsq - w0sq) + wsq * w0sq * Qrsq; + } else { + num = (wsq - G*w0sq) * (wsq - G*w0sq) + wsq * w0sq * Qrsq; + } + den = wsq * wsq + w0sq * w0sq; + + return sqrt(num / den); +} + +// Returns the gain of analog (s-plane) highpass/lowpass evaluated at w +// Q = sqrt(0.5) = 2nd order Butterworth +static double analogFilter(double w0, int isHigh, double w) { + double w0sq, wsq; + double num, den; + + w0sq = w0 * w0; + wsq = w * w; + + if (isHigh) { + num = wsq * wsq; + } else { + num = w0sq * w0sq; + } + den = wsq * wsq + w0sq * w0sq; + + return sqrt(num / den); +} + +// +// Biquad Peaking EQ using analog matching. +// NOTE: Peak topology becomes ill-conditioned as w0 approaches pi. +// +static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { + double G, G1, Gsq, G1sq, Qsq; + double G11, G00, Gratio; + double wpi, wh, w0sq, whsq; + double Wsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogPeak(w0, G, Q, wpi); + + G1sq = G1 * G1; + Gsq = G * G; + Qsq = Q * Q; + + // compute the analog half-gain frequency + temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); + wh = sqrt(temp) * w0 / (Q * M_SQRT2); + + // prewarp freqs of w0 and wh + w0 = tan(0.5 * w0); + wh = tan(0.5 * wh); + w0sq = w0 * w0; + whsq = wh * wh; + + // compute Wsq, from asymmetry due to G1 + G11 = Gsq - G1sq; + G00 = Gsq - 1.0; + Gratio = G11 / G00; + Wsq = w0sq * sqrt(Gratio); + + // compute B, matching gains at w0 and wh + temp = 2.0 * Wsq * (G1 - sqrt(Gratio)); + temp += Gsq * whsq * (1.0 - G1sq) / G00; + temp += G * Gratio * (w0sq - whsq) * (w0sq - whsq) / whsq; + B = sqrt(temp); + + // compute A, matching gains at w0 and wh + temp = 2.0 * Wsq; + temp += (2.0 * G11 * w0sq + (G1sq - G) * whsq) / (G - Gsq); + temp += Gratio * w0sq * w0sq / (G * whsq); + A = sqrt(temp); + + // design digital filter via bilinear tranform + b0 = G1 + B + Wsq; + b1 = 2.0 * (Wsq - G1); + b2 = G1 - B + Wsq; + a0 = 1.0 + A + Wsq; + a1 = 2.0 * (Wsq - 1.0); + a2 = 1.0 - A + Wsq; + + // for unity gain, ensure poles/zeros in the right place. + // needed for smooth interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Peaking EQ using a shelf instead of peak. +// +// This uses a shelf topology, matched to the analog peaking filter located above Nyquist. +// +// NOTE: the result is close, but not identical to BQPeakBelowPi(), since a pole/zero +// pair must jump to the right side of the real axis. Eg. inflection at the peak goes away. +// However, interpolation from peak to shelf is well behaved if the switch is made near pi, +// as the pole/zero be near (and travel down) the real axis. +// +static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { + double G, G1, Gsq, Qsq; + double wpi, wh, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = M_PI; + if (w0 < M_PI) { + G1 = G; // use the peak gain + } else { + G1 = analogPeak(w0, G, Q, wpi); // use Nyquist gain of analog response + } + + Gsq = G * G; + Qsq = Q * Q; + + // compute the analog half-gain frequency + temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); + wh = sqrt(temp) * w0 / (Q * M_SQRT2); + + // approximate wn and wd + // use half-gain frequency as mapping + wn = 0.5 * wh / sqrt(sqrt((G1))); + wd = wn * sqrt(G1); + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogPeak(w0, G, Q, wna); + gd = temp * analogPeak(w0, G, Q, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // for unity gain, ensure poles/zeros are in the right place. + // allows smooth coefficient interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Peaking EQ using analog matching. +// Supports full range of w0. +// +static void BQPeak(double coef[5], double w0, double dbgain, double Q) { + w0 = MAX(w0, 0.0); // allow w0 > pi + + Q = MIN(MAX(Q, 1.0e-6), 1.0e+6); + + // Switch from peak to shelf, just before w0 = pi. + // Too early causes a jump in the peak location, which interpolates to lowered gains. + // Too late becomes ill-conditioned, and makes no improvement to interpolated response. + // 3.14 is a good choice. + if (w0 > 3.14) { + BQPeakAbovePi(coef, w0, dbgain, Q); + } else { + BQPeakBelowPi(coef, w0, dbgain, Q); + } +} + +// +// Biquad Shelf using analog matching. +// +static void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { + double G, G1; + double wpi, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + w0 = MAX(w0, 0.0); // allow w0 > pi + + resonance = MIN(MAX(resonance, 0.0), 1.0); + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogShelf(w0, G, resonance, isHigh, wpi); + + // approximate wn and wd + if (isHigh) { + // use center as mapping + wn = 0.5 * w0 / sqrt(sqrt((G * G1))); + wd = wn * sqrt(G1); + } else { + // use wd as mapping + wd = 0.5 * w0; + wn = wd * sqrt(G/G1); + } + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogShelf(w0, G, resonance, isHigh, wna); + gd = temp * analogShelf(w0, G, resonance, isHigh, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // for unity gain, ensure poles/zeros in the right place. + // needed for smooth interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Lowpass/Highpass using analog matching. +// Q = sqrt(0.5) = 2nd order Butterworth +// +static void BQFilter(double coef[5], double w0, int isHigh) { + double G1; + double wpi, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + + w0 = MAX(w0, 0.0); // allow w0 > pi for lowpass + + if (isHigh) { + + w0 = MIN(w0, M_PI); // disallow w0 > pi for highpass + + // compute the Nyquist gain + wpi = M_PI; + G1 = analogFilter(w0, isHigh, wpi); + + // approximate wn and wd + wn = 0.0; // zeros at zero + wd = 0.5 * w0; + + Wnsq = wn * wn; + Wdsq = wd * wd; + + // compute B and A + B = 0.0; + A = M_SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; + + } else { + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogFilter(w0, isHigh, wpi); + + // approximate wn and wd + wd = 0.5 * w0; + wn = wd * sqrt(1.0/G1); // down G1 at pi, instead of zeros + + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogFilter(w0, isHigh, wna); + gd = temp * analogFilter(w0, isHigh, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + } + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// PoleZero Shelf. For Lowpass/Highpass, setCoef dbgain to -100dB. +// NOTE: w0 always sets the pole frequency (3dB corner from unity gain) +// +static void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { + double G, G0, G1; + double b0, b1, a0, a1; + double temp, scale; + + w0 = MAX(w0, 0.0); // allow w0 > pi + + // convert boost into cut, invert later + G = dBToGain(-fabs(dbgain)); + + if (isHigh) { + G0 = 1.0; // gain at DC + G1 = G; // gain at Nyquist + } else { + G0 = G; + G1 = 1.0; + } + + b0 = 1.0; + a0 = 1.0; + b1 = -exp(-w0 * G0 / G1); + a1 = -exp(-w0); + + b1 += 0.12 * (1.0 + b1) * (1.0 + b1) * (1.0 - G1); // analog-matched gain near Nyquist + + scale = G0 * (1.0 + a1) / (1.0 + b1); + b0 *= scale; + b1 *= scale; + + // invert filter for boost + if (dbgain > 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = a1 * scale; +} + +class BandwidthEQ { + + float _buffer[4] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + + float _dcL = 0.0f; + float _dcR = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + float _a1 = 0.0f; + float _a2 = 0.0f; + + float _alpha = 0.0f; + +public: + void setFreq(float freq, float sampleRate) { + freq = MIN(MAX(freq, 1.0f), 24000.0f); + + // lowpass filter, -3dB @ freq + double coef[5]; + BQFilter(coef, M_PI * freq / (0.5 * sampleRate), 0); + _b0 = (float)coef[0]; + _b1 = (float)coef[1]; + _b2 = (float)coef[2]; + _a1 = (float)coef[3]; + _a2 = (float)coef[4]; + + // DC-blocking filter, -3dB @ 10Hz + _alpha = (float)(1.0 - exp(-M_PI * 10.0 / (0.5 * sampleRate))); + } + + void process(float input0, float input1, float& output0, float& output1) { + output0 = _output0; + output1 = _output1; + + // prevent denormalized zero-input limit cycles in the reverb + input0 += 1.0e-20f; + input1 += 1.0e-20f; + + // remove DC + input0 -= _dcL; + input1 -= _dcR; + + _dcL += _alpha * input0; + _dcR += _alpha * input1; + + // transposed Direct Form II + _output0 = _b0 * input0 + _buffer[0]; + _buffer[0] = _b1 * input0 - _a1 * _output0 + _buffer[1]; + _buffer[1] = _b2 * input0 - _a2 * _output0; + + _output1 = _b0 * input1 + _buffer[2]; + _buffer[2] = _b1 * input1 - _a1 * _output1 + _buffer[3]; + _buffer[3] = _b2 * input1 - _a2 * _output1; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + _dcL = 0.0f; + _dcR = 0.0f; + } +}; + +template +class DelayLine { + + float _buffer[N] {}; + + float _output = 0.0f; + + int _index = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _delay = d; + } + + void process(float input, float& output) { + output = _output; + + int k = (_index - _delay) & (N - 1); + + _output = _buffer[k]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +template +class Allpass { + + float _buffer[N] {}; + + float _output = 0.0f; + float _coef = 0.5f; + + int _index0 = 0; + int _index1 = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _index1 = (_index0 - d) & (N - 1); + _delay = d; + } + + int getDelay() { + return _delay; + } + + void setCoef(float coef) { + coef = MIN(MAX(coef, -1.0f), 1.0f); + + _coef = coef; + } + + void process(float input, float& output) { + output = _output; + + _output = _buffer[_index1] - _coef * input; // feedforward path + _buffer[_index0] = input + _coef * _output; // feedback path + + _index0 = (_index0 + 1) & (N - 1); + _index1 = (_index1 + 1) & (N - 1); + } + + void getOutput(float& output) { + output = _output; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class RandomLFO { + + int32_t _y0 = 0; + int32_t _y1 = 0; + int32_t _k = 0; + + int32_t _gain = 0; + + uint32_t _rand0 = 0; + int32_t _q0 = 0; // prev + int32_t _r0 = 0; // next + int32_t _m0 = _r0/2 - _q0/2; // slope + int32_t _b0 = _r0/2 + _q0/2; // offset + + uint32_t _rand1 = 0; + int32_t _q1 = 0; + int32_t _r1 = 0; + int32_t _m1 = _q1/2 - _r1/2; + int32_t _b1 = _q1/2 + _r1/2; + +public: + void setFreq(float freq, float sampleRate) { + freq = MIN(freq, 1/16.0f * sampleRate); + freq = MAX(freq, 1/16777216.0f * sampleRate); + + // amplitude slightly less than 1.0 + _y0 = (int32_t)(0.000 * FIXQ31); + _y1 = (int32_t)(0.999 * cos(M_PI * freq / sampleRate) * FIXQ31); + + _k = (int32_t)(2.0 * sin(M_PI * freq / sampleRate) * FIXQ32); + } + + void setGain(int32_t gain) { + gain = MIN(MAX(gain, 0), 0x7fffffff); + + _gain = gain; + } + + void process(int32_t& lfoSin, int32_t& lfoCos) { + lfoSin = _y0; + lfoCos = _y1; + + // "Magic Circle" quadrature oscillator + _y1 -= MULHI(_k, _y0); + _y0 += MULHI(_k, _y1); + + // since the oscillators are in quadrature, zero-crossing in one detects a peak in the other + if ((lfoCos ^ _y1) < 0) { + //_rand0 = 69069 * _rand0 + 1; + _rand0 = (11 * _rand0 + 0x04000000) & 0xfc000000; // periodic version + + _q0 = _r0; + _r0 = 2 * MULHI((int32_t)_rand0, _gain); // Q31 + + // scale the peak-to-peak segment to traverse from q0 to r0 + _m0 = _r0/2 - _q0/2; // slope in Q31 + _b0 = _r0/2 + _q0/2; // offset in Q31 + + int32_t sign = _y1 >> 31; + _m0 = (_m0 ^ sign) - sign; + } + if ((lfoSin ^ _y0) < 0) { + //_rand1 = 69069 * _rand1 + 1; + _rand1 = (11 * _rand1 + 0x04000000) & 0xfc000000; // periodic version + + _q1 = _r1; + _r1 = 2 * MULHI((int32_t)_rand1, _gain); // Q31 + + // scale the peak-to-peak segment to traverse from q1 to r1 + _m1 = _q1/2 - _r1/2; // slope in Q31 + _b1 = _q1/2 + _r1/2; // offset in Q31 + + int32_t sign = _y0 >> 31; + _m1 = (_m1 ^ sign) - sign; + } + + lfoSin = 2 * MULHI(lfoSin, _m0) + _b0; // Q31 + lfoCos = 2 * MULHI(lfoCos, _m1) + _b1; // Q31 + } +}; + +template +class AllPassMod { + + float _buffer[N] {}; + + float _output = 0.0f; + float _coef = 0.5f; + + int _index = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _delay = d; + } + + int getDelay() { + return _delay; + } + + void setCoef(float coef) { + coef = MIN(MAX(coef, -1.0f), 1.0f); + + _coef = coef; + } + + void process(float input, int32_t mod, float& output) { + output = _output; + + // add modulation to delay + uint32_t offset = _delay + (mod >> MOD_FRACBITS); + float frac = (mod & MOD_FRACMASK) * QMOD_TO_FLOAT; + + // 3rd-order Lagrange interpolation + int k0 = (_index - (offset-1)) & (N - 1); + int k1 = (_index - (offset+0)) & (N - 1); + int k2 = (_index - (offset+1)) & (N - 1); + int k3 = (_index - (offset+2)) & (N - 1); + + float x0 = _buffer[k0]; + float x1 = _buffer[k1]; + float x2 = _buffer[k2]; + float x3 = _buffer[k3]; + + // compute the polynomial coefficients + float c0 = (1/6.0f) * (x3 - x0) + (1/2.0f) * (x1 - x2); + float c1 = (1/2.0f) * (x0 + x2) - x1; + float c2 = x2 - (1/3.0f) * x0 - (1/2.0f) * x1 - (1/6.0f) * x3; + float c3 = x1; + + // compute the polynomial + float delayMod = ((c0 * frac + c1) * frac + c2) * frac + c3; + + _output = delayMod - _coef * input; // feedforward path + _buffer[_index] = input + _coef * _output; // feedback path + + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class LowpassEQ { + + float _buffer[2] {}; + + float _output = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + +public: + void setFreq(float sampleRate) { + sampleRate = MIN(MAX(sampleRate, 24000.0f), 48000.0f); + + // two-zero lowpass filter, with zeros at approximately 12khz + // zero radius is adjusted to match the response from 0..9khz + _b0 = 0.5f; + _b1 = 0.5f * sqrtf(2.0f * 12000.0f/(0.5f * sampleRate) - 1.0f); + _b2 = 0.5f - _b1; + } + + void process(float input, float& output) { + output = _output; + + _output = _b0 * input + _b1 * _buffer[0] + _b2 * _buffer[1]; + _buffer[1] = _buffer[0]; + _buffer[0] = input; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class DampingEQ { + + float _buffer[2] {}; + + float _output = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + float _a1 = 0.0f; + float _a2 = 0.0f; + +public: + void setCoef(float dBgain0, float dBgain1, float freq0, float freq1, float sampleRate) { + dBgain0 = MIN(MAX(dBgain0, -100.0f), 100.0f); + dBgain1 = MIN(MAX(dBgain1, -100.0f), 100.0f); + freq0 = MIN(MAX(freq0, 1.0f), 24000.0f); + freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); + + double coefLo[3], coefHi[3]; + PZShelf(coefLo, M_PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf + PZShelf(coefHi, M_PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + + // convolve into a single biquad + _b0 = (float)(coefLo[0] * coefHi[0]); + _b1 = (float)(coefLo[0] * coefHi[1] + coefLo[1] * coefHi[0]); + _b2 = (float)(coefLo[1] * coefHi[1]); + _a1 = (float)(coefLo[2] + coefHi[2]); + _a2 = (float)(coefLo[2] * coefHi[2]); + } + + void process(float input, float& output) { + output = _output; + + // transposed Direct Form II + _output = _b0 * input + _buffer[0]; + _buffer[0] = _b1 * input - _a1 * _output + _buffer[1]; + _buffer[1] = _b2 * input - _a2 * _output; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +template +class MultiTap2 { + + float _buffer[N] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + + float _gain0 = 1.0f; + float _gain1 = 1.0f; + + int _index = 0; + int _delay0 = N; + int _delay1 = N; + +public: + void setDelay(int d0, int d1) { + d0 = MIN(MAX(d0, 1), N); + d1 = MIN(MAX(d1, 1), N); + + _delay0 = d0; + _delay1 = d1; + } + + int getDelay(int k) { + switch (k) { + case 0: return _delay0; + case 1: return _delay1; + default: return 0; + } + } + + void setGain(float g0, float g1) { + _gain0 = g0; + _gain1 = g1; + } + + void process(float input, float& output0, float& output1) { + output0 = _output0; + output1 = _output1; + + int k0 = (_index - _delay0) & (N - 1); + int k1 = (_index - _delay1) & (N - 1); + + _output0 = _gain0 * _buffer[k0]; + _output1 = _gain1 * _buffer[k1]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + } +}; + +template +class MultiTap3 { + + float _buffer[N] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + float _output2 = 0.0f; + + float _gain0 = 1.0f; + float _gain1 = 1.0f; + float _gain2 = 1.0f; + + int _index = 0; + int _delay0 = N; + int _delay1 = N; + int _delay2 = N; + +public: + void setDelay(int d0, int d2) { + d0 = MIN(MAX(d0, 1), N); + d2 = MIN(MAX(d2, 1), N); + + _delay0 = d0; + _delay1 = d0 - 1; + _delay2 = d2; + } + + int getDelay(int k) { + switch (k) { + case 0: return _delay0; + case 1: return _delay1; + case 2: return _delay2; + default: return 0; + } + } + + void setGain(float g0, float g1, float g2) { + _gain0 = g0; + _gain1 = g1; + _gain2 = g2; + } + + void process(float input, float& output0, float& output1, float& output2) { + output0 = _output0; + output1 = _output1; + output2 = _output2; + + int k0 = (_index - _delay0) & (N - 1); + int k1 = (_index - _delay1) & (N - 1); + int k2 = (_index - _delay2) & (N - 1); + + _output0 = _gain0 * _buffer[k0]; + _output1 = _gain1 * _buffer[k1]; + _output2 = _gain2 * _buffer[k2]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + _output2 = 0.0f; + } +}; + +// +// Stereo Reverb +// +class ReverbImpl { + + // Preprocess + BandwidthEQ _bw; + DelayLine _dl0; + DelayLine _dl1; + + // Early Left + float _earlyMix1L = 0.0f; + float _earlyMix2L = 0.0f; + + MultiTap3 _mt0; + Allpass _ap0; + MultiTap3 _mt1; + Allpass _ap1; + Allpass _ap2; + MultiTap2 _mt2; + + // Early Right + float _earlyMix1R = 0.0f; + float _earlyMix2R = 0.0f; + + MultiTap3 _mt3; + Allpass _ap3; + MultiTap3 _mt4; + Allpass _ap4; + Allpass _ap5; + MultiTap2 _mt5; + + RandomLFO _lfo; + + // Late + Allpass _ap6; + AllPassMod _ap7; + DampingEQ _eq0; + MultiTap2 _mt6; + + Allpass _ap8; + AllPassMod _ap9; + DampingEQ _eq1; + MultiTap2 _mt7; + + Allpass _ap10; + Allpass _ap11; + Allpass _ap12; + Allpass _ap13; + MultiTap2 _mt8; + LowpassEQ _lp0; + + Allpass _ap14; + Allpass _ap15; + Allpass _ap16; + Allpass _ap17; + MultiTap2 _mt9; + LowpassEQ _lp1; + + // Output Left + Allpass _ap18; + Allpass _ap19; + + // Output Right + Allpass _ap20; + Allpass _ap21; + + float _earlyGain = 0.0f; + float _wetDryMix = 0.0f; + +public: + void setParameters(ReverbParameters *p); + void process(float** inputs, float** outputs, int numFrames); + void reset(); +}; + +static const short primeTable[] = { + 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, + 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, + 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, + 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, + 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, + 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, + 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, + 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, + 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, + 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, + 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, + 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, + 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, + 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, + 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, + 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, + 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, + 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, + 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, + 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, + 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, + 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, + 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, + 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, + 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, + 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, + 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, + 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, + 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, + 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, + 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, + 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, + 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, + 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, + 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, + 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, + 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, + 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, + 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, + 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, + 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, + 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, + 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, + 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, + 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, + 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, + 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, + 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, + 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, + 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, + 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, + 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, + 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, + 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, + 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, + 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, + 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, + 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, + 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, +}; + +static int getPrime(int n) { + int low = 0; + int high = sizeof(primeTable) / sizeof(primeTable[0]) - 1; + + // clip to table limits + if (n <= primeTable[low]) { + return primeTable[low]; + } + if (n >= primeTable[high]) { + return primeTable[high]; + } + + // binary search + while (low <= high) { + int mid = (low + high) >> 1; + + if (n < primeTable[mid]) { + high = mid - 1; + } else if (n > primeTable[mid]) { + low = mid + 1; + } else { + return n; // found it + } + } + + //return primeTable[high]; // lower prime + //return (n - primeTable[high]) < (primeTable[low] - n) ? primeTable[high] : primeTable[low]; // nearest prime + return primeTable[low]; // higher prime +} + +static int scaleDelay(float delay, float sampleRate) { + return getPrime((int)(delay * (sampleRate/48000.0f) + 0.5f)); +} + +// +// Piecewise-linear lookup tables +// input clamped to [0.0f, 100.0f] +// +static const float earlyMix0Table[][2] = { + 0.0000f, 0.6000f, + 63.3333f, 0.0800f, + 83.3333f, 0.0200f, + 93.3333f, 0.0048f, + 100.0000f, 0.0048f, +}; + +static const float earlyMix1Table[][2] = { + 0.0000f, 0.3360f, + 20.0000f, 0.6000f, + 100.0000f, 0.0240f, +}; + +static const float earlyMix2Table[][2] = { + 0.0000f, 0.0480f, + 13.3333f, 0.0960f, + 53.3333f, 0.9600f, + 100.0000f, 0.1200f, +}; + +static const float lateMix0Table[][2] = { + 0.0000f, 0.1250f, + 13.3333f, 0.1875f, + 66.6666f, 0.7500f, + 100.0000f, 0.8750f, +}; + +static const float lateMix1Table[][2] = { + 0.0000f, 0.9990f, + 33.3333f, 0.5000f, + 66.6666f, 0.9990f, + 93.3333f, 0.6000f, + 100.0000f, 0.6000f, +}; + +static const float lateMix2Table[][2] = { + 0.0000f, 0.9990f, + 33.3333f, 0.9990f, + 63.3333f, 0.4500f, + 100.0000f, 0.9990f, +}; + +static const float diffusionCoefTable[][2] = { + 0.0000f, 0.0000f, + 20.0000f, 0.0470f, + 33.3333f, 0.0938f, + 46.6666f, 0.1563f, + 60.0000f, 0.2344f, + 73.3333f, 0.3125f, + 93.3333f, 0.5000f, + 100.0000f, M_PHI, +}; + +static const float roomSizeTable[][2] = { + 0.0000f, 0.1500f, + 25.0000f, 0.3000f, + 50.0000f, 0.5000f, + 100.0000f, 1.0000f, +}; + +static float interpolateTable(const float table[][2], float x) { + x = MIN(MAX(x, 0.0f), 100.0f); + + // locate the segment in the table + int i = 0; + while (x > table[i+1][0]) { + i++; + } + + // linear interpolate + float frac = (x - table[i+0][0]) / (table[i+1][0] - table[i+0][0]); + return table[i+0][1] + frac * (table[i+1][1] - table[i+0][1]); +} + +void ReverbImpl::setParameters(ReverbParameters *p) { + + float sampleRate = MIN(MAX(p->sampleRate, 24000.0f), 48000.0f); + + // Bandwidth + _bw.setFreq(p->bandwidth, sampleRate); + + // Modulation + _lfo.setFreq(p->modRate, sampleRate); + _lfo.setGain((int32_t)MIN(MAX(p->modDepth * (1/100.0) * FIXQ31, 0.0), 0X7fffffff)); + + // + // Set delays + // + int preDelay = (int)(p->preDelay * (1/1000.0f) * sampleRate + 0.5f); + preDelay = MIN(MAX(preDelay, 1), M_PD0); + _dl0.setDelay(preDelay); + _dl1.setDelay(preDelay); + + // RoomSize scalefactor + float roomSize = interpolateTable(roomSizeTable, p->roomSize); + + // Density scalefactors + float density0 = p->density * (1/25.0f) - 0.0f; + float density1 = p->density * (1/25.0f) - 1.0f; + float density2 = p->density * (1/25.0f) - 2.0f; + float density3 = p->density * (1/25.0f) - 3.0f; + density0 = MIN(MAX(density0, 0.0f), 1.0f); + density1 = MIN(MAX(density1, 0.0f), 1.0f); + density2 = MIN(MAX(density2, 0.0f), 1.0f); + density3 = MIN(MAX(density3, 0.0f), 1.0f); + + // Early delays + _ap0.setDelay(scaleDelay(M_AP0 * 1.0f, sampleRate)); + _ap1.setDelay(scaleDelay(M_AP1 * 1.0f, sampleRate)); + _ap2.setDelay(scaleDelay(M_AP2 * 1.0f, sampleRate)); + _ap3.setDelay(scaleDelay(M_AP3 * 1.0f, sampleRate)); + _ap4.setDelay(scaleDelay(M_AP4 * 1.0f, sampleRate)); + _ap5.setDelay(scaleDelay(M_AP5 * 1.0f, sampleRate)); + + _mt0.setDelay(scaleDelay(M_MT0 * roomSize, sampleRate), 1); + _mt1.setDelay(scaleDelay(M_MT1 * roomSize, sampleRate), scaleDelay(M_MT1_2 * 1.0f, sampleRate)); + _mt2.setDelay(scaleDelay(M_MT2 * roomSize, sampleRate), 1); + _mt3.setDelay(scaleDelay(M_MT3 * roomSize, sampleRate), 1); + _mt4.setDelay(scaleDelay(M_MT4 * roomSize, sampleRate), scaleDelay(M_MT4_2 * 1.0f, sampleRate)); + _mt5.setDelay(scaleDelay(M_MT5 * roomSize, sampleRate), 1); + + // Late delays + _ap6.setDelay(scaleDelay(M_AP6 * roomSize * density3, sampleRate)); + _ap7.setDelay(scaleDelay(M_AP7 * roomSize, sampleRate)); + _ap8.setDelay(scaleDelay(M_AP8 * roomSize * density3, sampleRate)); + _ap9.setDelay(scaleDelay(M_AP9 * roomSize, sampleRate)); + _ap10.setDelay(scaleDelay(M_AP10 * roomSize * density1, sampleRate)); + _ap11.setDelay(scaleDelay(M_AP11 * roomSize * density2, sampleRate)); + _ap12.setDelay(scaleDelay(M_AP12 * roomSize, sampleRate)); + _ap13.setDelay(scaleDelay(M_AP13 * roomSize * density3, sampleRate)); + _ap14.setDelay(scaleDelay(M_AP14 * roomSize * density1, sampleRate)); + _ap15.setDelay(scaleDelay(M_AP15 * roomSize * density2, sampleRate)); + _ap16.setDelay(scaleDelay(M_AP16 * roomSize * density3, sampleRate)); + _ap17.setDelay(scaleDelay(M_AP17 * roomSize * density3, sampleRate)); + + int lateDelay = scaleDelay(p->lateDelay * (1/1000.0f) * 48000, sampleRate); + lateDelay = MIN(MAX(lateDelay, 1), M_LD0); + + _mt6.setDelay(scaleDelay(M_MT6 * roomSize * density3, sampleRate), lateDelay); + _mt7.setDelay(scaleDelay(M_MT7 * roomSize * density2, sampleRate), lateDelay); + _mt8.setDelay(scaleDelay(M_MT8 * roomSize * density0, sampleRate), lateDelay); + _mt9.setDelay(scaleDelay(M_MT9 * roomSize, sampleRate), lateDelay); + + // Output delays + _ap18.setDelay(scaleDelay(M_AP18 * 1.0f, sampleRate)); + _ap19.setDelay(scaleDelay(M_AP19 * 1.0f, sampleRate)); + _ap20.setDelay(scaleDelay(M_AP20 * 1.0f, sampleRate)); + _ap21.setDelay(scaleDelay(M_AP21 * 1.0f, sampleRate)); + + // RT60 is determined by mean delay of feedback paths + int loopDelay; + loopDelay = _ap6.getDelay(); + loopDelay += _ap7.getDelay(); + loopDelay += _ap8.getDelay(); + loopDelay += _ap9.getDelay(); + loopDelay += _ap10.getDelay(); + loopDelay += _ap11.getDelay(); + loopDelay += _ap12.getDelay(); + loopDelay += _ap13.getDelay(); + loopDelay += _ap14.getDelay(); + loopDelay += _ap15.getDelay(); + loopDelay += _ap16.getDelay(); + loopDelay += _ap17.getDelay(); + loopDelay += _mt6.getDelay(0); + loopDelay += _mt7.getDelay(0); + loopDelay += _mt8.getDelay(0); + loopDelay += _mt9.getDelay(0); + loopDelay /= 2; + + // + // Set gains + // + float rt60 = MIN(MAX(p->reverbTime, 0.01f), 100.0f); + float rt60Gain = -60.0f * loopDelay / (rt60 * sampleRate); // feedback gain (dB) for desired RT + + float bassMult = MIN(MAX(p->bassMult, 0.1f), 10.0f); + float bassGain = (1.0f / bassMult - 1.0f) * rt60Gain; // filter gain (dB) that results in RT *= mult + + float loopGain1 = sqrtf(0.5f * dBToGain(rt60Gain)); // distributed (series-parallel) loop gain + float loopGain2 = 0.9f - (0.63f * loopGain1); + + // Damping + _eq0.setCoef(bassGain, p->highGain, p->bassFreq, p->highFreq, sampleRate); + _eq1.setCoef(bassGain, p->highGain, p->bassFreq, p->highFreq, sampleRate); + _lp0.setFreq(sampleRate); + _lp1.setFreq(sampleRate); + + float earlyDiffusionCoef = interpolateTable(diffusionCoefTable, p->earlyDiffusion); + + // Early Left + _earlyMix1L = interpolateTable(earlyMix1Table, p->earlyMixRight); + _earlyMix2L = interpolateTable(earlyMix2Table, p->earlyMixLeft); + + _mt0.setGain(0.2f, 0.4f, interpolateTable(earlyMix0Table, p->earlyMixLeft)); + + _ap0.setCoef(earlyDiffusionCoef); + _ap1.setCoef(earlyDiffusionCoef); + _ap2.setCoef(earlyDiffusionCoef); + + _mt1.setGain(0.2f, 0.6f, interpolateTable(lateMix0Table, p->lateMixLeft) * 0.125f); + + _mt2.setGain(interpolateTable(lateMix1Table, p->lateMixLeft) * loopGain2, + interpolateTable(lateMix2Table, p->lateMixLeft) * loopGain2); + + // Early Right + _earlyMix1R = interpolateTable(earlyMix1Table, p->earlyMixLeft); + _earlyMix2R = interpolateTable(earlyMix2Table, p->earlyMixRight); + + _mt3.setGain(0.2f, 0.4f, interpolateTable(earlyMix0Table, p->earlyMixRight)); + + _ap3.setCoef(earlyDiffusionCoef); + _ap4.setCoef(earlyDiffusionCoef); + _ap5.setCoef(earlyDiffusionCoef); + + _mt4.setGain(0.2f, 0.6f, interpolateTable(lateMix0Table, p->lateMixRight) * 0.125f); + + _mt5.setGain(interpolateTable(lateMix1Table, p->lateMixRight) * loopGain2, + interpolateTable(lateMix2Table, p->lateMixRight) * loopGain2); + + _earlyGain = dBToGain(p->earlyGain); + + // Late + float lateDiffusionCoef = interpolateTable(diffusionCoefTable, p->lateDiffusion); + _ap6.setCoef(lateDiffusionCoef); + _ap7.setCoef(lateDiffusionCoef); + _ap8.setCoef(lateDiffusionCoef); + _ap9.setCoef(lateDiffusionCoef); + + _ap10.setCoef(M_PHI); + _ap11.setCoef(M_PHI); + _ap12.setCoef(lateDiffusionCoef); + _ap13.setCoef(lateDiffusionCoef); + + _ap14.setCoef(M_PHI); + _ap15.setCoef(M_PHI); + _ap16.setCoef(lateDiffusionCoef); + _ap17.setCoef(lateDiffusionCoef); + + float lateGain = dBToGain(p->lateGain) * 2.0f; + _mt6.setGain(loopGain1, lateGain * interpolateTable(lateMix0Table, p->lateMixLeft)); + _mt7.setGain(loopGain1, lateGain * interpolateTable(lateMix0Table, p->lateMixRight)); + _mt8.setGain(loopGain1, lateGain * interpolateTable(lateMix2Table, p->lateMixLeft) * loopGain2 * 0.125f); + _mt9.setGain(loopGain1, lateGain * interpolateTable(lateMix2Table, p->lateMixRight) * loopGain2 * 0.125f); + + // Output + float outputDiffusionCoef = lateDiffusionCoef * 0.6f; + _ap18.setCoef(outputDiffusionCoef); + _ap19.setCoef(outputDiffusionCoef); + _ap20.setCoef(outputDiffusionCoef); + _ap21.setCoef(outputDiffusionCoef); + + _wetDryMix = p->wetDryMix * (1/100.0f); + _wetDryMix = MIN(MAX(_wetDryMix, 0.0f), 1.0f); +} + +void ReverbImpl::process(float** inputs, float** outputs, int numFrames) { + + for (int i = 0; i < numFrames; i++) { + float x0, x1, y0, y1, y2, y3; + + // Preprocess + x0 = inputs[0][i]; + x1 = inputs[1][i]; + _bw.process(x0, x1, x0, x1); + + float preL, preR; + _dl0.process(x0, preL); + _dl1.process(x1, preR); + + // Early Left + float early0L, early1L, early2L, earlyOutL; + _mt0.process(preL, x0, x1, y0); + _ap0.process(x0 + x1, y1); + _mt1.process(y1, x0, x1, early0L); + _ap1.process(x0 + x1, y2); + _ap2.process(y2, x0); + _mt2.process(x0, early1L, early2L); + + earlyOutL = (y0 + y1 * _earlyMix1L + y2 * _earlyMix2L) * _earlyGain; + + // Early Right + float early0R, early1R, early2R, earlyOutR; + _mt3.process(preR, x0, x1, y0); + _ap3.process(x0 + x1, y1); + _mt4.process(y1, x0, x1, early0R); + _ap4.process(x0 + x1, y2); + _ap5.process(y2, x0); + _mt5.process(x0, early1R, early2R); + + earlyOutR = (y0 + y1 * _earlyMix1R + y2 * _earlyMix2R) * _earlyGain; + + // LFO update + int32_t lfoSin, lfoCos; + _lfo.process(lfoSin, lfoCos); + + // Late + float lateOut0; + _ap6.getOutput(x0); + _ap7.process(x0, lfoSin, x0); + _eq0.process(-early0L + x0, x0); + _mt6.process(x0, y0, lateOut0); + + float lateOut1; + _ap8.getOutput(x0); + _ap9.process(x0, lfoCos, x0); + _eq1.process(-early0R + x0, x0); + _mt7.process(x0, y1, lateOut1); + + float lateOut2; + _ap10.getOutput(x0); + _ap11.process(-early2L + x0, x0); + _ap12.process(x0, x0); + _ap13.process(-early2L - x0, x0); + _mt8.process(-early0L + x0, x0, lateOut2); + _lp0.process(x0, y2); + + float lateOut3; + _ap14.getOutput(x0); + _ap15.process(-early2R + x0, x0); + _ap16.process(x0, x0); + _ap17.process(-early2R - x0, x0); + _mt9.process(-early0R + x0, x0, lateOut3); + _lp1.process(x0, y3); + + // Feedback matrix + _ap6.process(early1L + y2 - y3, x0); + _ap8.process(early1R - y2 - y3, x0); + _ap10.process(-early2R + y0 + y1, x0); + _ap14.process(-early2L - y0 + y1, x0); + + // Output Left + _ap18.process(-earlyOutL + lateOut0 + lateOut3, x0); + _ap19.process(x0, y0); + + // Output Right + _ap20.process(-earlyOutR + lateOut1 + lateOut2, x1); + _ap21.process(x1, y1); + + x0 = inputs[0][i]; + x1 = inputs[1][i]; + outputs[0][i] = x0 + (y0 - x0) * _wetDryMix; + outputs[1][i] = x1 + (y1 - x1) * _wetDryMix; + } +} + +// clear internal state, but retain settings +void ReverbImpl::reset() { + + _bw.reset(); + + _dl0.reset(); + _dl1.reset(); + + _mt0.reset(); + _mt1.reset(); + _mt2.reset(); + _mt3.reset(); + _mt4.reset(); + _mt5.reset(); + _mt6.reset(); + _mt7.reset(); + _mt8.reset(); + _mt9.reset(); + + _ap0.reset(); + _ap1.reset(); + _ap2.reset(); + _ap3.reset(); + _ap4.reset(); + _ap5.reset(); + _ap6.reset(); + _ap7.reset(); + _ap8.reset(); + _ap9.reset(); + _ap10.reset(); + _ap11.reset(); + _ap12.reset(); + _ap13.reset(); + _ap14.reset(); + _ap15.reset(); + _ap16.reset(); + _ap17.reset(); + _ap18.reset(); + _ap19.reset(); + _ap20.reset(); + _ap21.reset(); + + _eq0.reset(); + _eq1.reset(); + + _lp0.reset(); + _lp1.reset(); +} + +// +// Public API +// + +static const int REVERB_BLOCK = 1024; + +AudioReverb::AudioReverb(float sampleRate) { + + _impl = new ReverbImpl; + + // format conversion buffers + _inout[0] = new float[REVERB_BLOCK]; + _inout[1] = new float[REVERB_BLOCK]; + + // default parameters + ReverbParameters p; + p.sampleRate = sampleRate; + p.bandwidth = 10000.0f; + + p.preDelay = 20.0f; + p.lateDelay = 0.0f; + + p.reverbTime = 2.0f; + + p.earlyDiffusion = 100.0f; + p.lateDiffusion = 100.0f; + + p.roomSize = 50.0f; + p.density = 100.0f; + + p.bassMult = 1.5f; + p.bassFreq = 250.0f; + p.highGain = -6.0f; + p.highFreq = 3000.0f; + + p.modRate = 2.3f; + p.modDepth = 50.0f; + + p.earlyGain = 0.0f; + p.lateGain = 0.0f; + + p.earlyMixLeft = 20.0f; + p.earlyMixRight = 20.0f; + p.lateMixLeft = 90.0f; + p.lateMixRight = 90.0f; + + p.wetDryMix = 100.0f; + + setParameters(&p); +} + +AudioReverb::~AudioReverb() { + delete _impl; + + delete[] _inout[0]; + delete[] _inout[1]; +} + +void AudioReverb::setParameters(ReverbParameters *p) { + _params = *p; + _impl->setParameters(p); +}; + +void AudioReverb::getParameters(ReverbParameters *p) { + *p = _params; +}; + +void AudioReverb::reset() { + _impl->reset(); +} + +void AudioReverb::render(float** inputs, float** outputs, int numFrames) { + _impl->process(inputs, outputs, numFrames); +} + +// +// on x86 architecture, assume that SSE2 is present +// +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) + +#include + +// convert int16_t to float, deinterleave stereo +void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) { + __m128 scale = _mm_set1_ps(1/32768.0f); + + int i = 0; + for (; i < numFrames - 3; i += 4) { + __m128i a0 = _mm_loadu_si128((__m128i*)&input[2*i]); + __m128i a1 = a0; + + // deinterleave and sign-extend + a0 = _mm_madd_epi16(a0, _mm_set1_epi32(0x00000001)); + a1 = _mm_madd_epi16(a1, _mm_set1_epi32(0x00010000)); + + __m128 f0 = _mm_mul_ps(_mm_cvtepi32_ps(a0), scale); + __m128 f1 = _mm_mul_ps(_mm_cvtepi32_ps(a1), scale); + + _mm_storeu_ps(&outputs[0][i], f0); + _mm_storeu_ps(&outputs[1][i], f1); + } + for (; i < numFrames; i++) { + __m128i a0 = _mm_cvtsi32_si128(*(int32_t*)&input[2*i]); + __m128i a1 = a0; + + // deinterleave and sign-extend + a0 = _mm_madd_epi16(a0, _mm_set1_epi32(0x00000001)); + a1 = _mm_madd_epi16(a1, _mm_set1_epi32(0x00010000)); + + __m128 f0 = _mm_mul_ps(_mm_cvtepi32_ps(a0), scale); + __m128 f1 = _mm_mul_ps(_mm_cvtepi32_ps(a1), scale); + + _mm_store_ss(&outputs[0][i], f0); + _mm_store_ss(&outputs[1][i], f1); + } +} + +// fast TPDF dither in [-1.0f, 1.0f] +static inline __m128 dither4() { + static __m128i rz; + + // update the 8 different maximum-length LCGs + rz = _mm_mullo_epi16(rz, _mm_set_epi16(25173, -25511, -5975, -23279, 19445, -27591, 30185, -3495)); + rz = _mm_add_epi16(rz, _mm_set_epi16(13849, -32767, 105, -19675, -7701, -32679, -13225, 28013)); + + // promote to 32-bit + __m128i r0 = _mm_unpacklo_epi16(rz, _mm_setzero_si128()); + __m128i r1 = _mm_unpackhi_epi16(rz, _mm_setzero_si128()); + + // return (r0 - r1) * (1/65536.0f); + __m128 d0 = _mm_cvtepi32_ps(_mm_sub_epi32(r0, r1)); + return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f)); +} + +// convert float to int16_t, interleave stereo +void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) { + __m128 scale = _mm_set1_ps(32768.0f); + + int i = 0; + for (; i < numFrames - 3; i += 4) { + __m128 f0 = _mm_mul_ps(_mm_loadu_ps(&inputs[0][i]), scale); + __m128 f1 = _mm_mul_ps(_mm_loadu_ps(&inputs[1][i]), scale); + + __m128 d0 = dither4(); + f0 = _mm_add_ps(f0, d0); + f1 = _mm_add_ps(f1, d0); + + // round and saturate + __m128i a0 = _mm_cvtps_epi32(f0); + __m128i a1 = _mm_cvtps_epi32(f1); + a0 = _mm_packs_epi32(a0, a0); + a1 = _mm_packs_epi32(a1, a1); + + // interleave + a0 = _mm_unpacklo_epi16(a0, a1); + _mm_storeu_si128((__m128i*)&output[2*i], a0); + } + for (; i < numFrames; i++) { + __m128 f0 = _mm_mul_ps(_mm_load_ss(&inputs[0][i]), scale); + __m128 f1 = _mm_mul_ps(_mm_load_ss(&inputs[1][i]), scale); + + __m128 d0 = dither4(); + f0 = _mm_add_ps(f0, d0); + f1 = _mm_add_ps(f1, d0); + + // round and saturate + __m128i a0 = _mm_cvtps_epi32(f0); + __m128i a1 = _mm_cvtps_epi32(f1); + a0 = _mm_packs_epi32(a0, a0); + a1 = _mm_packs_epi32(a1, a1); + + // interleave + a0 = _mm_unpacklo_epi16(a0, a1); + *(int32_t*)&output[2*i] = _mm_cvtsi128_si32(a0); + } +} + +#else + +// convert int16_t to float, deinterleave stereo +void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) { + const float scale = 1/32768.0f; + + for (int i = 0; i < numFrames; i++) { + outputs[0][i] = (float)input[2*i + 0] * scale; + outputs[1][i] = (float)input[2*i + 1] * scale; + } +} + +// fast TPDF dither in [-1.0f, 1.0f] +static inline float dither() { + static uint32_t rz = 0; + rz = rz * 69069 + 1; + int32_t r0 = rz & 0xffff; + int32_t r1 = rz >> 16; + return (int32_t)(r0 - r1) * (1/65536.0f); +} + +// convert float to int16_t, interleave stereo +void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) { + const float scale = 32768.0f; + + for (int i = 0; i < numFrames; i++) { + + float f0 = inputs[0][i] * scale; + float f1 = inputs[1][i] * scale; + + float d = dither(); + f0 += d; + f1 += d; + + // round and saturate + f0 += (f0 < 0.0f ? -0.5f : +0.5f); + f1 += (f1 < 0.0f ? -0.5f : +0.5f); + f0 = MIN(MAX(f0, -32768.0f), 32767.0f); + f1 = MIN(MAX(f1, -32768.0f), 32767.0f); + + // interleave + output[2*i + 0] = (int16_t)f0; + output[2*i + 1] = (int16_t)f1; + } +} + +#endif + +// +// This version handles input/output as interleaved int16_t +// +void AudioReverb::render(const int16_t* input, int16_t* output, int numFrames) { + + while (numFrames) { + + int n = MIN(numFrames, REVERB_BLOCK); + + convertInputFromInt16(input, _inout, n); + + _impl->process(_inout, _inout, n); + + convertOutputToInt16(_inout, output, n); + + input += 2 * n; + output += 2 * n; + numFrames -= n; + } +} diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h new file mode 100644 index 0000000000..f135a46127 --- /dev/null +++ b/libraries/audio/src/AudioReverb.h @@ -0,0 +1,76 @@ +// +// AudioReverb.h +// libraries/audio/src +// +// Created by Ken Cooke on 10/11/15. +// Copyright 2015 High Fidelity, Inc. +// + +#ifndef hifi_AudioReverb_h +#define hifi_AudioReverb_h + +#include "stdint.h" + +typedef struct ReverbParameters { + + float sampleRate; // [24000, 48000] Hz + float bandwidth; // [20, 24000] Hz + + float preDelay; // [0, 333] ms + float lateDelay; // [0, 166] ms + + float reverbTime; // [0.1, 100] seconds + + float earlyDiffusion; // [0, 100] percent + float lateDiffusion; // [0, 100] percent + + float roomSize; // [0, 100] percent + float density; // [0, 100] percent + + float bassMult; // [0.1, 10] ratio + float bassFreq; // [10, 500] Hz + float highGain; // [-24, 0] dB + float highFreq; // [1000, 12000] Hz + + float modRate; // [0.1, 10] Hz + float modDepth; // [0, 100] percent + + float earlyGain; // [-96, +24] dB + float lateGain; // [-96, +24] dB + + float earlyMixLeft; // [0, 100] percent + float earlyMixRight; // [0, 100] percent + float lateMixLeft; // [0, 100] percent + float lateMixRight; // [0, 100] percent + + float wetDryMix; // [0, 100] percent + +} ReverbParameters; + +class ReverbImpl; + +class AudioReverb { + + ReverbImpl *_impl; + ReverbParameters _params; + + float* _inout[2]; + void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); + void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); + +public: + AudioReverb(float sampleRate); + ~AudioReverb(); + + void setParameters(ReverbParameters *p); + void getParameters(ReverbParameters *p); + void reset(); + + // deinterleaved float input/output (native format) + void render(float** inputs, float** outputs, int numFrames); + + // interleaved int16_t input/output + void render(const int16_t* input, int16_t* output, int numFrames); +}; + +#endif // hifi_AudioReverb_h From c61dad108c5125fad38cf1e360c94904a6fc4bfa Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 09:16:18 -0800 Subject: [PATCH 023/165] Replace Gverb with new reverb --- libraries/audio-client/src/AudioClient.cpp | 184 ++++++++++++--------- libraries/audio-client/src/AudioClient.h | 12 +- 2 files changed, 114 insertions(+), 82 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a506fe217c..daf89d3473 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -119,7 +119,7 @@ AudioClient::AudioClient() : _audioSourceInjectEnabled(false), _reverb(false), _reverbOptions(&_scriptReverbOptions), - _gverb(NULL), + //_gverb(NULL), _inputToNetworkResampler(NULL), _networkToOutputResampler(NULL), _loopbackResampler(NULL), @@ -145,8 +145,8 @@ AudioClient::AudioClient() : updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS); // create GVerb filter - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket"); @@ -160,9 +160,9 @@ AudioClient::AudioClient() : AudioClient::~AudioClient() { stop(); - if (_gverb) { - gverb_free(_gverb); - } + //if (_gverb) { + // gverb_free(_gverb); + //} } void AudioClient::reset() { @@ -173,7 +173,8 @@ void AudioClient::reset() { _sourceGain.reset(); _inputGain.reset(); - gverb_flush(_gverb); + //gverb_flush(_gverb); + _stereoReverb.reset(); } void AudioClient::audioMixerKilled() { @@ -568,27 +569,42 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -ty_gverb* AudioClient::createGverbFilter() { - // Initialize a new gverb instance - ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), - _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), - _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), - _reverbOptions->getTailLevel()); +//ty_gverb* AudioClient::createGverbFilter() { +// // Initialize a new gverb instance +// ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), +// _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), +// _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), +// _reverbOptions->getTailLevel()); +// +// return filter; +//} - return filter; -} - -void AudioClient::configureGverbFilter(ty_gverb* filter) { +void AudioClient::configureReverb() { // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); - gverb_set_revtime(filter, _reverbOptions->getReverbTime()); - gverb_set_damping(filter, _reverbOptions->getDamping()); - gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); - gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); - gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); + //gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); + //gverb_set_revtime(filter, _reverbOptions->getReverbTime()); + //gverb_set_damping(filter, _reverbOptions->getDamping()); + //gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); + //gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); + //gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); + + ReverbParameters p; + _stereoReverb.getParameters(&p); + + // for now, use the gverb settings + p.sampleRate = _outputFormat.sampleRate(); + p.roomSize = _reverbOptions->getRoomSize(); + p.reverbTime = _reverbOptions->getReverbTime(); + p.highGain = -24.0f * _reverbOptions->getDamping(); + p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); + //p.earlyGain = _reverbOptions->getEarlyLevel(); + //p.lateGain = _reverbOptions->getTailLevel(); + p.wetDryMix = _shouldEchoLocally ? DB_CO(_reverbOptions->getWetLevel()) : 100.0f; // !_shouldEchoLocally apparently means 100% wet? + + _stereoReverb.setParameters(&p); } -void AudioClient::updateGverbOptions() { +void AudioClient::updateReverbOptions() { bool reverbChanged = false; if (_receivedAudioStream.hasReverb()) { @@ -599,6 +615,7 @@ void AudioClient::updateGverbOptions() { if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); // Not part of actual filter config, no need to set reverbChanged to true + reverbChanged = true; } if (_reverbOptions != &_zoneReverbOptions) { @@ -611,9 +628,9 @@ void AudioClient::updateGverbOptions() { } if (reverbChanged) { - gverb_free(_gverb); - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //gverb_free(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); } } @@ -621,7 +638,8 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - gverb_flush(_gverb); + //gverb_flush(_gverb); + _stereoReverb.reset(); } } @@ -641,49 +659,49 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) { if (_reverbOptions == &_scriptReverbOptions) { // Apply them to the reverb instances - gverb_free(_gverb); - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //gverb_free(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); } } -void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, - QAudioFormat& audioFormat, bool noEcho) { - float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - float dryFraction = 1.0f - wetFraction; - - float lValue,rValue; - for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { - // Run GVerb - float value = (float)samplesData[sample]; - gverb_do(gverb, value, &lValue, &rValue); - - // Mix, accounting for clipping, the left and right channels. Ignore the rest. - for (int j = sample; j < sample + audioFormat.channelCount(); j++) { - if (j == sample) { - // left channel - int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), - AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); - samplesData[j] = (int16_t)lResult; - - if (noEcho) { - reverbAlone[j] = (int16_t)lValue * wetFraction; - } - } else if (j == (sample + 1)) { - // right channel - int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), - AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); - samplesData[j] = (int16_t)rResult; - - if (noEcho) { - reverbAlone[j] = (int16_t)rValue * wetFraction; - } - } else { - // ignore channels above 2 - } - } - } -} +//void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, +// QAudioFormat& audioFormat, bool noEcho) { +// float wetFraction = DB_CO(_reverbOptions->getWetLevel()); +// float dryFraction = 1.0f - wetFraction; +// +// float lValue,rValue; +// for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { +// // Run GVerb +// float value = (float)samplesData[sample]; +// gverb_do(gverb, value, &lValue, &rValue); +// +// // Mix, accounting for clipping, the left and right channels. Ignore the rest. +// for (int j = sample; j < sample + audioFormat.channelCount(); j++) { +// if (j == sample) { +// // left channel +// int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), +// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); +// samplesData[j] = (int16_t)lResult; +// +// if (noEcho) { +// reverbAlone[j] = (int16_t)lValue * wetFraction; +// } +// } else if (j == (sample + 1)) { +// // right channel +// int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), +// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); +// samplesData[j] = (int16_t)rResult; +// +// if (noEcho) { +// reverbAlone[j] = (int16_t)rValue * wetFraction; +// } +// } else { +// // ignore channels above 2 +// } +// } +// } +//} void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. @@ -715,30 +733,42 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount); } - static QByteArray reverbAlone; // Intermediary for local reverb with no echo + //static QByteArray reverbAlone; // Intermediary for local reverb with no echo static QByteArray loopBackByteArray; int numInputSamples = inputByteArray.size() / sizeof(int16_t); int numLoopbackSamples = numDestinationSamplesRequired(_inputFormat, _outputFormat, numInputSamples); - reverbAlone.resize(numInputSamples * sizeof(int16_t)); + //reverbAlone.resize(numInputSamples * sizeof(int16_t)); loopBackByteArray.resize(numLoopbackSamples * sizeof(int16_t)); int16_t* inputSamples = reinterpret_cast(inputByteArray.data()); - int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); + //int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); int16_t* loopbackSamples = reinterpret_cast(loopBackByteArray.data()); - if (hasReverb) { - updateGverbOptions(); - addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, - _inputFormat, !_shouldEchoLocally); - } + //if (hasReverb) { + // updateGverbOptions(); + // addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, + // _inputFormat, !_shouldEchoLocally); + //} + + //possibleResampling(_loopbackResampler, + // (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, + // numInputSamples, numLoopbackSamples, + // _inputFormat, _outputFormat); possibleResampling(_loopbackResampler, - (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, + inputSamples, loopbackSamples, numInputSamples, numLoopbackSamples, _inputFormat, _outputFormat); + if (hasReverb) { + // always use the stereo reverb output + assert(_outputFormat.channelCount() == 2); + updateReverbOptions(); + _stereoReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); + } + _loopbackOutputDevice->write(loopBackByteArray); } diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 7d2b5a783f..c2a235938b 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -46,6 +46,7 @@ #include "AudioIOStats.h" #include "AudioNoiseGate.h" #include "AudioSRC.h" +#include "AudioReverb.h" #ifdef _WIN32 #pragma warning( push ) @@ -262,7 +263,8 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - ty_gverb* _gverb; + //ty_gverb* _gverb; + AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample AudioSRC* _inputToNetworkResampler; @@ -270,10 +272,10 @@ private: AudioSRC* _loopbackResampler; // Adds Reverb - ty_gverb* createGverbFilter(); - void configureGverbFilter(ty_gverb* filter); - void updateGverbOptions(); - void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); + //ty_gverb* createGverbFilter(); + void configureReverb(); + void updateReverbOptions(); + //void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); void handleLocalEchoAndReverb(QByteArray& inputByteArray); From 8ae3fa61c50d846cab1bf4c423e0bc47168b3045 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 10:06:40 -0800 Subject: [PATCH 024/165] Fix compiler issues --- libraries/audio/src/AudioReverb.cpp | 60 ++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index 3f28a9c00d..a822da3377 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -17,8 +17,8 @@ #include inline static int MULHI(int a, int b) { - long long c = __emul(a, b); - return ((int*)&c)[1]; + long long c = __emul(a, b); + return ((int*)&c)[1]; } #else @@ -33,10 +33,10 @@ inline static int MULHI(int a, int b) { #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -static const float M_PHI = 0.6180339887f; // maximum allpass diffusion +static const float PHI = 0.6180339887f; // maximum allpass diffusion -static const double M_PI = 3.14159265358979323846; -static const double M_SQRT2 = 1.41421356237309504880; +static const double PI = 3.14159265358979323846; +static const double SQRT2 = 1.41421356237309504880; static const double FIXQ31 = 2147483648.0; static const double FIXQ32 = 4294967296.0; @@ -208,8 +208,8 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { G = MAX(G, 1.001); // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogPeak(w0, G, Q, wpi); G1sq = G1 * G1; @@ -218,7 +218,7 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { // compute the analog half-gain frequency temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); - wh = sqrt(temp) * w0 / (Q * M_SQRT2); + wh = sqrt(temp) * w0 / (Q * SQRT2); // prewarp freqs of w0 and wh w0 = tan(0.5 * w0); @@ -305,8 +305,8 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { G = MAX(G, 1.001); // compute the Nyquist gain - wpi = M_PI; - if (w0 < M_PI) { + wpi = PI; + if (w0 < PI) { G1 = G; // use the peak gain } else { G1 = analogPeak(w0, G, Q, wpi); // use Nyquist gain of analog response @@ -317,7 +317,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { // compute the analog half-gain frequency temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); - wh = sqrt(temp) * w0 / (Q * M_SQRT2); + wh = sqrt(temp) * w0 / (Q * SQRT2); // approximate wn and wd // use half-gain frequency as mapping @@ -425,8 +425,8 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, G = MAX(G, 1.001); // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogShelf(w0, G, resonance, isHigh, wpi); // approximate wn and wd @@ -513,10 +513,10 @@ static void BQFilter(double coef[5], double w0, int isHigh) { if (isHigh) { - w0 = MIN(w0, M_PI); // disallow w0 > pi for highpass + w0 = MIN(w0, PI); // disallow w0 > pi for highpass // compute the Nyquist gain - wpi = M_PI; + wpi = PI; G1 = analogFilter(w0, isHigh, wpi); // approximate wn and wd @@ -528,13 +528,13 @@ static void BQFilter(double coef[5], double w0, int isHigh) { // compute B and A B = 0.0; - A = M_SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; + A = SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; } else { // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogFilter(w0, isHigh, wpi); // approximate wn and wd @@ -653,7 +653,7 @@ public: // lowpass filter, -3dB @ freq double coef[5]; - BQFilter(coef, M_PI * freq / (0.5 * sampleRate), 0); + BQFilter(coef, PI * freq / (0.5 * sampleRate), 0); _b0 = (float)coef[0]; _b1 = (float)coef[1]; _b2 = (float)coef[2]; @@ -661,7 +661,7 @@ public: _a2 = (float)coef[4]; // DC-blocking filter, -3dB @ 10Hz - _alpha = (float)(1.0 - exp(-M_PI * 10.0 / (0.5 * sampleRate))); + _alpha = (float)(1.0 - exp(-PI * 10.0 / (0.5 * sampleRate))); } void process(float input0, float input1, float& output0, float& output1) { @@ -809,9 +809,9 @@ public: // amplitude slightly less than 1.0 _y0 = (int32_t)(0.000 * FIXQ31); - _y1 = (int32_t)(0.999 * cos(M_PI * freq / sampleRate) * FIXQ31); + _y1 = (int32_t)(0.999 * cos(PI * freq / sampleRate) * FIXQ31); - _k = (int32_t)(2.0 * sin(M_PI * freq / sampleRate) * FIXQ32); + _k = (int32_t)(2.0 * sin(PI * freq / sampleRate) * FIXQ32); } void setGain(int32_t gain) { @@ -895,7 +895,7 @@ public: output = _output; // add modulation to delay - uint32_t offset = _delay + (mod >> MOD_FRACBITS); + int32_t offset = _delay + (mod >> MOD_FRACBITS); float frac = (mod & MOD_FRACMASK) * QMOD_TO_FLOAT; // 3rd-order Lagrange interpolation @@ -985,8 +985,8 @@ public: freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); double coefLo[3], coefHi[3]; - PZShelf(coefLo, M_PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf - PZShelf(coefHi, M_PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + PZShelf(coefLo, PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf + PZShelf(coefHi, PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf // convolve into a single biquad _b0 = (float)(coefLo[0] * coefHi[0]); @@ -1374,7 +1374,7 @@ static const float diffusionCoefTable[][2] = { 60.0000f, 0.2344f, 73.3333f, 0.3125f, 93.3333f, 0.5000f, - 100.0000f, M_PHI, + 100.0000f, PHI, }; static const float roomSizeTable[][2] = { @@ -1552,13 +1552,13 @@ void ReverbImpl::setParameters(ReverbParameters *p) { _ap8.setCoef(lateDiffusionCoef); _ap9.setCoef(lateDiffusionCoef); - _ap10.setCoef(M_PHI); - _ap11.setCoef(M_PHI); + _ap10.setCoef(PHI); + _ap11.setCoef(PHI); _ap12.setCoef(lateDiffusionCoef); _ap13.setCoef(lateDiffusionCoef); - _ap14.setCoef(M_PHI); - _ap15.setCoef(M_PHI); + _ap14.setCoef(PHI); + _ap15.setCoef(PHI); _ap16.setCoef(lateDiffusionCoef); _ap17.setCoef(lateDiffusionCoef); From 1a7f06dc95a7f72b31bf21dc119ed96ad9c4fec7 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 10:26:06 -0800 Subject: [PATCH 025/165] Removed the commented-out Gverb code --- libraries/audio-client/src/AudioClient.cpp | 112 +-------------------- libraries/audio-client/src/AudioClient.h | 5 - 2 files changed, 2 insertions(+), 115 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index daf89d3473..eb0be9dc17 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -33,29 +33,6 @@ #include #include -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -#ifdef WIN32 -#pragma warning (push) -#pragma warning (disable: 4273 4305) -#endif - -extern "C" { - #include - #include -} - -#ifdef WIN32 -#pragma warning (pop) -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - #include #include #include @@ -119,7 +96,6 @@ AudioClient::AudioClient() : _audioSourceInjectEnabled(false), _reverb(false), _reverbOptions(&_scriptReverbOptions), - //_gverb(NULL), _inputToNetworkResampler(NULL), _networkToOutputResampler(NULL), _loopbackResampler(NULL), @@ -144,8 +120,6 @@ AudioClient::AudioClient() : connect(updateTimer, &QTimer::timeout, this, &AudioClient::checkDevices); updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS); - // create GVerb filter - //_gverb = createGverbFilter(); configureReverb(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); @@ -159,10 +133,6 @@ AudioClient::AudioClient() : AudioClient::~AudioClient() { stop(); - - //if (_gverb) { - // gverb_free(_gverb); - //} } void AudioClient::reset() { @@ -172,8 +142,6 @@ void AudioClient::reset() { _toneSource.reset(); _sourceGain.reset(); _inputGain.reset(); - - //gverb_flush(_gverb); _stereoReverb.reset(); } @@ -569,29 +537,11 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -//ty_gverb* AudioClient::createGverbFilter() { -// // Initialize a new gverb instance -// ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), -// _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), -// _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), -// _reverbOptions->getTailLevel()); -// -// return filter; -//} - void AudioClient::configureReverb() { - // Configure the instance (these functions are not super well named - they actually set several internal variables) - //gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); - //gverb_set_revtime(filter, _reverbOptions->getReverbTime()); - //gverb_set_damping(filter, _reverbOptions->getDamping()); - //gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); - //gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); - //gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); - ReverbParameters p; _stereoReverb.getParameters(&p); - // for now, use the gverb settings + // for now, reuse the gverb parameters p.sampleRate = _outputFormat.sampleRate(); p.roomSize = _reverbOptions->getRoomSize(); p.reverbTime = _reverbOptions->getReverbTime(); @@ -599,7 +549,7 @@ void AudioClient::configureReverb() { p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); //p.earlyGain = _reverbOptions->getEarlyLevel(); //p.lateGain = _reverbOptions->getTailLevel(); - p.wetDryMix = _shouldEchoLocally ? DB_CO(_reverbOptions->getWetLevel()) : 100.0f; // !_shouldEchoLocally apparently means 100% wet? + p.wetDryMix = _shouldEchoLocally ? powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)) : 100.0f; _stereoReverb.setParameters(&p); } @@ -614,7 +564,6 @@ void AudioClient::updateReverbOptions() { } if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - // Not part of actual filter config, no need to set reverbChanged to true reverbChanged = true; } @@ -628,8 +577,6 @@ void AudioClient::updateReverbOptions() { } if (reverbChanged) { - //gverb_free(_gverb); - //_gverb = createGverbFilter(); configureReverb(); } } @@ -638,7 +585,6 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - //gverb_flush(_gverb); _stereoReverb.reset(); } } @@ -659,50 +605,10 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) { if (_reverbOptions == &_scriptReverbOptions) { // Apply them to the reverb instances - //gverb_free(_gverb); - //_gverb = createGverbFilter(); configureReverb(); } } -//void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, -// QAudioFormat& audioFormat, bool noEcho) { -// float wetFraction = DB_CO(_reverbOptions->getWetLevel()); -// float dryFraction = 1.0f - wetFraction; -// -// float lValue,rValue; -// for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { -// // Run GVerb -// float value = (float)samplesData[sample]; -// gverb_do(gverb, value, &lValue, &rValue); -// -// // Mix, accounting for clipping, the left and right channels. Ignore the rest. -// for (int j = sample; j < sample + audioFormat.channelCount(); j++) { -// if (j == sample) { -// // left channel -// int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); -// samplesData[j] = (int16_t)lResult; -// -// if (noEcho) { -// reverbAlone[j] = (int16_t)lValue * wetFraction; -// } -// } else if (j == (sample + 1)) { -// // right channel -// int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); -// samplesData[j] = (int16_t)rResult; -// -// if (noEcho) { -// reverbAlone[j] = (int16_t)rValue * wetFraction; -// } -// } else { -// // ignore channels above 2 -// } -// } -// } -//} - void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); @@ -733,30 +639,16 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount); } - //static QByteArray reverbAlone; // Intermediary for local reverb with no echo static QByteArray loopBackByteArray; int numInputSamples = inputByteArray.size() / sizeof(int16_t); int numLoopbackSamples = numDestinationSamplesRequired(_inputFormat, _outputFormat, numInputSamples); - //reverbAlone.resize(numInputSamples * sizeof(int16_t)); loopBackByteArray.resize(numLoopbackSamples * sizeof(int16_t)); int16_t* inputSamples = reinterpret_cast(inputByteArray.data()); - //int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); int16_t* loopbackSamples = reinterpret_cast(loopBackByteArray.data()); - //if (hasReverb) { - // updateGverbOptions(); - // addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, - // _inputFormat, !_shouldEchoLocally); - //} - - //possibleResampling(_loopbackResampler, - // (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, - // numInputSamples, numLoopbackSamples, - // _inputFormat, _outputFormat); - possibleResampling(_loopbackResampler, inputSamples, loopbackSamples, numInputSamples, numLoopbackSamples, diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index c2a235938b..30e60d1775 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -75,8 +75,6 @@ class QAudioInput; class QAudioOutput; class QIODevice; -typedef struct ty_gverb ty_gverb; - class NLPacket; @@ -263,7 +261,6 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - //ty_gverb* _gverb; AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample @@ -272,10 +269,8 @@ private: AudioSRC* _loopbackResampler; // Adds Reverb - //ty_gverb* createGverbFilter(); void configureReverb(); void updateReverbOptions(); - //void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); void handleLocalEchoAndReverb(QByteArray& inputByteArray); From cc90662bf050b7cf3cf3ec51313e284ed00a8351 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 12:17:27 -0800 Subject: [PATCH 026/165] PR feedback --- libraries/audio/src/AudioReverb.cpp | 8 ++++---- libraries/audio/src/AudioReverb.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index a822da3377..f06bbe76ed 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -244,7 +244,7 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { temp += Gratio * w0sq * w0sq / (G * whsq); A = sqrt(temp); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 + B + Wsq; b1 = 2.0 * (Wsq - G1); b2 = G1 - B + Wsq; @@ -347,7 +347,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); A = temp * sqrt(num / den); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); @@ -463,7 +463,7 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); A = temp * sqrt(num / den); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); @@ -566,7 +566,7 @@ static void BQFilter(double coef[5], double w0, int isHigh) { A = temp * sqrt(num / den); } - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h index f135a46127..92e9c0009b 100644 --- a/libraries/audio/src/AudioReverb.h +++ b/libraries/audio/src/AudioReverb.h @@ -50,14 +50,6 @@ typedef struct ReverbParameters { class ReverbImpl; class AudioReverb { - - ReverbImpl *_impl; - ReverbParameters _params; - - float* _inout[2]; - void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); - void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); - public: AudioReverb(float sampleRate); ~AudioReverb(); @@ -71,6 +63,14 @@ public: // interleaved int16_t input/output void render(const int16_t* input, int16_t* output, int numFrames); + +private: + ReverbImpl *_impl; + ReverbParameters _params; + + float* _inout[2]; + void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); + void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); }; #endif // hifi_AudioReverb_h From 2489eaa30e3c0384baf90f9ae8f14397d54a022a Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 08:32:13 -0800 Subject: [PATCH 027/165] Changed the audio pipeline to allow stereo reverberation, using separate source (loopback audio) and listener (received audio) reverbs. --- libraries/audio-client/src/AudioClient.cpp | 40 ++++++++++++++++------ libraries/audio-client/src/AudioClient.h | 3 +- libraries/audio/src/AudioEffectOptions.cpp | 6 ++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index eb0be9dc17..81af183c0f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -142,7 +142,8 @@ void AudioClient::reset() { _toneSource.reset(); _sourceGain.reset(); _inputGain.reset(); - _stereoReverb.reset(); + _sourceReverb.reset(); + _listenerReverb.reset(); } void AudioClient::audioMixerKilled() { @@ -539,7 +540,7 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { void AudioClient::configureReverb() { ReverbParameters p; - _stereoReverb.getParameters(&p); + _listenerReverb.getParameters(&p); // for now, reuse the gverb parameters p.sampleRate = _outputFormat.sampleRate(); @@ -547,11 +548,19 @@ void AudioClient::configureReverb() { p.reverbTime = _reverbOptions->getReverbTime(); p.highGain = -24.0f * _reverbOptions->getDamping(); p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); - //p.earlyGain = _reverbOptions->getEarlyLevel(); - //p.lateGain = _reverbOptions->getTailLevel(); - p.wetDryMix = _shouldEchoLocally ? powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)) : 100.0f; + p.earlyGain = _reverbOptions->getEarlyLevel(); + p.lateGain = _reverbOptions->getTailLevel(); + p.wetDryMix = 100.0f * powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)); + _listenerReverb.setParameters(&p); - _stereoReverb.setParameters(&p); + // used for adding self-reverb to loopback audio + p.wetDryMix = _shouldEchoLocally ? 0.0f : 100.0f; // local echo is 100% dry + p.preDelay = 0.0f; + p.earlyGain = -96.0f; // disable ER + p.lateGain -= 6.0f; // quieter than listener reverb + p.lateMixLeft = 0.0f; + p.lateMixRight = 0.0f; + _sourceReverb.setParameters(&p); } void AudioClient::updateReverbOptions() { @@ -585,7 +594,8 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - _stereoReverb.reset(); + _sourceReverb.reset(); + _listenerReverb.reset(); } } @@ -654,11 +664,11 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { numInputSamples, numLoopbackSamples, _inputFormat, _outputFormat); + // apply stereo reverb at the source, to the loopback audio if (hasReverb) { - // always use the stereo reverb output assert(_outputFormat.channelCount() == 2); updateReverbOptions(); - _stereoReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); + _sourceReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); } _loopbackOutputDevice->write(loopBackByteArray); @@ -867,12 +877,20 @@ void AudioClient::processReceivedSamples(const QByteArray& inputBuffer, QByteArr outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples = reinterpret_cast(inputBuffer.data()); + int16_t* outputSamples = reinterpret_cast(outputBuffer.data()); // copy the packet from the RB to the output - possibleResampling(_networkToOutputResampler, receivedSamples, - reinterpret_cast(outputBuffer.data()), + possibleResampling(_networkToOutputResampler, receivedSamples, outputSamples, numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); + + // apply stereo reverb at the listener, to the received audio + bool hasReverb = _receivedAudioStream.hasReverb(); + if (hasReverb) { + assert(_outputFormat.channelCount() == 2); + updateReverbOptions(); + _listenerReverb.render(outputSamples, outputSamples, numDeviceOutputSamples/2); + } } void AudioClient::sendMuteEnvironmentPacket() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 30e60d1775..2c2a9f36ff 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -261,7 +261,8 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; + AudioReverb _sourceReverb { AudioConstants::SAMPLE_RATE }; + AudioReverb _listenerReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample AudioSRC* _inputToNetworkResampler; diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 221d70aa75..a61213d9c4 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -28,10 +28,10 @@ AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : _damping(0.5f), _spread(15.0f), _inputBandwidth(0.75f), - _earlyLevel(-22.0f), - _tailLevel(-28.0f), + _earlyLevel(-12.0f), + _tailLevel(-18.0f), _dryLevel(0.0f), - _wetLevel(6.0f) { + _wetLevel(0.0f) { if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); } From 3060aa960d9b1467cd2394ddda11fc9af90eb4e9 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 09:23:58 -0800 Subject: [PATCH 028/165] Fix the case when local-echo and self-reverb both active --- libraries/audio-client/src/AudioClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9c4349013f..d0f2af37af 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -555,7 +555,7 @@ void AudioClient::configureReverb() { _listenerReverb.setParameters(&p); // used for adding self-reverb to loopback audio - p.wetDryMix = _shouldEchoLocally ? 0.0f : 100.0f; // local echo is 100% dry + p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER p.lateGain -= 6.0f; // quieter than listener reverb @@ -666,7 +666,7 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _inputFormat, _outputFormat); // apply stereo reverb at the source, to the loopback audio - if (hasReverb) { + if (!_shouldEchoLocally && hasReverb) { assert(_outputFormat.channelCount() == 2); updateReverbOptions(); _sourceReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); From 2c98976ef258d5294e51b776cbff136ad3b6cdee Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 10:05:10 -0800 Subject: [PATCH 029/165] Fix bug from implicit cast --- libraries/audio/src/AudioSRC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSRC.cpp b/libraries/audio/src/AudioSRC.cpp index 59fe29df36..c187d381a4 100644 --- a/libraries/audio/src/AudioSRC.cpp +++ b/libraries/audio/src/AudioSRC.cpp @@ -1218,7 +1218,7 @@ static inline float dither() { rz = rz * 69069 + 1; int32_t r0 = rz & 0xffff; int32_t r1 = rz >> 16; - return (r0 - r1) * (1/65536.0f); + return (int32_t)(r0 - r1) * (1/65536.0f); } // convert float to int16_t, interleave stereo From 0b1fa4f60f858bab217cf6bd90f739ca532561d3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 08:21:10 -0800 Subject: [PATCH 030/165] add interface for getters for specific joints --- .../src/SceneScriptingInterface.h | 6 ++-- libraries/shared/src/SpatiallyNestable.cpp | 30 +++++++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 10 +++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 95919d6c0c..16db9f78f4 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -107,8 +107,8 @@ public: Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; } - Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; } + Q_INVOKABLE void setEngineDisplayItemStatus(uint32_t display) { _drawItemStatus = display; } + Q_INVOKABLE uint32_t doEngineDisplayItemStatus() { return _drawItemStatus; } Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } @@ -143,7 +143,7 @@ protected: int _maxDrawnTransparentItems = -1; int _maxDrawnOverlay3DItems = -1; - bool _drawItemStatus = false; + uint32_t _drawItemStatus = false; bool _drawHitEffect = false; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 1d058b56df..bd7e244fb0 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -121,6 +121,12 @@ const glm::vec3& SpatiallyNestable::getPosition() const { return _absolutePositionCache; } +const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { + getTransform(); // update _worldTransformCache + // XXX ... something with joints + return _absolutePositionCache; +} + void SpatiallyNestable::setPosition(const glm::vec3& position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; @@ -135,6 +141,11 @@ const glm::quat& SpatiallyNestable::getOrientation() const { return _absoluteRotationCache; } +const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { + // XXX something with joints... + return getOrientation(); +} + void SpatiallyNestable::setOrientation(const glm::quat& orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; @@ -149,6 +160,12 @@ const Transform& SpatiallyNestable::getTransform() const { return _worldTransformCache; } +const Transform& SpatiallyNestable::getTransform(int jointIndex) const { + getTransform(); // update _worldTransformCache + // XXX ... something with joints + return _worldTransformCache; +} + void SpatiallyNestable::setTransform(const Transform& transform) { Transform parentTransform = getParentTransform(); Transform::inverseMult(_transform, parentTransform, transform); @@ -158,6 +175,11 @@ const glm::vec3& SpatiallyNestable::getScale() const { return _transform.getScale(); } +const glm::vec3& SpatiallyNestable::getScale(int jointIndex) const { + // XXX ... something with joints + return getScale(); +} + void SpatiallyNestable::setScale(const glm::vec3& scale) { _transform.setScale(scale); } @@ -204,3 +226,11 @@ QList SpatiallyNestable::getChildren() const { } return children; } + + +const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { + _jointInObjectFrameCache.resize(jointIndex); + // XXX + _jointInObjectFrameCache[jointIndex] = Transform(); + return _jointInObjectFrameCache[jointIndex]; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6550eb721e..65f31c276a 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -59,11 +59,17 @@ public: virtual void setPosition(const glm::vec3& position); virtual const glm::quat& getOrientation() const; + virtual const glm::quat& getOrientation(int jointIndex) const; virtual void setOrientation(const glm::quat& orientation); virtual const glm::vec3& getScale() const; virtual void setScale(const glm::vec3& scale); + // get world location of a specific joint + virtual const Transform& getTransform(int jointIndex) const; + virtual const glm::vec3& getPosition(int jointIndex) const; + virtual const glm::vec3& getScale(int jointIndex) const; + // object's parent's frame virtual const Transform& getLocalTransform() const; virtual void setLocalTransform(const Transform& transform); @@ -80,6 +86,9 @@ public: QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } + // this object's frame + virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -102,6 +111,7 @@ private: mutable glm::quat _absoluteRotationCache; mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; + mutable QVector _jointInObjectFrameCache; }; From 4646c0c1030b8c67ca4768d443fb39097a446067 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 10:49:31 -0800 Subject: [PATCH 031/165] unmangle merge --- libraries/audio/src/AudioConstants.h | 2 +- libraries/avatars/src/AvatarData.cpp | 13 ------------- libraries/avatars/src/AvatarData.h | 1 - .../src/RenderableModelEntityItem.cpp | 4 ++-- .../src/RenderableParticleEffectEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- .../src/RenderableZoneEntityItem.cpp | 4 ++-- libraries/entities/src/PolyLineEntityItem.cpp | 2 +- .../oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 5 ++++- 9 files changed, 12 insertions(+), 23 deletions(-) diff --git a/libraries/audio/src/AudioConstants.h b/libraries/audio/src/AudioConstants.h index e252a5354d..785060d364 100644 --- a/libraries/audio/src/AudioConstants.h +++ b/libraries/audio/src/AudioConstants.h @@ -35,4 +35,4 @@ namespace AudioConstants { } -#endif // hifi_AudioConstants_h \ No newline at end of file +#endif // hifi_AudioConstants_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 26f771f3bc..14985cdbf3 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -785,11 +785,6 @@ std::shared_ptr AvatarData::getRecordingBasis() const { return _recordingBasis; } -void AvatarData::changeReferential(Referential* ref) { - delete _referential; - _referential = ref; -} - void AvatarData::setRawJointData(QVector data) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setRawJointData", Q_ARG(QVector, data)); @@ -1376,14 +1371,6 @@ void AvatarData::clearRecordingBasis() { _recordingBasis.reset(); } -Transform AvatarData::getTransform() const { - Transform result; - result.setRotation(getOrientation()); - result.setTranslation(getPosition()); - result.setScale(getTargetScale()); - return result; -} - static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform"); static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform"); static const QString JSON_AVATAR_JOINT_ARRAY = QStringLiteral("jointArray"); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 26f9e38f99..7c5a967c97 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -334,7 +334,6 @@ public: bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } - Transform getTransform() const; void clearRecordingBasis(); TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c58915d14f..0a67d73e81 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -193,7 +193,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p if (_model) { render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); // note: we don't care if the model fails to add items, we always added our meta item and therefore we return // true so that the system knows our meta item is in the scene! @@ -237,7 +237,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); scene->enqueuePendingChanges(pendingChanges); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index fa5d8c17f2..dca9c10849 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -143,7 +143,7 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, auto renderData = ParticlePayload::Pointer(particlePayload); auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData)); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_renderItemId, renderPayload); _scene = scene; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5f14cee776..5363da772b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -551,7 +551,7 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_myItem, renderPayload); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 205f2bc531..ca16b3aca1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -117,7 +117,7 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, false); scene->enqueuePendingChanges(pendingChanges); @@ -211,7 +211,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_myMetaItem, renderPayload); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 22f27c5287..179705e5f5 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -31,7 +31,7 @@ EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, cons return entity; } -PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _lineWidth(DEFAULT_LINE_WIDTH), _pointsChanged(true), diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index ddf251778f..3898d586ad 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -167,7 +167,10 @@ void OculusLegacyDisplayPlugin::activate() { } }); - ovrBool result = ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); + #ifndef QT_NO_DEBUG + ovrBool result = + #endif + ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); Q_ASSERT(result); } From a9669531ae324c90d34bd1caa3c9c931dccca893 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 11:53:16 -0800 Subject: [PATCH 032/165] quiet a warning --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 3898d586ad..9d10d176e6 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -167,11 +167,11 @@ void OculusLegacyDisplayPlugin::activate() { } }); - #ifndef QT_NO_DEBUG + #ifndef NDEBUG ovrBool result = #endif ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); - Q_ASSERT(result); + assert(result); } void OculusLegacyDisplayPlugin::deactivate() { From abfc3e994a534ac82235be74cc95611faa8f663d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 22 Nov 2015 07:18:12 -0800 Subject: [PATCH 033/165] AvatarData::toFrame expects a scaled transform --- libraries/avatars/src/AvatarData.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 14985cdbf3..cc75404748 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1425,13 +1425,15 @@ QByteArray AvatarData::toFrame(const AvatarData& avatar) { } auto recordingBasis = avatar.getRecordingBasis(); + Transform avatarTransform = avatar.getTransform(); + avatarTransform.setScale(avatar.getTargetScale()); if (recordingBasis) { root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis); // Find the relative transform - auto relativeTransform = recordingBasis->relativeTransform(avatar.getTransform()); + auto relativeTransform = recordingBasis->relativeTransform(avatarTransform); root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform); } else { - root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatar.getTransform()); + root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatarTransform); } // Skeleton pose From a0c1f9a1f9d8944fd33bb0f8f6d736cf0acd2666 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 22 Nov 2015 13:11:37 -0800 Subject: [PATCH 034/165] progress toward having things be children of specific joints rather than just of other objects --- libraries/entities/src/EntityItem.h | 4 +++ libraries/shared/src/SpatiallyNestable.cpp | 30 ++++++++++++++-------- libraries/shared/src/SpatiallyNestable.h | 3 +++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e2368f92fd..8d47037f6b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -403,6 +403,10 @@ public: QList getActionsOfType(EntityActionType typeToGet); + // these are in the frame of this object + virtual glm::quat getJointRotation(int index) const { return glm::quat(); } + virtual glm::vec3 getJointTranslation(int index) const { return glm::vec3(0.0f); } + protected: const QByteArray getActionDataInternal() const; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index bd7e244fb0..87ef7565fb 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -12,8 +12,6 @@ #include "DependencyManager.h" #include "SpatiallyNestable.h" -// TODO -- make use of parent joint index - SpatiallyNestable::SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : _nestableType(nestableType), @@ -28,7 +26,7 @@ Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); if (parent) { - Transform parentTransform = parent->getTransform(); + Transform parentTransform = parent->getTransform(_parentJointIndex); result = parentTransform.setScale(1.0f); } return result; @@ -123,8 +121,10 @@ const glm::vec3& SpatiallyNestable::getPosition() const { const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { getTransform(); // update _worldTransformCache - // XXX ... something with joints - return _absolutePositionCache; + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex].getTranslation(); } void SpatiallyNestable::setPosition(const glm::vec3& position) { @@ -142,8 +142,11 @@ const glm::quat& SpatiallyNestable::getOrientation() const { } const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { - // XXX something with joints... - return getOrientation(); + getTransform(); // update _worldTransformCache + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex + 1); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex].getRotation(); } void SpatiallyNestable::setOrientation(const glm::quat& orientation) { @@ -162,8 +165,10 @@ const Transform& SpatiallyNestable::getTransform() const { const Transform& SpatiallyNestable::getTransform(int jointIndex) const { getTransform(); // update _worldTransformCache - // XXX ... something with joints - return _worldTransformCache; + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex + 1); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex]; } void SpatiallyNestable::setTransform(const Transform& transform) { @@ -229,8 +234,11 @@ QList SpatiallyNestable::getChildren() const { const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { - _jointInObjectFrameCache.resize(jointIndex); - // XXX + _jointInObjectFrameCache.resize(jointIndex + 1); _jointInObjectFrameCache[jointIndex] = Transform(); + glm::vec3 position = getJointTranslation(jointIndex); + glm::quat orientation = getJointRotation(jointIndex); + _jointInObjectFrameCache[jointIndex].setRotation(orientation); + _jointInObjectFrameCache[jointIndex].setTranslation(position); return _jointInObjectFrameCache[jointIndex]; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 65f31c276a..30602d26b4 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -88,6 +88,8 @@ public: // this object's frame virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + virtual glm::quat getJointRotation(int index) const = 0; + virtual glm::vec3 getJointTranslation(int index) const = 0; protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData @@ -112,6 +114,7 @@ private: mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; mutable QVector _jointInObjectFrameCache; + mutable QVector _jointInWorldFrameCache; }; From a08bad8cbdb97b90dab7d4b8fd77675dbfbe3a62 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 13:46:32 -0800 Subject: [PATCH 035/165] for models, relay getJointRotation and getJointTranslation to the model --- .../src/RenderableModelEntityItem.cpp | 20 +++++++++++++++++++ .../src/RenderableModelEntityItem.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0a67d73e81..ce659acfa6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -562,3 +562,23 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } + +glm::quat getJointRotation(int index) const { + if (_model) { + glm::quat result; + if (_model->getJointRotation(index, result)) { + return result; + } + } + return glm::quat(); +} + +glm::vec3 getJointTranslation(int index) const { + if (_model) { + glm::vec3 result; + if (_model->getJointTranslation(index, result)) { + return result; + } + } + return glm::vec3(0.0f); +} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 34e2bacb47..2187c0edb3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -67,6 +67,10 @@ public: virtual bool contains(const glm::vec3& point) const; + // these are in the frame of this object + virtual glm::quat getJointRotation(int index) const; + virtual glm::vec3 getJointTranslation(int index) const; + private: void remapTextures(); From ba30e016644a61c2d2a4a2b3697011303511bcf4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 14:12:49 -0800 Subject: [PATCH 036/165] include global position in avatar-mixer protocol so server knows where avatars are in world-space --- assignment-client/src/avatars/AvatarMixer.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 1 + libraries/avatars/src/AvatarData.cpp | 6 ++++++ libraries/avatars/src/AvatarData.h | 7 +++++++ .../entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index ae627caf00..174ba04311 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -157,7 +157,7 @@ void AvatarMixer::broadcastAvatarData() { ++_sumListeners; AvatarData& avatar = nodeData->getAvatar(); - glm::vec3 myPosition = avatar.getLocalPosition(); // XXX should be world position + glm::vec3 myPosition = avatar.getClientGlobalPosition(); // reset the internal state for correct random number distribution distribution.reset(); @@ -290,7 +290,7 @@ void AvatarMixer::broadcastAvatarData() { // The full rate distance is the distance at which EVERY update will be sent for this avatar // at twice the full rate distance, there will be a 50% chance of sending this avatar's update - glm::vec3 otherPosition = otherAvatar.getLocalPosition(); // XXX should be world position + glm::vec3 otherPosition = otherAvatar.getClientGlobalPosition(); float distanceToAvatar = glm::length(myPosition - otherPosition); // potentially update the max full rate distance for this frame diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 254d1c068f..9d3981f4a0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -193,6 +193,7 @@ MyAvatar::~MyAvatar() { QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { CameraMode mode = qApp->getCamera()->getMode(); + _globalPosition = getPosition(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer glm::vec3 oldPosition = getPosition(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index cc75404748..dfae86f132 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -210,6 +210,9 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { memcpy(destinationBuffer, &position, sizeof(position)); destinationBuffer += sizeof(position); + memcpy(destinationBuffer, &_globalPosition, sizeof(_globalPosition)); + destinationBuffer += sizeof(_globalPosition); + // Body rotation glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation())); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y); @@ -492,6 +495,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { memcpy(&position, sourceBuffer, sizeof(position)); sourceBuffer += sizeof(position); + memcpy(&_globalPosition, sourceBuffer, sizeof(_globalPosition)); + sourceBuffer += sizeof(_globalPosition); + if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) { if (shouldLogError(now)) { qCDebug(avatars) << "Discard nan AvatarData::position; displayName = '" << _displayName << "'"; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7c5a967c97..5465c764f9 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -338,6 +338,8 @@ public: TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); + glm::vec3 getClientGlobalPosition() { return _globalPosition; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -403,6 +405,11 @@ protected: // During playback, it holds the origin from which to play the relative positions in the clip TransformPointer _recordingBasis; + // _globalPosition is sent along with localPosition + parent because the avatar-mixer doesn't know + // where Entities are located. This is currently only used by the mixer to decide how often to send + // updates about one avatar to another. + glm::vec3 _globalPosition; + private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ce659acfa6..ddacc78fd0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -563,7 +563,7 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } -glm::quat getJointRotation(int index) const { +glm::quat RenderableModelEntityItem::getJointRotation(int index) const { if (_model) { glm::quat result; if (_model->getJointRotation(index, result)) { @@ -573,7 +573,7 @@ glm::quat getJointRotation(int index) const { return glm::quat(); } -glm::vec3 getJointTranslation(int index) const { +glm::vec3 RenderableModelEntityItem::getJointTranslation(int index) const { if (_model) { glm::vec3 result; if (_model->getJointTranslation(index, result)) { From 5fe41662d802ef852852a5db0d5c37cfefa0a837 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 14:31:40 -0800 Subject: [PATCH 037/165] fix comment header paths --- assignment-client/src/entities/AssignmentParentFinder.cpp | 2 +- assignment-client/src/entities/AssignmentParentFinder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index 3e6fc2ed38..5fe4742b90 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -1,6 +1,6 @@ // // AssignmentParentFinder.cpp -// assignment-client/src/ +// assignment-client/src/entities // // Created by Seth Alves on 2015-10-22 // Copyright 2015 High Fidelity, Inc. diff --git a/assignment-client/src/entities/AssignmentParentFinder.h b/assignment-client/src/entities/AssignmentParentFinder.h index 4d2e080443..99fa58ffed 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.h +++ b/assignment-client/src/entities/AssignmentParentFinder.h @@ -1,6 +1,6 @@ // // AssignmentParentFinder.h -// interface/src/ +// interface/src/entities // // Created by Seth Alves on 2015-10-21 // Copyright 2015 High Fidelity, Inc. From bba5bf7a21012302a49269bda3efa5051f4b8bb1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 11:28:00 -0800 Subject: [PATCH 038/165] Trying to get the Agent to Mater more reliable --- examples/acScripts/playbackAgents.js | 48 ++++++++--- examples/acScripts/playbackMaster.js | 120 +++++++++++++++++++++------ 2 files changed, 132 insertions(+), 36 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 16dd469a89..864e821175 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -11,7 +11,6 @@ // Set the following variables to the values needed var commandChannel = "com.highfidelity.PlaybackChannel1"; -var clip_url = null; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; @@ -22,6 +21,12 @@ var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; var UNKNOWN_AGENT_ID = -2; var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +var NUM_CYCLES_BEFORE_RESET = 5; +var notifyAlive = false; + // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -32,6 +37,7 @@ var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -48,17 +54,14 @@ Recording.setPlayerUseSkeletonModel(useAvatarModel); function getAction(channel, message, senderID) { if(subscribed) { + var command = JSON.parse(message); print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); if (command.id_key == id || command.id_key == -1) { - if (command.action_key === 6) { - clip_url = command.clip_url_key; - } action = command.action_key; - print("That command was for me!"); - print("My clip is: " + clip_url); + print("That command was for me! Agent with id: " + id); } else { action = DO_NOTHING; } @@ -104,11 +107,21 @@ function getAction(channel, message, senderID) { Agent.isAvatar = false; break; case LOAD: - print("Load"); - if(clip_url !== null) { - Recording.loadRecording(clip_url); + print("Load"); + if (!Agent.isAvatar) { + Agent.isAvatar = true; + } + if(command.clip_url_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.clip_url_key); + Recording.loadRecording(command.clip_url_key); + } else { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; + case ALIVE: + print("Alive"); + notifyAlive = true; + break; case DO_NOTHING: break; default: @@ -136,11 +149,26 @@ function update(deltaTime) { print("I'm the agent and I am ready to receive!"); } if (subscribed && id == UNKNOWN_AGENT_ID) { - print("sending ready, id:" + id); + Messages.sendMessage(announceIDChannel, "ready"); } } + if (subscribed && id != UNKNOWN_AGENT_ID) { + timeSinceLastAlive += deltaTime; + if (notifyAlive) { + timeSinceLastAlive = 0; + notifyAlive = false; + print("Master Alive"); + } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + print("Master Lost, reseting Agent"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Agent.isAvatar = false; + id = UNKNOWN_AGENT_ID; + } + } } Messages.messageReceived.connect(function (channel, message, senderID) { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 4703f0e4fd..2c9d4f77eb 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,9 +14,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) -var channel = "com.highfidelity.PlaybackChannel1"; +var commandChannel = "com.highfidelity.PlaybackChannel1"; var subscribed = false; -var clip_url = null; var input_text = null; var knownAgents = new Array; // We will add our known agents here when we discover them @@ -24,9 +23,15 @@ var knownAgents = new Array; // We will add our known agents here when we discov // available playbackAgents will announce their sessionID here. var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; -// Script. DO NOT MODIFY BEYOND THIS LINE. -Script.include("../libraries/toolBars.js"); +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +// Script. DO NOT MODIFY BEYOND THIS LINE. +//Script.include("../libraries/toolBars.js"); +Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); + +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -52,6 +57,9 @@ var playLoopIcon = new Array(); var stopIcon = new Array(); var loadIcon = new Array(); +var performanceJSON = null; +var performanceLoadedNeedUpdate = false; + setupPlayback(); function setupPlayback() { @@ -59,7 +67,7 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(channel); + Messages.subscribe(commandChannel); subscribed = true; setupToolBars(); } @@ -139,7 +147,27 @@ function setupToolBars() { } } -function sendCommand(id, action) { +function loadAvatarClipsFromPerformanceJSON(performanceJSON) { + if (performanceJSON.avatarClips) { + var numClips = performanceJSON.avatarClips.length; + print("Performance file contains:" + JSON.stringify(performanceJSON)); + print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); + + if (numClips > knownAgents.length) { + numClips = knownAgents.length; + } + + for (i = 0; i < numClips; i++) { + var clipURL = performanceJSON.avatarClips[i]; + print("Loading clip " + clipURL + " to Agent #" + i); + sendCommand(i, LOAD, clipURL); + } + } else { + print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + } +} + +function sendCommand(id, action, argument) { if (action === SHOW) { toolBars[id].selectTool(onOffIcon[id], false); toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); @@ -152,24 +180,48 @@ function sendCommand(id, action) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); + } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } if (id == (toolBars.length - 1)) { - id = -1; // Master command becomes broadcast. - } - - var message = { - id_key: id, - action_key: action, - clip_url_key: clip_url - }; - - if(subscribed){ - Messages.sendMessage(channel, JSON.stringify(message)); - print("Message sent!"); - clip_url = null; + + if (action == LOAD) { + if (performanceLoadedNeedUpdate == false) { + Assets.downloadData(argument, function (data) { + performanceJSON = JSON.parse(data); + performanceLoadedNeedUpdate = true; + // print("Performance file contains:" + JSON.stringify(performanceJSON)); + }); + return; + } + } else { + id = -1; + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } + } + } else { + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } } } @@ -193,8 +245,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { // Check individual controls @@ -214,8 +265,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { @@ -240,13 +290,25 @@ function moveUI() { } } -function update() { +function update(deltaTime) { var newDimensions = Controller.getViewportDimensions(); if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) { windowDimensions = newDimensions; moveUI(); } + + if (performanceLoadedNeedUpdate) { + loadAvatarClipsFromPerformanceJSON(performanceJSON); + performanceLoadedNeedUpdate = false; + } + + timeSinceLastAlive += deltaTime; + if (timeSinceLastAlive > ALIVE_PERIOD) { + timeSinceLastAlive = 0; + print("ping alive"); + sendCommand((toolBars.length - 1), ALIVE); + } } function scriptEnding() { @@ -256,7 +318,7 @@ function scriptEnding() { } if (subscribed) { - Messages.unsubscribe(channel); + Messages.unsubscribe(commandChannel); } Messages.unsubscribe(announceIDChannel); } @@ -272,13 +334,19 @@ Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message == "ready") { // check to see if we know about this agent if (knownAgents.indexOf(senderID) < 0) { + print("New agent to be hired " + senderID); var indexOfNewAgent = knownAgents.length; knownAgents[indexOfNewAgent] = senderID; var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); + print("Hired new Agent " + senderID + " #" + indexOfNewAgent); Messages.sendMessage(announceIDChannel, acknowledgeMessage); + } else { + + print("New agent still sending ready ? " + senderID); } } }); -moveUI(); \ No newline at end of file +moveUI(); From e25d4c17e8943092f9046dab7fe1d7361dc9747c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 09:29:40 +1300 Subject: [PATCH 039/165] Fix InputController (Leap Motion) not able to be created --- .../src/scripting/ControllerScriptingInterface.cpp | 12 ++++++------ .../src/scripting/ControllerScriptingInterface.h | 4 ++-- libraries/script-engine/src/ScriptEngine.cpp | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 547f16ea8b..719bfe7f1f 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -84,11 +84,11 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const { return qApp->getUiSize(); } -controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { - // This is where we retreive the Device Tracker category and then the sub tracker within it +controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { + // This is where we retrieve the Device Tracker category and then the sub tracker within it auto icIt = _inputControllers.find(0); if (icIt != _inputControllers.end()) { - return (*icIt).second; + return (*icIt).second.get(); } @@ -110,15 +110,15 @@ controller::InputController::Pointer ControllerScriptingInterface::createInputCo controller::InputController::Pointer inputController = std::make_shared(deviceID, trackerID, this); controller::InputController::Key key = inputController->getKey(); _inputControllers.insert(InputControllerMap::value_type(key, inputController)); - return inputController; + return inputController.get(); } } } - return controller::InputController::Pointer(); + return nullptr; } -void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) { +void ControllerScriptingInterface::releaseInputController(controller::InputController* input) { _inputControllers.erase(input->getKey()); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 4c69551dd2..22d8f8be1f 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -96,8 +96,8 @@ public slots: virtual glm::vec2 getViewportDimensions() const; /// Factory to create an InputController - virtual controller::InputController::Pointer createInputController(const QString& deviceName, const QString& tracker); - virtual void releaseInputController(controller::InputController::Pointer input); + virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker); + virtual void releaseInputController(controller::InputController* input); signals: void keyPressEvent(const KeyEvent& event); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 995a92bf83..49009a3ad2 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -81,6 +81,9 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { out = qobject_cast(object.toQObject()); } +Q_DECLARE_METATYPE(controller::InputController*) +static int inputControllerPointerId = qRegisterMetaType(); + QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { return engine->newQObject(in); } @@ -89,8 +92,6 @@ void inputControllerFromScriptValue(const QScriptValue &object, controller::Inpu out = qobject_cast(object.toQObject()); } - - static bool hasCorrectSyntax(const QScriptProgram& program) { const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { From 5ecbaa5b93b92ac821db8b3db7af2022990dfef1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 09:43:55 +1300 Subject: [PATCH 040/165] Fix InputController (Leap Motion) not being updated --- interface/src/Application.cpp | 2 ++ interface/src/scripting/ControllerScriptingInterface.cpp | 9 +++++++-- interface/src/scripting/ControllerScriptingInterface.h | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dc218ecdc..189234894d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2825,6 +2825,8 @@ void Application::update(float deltaTime) { } } + _controllerScriptingInterface->updateInputControllers(); + // Transfer the user inputs to the driveKeys // FIXME can we drop drive keys and just have the avatar read the action states directly? myAvatar->clearDriveKeys(); diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 719bfe7f1f..11053154b6 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -89,8 +89,7 @@ controller::InputController* ControllerScriptingInterface::createInputController auto icIt = _inputControllers.find(0); if (icIt != _inputControllers.end()) { return (*icIt).second.get(); - } - + } // Look for device DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString()); @@ -122,6 +121,12 @@ void ControllerScriptingInterface::releaseInputController(controller::InputContr _inputControllers.erase(input->getKey()); } +void ControllerScriptingInterface::updateInputControllers() { + for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) { + (*it).second->update(); + } +} + InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : _deviceTrackerId(deviceTrackerId), _subTrackerId(subTrackerId), diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 22d8f8be1f..8bd698cfb2 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -85,6 +85,8 @@ public: bool isKeyCaptured(const KeyEvent& event) const; bool isJoystickCaptured(int joystickIndex) const; + void updateInputControllers(); + public slots: virtual void captureKeyEvents(const KeyEvent& event); From 6736eefbc11e7932d476d0acecd2624dae06fe13 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 14:14:22 +1300 Subject: [PATCH 041/165] Fix arm and finger joint control in leapHands.js for desktop mode --- examples/controllers/leap/leapHands.js | 33 ++++++++++---------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 6bdca051be..04b65349a9 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -193,13 +193,12 @@ var leapHands = (function () { } // Set avatar arms vertical, forearms horizontal, as "zero" position for calibration - MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0)); - MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); - MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); - MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 90.0)); - MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); - MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); - + MyAvatar.setJointRotation("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); + MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 90.0, 90.0)); + MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); + MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0,0.0, 0.0)); + MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, -90.0, -90.0)); + MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); // Wait for arms to assume their positions before calculating Script.setTimeout(finishCalibration, CALIBRATION_TIME); @@ -421,22 +420,14 @@ var leapHands = (function () { // Hand rotation in camera coordinates ... handRotation = { - x: handRotation.z, - y: handRotation.y, - z: handRotation.x, - w: handRotation.w + x: -handRotation.x, + y: -handRotation.z, + z: -handRotation.y, + w: handRotation.w, }; // Hand rotation in avatar coordinates ... - if (h === 0) { - handRotation.x = -handRotation.x; - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - handRotation); - } else { - handRotation.z = -handRotation.z; - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - handRotation); - } + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); } // Set hand position and orientation ... @@ -462,7 +453,7 @@ var leapHands = (function () { w: locRotation.w }; } - MyAvatar.setJointData(fingers[h][i][j].jointName, locRotation); + MyAvatar.setJointRotation(fingers[h][i][j].jointName, locRotation); } } } From bad01d02f82d148f343d68ea449a60b31d2b577b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 18:31:28 -0800 Subject: [PATCH 042/165] building the master/agent api --- examples/acScripts/AgentPoolControler.js | 214 +++++++++++++++++++++++ examples/acScripts/playbackAgents.js | 42 +++-- examples/acScripts/playbackMaster.js | 43 ++--- 3 files changed, 258 insertions(+), 41 deletions(-) create mode 100644 examples/acScripts/AgentPoolControler.js diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js new file mode 100644 index 0000000000..353480e2cf --- /dev/null +++ b/examples/acScripts/AgentPoolControler.js @@ -0,0 +1,214 @@ +// +// AgentPoolController.js +// acScripts +// +// Created by Sam Gateau on 11/23/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; +var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + +// The time between alive messages on the command channel +var ALIVE_PERIOD = 1; + +var NUM_CYCLES_BEFORE_RESET = 5; + +// Service Actions +var AGENT_READY = "ready"; +var INVALID_ACTOR = -2; + +var MASTER_INDEX = -1; + +var MASTER_ALIVE = -1; + +function printDebug(message) { + print(message); +} + +(function() { + + var makeMessage = function(id, action, argument) { + var message = { + id_key: id, + action_key: action, + argument_key: argument + }; + return message; + }; + + var unpackMessage = function(message) { + return JSON.parse(message); + }; + + // master side + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.subscribed = false; + }; + + MasterController.prototype.reset = function() { + if (this.subscribed) { + this.timeSinceLastAlive = 0; + + } + + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + + this.timeSinceLastAlive = 0; + + var localThis = this; + + Messages.messageReceived.connect(function (channel, message, senderID) { + printDebug("Agent received"); + if (channel == ANNOUNCE_CHANNEL) { + printDebug("Agent received"); + // localThis._processAgentMessage(message, senderID); + } + }); + + // ready to roll, enable + this.subscribed = true; + }; + + MasterController.prototype._processAgentMessage = function(message, senderID) { + if (message == AGENT_READY) { + + // check to see if we know about this agent + if (this.knownAgents.indexOf(senderID) < 0) { + + var indexOfNewAgent = this.knownAgents.length; + this.knownAgents[indexOfNewAgent] = senderID; + printDebug("New agent available to be hired " + senderID); + + var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); + } else { + + printDebug("New agent still sending ready ? " + senderID); + } + } + }; + + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.timeSinceLastAlive = 0; + this.subscribed = true; + } + }; + + MasterController.prototype.sendCommand = function(target, action, argument) { + if (this.subscribed) { + var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + printDebug("Master sent message: " + messageJSON); + } + }; + + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + printDebug("Master ping alive"); + this.sendCommand(MASTER_INDEX, MASTER_ALIVE); + } + }; + + + this.MasterController = MasterController; + + // agent side + var AgentController = function() { + this.timeSinceLastAlive = 0; + this.subscribed = false; + this.actorIndex = INVALID_ACTOR; + this.notifyAlive = false; + }; + + AgentController.prototype.reset = function() { + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + } + + this.timeSinceLastAlive = 0; + + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (id == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + if (agentID == Agent.sessionUUID) { + // localThis.actorIndex = agentIndex; + Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + return; + } + if (channel == COMMAND_CHANNEL) { + var command = unpackMessage(message); + printDebug("Received command = " == command); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + // localThis.notifyAlive = true; + } else { + // localThis._processMasterMessage(command, senderID); + } + } else { + // ignored + } + return; + } + }); + + // ready to roll, enable + this.subscribed = true; + printDebug("In Reset"); + }; + + AgentController.prototype._processMasterMessage = function(command, senderID) { + printDebug("True action received = " + JSON.stringify(command) + senderID); + }; + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + printDebug("In update of client"); + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); + printDebug("Client Ready"); + } else { + if (this.notifyAlive) { + this.notifyAlive = false; + printDebug("Master Alive"); + } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + printDebug("Master Lost, reseting Agent"); + this.actorIndex = UNKNOWN_AGENT_ID; + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + + this.AgentController = AgentController; +})(); + + + diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 864e821175..96502a7816 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,24 +8,27 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Agent.isAvatar = true; +Script.include("./AgentPoolControler.js"); // Set the following variables to the values needed -var commandChannel = "com.highfidelity.PlaybackChannel1"; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; +var agentController = new AgentController(); + // ID of the agent. Two agents can't have the same ID. -var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; -var UNKNOWN_AGENT_ID = -2; -var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +//var UNKNOWN_AGENT_ID = -2; +//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged // The time between alive messages on the command channel -var timeSinceLastAlive = 0; +/*var timeSinceLastAlive = 0; var ALIVE_PERIOD = 5; var NUM_CYCLES_BEFORE_RESET = 5; var notifyAlive = false; +*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -118,7 +121,7 @@ function getAction(channel, message, senderID) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case ALIVE: + case MASTER_ALIVE: print("Alive"); notifyAlive = true; break; @@ -138,10 +141,16 @@ function getAction(channel, message, senderID) { function update(deltaTime) { - + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!agentController.subscribed) { + agentController.reset(); + } + } + /* + totalTime += deltaTime; - - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!subscribed) { Messages.subscribe(commandChannel); // command channel Messages.subscribe(announceIDChannel); // id announce channel @@ -168,9 +177,11 @@ function update(deltaTime) { Agent.isAvatar = false; id = UNKNOWN_AGENT_ID; } - } -} + }*/ + agentController.update(deltaTime); +} +/* Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message != "ready") { // If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me @@ -187,6 +198,13 @@ Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == commandChannel) { getAction(channel, message, senderID); } -}); +});*/ + +function scriptEnding() { + + agentController.destroy(); +} + Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 2c9d4f77eb..eb7f86518f 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,30 +8,22 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("./AgentPoolControler.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var masterController = new MasterController(); var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) -var commandChannel = "com.highfidelity.PlaybackChannel1"; -var subscribed = false; var input_text = null; -var knownAgents = new Array; // We will add our known agents here when we discover them - -// available playbackAgents will announce their sessionID here. -var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; - -// The time between alive messages on the command channel -var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); -var ALIVE = -1; + var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -67,9 +59,8 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(commandChannel); - subscribed = true; setupToolBars(); + masterController.reset(); } function setupToolBars() { @@ -180,7 +171,6 @@ function sendCommand(id, action, argument) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } @@ -199,6 +189,8 @@ function sendCommand(id, action, argument) { } else { id = -1; + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -208,10 +200,11 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } else { - + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -221,7 +214,7 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } @@ -303,12 +296,7 @@ function update(deltaTime) { performanceLoadedNeedUpdate = false; } - timeSinceLastAlive += deltaTime; - if (timeSinceLastAlive > ALIVE_PERIOD) { - timeSinceLastAlive = 0; - print("ping alive"); - sendCommand((toolBars.length - 1), ALIVE); - } + masterController.update(deltaTime); } function scriptEnding() { @@ -317,10 +305,7 @@ function scriptEnding() { Overlays.deleteOverlay(nameOverlays[i]); } - if (subscribed) { - Messages.unsubscribe(commandChannel); - } - Messages.unsubscribe(announceIDChannel); + masterController.destroy(); } Controller.mousePressEvent.connect(mousePressEvent); @@ -328,7 +313,7 @@ Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - +/* Messages.subscribe(announceIDChannel); Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message == "ready") { @@ -348,5 +333,5 @@ Messages.messageReceived.connect(function (channel, message, senderID) { } }); - +*/ moveUI(); From 566b27156c710a08ef294f3f3ce6508ec70f675a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 15:45:33 +1300 Subject: [PATCH 043/165] Fix hand and finger joint control in leapHands.js for HMD mode --- examples/controllers/leap/leapHands.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 04b65349a9..42df89084d 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -381,23 +381,14 @@ var leapHands = (function () { // Hand rotation in camera coordinates ... handRotation = { - x: handRotation.z, - y: handRotation.y, - z: handRotation.x, - w: handRotation.w + x: -handRotation.x, + y: -handRotation.z, + z: -handRotation.y, + w: handRotation.w, }; // Hand rotation in avatar coordinates ... - if (h === 0) { - handRotation.x = -handRotation.x; - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation); - } else { - handRotation.z = -handRotation.z; - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation); - } - + handRotation = Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), handRotation); cameraOrientation.x = -cameraOrientation.x; cameraOrientation.z = -cameraOrientation.z; handRotation = Quat.multiply(cameraOrientation, handRotation); From 46cbc349d15d7f103e4568abb42fa183f2e9f7d8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 16:39:09 +1300 Subject: [PATCH 044/165] Fix laserPointer.js for Hydras Leap Motion working already. --- examples/controllers/leap/laserPointer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/controllers/leap/laserPointer.js b/examples/controllers/leap/laserPointer.js index 156e9ba298..c8c3cf372a 100644 --- a/examples/controllers/leap/laserPointer.js +++ b/examples/controllers/leap/laserPointer.js @@ -23,7 +23,8 @@ var laserPointer = (function () { function isHandPointing(hand) { var MINIMUM_TRIGGER_PULL = 0.9; - return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL; + var controller = hand === 0 ? Controller.Standard.LT : Controller.Standard.RT; + return Controller.getValue(controller) > MINIMUM_TRIGGER_PULL; } function isFingerPointing(hand) { From 6e076985f2ececbb2013cb14d7f72e346ce91394 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Nov 2015 16:46:53 +1300 Subject: [PATCH 045/165] JSLint --- examples/controllers/leap/laserPointer.js | 5 +++-- examples/controllers/leap/leapHands.js | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/controllers/leap/laserPointer.js b/examples/controllers/leap/laserPointer.js index c8c3cf372a..c7d72e6cff 100644 --- a/examples/controllers/leap/laserPointer.js +++ b/examples/controllers/leap/laserPointer.js @@ -22,8 +22,9 @@ var laserPointer = (function () { ]; function isHandPointing(hand) { - var MINIMUM_TRIGGER_PULL = 0.9; - var controller = hand === 0 ? Controller.Standard.LT : Controller.Standard.RT; + var MINIMUM_TRIGGER_PULL = 0.9, + controller; + controller = hand === 0 ? Controller.Standard.LT : Controller.Standard.RT; return Controller.getValue(controller) > MINIMUM_TRIGGER_PULL; } diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 42df89084d..7835df7452 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -196,7 +196,7 @@ var leapHands = (function () { MyAvatar.setJointRotation("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 90.0, 90.0)); MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); - MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0,0.0, 0.0)); + MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, -90.0, -90.0)); MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); @@ -384,7 +384,7 @@ var leapHands = (function () { x: -handRotation.x, y: -handRotation.z, z: -handRotation.y, - w: handRotation.w, + w: handRotation.w }; // Hand rotation in avatar coordinates ... @@ -414,7 +414,7 @@ var leapHands = (function () { x: -handRotation.x, y: -handRotation.z, z: -handRotation.y, - w: handRotation.w, + w: handRotation.w }; // Hand rotation in avatar coordinates ... From 574eb3dc99d2e8115dbccac953ab1d3ea0333d23 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Wed, 25 Nov 2015 02:50:12 -0800 Subject: [PATCH 046/165] Improving the Master/Agent api --- examples/acScripts/AgentPoolControler.js | 221 +++++++++++++---------- examples/acScripts/playbackAgents.js | 95 +++------- examples/acScripts/playbackMaster.js | 44 ----- 3 files changed, 147 insertions(+), 213 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 353480e2cf..60b906381a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -9,27 +9,26 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; -var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - -// The time between alive messages on the command channel -var ALIVE_PERIOD = 1; - -var NUM_CYCLES_BEFORE_RESET = 5; - -// Service Actions -var AGENT_READY = "ready"; -var INVALID_ACTOR = -2; - -var MASTER_INDEX = -1; - -var MASTER_ALIVE = -1; - function printDebug(message) { print(message); } (function() { + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 5; + + // Service Actions + var AGENT_READY = "ready"; + var INVALID_ACTOR = -2; + + var MASTER_INDEX = -1; + + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; var makeMessage = function(id, action, argument) { var message = { @@ -45,38 +44,41 @@ function printDebug(message) { }; // master side + //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; this.subscribed = false; }; - MasterController.prototype.reset = function() { - if (this.subscribed) { - this.timeSinceLastAlive = 0; - + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; } + }; - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - - this.timeSinceLastAlive = 0; - - var localThis = this; - - Messages.messageReceived.connect(function (channel, message, senderID) { - printDebug("Agent received"); - if (channel == ANNOUNCE_CHANNEL) { - printDebug("Agent received"); - // localThis._processAgentMessage(message, senderID); - } - }); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } // ready to roll, enable this.subscribed = true; + printDebug("Master Started"); }; - MasterController.prototype._processAgentMessage = function(message, senderID) { + MasterController.prototype._processAnnounceMessage = function(message, senderID) { if (message == AGENT_READY) { // check to see if we know about this agent @@ -89,20 +91,10 @@ function printDebug(message) { var acknowledgeMessage = senderID + "." + indexOfNewAgent; Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); } else { - printDebug("New agent still sending ready ? " + senderID); } } }; - - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.timeSinceLastAlive = 0; - this.subscribed = true; - } - }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { @@ -121,83 +113,109 @@ function printDebug(message) { } }; - this.MasterController = MasterController; // agent side + //--------------------------------- var AgentController = function() { + this.subscribed = false; + this.timeSinceLastAlive = 0; - this.subscribed = false; + this.numCyclesWithoutAlive = 0; this.actorIndex = INVALID_ACTOR; this.notifyAlive = false; + + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; }; + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); Messages.subscribe(ANNOUNCE_CHANNEL); - } - - this.timeSinceLastAlive = 0; - - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (id == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - if (agentID == Agent.sessionUUID) { - // localThis.actorIndex = agentIndex; - Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - return; - } - if (channel == COMMAND_CHANNEL) { - var command = unpackMessage(message); - printDebug("Received command = " == command); - - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - // localThis.notifyAlive = true; - } else { - // localThis._processMasterMessage(command, senderID); - } - } else { - // ignored + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; } - return; - } - }); - - // ready to roll, enable + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } this.subscribed = true; - printDebug("In Reset"); + printDebug("Client Started"); }; - AgentController.prototype._processMasterMessage = function(command, senderID) { - printDebug("True action received = " + JSON.stringify(command) + senderID); + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } }; AgentController.prototype.update = function(deltaTime) { this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - printDebug("In update of client"); if (this.actorIndex == INVALID_ACTOR) { Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - printDebug("Client Ready"); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); } else { - if (this.notifyAlive) { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; printDebug("Master Alive"); - } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - printDebug("Master Lost, reseting Agent"); - this.actorIndex = UNKNOWN_AGENT_ID; + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); } } } @@ -206,6 +224,19 @@ function printDebug(message) { } }; + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + this.actorIndex= INVALID_ACTOR; + this.notifyAlive = false; + this.timeSinceLastAlive = 0; + this.numCyclesWithoutAlive = 0; + // then custom fire if was hired + if (wasHired) { + this.onFired(); + } + } + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 96502a7816..f7630cad48 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -10,6 +10,7 @@ // Agent.isAvatar = true; Script.include("./AgentPoolControler.js"); +var agentController = new AgentController(); // Set the following variables to the values needed var playFromCurrentLocation = true; @@ -17,18 +18,6 @@ var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; -var agentController = new AgentController(); - -// ID of the agent. Two agents can't have the same ID. -//var UNKNOWN_AGENT_ID = -2; -//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged - -// The time between alive messages on the command channel -/*var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; -var NUM_CYCLES_BEFORE_RESET = 5; -var notifyAlive = false; -*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -36,7 +25,6 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; var totalTime = 0; -var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. @@ -55,10 +43,10 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(channel, message, senderID) { - if(subscribed) { +function getAction(command) { + if(true) { - var command = JSON.parse(message); + // var command = JSON.parse(message); print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); if (command.id_key == id || command.id_key == -1) { @@ -114,17 +102,13 @@ function getAction(channel, message, senderID) { if (!Agent.isAvatar) { Agent.isAvatar = true; } - if(command.clip_url_key !== null) { - print("Agent #" + id + " loading clip URL: " + command.clip_url_key); - Recording.loadRecording(command.clip_url_key); + if(command.argument_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); } else { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case MASTER_ALIVE: - print("Alive"); - notifyAlive = true; - break; case DO_NOTHING: break; default: @@ -139,66 +123,29 @@ function getAction(channel, message, senderID) { } } +function agentHired() { + print("Agent Hired from playbackAgents.js"); +} + +function agentFired() { + print("Agent Fired from playbackAgents.js"); +} + function update(deltaTime) { - totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); + agentController.onCommand = getAction; + agentController.onHired = agentHired; + agentController.onFired = agentFired; } } - /* - - totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER) { - if (!subscribed) { - Messages.subscribe(commandChannel); // command channel - Messages.subscribe(announceIDChannel); // id announce channel - subscribed = true; - print("I'm the agent and I am ready to receive!"); - } - if (subscribed && id == UNKNOWN_AGENT_ID) { - - Messages.sendMessage(announceIDChannel, "ready"); - } - } - - if (subscribed && id != UNKNOWN_AGENT_ID) { - timeSinceLastAlive += deltaTime; - if (notifyAlive) { - timeSinceLastAlive = 0; - notifyAlive = false; - print("Master Alive"); - } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - print("Master Lost, reseting Agent"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - Agent.isAvatar = false; - id = UNKNOWN_AGENT_ID; - } - }*/ agentController.update(deltaTime); } -/* -Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == announceIDChannel && message != "ready") { - // If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me - if (id == UNKNOWN_AGENT_ID) { - var parts = message.split("."); - var agentID = parts[0]; - var agentIndex = parts[1]; - if (agentID == Agent.sessionUUID) { - id = agentIndex; - Messages.unsubscribe(announceIDChannel); // id announce channel - } - } - } - if (channel == commandChannel) { - getAction(channel, message, senderID); - } -});*/ + function scriptEnding() { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index eb7f86518f..1444ae3cf1 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -190,31 +190,9 @@ function sendCommand(id, action, argument) { id = -1; masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } else { masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } @@ -312,26 +290,4 @@ Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - -/* -Messages.subscribe(announceIDChannel); -Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == announceIDChannel && message == "ready") { - // check to see if we know about this agent - if (knownAgents.indexOf(senderID) < 0) { - print("New agent to be hired " + senderID); - var indexOfNewAgent = knownAgents.length; - knownAgents[indexOfNewAgent] = senderID; - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); - print("Hired new Agent " + senderID + " #" + indexOfNewAgent); - Messages.sendMessage(announceIDChannel, acknowledgeMessage); - } else { - - print("New agent still sending ready ? " + senderID); - } - - } -}); -*/ moveUI(); From cd2e610e173bbb3a82592680e1b2d212e9126e5f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 15:35:15 -0800 Subject: [PATCH 047/165] Remove OctreeElement's UpdateHooks --- libraries/octree/src/OctreeElement.cpp | 23 ----------------------- libraries/octree/src/OctreeElement.h | 14 -------------- 2 files changed, 37 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 5f03627f1a..1313dc499d 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -115,7 +115,6 @@ OctreeElement::~OctreeElement() { void OctreeElement::markWithChangedTime() { _lastChanged = usecTimestampNow(); - notifyUpdateHooks(); // if the node has changed, notify our hooks } // This method is called by Octree when the subtree below this node @@ -551,28 +550,6 @@ void OctreeElement::notifyDeleteHooks() { _deleteHooksNotified = true; } -std::vector OctreeElement::_updateHooks; - -void OctreeElement::addUpdateHook(OctreeElementUpdateHook* hook) { - _updateHooks.push_back(hook); -} - -void OctreeElement::removeUpdateHook(OctreeElementUpdateHook* hook) { - for (unsigned int i = 0; i < _updateHooks.size(); i++) { - if (_updateHooks[i] == hook) { - _updateHooks.erase(_updateHooks.begin() + i); - return; - } - } -} - -void OctreeElement::notifyUpdateHooks() { - for (unsigned int i = 0; i < _updateHooks.size(); i++) { - _updateHooks[i]->elementUpdated(shared_from_this()); - } -} - - bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { // center and radius are in meters, so we have to scale the _cube into world-frame diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index d705b64acd..ed92e8a193 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -48,13 +48,6 @@ public: virtual void elementDeleted(OctreeElementPointer element) = 0; }; -// Callers who want update hook callbacks should implement this class -class OctreeElementUpdateHook { -public: - virtual void elementUpdated(OctreeElementPointer element) = 0; -}; - - class OctreeElement: public std::enable_shared_from_this { protected: @@ -184,9 +177,6 @@ public: static void addDeleteHook(OctreeElementDeleteHook* hook); static void removeDeleteHook(OctreeElementDeleteHook* hook); - static void addUpdateHook(OctreeElementUpdateHook* hook); - static void removeUpdateHook(OctreeElementUpdateHook* hook); - static void resetPopulationStatistics(); static unsigned long getNodeCount() { return _voxelNodeCount; } static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } @@ -245,7 +235,6 @@ protected: void calculateAACube(); void notifyDeleteHooks(); - void notifyUpdateHooks(); AACube _cube; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes @@ -292,9 +281,6 @@ protected: static QReadWriteLock _deleteHooksLock; static std::vector _deleteHooks; - //static QReadWriteLock _updateHooksLock; - static std::vector _updateHooks; - static AtomicUIntStat _voxelNodeCount; static AtomicUIntStat _voxelNodeLeafCount; From a5b64473af481adc62d085f1417ae7e56ec1277b Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 25 Nov 2015 16:15:04 -0800 Subject: [PATCH 048/165] Fix bugs --- libraries/audio-client/src/AudioClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index d0f2af37af..b141c70272 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -547,8 +547,8 @@ void AudioClient::configureReverb() { p.sampleRate = _outputFormat.sampleRate(); p.roomSize = _reverbOptions->getRoomSize(); p.reverbTime = _reverbOptions->getReverbTime(); - p.highGain = -24.0f * _reverbOptions->getDamping(); - p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); + p.highGain = -24.0f * (1.0f - _reverbOptions->getDamping()); + p.bandwidth = 10000.0f * _reverbOptions->getInputBandwidth(); p.earlyGain = _reverbOptions->getEarlyLevel(); p.lateGain = _reverbOptions->getTailLevel(); p.wetDryMix = 100.0f * powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)); @@ -558,7 +558,7 @@ void AudioClient::configureReverb() { p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER - p.lateGain -= 6.0f; // quieter than listener reverb + p.lateGain -= 12.0f; // quieter than listener reverb p.lateMixLeft = 0.0f; p.lateMixRight = 0.0f; _sourceReverb.setParameters(&p); @@ -811,7 +811,7 @@ void AudioClient::processReceivedSamples(const QByteArray& inputBuffer, QByteArr _desiredOutputFormat, _outputFormat); // apply stereo reverb at the listener, to the received audio - bool hasReverb = _receivedAudioStream.hasReverb(); + bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); if (hasReverb) { assert(_outputFormat.channelCount() == 2); updateReverbOptions(); From 3273fbcad42f8e4dafc2b117758669d02d89783c Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Nov 2015 17:10:38 -0800 Subject: [PATCH 049/165] Creating the master / agent hiring system --- examples/acScripts/AgentPoolControler.js | 448 +++++++++++++---------- examples/acScripts/playbackMaster.js | 56 +-- 2 files changed, 292 insertions(+), 212 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 60b906381a..ec0fdf4b87 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -10,235 +10,305 @@ // function printDebug(message) { - print(message); + print(message); } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - // The time between alive messages on the command channel - var ALIVE_PERIOD = 3; - var NUM_CYCLES_BEFORE_RESET = 5; + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 8; - // Service Actions - var AGENT_READY = "ready"; - var INVALID_ACTOR = -2; + // Service Actions + var MASTER_ID = -1; + var AGENT_READY = "ready"; + var AGENT_LOST = "agentLost"; - var MASTER_INDEX = -1; + var INVALID_ACTOR = -2; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; - var makeMessage = function(id, action, argument) { - var message = { + var AGENTS_BROADCAST = -1; + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; + + var makeUniqueUUID = function(SEUUID) { + //return SEUUID + Math.random(); + // forget complexity, just give me a four digit pin + return (Math.random() * 10000).toFixed(0); + } + + var packAnnounceMessage = function(dest, command, src) { + var message = { + dest: dest, + command: command, + src: src + }; + return JSON.stringify(message); + }; + + var unpackAnnounceMessage = function(message) { + return JSON.parse(message); + }; + + var packCommandMessage = function(id, action, argument) { + var message = { id_key: id, action_key: action, argument_key: argument - }; - return message; - }; - - var unpackMessage = function(message) { - return JSON.parse(message); - }; - - // master side - //--------------------------------- - var MasterController = function() { - this.timeSinceLastAlive = 0; - this.knownAgents = new Array; - this.subscribed = false; + }; + return JSON.stringify(message); }; - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; + var unpackCommandMessage = function(message) { + return JSON.parse(message); + }; + + // master side + //--------------------------------- + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.hiringAgentsQueue = new Array; + this.subscribed = false; + }; - MasterController.prototype.reset = function() { - this.timeSinceLastAlive = 0; + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - }); - } - // ready to roll, enable - this.subscribed = true; - printDebug("Master Started"); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } + // ready to roll, enable + this.subscribed = true; + printDebug("Master Started"); }; MasterController.prototype._processAnnounceMessage = function(message, senderID) { - if (message == AGENT_READY) { - - // check to see if we know about this agent - if (this.knownAgents.indexOf(senderID) < 0) { - - var indexOfNewAgent = this.knownAgents.length; - this.knownAgents[indexOfNewAgent] = senderID; - printDebug("New agent available to be hired " + senderID); - - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); - } else { - printDebug("New agent still sending ready ? " + senderID); - } - } + var message = unpackAnnounceMessage(message); + if (message.dest == MASTER_ID) { + if (message.command == AGENT_READY) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + if (this.hiringAgentsQueue.length > 0) { + var hiringHandler = this.hiringAgentsQueue.pop(); + hiringHandler(message.src); + } else { + //No hiring in queue so bail + return; + } + } else { + // Master think the agent is hired but not the other way around, forget about it + printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } else if (message.command == AGENT_LOST) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } + } }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + var messageJSON = packCommandMessage(target, action, argument); Messages.sendMessage(COMMAND_CHANNEL, messageJSON); - printDebug("Master sent message: " + messageJSON); } - }; - - MasterController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - this.timeSinceLastAlive = 0; - printDebug("Master ping alive"); - this.sendCommand(MASTER_INDEX, MASTER_ALIVE); - } - }; - - this.MasterController = MasterController; - - // agent side - //--------------------------------- - var AgentController = function() { - this.subscribed = false; - - this.timeSinceLastAlive = 0; - this.numCyclesWithoutAlive = 0; - this.actorIndex = INVALID_ACTOR; - this.notifyAlive = false; - - this.onHired = function() {}; - this.onCommand = function(command) {}; - this.onFired = function() {}; }; - AgentController.prototype.destroy = function() { - if (this.subscribed) { - this.fire(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; - - AgentController.prototype.reset = function() { - // If already hired, fire - this.fired(); - - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - if (channel == COMMAND_CHANNEL) { - localThis._processCommandMessage(message, senderID); - return; - } - }); - } - this.subscribed = true; - printDebug("Client Started"); + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + } }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - } - AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); + MasterController.prototype.hireAgent = function(onHired) { + var localThis = this; + this.hiringAgentsQueue.unshift(function(agentID) { + printDebug("hiring callback with agent " + agentID); + + var indexOfNewAgent = localThis.knownAgents.length; + localThis.knownAgents[indexOfNewAgent] = agentID; + + printDebug("New agent available to be hired " + agentID + " " + index); + var hireMessage = "HIRE." + index; + var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); + Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fire(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } - } else { - // ignored - } + if (onHired != null) { + onHired(index); + } + }) }; - AgentController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); - } else { - this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); - this.fired(); - } - } - } + this.MasterController = MasterController; - this.timeSinceLastAlive = 0; - } - }; + // agent side + //--------------------------------- + var AgentController = function() { + this.subscribed = false; + + this._init(); - AgentController.prototype.fired = function() { - // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - this.actorIndex= INVALID_ACTOR; + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; + }; + + AgentController.prototype._init = function() { + this.actorIndex= INVALID_ACTOR; this.notifyAlive = false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; + this.actorUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.actorUUID = " + this.actorUUID); + } + + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } + this.subscribed = true; + printDebug("Client Started"); + }; + + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + var announce = unpackCommandMessage(message); + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (announce.dest == this.actorUUID) { + if (announce.command != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + printDebug(announce.command); + + var parts = announce.command.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + // if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + // } + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackCommandMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } + }; + + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + } else { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { + this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; + printDebug("Master Alive"); + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + + // Post a last message to master in case it still listen to warn that this agent is losing it + if (wasHired) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); + } + + // reset + this._init(); + // then custom fire if was hired - if (wasHired) { - this.onFired(); - } - } + if (wasHired) { + this.onFired(); + } + } - this.AgentController = AgentController; + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 1444ae3cf1..929f384514 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -54,13 +54,23 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); +function onHiring(agentID, index) { + print("agent hired from playbackMaster! " + agentID + " " + index) +} + function setupPlayback() { ac_number = Window.prompt("Insert number of agents: ","1"); if (ac_number === "" || ac_number === null) { ac_number = 1; - } - setupToolBars(); + } masterController.reset(); + + for (var i = 0; i < ac_number; i++) { + masterController.hireAgent(onHiring); + } + + setupToolBars(); + } function setupToolBars() { @@ -96,13 +106,13 @@ function setupToolBars() { var playLoopWidthFactor = 1.65; playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFactor * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); stopIcon[i] = toolBars[i].addTool({ imageURL: TOOL_ICON_URL + "recording-stop.svg", @@ -121,20 +131,20 @@ function setupToolBars() { }, false); nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: (i == ac_number) ? "Master" : i + ". " + + ((i < names.length) ? names[i] : + "AC" + i), + x: 0, y: 0, + width: toolBars[i].width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + })); } } From a364e85e1dec5285b0350134274c3e32e080ec6d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 17:21:56 -0800 Subject: [PATCH 050/165] Remove DeleteHooks --- .../src/octree/OctreeQueryNode.cpp | 2 - .../src/octree/OctreeSendThread.h | 1 - libraries/entities/src/EntityTree.cpp | 7 +--- libraries/entities/src/EntityTreeElement.cpp | 23 +--------- libraries/octree/src/OctreeElement.cpp | 33 --------------- libraries/octree/src/OctreeElement.h | 22 ++-------- libraries/octree/src/OctreeElementBag.cpp | 42 ++++--------------- libraries/octree/src/OctreeElementBag.h | 12 ++---- 8 files changed, 18 insertions(+), 124 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f70ff62f91..10f1d2ec14 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -59,7 +59,6 @@ OctreeQueryNode::~OctreeQueryNode() { void OctreeQueryNode::nodeKilled() { _isShuttingDown = true; - elementBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications if (_octreeSendThread) { // just tell our thread we want to shutdown, this is asynchronous, and fast, we don't need or want it to block // while the thread actually shuts down @@ -69,7 +68,6 @@ void OctreeQueryNode::nodeKilled() { void OctreeQueryNode::forceNodeShutdown() { _isShuttingDown = true; - elementBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications if (_octreeSendThread) { // we really need to force our thread to shutdown, this is synchronous, we will block while the thread actually // shuts down because we really need it to shutdown, and it's ok if we wait for it to complete diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 6e640942e7..6775e56820 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -17,7 +17,6 @@ #include #include -#include #include "OctreeQueryNode.h" diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9eac14e4b4..5ac892de94 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -44,12 +44,7 @@ void EntityTree::createRootElement() { } OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { - EntityTreeElementPointer newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode), - // see comment int EntityTreeElement::createNewElement - [=](EntityTreeElement* dyingElement) { - EntityTreeElementPointer tmpSharedPointer(dyingElement); - dyingElement->notifyDeleteHooks(); - }); + auto newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode)); newElement->setTree(std::static_pointer_cast(shared_from_this())); return std::static_pointer_cast(newElement); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 02552ef488..8403db8b2f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -28,29 +28,8 @@ EntityTreeElement::~EntityTreeElement() { _octreeMemoryUsage -= sizeof(EntityTreeElement); } -// This will be called primarily on addChildAt(), which means we're adding a child of our -// own type to our own tree. This means we should initialize that child with any tree and type -// specific settings that our children must have. OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCode) { - EntityTreeElementPointer newChild = - EntityTreeElementPointer(new EntityTreeElement(octalCode), - // This is a little bit horrible, but I haven't found a better way. The OctreeElement - // destructor used to call notifyDeleteHooks(), which calls zero or more of - // OctreeElementDeleteHook::elementDeleted - // which (now) expects an OctreeElementPointer argument. The destructor doesn't have - // access to the shared pointer (which has had its reference count drop to zero, - // or the destructor wouldn't have been called). The destructor also can't - // make a new shared pointer -- shared_from_this() is forbidden in a destructor, and - // using OctreeElementPointer(this) also fails. So, I've installed a custom deleter: - [=](EntityTreeElement* dyingElement) { - // make a new shared pointer with a reference count of 1 (and no custom deleter) - EntityTreeElementPointer tmpSharedPointer(dyingElement); - // call notifyDeleteHooks which will use shared_from_this() to get this same - // shared pointer, for use with the elementDeleted calls. - dyingElement->notifyDeleteHooks(); - // And now tmpSharedPointer's reference count drops to zero and the - // normal destructors are called. - }); + auto newChild = EntityTreeElementPointer(new EntityTreeElement(octalCode)); newChild->setTree(_myTree); return newChild; } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 1313dc499d..f16e1dc88d 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -95,10 +95,6 @@ void OctreeElement::init(unsigned char * octalCode) { } OctreeElement::~OctreeElement() { - // We can't call notifyDeleteHooks from here: - // notifyDeleteHooks(); - // see comment in EntityTreeElement::createNewElement. - assert(_deleteHooksNotified); _voxelNodeCount--; if (isLeaf()) { _voxelNodeLeafCount--; @@ -521,35 +517,6 @@ float OctreeElement::distanceToPoint(const glm::vec3& point) const { return distance; } -QReadWriteLock OctreeElement::_deleteHooksLock; -std::vector OctreeElement::_deleteHooks; - -void OctreeElement::addDeleteHook(OctreeElementDeleteHook* hook) { - _deleteHooksLock.lockForWrite(); - _deleteHooks.push_back(hook); - _deleteHooksLock.unlock(); -} - -void OctreeElement::removeDeleteHook(OctreeElementDeleteHook* hook) { - _deleteHooksLock.lockForWrite(); - for (unsigned int i = 0; i < _deleteHooks.size(); i++) { - if (_deleteHooks[i] == hook) { - _deleteHooks.erase(_deleteHooks.begin() + i); - break; - } - } - _deleteHooksLock.unlock(); -} - -void OctreeElement::notifyDeleteHooks() { - _deleteHooksLock.lockForRead(); - for (unsigned int i = 0; i < _deleteHooks.size(); i++) { - _deleteHooks[i]->elementDeleted(shared_from_this()); - } - _deleteHooksLock.unlock(); - _deleteHooksNotified = true; -} - bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { // center and radius are in meters, so we have to scale the _cube into world-frame diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index ed92e8a193..c686970c3a 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -33,20 +33,15 @@ class EncodeBitstreamParams; class Octree; class OctreeElement; class OctreeElementBag; -class OctreeElementDeleteHook; class OctreePacketData; class ReadBitstreamToTreeParams; class Shape; class VoxelSystem; -typedef std::shared_ptr OctreeElementPointer; -typedef std::shared_ptr ConstOctreeElementPointer; -typedef std::shared_ptr OctreePointer; -// Callers who want delete hook callbacks should implement this class -class OctreeElementDeleteHook { -public: - virtual void elementDeleted(OctreeElementPointer element) = 0; -}; +using OctreeElementPointer = std::shared_ptr; +using OctreeElementWeakPointer = std::weak_ptr; +using ConstOctreeElementPointer = std::shared_ptr; +using OctreePointer = std::shared_ptr; class OctreeElement: public std::enable_shared_from_this { @@ -174,9 +169,6 @@ public: bool matchesSourceUUID(const QUuid& sourceUUID) const; static uint16_t getSourceNodeUUIDKey(const QUuid& sourceUUID); - static void addDeleteHook(OctreeElementDeleteHook* hook); - static void removeDeleteHook(OctreeElementDeleteHook* hook); - static void resetPopulationStatistics(); static unsigned long getNodeCount() { return _voxelNodeCount; } static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } @@ -234,7 +226,6 @@ protected: void setChildAtIndex(int childIndex, OctreeElementPointer child); void calculateAACube(); - void notifyDeleteHooks(); AACube _cube; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes @@ -276,11 +267,6 @@ protected: _unknownBufferIndex : 1, _childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit - bool _deleteHooksNotified = false; - - static QReadWriteLock _deleteHooksLock; - static std::vector _deleteHooks; - static AtomicUIntStat _voxelNodeCount; static AtomicUIntStat _voxelNodeLeafCount; diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index 5af63c7bb1..167c3560d6 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -12,54 +12,30 @@ #include "OctreeElementBag.h" #include -OctreeElementBag::OctreeElementBag() : - _bagElements() -{ - OctreeElement::addDeleteHook(this); - _hooked = true; -} - -OctreeElementBag::~OctreeElementBag() { - unhookNotifications(); - deleteAll(); -} - -void OctreeElementBag::unhookNotifications() { - if (_hooked) { - OctreeElement::removeDeleteHook(this); - _hooked = false; - } -} - -void OctreeElementBag::elementDeleted(OctreeElementPointer element) { - remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() -} - - void OctreeElementBag::deleteAll() { _bagElements.clear(); } - void OctreeElementBag::insert(OctreeElementPointer element) { - _bagElements.insert(element); + _bagElements.insert(element.get(), element); } OctreeElementPointer OctreeElementBag::extract() { - OctreeElementPointer result = NULL; + OctreeElementPointer result; - if (_bagElements.size() > 0) { - QSet::iterator front = _bagElements.begin(); - result = *front; - _bagElements.erase(front); + // Find the first element still alive + while (!_bagElements.empty() && !result) { + auto it = _bagElements.begin(); + result = it->lock(); + _bagElements.erase(it); } return result; } bool OctreeElementBag::contains(OctreeElementPointer element) { - return _bagElements.contains(element); + return _bagElements.contains(element.get()); } void OctreeElementBag::remove(OctreeElementPointer element) { - _bagElements.remove(element); + _bagElements.remove(element.get()); } diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index 8ef01b44a2..b5f4d5dcf5 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -17,12 +17,10 @@ #define hifi_OctreeElementBag_h #include "OctreeElement.h" +#include -class OctreeElementBag : public OctreeElementDeleteHook { - +class OctreeElementBag { public: - OctreeElementBag(); - ~OctreeElementBag(); void insert(OctreeElementPointer element); // put a element into the bag OctreeElementPointer extract(); // pull a element out of the bag (could come in any order) @@ -32,13 +30,9 @@ public: int count() const { return _bagElements.size(); } void deleteAll(); - virtual void elementDeleted(OctreeElementPointer element); - - void unhookNotifications(); private: - QSet _bagElements; - bool _hooked; + QHash _bagElements; }; typedef QMap OctreeElementExtraEncodeData; From a40ead077fb4df79b26563a502002ec1144f6992 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 25 Nov 2015 20:37:51 -0800 Subject: [PATCH 051/165] Mouth animation improvements --- interface/src/avatar/Head.cpp | 47 ++++++++++++++++++++--------------- interface/src/avatar/Head.h | 2 ++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index e8452583fc..b214ba2976 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -43,9 +43,11 @@ Head::Head(Avatar* owningAvatar) : _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _audioJawOpen(0.0f), + _trailingAudioJawOpen(0.0f), _mouth2(0.0f), _mouth3(0.0f), _mouth4(0.0f), + _mouthTime(0.0f), _renderLookatVectors(false), _renderLookatTarget(false), _saccade(0.0f, 0.0f, 0.0f), @@ -246,28 +248,33 @@ void Head::calculateMouthShapes() { const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; - float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; - if (audioDelta > _audioJawOpen) { - _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } else { - _audioJawOpen *= JAW_CLOSE_RATE; - } - _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + const float TIMESTEP_CONSTANT = 0.0032f; + const float MMMM_POWER = 0.10f; + const float SMILE_POWER = 0.10f; + const float FUNNEL_POWER = 0.35f; + const float MMMM_SPEED = 2.685f; + const float SMILE_SPEED = 1.0f; + const float FUNNEL_SPEED = 2.335f; + const float STOP_GAIN = 5.0f; - // _mouth2 = "mmmm" shape - // _mouth3 = "funnel" shape - // _mouth4 = "smile" shape - const float FUNNEL_PERIOD = 0.985f; - const float FUNNEL_RANDOM_PERIOD = 0.01f; - const float MMMM_POWER = 0.25f; - const float MMMM_PERIOD = 0.91f; - const float MMMM_RANDOM_PERIOD = 0.15f; - const float SMILE_PERIOD = 0.925f; - const float SMILE_RANDOM_PERIOD = 0.05f; + // From the change in loudness, decide how much to open or close the jaw + float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; + if (audioDelta > _audioJawOpen) { + _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; + } + else { + _audioJawOpen *= JAW_CLOSE_RATE; + } + _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + + // Advance time at a rate proportional to loudness, and move the mouth shapes through + // a cycle at differing speeds to create a continuous random blend of shapes. + _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; + _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); - _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); - _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); } void Head::applyEyelidOffset(glm::quat headOrientation) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 1fbfceca92..93637b7d3c 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -124,9 +124,11 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; + float _trailingAudioJawOpen; float _mouth2; float _mouth3; float _mouth4; + float _mouthTime; bool _renderLookatVectors; bool _renderLookatTarget; glm::vec3 _saccade; From 37d3083e079ae183c63c27a9d383ccfb009e712a Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Thu, 26 Nov 2015 00:41:46 -0800 Subject: [PATCH 052/165] Getting the Actor class starting to work and usable for the playback master! --- examples/acScripts/AgentPoolControler.js | 40 ++++++++++++++++++------ examples/acScripts/playbackMaster.js | 19 ++++++++--- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index ec0fdf4b87..d528fc70fe 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -65,11 +65,22 @@ function printDebug(message) { return JSON.parse(message); }; + // Actor + //--------------------------------- + var Actor = function() { + this.agentID = INVALID_ACTOR; + this.onHired = function(actor) {}; + this.onLost = function(actor) {}; + }; + + this.Actor = Actor; + // master side //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; + this.hiredActors = new Array; this.hiringAgentsQueue = new Array; this.subscribed = false; }; @@ -126,6 +137,10 @@ function printDebug(message) { if (agentIndex < 0) { printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); this.knownAgents[agentIndex] = INVALID_ACTOR; + var lostActor = this.hiredActors[agentIndex]; + this.hiredActors[agentIndex] = null; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); } } } @@ -147,22 +162,27 @@ function printDebug(message) { }; - MasterController.prototype.hireAgent = function(onHired) { + MasterController.prototype.hireAgent = function(actor) { + if (actor == null) { + printDebug("trying to hire an agent with a null actor, abort"); + return; + } var localThis = this; this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID); - - var indexOfNewAgent = localThis.knownAgents.length; - localThis.knownAgents[indexOfNewAgent] = agentID; + printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); + + var indexOfNewAgent = localThis.knownAgents.push(agentID) + actor.agentID = agentID; + localThis.hiredActors.push(actor); - printDebug("New agent available to be hired " + agentID + " " + index); - var hireMessage = "HIRE." + index; + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var hireMessage = "HIRE." + indexOfNewAgent; var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); + + printDebug("message sent calling the actor" + JSON.stringify(actor) ); - if (onHired != null) { - onHired(index); - } + actor.onHired(actor); }) }; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 929f384514..3e60fc7a0e 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -17,7 +17,7 @@ var masterController = new MasterController(); var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) var input_text = null; - +var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); @@ -54,8 +54,14 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); -function onHiring(agentID, index) { - print("agent hired from playbackMaster! " + agentID + " " + index) +function onActorHired(actor) { + print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) +} + +function onActorLost(actor) { + print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) + + actors[actor.index] = null; } function setupPlayback() { @@ -66,7 +72,12 @@ function setupPlayback() { masterController.reset(); for (var i = 0; i < ac_number; i++) { - masterController.hireAgent(onHiring); + var newActor = new Actor(); + newActor.index = i; + newActor.onHired = onActorHired; + newActor.onLost = onActorLost; + masterController.hireAgent(newActor); + actors.push(newActor); } setupToolBars(); From 7df984e7b207528477d04a3e6eab5477573668f2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 05:30:01 -0800 Subject: [PATCH 053/165] fix deadlock when setting parentID to null --- interface/src/InterfaceParentFinder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index 1703ffc5d1..112bae5bb8 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -19,6 +19,10 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { SpatiallyNestableWeakPointer parent; + if (parentID.isNull()) { + return parent; + } + // search entities EntityTreeRenderer* treeRenderer = qApp->getEntities(); EntityTreePointer tree = treeRenderer->getTree(); From 36e293608a009ec6b1d067f8351673c728e6e555 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 05:31:52 -0800 Subject: [PATCH 054/165] more adding parentID to edit.js --- examples/html/entityProperties.html | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index bc6a6920d1..50fb205e3d 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -223,7 +223,9 @@ var elDimensionsZ = document.getElementById("property-dim-z"); var elResetToNaturalDimensions = document.getElementById("reset-to-natural-dimensions"); var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct"); - var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); + var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); + + var elParentID = document.getElementById("parent-id"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); @@ -453,6 +455,8 @@ elDimensionsY.value = properties.dimensions.y.toFixed(2); elDimensionsZ.value = properties.dimensions.z.toFixed(2); + elParentID.value = properties.parentID; + elRegistrationX.value = properties.registrationPoint.x.toFixed(2); elRegistrationY.value = properties.registrationPoint.y.toFixed(2); elRegistrationZ.value = properties.registrationPoint.z.toFixed(2); @@ -666,6 +670,8 @@ elDimensionsY.addEventListener('change', dimensionsChangeFunction); elDimensionsZ.addEventListener('change', dimensionsChangeFunction); + elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID)); + var registrationChangeFunction = createEmitVec3PropertyUpdateFunction( 'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ); elRegistrationX.addEventListener('change', registrationChangeFunction); @@ -1055,6 +1061,13 @@ +
+ ParentID +
+ +
+
+
Registration
From 10cf85bad975090e01cb95da7edbf2b815af7c0f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:02:53 -0800 Subject: [PATCH 055/165] fix some rotation handling in EntityItem, minimize diff vs master --- libraries/entities/src/EntityItem.cpp | 132 +++++++++++++------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c0dd79d00e..d60df17d78 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -241,7 +241,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); - APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); + APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); @@ -1045,7 +1045,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getVelocity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravity); @@ -1085,7 +1085,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c // a TerseUpdate includes the transform and its derivatives properties._position = getLocalPosition(); properties._velocity = _velocity; - properties._rotation = getRotation(); + properties._rotation = getLocalOrientation(); properties._angularVelocity = _angularVelocity; properties._acceleration = _acceleration; @@ -1314,27 +1314,6 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -void EntityItem::forSelfAndEachChildEntity(std::function actor) { - QQueue toProcess; - toProcess.enqueue(shared_from_this()); - - while (!toProcess.empty()) { - EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - actor(entity); - foreach (SpatiallyNestablePointer child, entity->getChildren()) { - if (child && child->getNestableType() == NestableTypes::Entity) { - toProcess.enqueue(child); - } - } - } -} - -void EntityItem::parentChanged() { - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; @@ -1347,34 +1326,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::setTransform(const Transform& transform) { - SpatiallyNestable::setTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalTransform(const Transform& transform) { - SpatiallyNestable::setLocalTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setPosition(const glm::vec3& position) { - SpatiallyNestable::setPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalPosition(const glm::vec3& position) { - SpatiallyNestable::setLocalPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updateRotation(const glm::quat& rotation) { if (shouldSuppressLocationEdits()) { return; @@ -1390,20 +1341,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::setRotation(const glm::quat& orientation) { - SpatiallyNestable::setOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalRotation(const glm::quat& orientation) { - SpatiallyNestable::setLocalOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updateDimensions(const glm::vec3& value) { if (getDimensions() != value) { setDimensions(value); @@ -1901,3 +1838,66 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG return result; } + +void EntityItem::forSelfAndEachChildEntity(std::function actor) { + QQueue toProcess; + toProcess.enqueue(shared_from_this()); + + while (!toProcess.empty()) { + EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); + actor(entity); + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + } +} + +void EntityItem::parentChanged() { + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setTransform(const Transform& transform) { + SpatiallyNestable::setTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalTransform(const Transform& transform) { + SpatiallyNestable::setLocalTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalPosition(const glm::vec3& position) { + SpatiallyNestable::setLocalPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setRotation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalRotation(const glm::quat& orientation) { + SpatiallyNestable::setLocalOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} From 6062691c2a58f42486a1e28d975818582eb8e144 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:04:27 -0800 Subject: [PATCH 056/165] minimize diff vs master --- libraries/entities/src/EntityItem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d60df17d78..24b0e7f977 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1326,6 +1326,13 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } +void EntityItem::updateDimensions(const glm::vec3& value) { + if (getDimensions() != value) { + setDimensions(value); + _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + } +} + void EntityItem::updateRotation(const glm::quat& rotation) { if (shouldSuppressLocationEdits()) { return; @@ -1341,13 +1348,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::updateDimensions(const glm::vec3& value) { - if (getDimensions() != value) { - setDimensions(value); - _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); - } -} - void EntityItem::updateMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however // we must protect the density range to help maintain stability of physics simulation From facf91faacf7cf6f9e5ec85ed2b91f4b7fcd8191 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:13:43 -0800 Subject: [PATCH 057/165] minimize diff vs master --- libraries/avatars/src/AvatarData.cpp | 82 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f7def48b9d..adfd10b2af 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -87,47 +87,6 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { return _defaultFullAvatarModelUrl; } -float AvatarData::getBodyYaw() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.y; -} - -void AvatarData::setBodyYaw(float bodyYaw) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.y = bodyYaw; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -float AvatarData::getBodyPitch() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.x; -} - -void AvatarData::setBodyPitch(float bodyPitch) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.x = bodyPitch; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -float AvatarData::getBodyRoll() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.z; -} - -void AvatarData::setBodyRoll(float bodyRoll) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.z = bodyRoll; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -void AvatarData::setPosition(const glm::vec3& position) { - SpatiallyNestable::setPosition(position); -} - -void AvatarData::setOrientation(const glm::quat& orientation) { - SpatiallyNestable::setOrientation(orientation); -} - // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); @@ -1616,3 +1575,44 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) { #endif result.fromJson(doc.object()); } + +float AvatarData::getBodyYaw() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.y; +} + +void AvatarData::setBodyYaw(float bodyYaw) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.y = bodyYaw; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyPitch() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.x; +} + +void AvatarData::setBodyPitch(float bodyPitch) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.x = bodyPitch; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyRoll() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.z; +} + +void AvatarData::setBodyRoll(float bodyRoll) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.z = bodyRoll; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +void AvatarData::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); +} + +void AvatarData::setOrientation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); +} From eb50c9de5f7b74966e0a07822c08db12ea620154 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 10:16:56 -0800 Subject: [PATCH 058/165] aabox delivered to scripts in properties should be in world space --- libraries/entities/src/EntityItemProperties.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8fa760930c..a1ce826072 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1491,10 +1491,12 @@ AABox EntityItemProperties::getAABox() const { glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); + glm::quat worldRotation = SpatiallyNestable::localToWorld(getRotation(), _parentID, _parentJointIndex); + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(worldRotation); // shift the extents to be relative to the position/registration point - rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + glm::vec3 worldPosition = SpatiallyNestable::localToWorld(_position, _parentID, _parentJointIndex); + rotatedExtentsRelativeToRegistrationPoint.shiftBy(worldPosition); return AABox(rotatedExtentsRelativeToRegistrationPoint); } From 204c3d839e487775542ffa3adf1d1b4aa6fb9cf9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 10:17:21 -0800 Subject: [PATCH 059/165] added localToWorld calls, put locks around access to _children hashtable --- libraries/shared/src/SpatiallyNestable.cpp | 53 +++++++++++++++++++--- libraries/shared/src/SpatiallyNestable.h | 6 +++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 87ef7565fb..f5d05a77ad 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -76,11 +76,15 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { } void SpatiallyNestable::beParentOfChild(SpatiallyNestablePointer newChild) const { - _children[newChild->getID()] = newChild; + _childrenLock.withWriteLock([&] { + _children[newChild->getID()] = newChild; + }); } void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { - _children.remove(newChild->getID()); + _childrenLock.withWriteLock([&] { + _children.remove(newChild->getID()); + }); } void SpatiallyNestable::setParentID(const QUuid& parentID) { @@ -110,6 +114,39 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { return result.getRotation(); } +glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + Transform positionTransform; + positionTransform.setTranslation(position); + Transform result; + Transform::mult(result, parentTransform, positionTransform); + return result.getTranslation(); +} + +glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + Transform orientationTransform; + orientationTransform.setRotation(orientation); + Transform result; + Transform::mult(result, parentTransform, orientationTransform); + return result.getRotation(); +} + + const glm::vec3& SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; @@ -223,12 +260,14 @@ void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { QList SpatiallyNestable::getChildren() const { QList children; - foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { - SpatiallyNestablePointer child = childWP.lock(); - if (child) { - children << child; + _childrenLock.withReadLock([&] { + foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + SpatiallyNestablePointer child = childWP.lock(); + if (child) { + children << child; + } } - } + }); return children; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 30602d26b4..74d9cc9a95 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -16,6 +16,7 @@ #include "Transform.h" #include "SpatialParentFinder.h" +#include "shared/ReadWriteLockable.h" class SpatiallyNestable; @@ -49,6 +50,9 @@ public: glm::vec3 worldToLocal(const glm::vec3& position); glm::quat worldToLocal(const glm::quat& orientation); + static glm::vec3 localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex); + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); @@ -101,6 +105,8 @@ protected: virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; virtual void forgetChild(SpatiallyNestablePointer newChild) const; + + mutable ReadWriteLockable _childrenLock; mutable QHash _children; virtual void parentChanged() {} // called when parent pointer is updated From cf39cac7fcfb24b38a47228ad8cc46d280d68970 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 12:50:33 -0800 Subject: [PATCH 060/165] attempt to make SpatiallyNestable data access thread-safe --- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- interface/src/avatar/Avatar.cpp | 4 +- interface/src/avatar/Avatar.h | 4 +- libraries/avatars/src/AvatarData.cpp | 4 +- libraries/avatars/src/AvatarData.h | 4 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 38 ++-- libraries/entities/src/EntityItem.h | 20 +- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- .../src/AbstractViewStateInterface.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 182 +++++++++++------- libraries/shared/src/SpatiallyNestable.h | 62 +++--- 19 files changed, 187 insertions(+), 153 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1088426fcc..f5781e727d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3329,7 +3329,7 @@ MyAvatar* Application::getMyAvatar() const { return DependencyManager::get()->getMyAvatar(); } -const glm::vec3& Application::getAvatarPosition() const { +const glm::vec3 Application::getAvatarPosition() const { return getMyAvatar()->getPosition(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 730158c689..0467926b47 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -185,7 +185,7 @@ public: virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual PickRay computePickRay(float x, float y) const; - virtual const glm::vec3& getAvatarPosition() const; + virtual const glm::vec3 getAvatarPosition() const; virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } virtual void endOverrideEnvironmentData() { _environment.endOverride(); } virtual qreal getDevicePixelRatio(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5aa6936fee..763d44274d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1212,12 +1212,12 @@ glm::quat Avatar::getRightPalmRotation() { return rightRotation; } -void Avatar::setPosition(const glm::vec3& position) { +void Avatar::setPosition(const glm::vec3 position) { AvatarData::setPosition(position); updateAttitude(); } -void Avatar::setOrientation(const glm::quat& orientation) { +void Avatar::setOrientation(const glm::quat orientation) { AvatarData::setOrientation(orientation); updateAttitude(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index c19efe032b..51768e4e71 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -161,8 +161,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setOrientation(const glm::quat orientation); public slots: diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index adfd10b2af..ec363756f6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1609,10 +1609,10 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } -void AvatarData::setPosition(const glm::vec3& position) { +void AvatarData::setPosition(const glm::vec3 position) { SpatiallyNestable::setPosition(position); } -void AvatarData::setOrientation(const glm::quat& orientation) { +void AvatarData::setOrientation(const glm::quat orientation) { SpatiallyNestable::setOrientation(orientation); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9b684ec989..8db0ef5897 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setOrientation(const glm::quat orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index bf3b2e7e95..393c0dc0dc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -44,7 +44,7 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { } } -void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { +void RenderableModelEntityItem::setDimensions(const glm::vec3 value) { _dimensionsInitialized = true; ModelEntityItem::setDimensions(value); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2187c0edb3..b86692753c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -28,7 +28,7 @@ public: virtual ~RenderableModelEntityItem(); - virtual void setDimensions(const glm::vec3& value) override; + virtual void setDimensions(const glm::vec3 value) override; virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 24b0e7f977..64b4fc5088 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1188,7 +1188,7 @@ const Transform EntityItem::getTransformToCenter() const { return result; } -void EntityItem::setDimensions(const glm::vec3& value) { +void EntityItem::setDimensions(const glm::vec3 value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } @@ -1860,44 +1860,44 @@ void EntityItem::parentChanged() { }); } -void EntityItem::setTransform(const Transform& transform) { +void EntityItem::setTransform(const Transform transform) { SpatiallyNestable::setTransform(transform); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalTransform(const Transform& transform) { +void EntityItem::setLocalTransform(const Transform transform) { SpatiallyNestable::setLocalTransform(transform); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setPosition(const glm::vec3& position) { +void EntityItem::setPosition(const glm::vec3 position) { SpatiallyNestable::setPosition(position); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalPosition(const glm::vec3& position) { +void EntityItem::setLocalPosition(const glm::vec3 position) { SpatiallyNestable::setLocalPosition(position); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setRotation(const glm::quat& orientation) { +void EntityItem::setRotation(const glm::quat orientation) { SpatiallyNestable::setOrientation(orientation); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalRotation(const glm::quat& orientation) { +void EntityItem::setLocalRotation(const glm::quat orientation) { SpatiallyNestable::setLocalOrientation(orientation); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 855f9568f1..cd5f97bee2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -196,8 +196,8 @@ public: void setDescription(QString value) { _description = value; } /// Dimensions in meters (0.0 - TREE_SCALE) - inline const glm::vec3& getDimensions() const { return getScale(); } - virtual void setDimensions(const glm::vec3& value); + inline const glm::vec3 getDimensions() const { return getScale(); } + virtual void setDimensions(const glm::vec3 value); float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } @@ -325,15 +325,15 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } - virtual void setTransform(const Transform& transform); - virtual void setLocalTransform(const Transform& transform); - // virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } - virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + virtual void setTransform(const Transform transform); + virtual void setLocalTransform(const Transform transform); + // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } + virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setPosition(const glm::vec3& position); - virtual void setLocalPosition(const glm::vec3& position); - virtual void setRotation(const glm::quat& orientation); - virtual void setLocalRotation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setLocalPosition(const glm::vec3 position); + virtual void setRotation(const glm::quat orientation); + virtual void setLocalRotation(const glm::quat orientation); // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index ac56fc9c1f..af3110c000 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -40,7 +40,7 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem( _cutoff = PI; } -void LightEntityItem::setDimensions(const glm::vec3& value) { +void LightEntityItem::setDimensions(const glm::vec3 value) { if (_isSpotlight) { // If we are a spotlight, treat the z value as our radius or length, and // recalculate the x/y dimensions to properly encapsulate the spotlight. diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 103c462809..edb2ca7b3c 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 893329d1ce..7d1cfb5c6b 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -41,7 +41,7 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void TextEntityItem::setDimensions(const glm::vec3& value) { +void TextEntityItem::setDimensions(const glm::vec3 value) { // NOTE: Text Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 1caceee085..2080912d92 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 5f113f1de4..35189074bb 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -34,7 +34,7 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void WebEntityItem::setDimensions(const glm::vec3& value) { +void WebEntityItem::setDimensions(const glm::vec3 value) { // NOTE: Web Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 8e9d924cde..49ab009bb2 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -22,7 +22,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index b65289933c..2954c1fce4 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -45,7 +45,7 @@ public: virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; - virtual const glm::vec3& getAvatarPosition() const = 0; + virtual const glm::vec3 getAvatarPosition() const = 0; virtual void postLambdaEvent(std::function f) = 0; virtual qreal getDevicePixelRatio() = 0; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index f5d05a77ad..d5e2104706 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -87,34 +87,38 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { }); } -void SpatiallyNestable::setParentID(const QUuid& parentID) { +void SpatiallyNestable::setParentID(const QUuid parentID) { if (_parentID != parentID) { _parentID = parentID; _parentKnowsMe = false; } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); + _transformLock.withReadLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + }); myWorldTransform.setTranslation(position); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { +glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); + _transformLock.withReadLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + }); myWorldTransform.setRotation(orientation); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getRotation(); } -glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -130,7 +134,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid paren return result.getTranslation(); } -glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -147,115 +151,152 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid pa } -const glm::vec3& SpatiallyNestable::getPosition() const { +const glm::vec3 SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; parentTransformDescaled.getMatrix(parentMat); glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); - _absolutePositionCache = glm::vec3(absPos); - return _absolutePositionCache; + return glm::vec3(absPos); } -const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex].getTranslation(); +const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame.getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3& position) { +void SpatiallyNestable::setPosition(const glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setTranslation(position); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + _transformLock.withWriteLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + }); } -const glm::quat& SpatiallyNestable::getOrientation() const { +const glm::quat SpatiallyNestable::getOrientation() const { Transform parentTransformDescaled = getParentTransform(); - _absoluteRotationCache = parentTransformDescaled.getRotation() * getLocalOrientation(); - return _absoluteRotationCache; + return parentTransformDescaled.getRotation() * getLocalOrientation(); } -const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex + 1); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex].getRotation(); +const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame.getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat& orientation) { +void SpatiallyNestable::setOrientation(const glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setRotation(orientation); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + _transformLock.withWriteLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + }); } -const Transform& SpatiallyNestable::getTransform() const { +const Transform SpatiallyNestable::getTransform() const { Transform parentTransform = getParentTransform(); - Transform::mult(_worldTransformCache, parentTransform, _transform); - return _worldTransformCache; + Transform result; + _transformLock.withReadLock([&] { + Transform::mult(result, parentTransform, _transform); + }); + return result; } -const Transform& SpatiallyNestable::getTransform(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex + 1); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex]; +const Transform SpatiallyNestable::getTransform(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame; } -void SpatiallyNestable::setTransform(const Transform& transform) { +void SpatiallyNestable::setTransform(const Transform transform) { Transform parentTransform = getParentTransform(); - Transform::inverseMult(_transform, parentTransform, transform); + _transformLock.withWriteLock([&] { + Transform::inverseMult(_transform, parentTransform, transform); + }); } -const glm::vec3& SpatiallyNestable::getScale() const { - return _transform.getScale(); +const glm::vec3 SpatiallyNestable::getScale() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getScale(); + }); + return result; } -const glm::vec3& SpatiallyNestable::getScale(int jointIndex) const { +const glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { // XXX ... something with joints return getScale(); } -void SpatiallyNestable::setScale(const glm::vec3& scale) { - _transform.setScale(scale); +void SpatiallyNestable::setScale(const glm::vec3 scale) { + _transformLock.withWriteLock([&] { + _transform.setScale(scale); + }); } -const Transform& SpatiallyNestable::getLocalTransform() const { - return _transform; +const Transform SpatiallyNestable::getLocalTransform() const { + Transform result; + _transformLock.withReadLock([&] { + result =_transform; + }); + return result; } -void SpatiallyNestable::setLocalTransform(const Transform& transform) { - _transform = transform; +void SpatiallyNestable::setLocalTransform(const Transform transform) { + _transformLock.withWriteLock([&] { + _transform = transform; + }); } -const glm::vec3& SpatiallyNestable::getLocalPosition() const { - return _transform.getTranslation(); +const glm::vec3 SpatiallyNestable::getLocalPosition() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getTranslation(); + }); + return result; } -void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { - _transform.setTranslation(position); +void SpatiallyNestable::setLocalPosition(const glm::vec3 position) { + _transformLock.withWriteLock([&] { + _transform.setTranslation(position); + }); } -const glm::quat& SpatiallyNestable::getLocalOrientation() const { - return _transform.getRotation(); +const glm::quat SpatiallyNestable::getLocalOrientation() const { + glm::quat result; + _transformLock.withReadLock([&] { + result = _transform.getRotation(); + }); + return result; } -void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { - _transform.setRotation(orientation); +void SpatiallyNestable::setLocalOrientation(const glm::quat orientation) { + _transformLock.withWriteLock([&] { + _transform.setRotation(orientation); + }); } -const glm::vec3& SpatiallyNestable::getLocalScale() const { - return _transform.getScale(); +const glm::vec3 SpatiallyNestable::getLocalScale() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getScale(); + }); + return result; } -void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { - _transform.setScale(scale); +void SpatiallyNestable::setLocalScale(const glm::vec3 scale) { + _transformLock.withWriteLock([&] { + _transform.setScale(scale); + }); } QList SpatiallyNestable::getChildren() const { @@ -272,12 +313,11 @@ QList SpatiallyNestable::getChildren() const { } -const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { - _jointInObjectFrameCache.resize(jointIndex + 1); - _jointInObjectFrameCache[jointIndex] = Transform(); +const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { + Transform jointInObjectFrame; glm::vec3 position = getJointTranslation(jointIndex); glm::quat orientation = getJointRotation(jointIndex); - _jointInObjectFrameCache[jointIndex].setRotation(orientation); - _jointInObjectFrameCache[jointIndex].setTranslation(position); - return _jointInObjectFrameCache[jointIndex]; + jointInObjectFrame.setRotation(orientation); + jointInObjectFrame.setTranslation(position); + return jointInObjectFrame; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 74d9cc9a95..5074779d8e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -41,57 +41,57 @@ public: virtual const QUuid& getID() const { return _id; } virtual void setID(const QUuid& id) { _id = id; } - virtual const QUuid& getParentID() const { return _parentID; } - virtual void setParentID(const QUuid& parentID); + virtual const QUuid getParentID() const { return _parentID; } + virtual void setParentID(const QUuid parentID); virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - glm::vec3 worldToLocal(const glm::vec3& position); - glm::quat worldToLocal(const glm::quat& orientation); + glm::vec3 worldToLocal(const glm::vec3 position); + glm::quat worldToLocal(const glm::quat orientation); - static glm::vec3 localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex); - static glm::quat localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); // world frame - virtual const Transform& getTransform() const; - virtual void setTransform(const Transform& transform); + virtual const Transform getTransform() const; + virtual void setTransform(const Transform transform); virtual Transform getParentTransform() const; - virtual const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3& position); + virtual const glm::vec3 getPosition() const; + virtual void setPosition(const glm::vec3 position); - virtual const glm::quat& getOrientation() const; - virtual const glm::quat& getOrientation(int jointIndex) const; - virtual void setOrientation(const glm::quat& orientation); + virtual const glm::quat getOrientation() const; + virtual const glm::quat getOrientation(int jointIndex) const; + virtual void setOrientation(const glm::quat orientation); - virtual const glm::vec3& getScale() const; - virtual void setScale(const glm::vec3& scale); + virtual const glm::vec3 getScale() const; + virtual void setScale(const glm::vec3 scale); // get world location of a specific joint - virtual const Transform& getTransform(int jointIndex) const; - virtual const glm::vec3& getPosition(int jointIndex) const; - virtual const glm::vec3& getScale(int jointIndex) const; + virtual const Transform getTransform(int jointIndex) const; + virtual const glm::vec3 getPosition(int jointIndex) const; + virtual const glm::vec3 getScale(int jointIndex) const; // object's parent's frame - virtual const Transform& getLocalTransform() const; - virtual void setLocalTransform(const Transform& transform); + virtual const Transform getLocalTransform() const; + virtual void setLocalTransform(const Transform transform); - virtual const glm::vec3& getLocalPosition() const; - virtual void setLocalPosition(const glm::vec3& position); + virtual const glm::vec3 getLocalPosition() const; + virtual void setLocalPosition(const glm::vec3 position); - virtual const glm::quat& getLocalOrientation() const; - virtual void setLocalOrientation(const glm::quat& orientation); + virtual const glm::quat getLocalOrientation() const; + virtual void setLocalOrientation(const glm::quat orientation); - virtual const glm::vec3& getLocalScale() const; - virtual void setLocalScale(const glm::vec3& scale); + virtual const glm::vec3 getLocalScale() const; + virtual void setLocalScale(const glm::vec3 scale); QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } // this object's frame - virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; virtual glm::quat getJointRotation(int index) const = 0; virtual glm::vec3 getJointTranslation(int index) const = 0; @@ -112,15 +112,9 @@ protected: virtual void parentChanged() {} // called when parent pointer is updated private: + mutable ReadWriteLockable _transformLock; Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. - - // these are so we can return by reference - mutable glm::vec3 _absolutePositionCache; - mutable glm::quat _absoluteRotationCache; - mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; - mutable QVector _jointInObjectFrameCache; - mutable QVector _jointInWorldFrameCache; }; From bbc9d5d1317ad655aa9ff5c3209770537ad9d62a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 13:04:45 -0800 Subject: [PATCH 061/165] add missing single-quote --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 50fb205e3d..9c1c37d2f6 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -670,7 +670,7 @@ elDimensionsY.addEventListener('change', dimensionsChangeFunction); elDimensionsZ.addEventListener('change', dimensionsChangeFunction); - elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID)); + elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID')); var registrationChangeFunction = createEmitVec3PropertyUpdateFunction( 'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ); From 9548b0e138e0b9ec840c3fa4f8268655ff028420 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 13:38:27 -0800 Subject: [PATCH 062/165] get parent-id field working --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 9c1c37d2f6..bef5c825c2 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -225,7 +225,7 @@ var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct"); var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); - var elParentID = document.getElementById("parent-id"); + var elParentID = document.getElementById("property-parent-id"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); From 3f43fde4592b5a964823b2bb048868764772262b Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 30 Nov 2015 04:11:17 -0800 Subject: [PATCH 063/165] AFter 3 days on that piece of shit i just give up, js is just too hard to debug, i m very sad --- examples/acScripts/AgentPoolControler.js | 67 ++- examples/acScripts/playbackAgents.js | 48 +-- examples/acScripts/playbackMaster.js | 514 +++++++++++++---------- 3 files changed, 354 insertions(+), 275 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index d528fc70fe..8965defe9c 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -52,9 +52,9 @@ function printDebug(message) { return JSON.parse(message); }; - var packCommandMessage = function(id, action, argument) { + var packCommandMessage = function(dest, action, argument) { var message = { - id_key: id, + dest_key: dest, action_key: action, argument_key: argument }; @@ -73,6 +73,10 @@ function printDebug(message) { this.onLost = function(actor) {}; }; + Actor.prototype.isConnected = function () { + return (this.agentID != INVALID_ACTOR); + } + this.Actor = Actor; // master side @@ -129,18 +133,19 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); + _clearAgent(agentIndex); } } else if (message.command == AGENT_LOST) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); - if (agentIndex < 0) { - printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; - var lostActor = this.hiredActors[agentIndex]; - this.hiredActors[agentIndex] = null; + if (agentIndex >= 0) { lostActor.agentID = INVALID_ACTOR; lostActor.onLost(lostActor); + _clearAgent(agentIndex); + } else { + return; } } } @@ -186,6 +191,38 @@ function printDebug(message) { }) }; + MasterController.prototype.fireAgent = function(actor) { + // check to see if we know about this agent + printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + var actorIndex = this.knownAgents.indexOf(actor.agentID); + if (actorIndex >= 0) { + printDebug("fired actor found #" + actorIndex); + + var currentAgentID = actor.agentID; + this._clearAgent(actorIndex); + printDebug("fired actor found #" + actorIndex); + + if (currentAgentID != INVALID_ACTOR) { + printDebug("fired actor is still connected, send fire command"); + this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); + } + } + } + + MasterController.prototype._clearAgent = function(actorIndex) { + // check to see if we know about this agent + if (actorIndex >= 0) { + printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; + this.hiredActors.splice(actorIndex, 1); + lostActor.agentID = INVALID_ACTOR; + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + + } + } + this.MasterController = MasterController; // agent side @@ -211,7 +248,7 @@ function printDebug(message) { AgentController.prototype.destroy = function() { if (this.subscribed) { - this.fire(); + this.fired(); Messages.unsubscribe(ANNOUNCE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; @@ -242,7 +279,7 @@ function printDebug(message) { }; AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackCommandMessage(message); + var announce = unpackAnnounceMessage(message); //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); if (announce.dest == this.actorUUID) { if (announce.command != AGENT_READY) { @@ -251,11 +288,11 @@ function printDebug(message) { printDebug(announce.command); var parts = announce.command.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; + var commandPart0 = parts[0]; + var commandPart1 = parts[1]; //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); // if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; + this.actorIndex = commandPart1; printDebug("Client " + this.actorIndex + " Hired!"); this.onHired(); // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel @@ -269,12 +306,12 @@ function printDebug(message) { var command = unpackCommandMessage(message); //printDebug("Received command = " + JSON.stringify(command)); - if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { if (command.action_key == MASTER_ALIVE) { this.notifyAlive = true; } else if (command.action_key == MASTER_FIRE_AGENT) { printDebug("Master firing Agent"); - this.fire(); + this.fired(); } else { printDebug("True action received = " + JSON.stringify(command) + senderID); this.onCommand(command); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index f7630cad48..ec704e35e9 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,7 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +// Agent is an avatar Agent.isAvatar = true; + Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -29,7 +32,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. var ALIVE = -1; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -47,22 +49,11 @@ function getAction(command) { if(true) { // var command = JSON.parse(message); - print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); - - if (command.id_key == id || command.id_key == -1) { - - action = command.action_key; - print("That command was for me! Agent with id: " + id); - } else { - action = DO_NOTHING; - } - - switch(action) { + print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + + switch(command.action_key) { case PLAY: print("Play"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -70,9 +61,6 @@ function getAction(command) { break; case PLAY_LOOP: print("Play loop"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -86,22 +74,15 @@ function getAction(command) { break; case SHOW: print("Show"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } break; case HIDE: - print("Hide"); + print("Hide"); if (Recording.isPlaying()) { Recording.stopPlaying(); } - Agent.isAvatar = false; break; case LOAD: print("Load"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if(command.argument_key !== null) { print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); @@ -109,26 +90,27 @@ function getAction(command) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case DO_NOTHING: - break; default: - print("Unknown action: " + action); + print("Unknown action: " + command.action_key); break; } - - if (Recording.isPlaying()) { - Recording.play(); - } } } function agentHired() { print("Agent Hired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Recording.setPlayerLoop(false); } function agentFired() { print("Agent Fired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3e60fc7a0e..3cf24a6071 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,15 +14,14 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var masterController = new MasterController(); -var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) -var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) var input_text = null; -var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); - +// We want small icons +Tool.IMAGE_HEIGHT /= 2; +Tool.IMAGE_WIDTH /= 2; var DO_NOTHING = 0; var PLAY = 1; @@ -41,245 +40,315 @@ var COLOR_MASTER = { red: 0, green: 0, blue: 0 }; var TEXT_HEIGHT = 12; var TEXT_MARGIN = 3; -var toolBars = new Array(); -var nameOverlays = new Array(); -var onOffIcon = new Array(); -var playIcon = new Array(); -var playLoopIcon = new Array(); -var stopIcon = new Array(); -var loadIcon = new Array(); +// Add new features to Actor class: +Actor.prototype.destroy = function() { + print("Actor.prototype.destroy"); -var performanceJSON = null; -var performanceLoadedNeedUpdate = false; - -setupPlayback(); - -function onActorHired(actor) { - print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) -} - -function onActorLost(actor) { - print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) - - actors[actor.index] = null; -} - -function setupPlayback() { - ac_number = Window.prompt("Insert number of agents: ","1"); - if (ac_number === "" || ac_number === null) { - ac_number = 1; - } - masterController.reset(); - - for (var i = 0; i < ac_number; i++) { - var newActor = new Actor(); - newActor.index = i; - newActor.onHired = onActorHired; - newActor.onLost = onActorLost; - masterController.hireAgent(newActor); - actors.push(newActor); - } - - setupToolBars(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); + print("Need to fire myself" + this.agentID); + masterController.fireAgent(this); } -function setupToolBars() { - if (toolBars.length > 0) { - print("Multiple calls to Recorder.js:setupToolBars()"); - return; - } - Tool.IMAGE_HEIGHT /= 2; - Tool.IMAGE_WIDTH /= 2; - - for (i = 0; i <= ac_number; i++) { - toolBars.push(new ToolBar(0, 0, ToolBar.HORIZONTAL)); - toolBars[i].setBack((i == ac_number) ? COLOR_MASTER : COLOR_TOOL_BAR, ALPHA_OFF); - - onOffIcon.push(toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "ac-on-off.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - x: 0, y: 0, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_ON, - visible: true - }, true, true)); - - playIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - var playLoopWidthFactor = 1.65; - playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - stopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-stop.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - loadIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-upload.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + +Actor.prototype.resetClip = function(clipURL, onLoadClip) { + this.clipURL = clipURL; + this.onLoadClip = onLoadClip; + if (this.isConnected()) { + this.onLoadClip(this); } } -function loadAvatarClipsFromPerformanceJSON(performanceJSON) { - if (performanceJSON.avatarClips) { - var numClips = performanceJSON.avatarClips.length; - print("Performance file contains:" + JSON.stringify(performanceJSON)); - print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); - if (numClips > knownAgents.length) { - numClips = knownAgents.length; - } - - for (i = 0; i < numClips; i++) { - var clipURL = performanceJSON.avatarClips[i]; - print("Loading clip " + clipURL + " to Agent #" + i); - sendCommand(i, LOAD, clipURL); - } +Actor.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, STOP); } else { - print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + return false; } + + return true; } -function sendCommand(id, action, argument) { - if (action === SHOW) { - toolBars[id].selectTool(onOffIcon[id], false); - toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, loadIcon[id]); - } else if (action === HIDE) { - toolBars[id].selectTool(onOffIcon[id], true); - toolBars[id].setAlpha(ALPHA_OFF, playIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (toolBars[id].toolSelected(onOffIcon[id])) { - return; - } +Actor.prototype._buildUI = function() { + print("Actor.prototype._buildUI = " + JSON.stringify(this)); - if (id == (toolBars.length - 1)) { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - if (action == LOAD) { - if (performanceLoadedNeedUpdate == false) { - Assets.downloadData(argument, function (data) { - performanceJSON = JSON.parse(data); - performanceLoadedNeedUpdate = true; - // print("Performance file contains:" + JSON.stringify(performanceJSON)); - }); - return; - } - } else { - id = -1; - - masterController.sendMessage(id, action, argument); - } - } else { - masterController.sendMessage(id, action, argument); - } + this.toolbar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "AC offline", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); } -function mousePressEvent(event) { - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); +Actor.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + this.toolbar.move(pos.x, pos.y); + + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); +} + +Director = function() { + this.actors = new Array(); + this.toolbar = null; + this._buildUI(); +}; + +Director.prototype.destroy = function () { + print("Director.prototype.destroy") + this.clearActors(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + +Director.prototype.clearActors = function () { + print("Director.prototype.clearActors") + for (var i = 0; i < this.actors.length; i++) { + print("Destroy actor #" + i) + this.actors[i].destroy(); + } + this.actors = new Array();// Brand new actors +} + +Director.prototype._buildUI = function () { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - // Check master control - var i = toolBars.length - 1; - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i])) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { + this.toolbar.setBack(COLOR_MASTER, ALPHA_OFF); + + this.onOffIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "ac-on-off.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + x: 0, y: 0, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_ON, + visible: true + }, true, true); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.loadIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-upload.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "Master", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); +} + +Director.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + this.clearActors(); + return true; + } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } + print("Performance file ready to be loaded url = " + input_text); + + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + } } else { // Check individual controls - for (i = 0; i < ac_number; i++) { - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i], false)) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - input_text = Window.prompt("Insert the url of the clip: ",""); - if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } - } else { - + for (var i = 0; i < this.actors.length; i++) { + if (this.actors[i].onMousePressEvent(clickedOverlay)) { + return true; } } + + return false; // nothing clicked from our known overlays } + + return true; +} + +Director.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + var relative = { x: pos.x, y: pos.y + (this.actors.length + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; + + this.toolbar.move(relative.x, windowDimensions.y - relative.y); + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); + + for (var i = 0; i < this.actors.length; i++) { + this.actors[i].moveUI({x: relative.x, y: windowDimensions.y - relative.y + + (i + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)}); + } +} + +Director.prototype.onPerformanceLoaded = function(performanceData) { + var performanceJSON = JSON.parse(performanceData); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); + if (performanceJSON.avatarClips != null) { + var numClips = performanceJSON.avatarClips.length; + print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); + + for (var i = 0; i < numClips; i++) { + if (i < this.actors.length) { + // load correct clip to actor + } else { + this.hireActor(performanceJSON.avatarClips[i]); + } + } + + } +} + + +Director.prototype.hireActor = function(clipURL) { + print("new actor = " + this.actors.length ); + var newActor = new Actor(); + newActor.clipURL = null; + newActor.onLoadClip = function(clip) {}; + + var localThis = this; + newActor.onHired = function(actor) { + print("agent hired from Director! " + actor.agentID) + Overlays.editOverlay(actor.nameOverlay, { + text: "AC " + actor.agentID, + backgroundColor: { red: 0, green: 255, blue: 0 } + }); + + if (actor.clipURL != null) { + print("agent hired, calling load clip for url " + actor.clipURL); + actor.onLoadClip(actor); + } + }; + + newActor.onLost = function(actor) { + print("agent lost from playbackMaster! " + actor.agentID); + var index = localThis.actors.indexOf(actor); + if (index >= 0) { + localThis.actors.splice(index, 1); + } + actor.destroy(); + } + + newActor.resetClip(clipURL, function(actor) { + print("Load clip for agent" + actor.agentID + " calling load clip for url " + actor.clipURL); + masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); + }); + + masterController.hireAgent(newActor); + newActor._buildUI(); + + this.actors.push(newActor); + + moveUI(); +} + + +masterController.reset(); +var director = new Director(); + +moveUI(); + + +function mousePressEvent(event) { + print("mousePressEvent"); + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + + // Check director and actors + director.onMousePressEvent(clickedOverlay); } function moveUI() { - var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; - var relative = { x: 70, y: 75 + (ac_number) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; - - for (i = 0; i <= ac_number; i++) { - toolBars[i].move(relative.x, - windowDimensions.y - relative.y + - i * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)); - - Overlays.editOverlay(nameOverlays[i], { - x: toolBars[i].x - ToolBar.SPACING, - y: toolBars[i].y - textSize - }); - } + director.moveUI({ x: 70, y: 75}); + } function update(deltaTime) { @@ -290,20 +359,12 @@ function update(deltaTime) { moveUI(); } - if (performanceLoadedNeedUpdate) { - loadAvatarClipsFromPerformanceJSON(performanceJSON); - performanceLoadedNeedUpdate = false; - } - masterController.update(deltaTime); } function scriptEnding() { - for (i = 0; i <= ac_number; i++) { - toolBars[i].cleanup(); - Overlays.deleteOverlay(nameOverlays[i]); - } - + print("cleanup") + director.destroy(); masterController.destroy(); } @@ -311,4 +372,3 @@ Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); -moveUI(); From ba379e8830f6fa3995de0370ed4c4d7f3b9f9360 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 30 Nov 2015 08:00:12 -0800 Subject: [PATCH 064/165] Tabs to spaces --- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/Head.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b214ba2976..f3b96c13e6 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -266,7 +266,7 @@ void Head::calculateMouthShapes() { _audioJawOpen *= JAW_CLOSE_RATE; } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); - _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); // Advance time at a rate proportional to loudness, and move the mouth shapes through // a cycle at differing speeds to create a continuous random blend of shapes. diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 93637b7d3c..ec88b295f7 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -124,11 +124,11 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; - float _trailingAudioJawOpen; + float _trailingAudioJawOpen; float _mouth2; float _mouth3; float _mouth4; - float _mouthTime; + float _mouthTime; bool _renderLookatVectors; bool _renderLookatTarget; glm::vec3 _saccade; From 2377875623f5c35e0df12dd0579d6049cf8fab0e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 30 Nov 2015 08:05:25 -0800 Subject: [PATCH 065/165] Tabs to spaces v2 --- interface/src/avatar/Head.cpp | 53 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index f3b96c13e6..b79e502bed 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -43,11 +43,11 @@ Head::Head(Avatar* owningAvatar) : _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _audioJawOpen(0.0f), - _trailingAudioJawOpen(0.0f), + _trailingAudioJawOpen(0.0f), _mouth2(0.0f), _mouth3(0.0f), _mouth4(0.0f), - _mouthTime(0.0f), + _mouthTime(0.0f), _renderLookatVectors(false), _renderLookatTarget(false), _saccade(0.0f, 0.0f, 0.0f), @@ -248,33 +248,32 @@ void Head::calculateMouthShapes() { const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; - const float TIMESTEP_CONSTANT = 0.0032f; - const float MMMM_POWER = 0.10f; - const float SMILE_POWER = 0.10f; - const float FUNNEL_POWER = 0.35f; - const float MMMM_SPEED = 2.685f; - const float SMILE_SPEED = 1.0f; - const float FUNNEL_SPEED = 2.335f; - const float STOP_GAIN = 5.0f; + const float TIMESTEP_CONSTANT = 0.0032f; + const float MMMM_POWER = 0.10f; + const float SMILE_POWER = 0.10f; + const float FUNNEL_POWER = 0.35f; + const float MMMM_SPEED = 2.685f; + const float SMILE_SPEED = 1.0f; + const float FUNNEL_SPEED = 2.335f; + const float STOP_GAIN = 5.0f; - // From the change in loudness, decide how much to open or close the jaw - float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; - if (audioDelta > _audioJawOpen) { - _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } - else { - _audioJawOpen *= JAW_CLOSE_RATE; - } - _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); - _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); - - // Advance time at a rate proportional to loudness, and move the mouth shapes through - // a cycle at differing speeds to create a continuous random blend of shapes. - _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; - _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + // From the change in loudness, decide how much to open or close the jaw + float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; + if (audioDelta > _audioJawOpen) { + _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; + } + else { + _audioJawOpen *= JAW_CLOSE_RATE; + } + _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + // Advance time at a rate proportional to loudness, and move the mouth shapes through + // a cycle at differing speeds to create a continuous random blend of shapes. + _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; + _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); } void Head::applyEyelidOffset(glm::quat headOrientation) { From 4add3e2e91dadb14b786b1851ea2ce0c9927565a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 09:41:15 -0800 Subject: [PATCH 066/165] rework worldToLocal, start on allowing scripts entity position/rotation to always be in world space --- .../entities/src/EntityItemProperties.cpp | 9 +++- libraries/entities/src/EntityItemProperties.h | 4 ++ libraries/entities/src/EntityPropertyFlags.h | 3 ++ .../entities/src/EntityScriptingInterface.cpp | 48 +++++++++++++++++++ libraries/physics/src/EntityMotionState.cpp | 5 +- libraries/shared/src/SpatiallyNestable.cpp | 37 ++++++++++---- libraries/shared/src/SpatiallyNestable.h | 4 +- 7 files changed, 95 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a1ce826072..d08e677c48 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -355,7 +355,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); - + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localrotation); } // Models only @@ -473,6 +474,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -598,6 +602,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); + COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition); + COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation); + _lastEdited = usecTimestampNow(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 981c1503fe..bcb48a1903 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -192,6 +192,10 @@ public: DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); + // these are used when bouncing location data into and out of scripts + DEFINE_PROPERTY_REF_WITH_SETTER(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); + DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); + static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index fd1e448aed..3bca911a56 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -154,6 +154,9 @@ enum EntityPropertyList { PROP_PARENT_ID, PROP_PARENT_JOINT_INDEX, + PROP_LOCAL_POSITION, // only used to convert values to and from scripts + PROP_LOCAL_ROTATION, // only used to convert values to and from scripts + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index bc57f2c72c..8a8150d017 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -64,6 +64,54 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { } } +EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entitySideProperties) { + // In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript, + // they are in world-space. The local versions are put into localPosition and localRotation and position and + // rotation are converted from local to world space. + EntityItemProperties scriptSideProperties = entitySideProperties; + scriptSideProperties.setLocalPosition(entitySideProperties.getPosition()); + scriptSideProperties.setLocalRotation(entitySideProperties.getRotation()); + + glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + scriptSideProperties.setPosition(worldPosition); + scriptSideProperties.setRotation(worldRotation); + + return scriptSideProperties; +} + + +EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scriptSideProperties) { + // convert position and rotation properties from world-space to local, unless localPosition and localRotation + // are set. If they are set, they overwrite position and rotation. + EntityItemProperties entitySideProperties = scriptSideProperties; + + if (scriptSideProperties.localPositionChanged()) { + entitySideProperties.setPosition(scriptSideProperties.getLocalPosition()); + } else if (scriptSideProperties.positionChanged()) { + glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + entitySideProperties.setPosition(localPosition); + } + + if (scriptSideProperties.localRotationChanged()) { + entitySideProperties.setRotation(scriptSideProperties.getLocalRotation()); + } else if (scriptSideProperties.rotationChanged()) { + glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + entitySideProperties.setRotation(localRotation); + } + + return entitySideProperties; +} + + QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { EntityItemProperties propertiesWithSimID = properties; propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9aa89a6a9c..707fa37192 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -455,8 +455,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q EntityItemProperties properties; // explicitly set the properties that changed so that they will be packed - properties.setPosition(_entity->worldToLocal(_serverPosition)); - properties.setRotation(_entity->worldToLocal(_serverRotation)); + properties.setPosition(_entity->getLocalPosition()); + properties.setRotation(_entity->getLocalOrientation()); + properties.setVelocity(_serverVelocity); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index d5e2104706..4469cfd3c3 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -94,24 +94,41 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position) { - Transform parentTransform = getParentTransform(); +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + + Transform positionTransform; + positionTransform.setTranslation(position); Transform myWorldTransform; - _transformLock.withReadLock([&] { - Transform::mult(myWorldTransform, parentTransform, _transform); - }); + Transform::mult(myWorldTransform, parentTransform, positionTransform); + myWorldTransform.setTranslation(position); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation) { - Transform parentTransform = getParentTransform(); +glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + + Transform orientationTransform; + orientationTransform.setRotation(orientation); Transform myWorldTransform; - _transformLock.withReadLock([&] { - Transform::mult(myWorldTransform, parentTransform, _transform); - }); + Transform::mult(myWorldTransform, parentTransform, orientationTransform); myWorldTransform.setRotation(orientation); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 5074779d8e..bbef61b93a 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,8 +47,8 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - glm::vec3 worldToLocal(const glm::vec3 position); - glm::quat worldToLocal(const glm::quat orientation); + static glm::vec3 worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex); static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); From 5019f79947eb5bc13f1fe87f867ed2e469c35073 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 11:48:34 -0800 Subject: [PATCH 067/165] Fix header name --- libraries/octree/src/OctreeElementBag.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index b5f4d5dcf5..c0bfa15472 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -17,7 +17,7 @@ #define hifi_OctreeElementBag_h #include "OctreeElement.h" -#include +#include class OctreeElementBag { public: From 4b87e0984806e7d2cb1eb1d4346defd4ddfe2c16 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 13:23:55 -0800 Subject: [PATCH 068/165] clean up some unneeded consts. get edit.js closer to working on parented entities --- .../entities/src/EntityItemProperties.cpp | 8 ++-- libraries/entities/src/EntityItemProperties.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 16 ++++++-- libraries/shared/src/SpatialParentFinder.h | 2 - libraries/shared/src/SpatiallyNestable.cpp | 38 +++++++++---------- libraries/shared/src/SpatiallyNestable.h | 38 +++++++++---------- 6 files changed, 55 insertions(+), 49 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d08e677c48..2ecb42a9ce 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -356,7 +356,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localrotation); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); } // Models only @@ -1498,12 +1498,10 @@ AABox EntityItemProperties::getAABox() const { glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - glm::quat worldRotation = SpatiallyNestable::localToWorld(getRotation(), _parentID, _parentJointIndex); - Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(worldRotation); + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(_rotation); // shift the extents to be relative to the position/registration point - glm::vec3 worldPosition = SpatiallyNestable::localToWorld(_position, _parentID, _parentJointIndex); - rotatedExtentsRelativeToRegistrationPoint.shiftBy(worldPosition); + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); return AABox(rotatedExtentsRelativeToRegistrationPoint); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index bcb48a1903..6bb6b1914c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -193,7 +193,7 @@ public: DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); // these are used when bouncing location data into and out of scripts - DEFINE_PROPERTY_REF_WITH_SETTER(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); + DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8a8150d017..ca963aca6d 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -113,7 +113,7 @@ EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scr QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { - EntityItemProperties propertiesWithSimID = properties; + EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); EntityItemID id = EntityItemID(QUuid::createUuid()); @@ -159,6 +159,15 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); if (entity) { + if (desiredProperties.getHasProperty(PROP_POSITION) || + desiredProperties.getHasProperty(PROP_ROTATION) || + desiredProperties.getHasProperty(PROP_LOCAL_POSITION) || + desiredProperties.getHasProperty(PROP_LOCAL_ROTATION)) { + // if we are explicitly getting position or rotation, we need parent information to make sense of them. + desiredProperties.setHasProperty(PROP_PARENT_ID); + desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX); + } + results = entity->getProperties(desiredProperties); // TODO: improve sitting points and naturalDimensions in the future, @@ -178,10 +187,11 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit }); } - return results; + return convertLocationToScriptSemantics(results); } -QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) { +QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) { + EntityItemProperties properties = convertLocationFromScriptSemantics(scriptSideProperties); EntityItemID entityID(id); // If we have a local entity tree set, then also update it. if (!_entityTree) { diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h index 9cadbaf8ce..936d497eae 100644 --- a/libraries/shared/src/SpatialParentFinder.h +++ b/libraries/shared/src/SpatialParentFinder.h @@ -19,8 +19,6 @@ class SpatiallyNestable; using SpatiallyNestableWeakPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; -class SpatialParentFinder; -using SpatialParentFinderPointer = std::shared_ptr; class SpatialParentFinder : public Dependency { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4469cfd3c3..31a0dd5647 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -94,7 +94,7 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -115,7 +115,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parent return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -135,7 +135,7 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid par return result.getRotation(); } -glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -151,7 +151,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parent return result.getTranslation(); } -glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -168,7 +168,7 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid par } -const glm::vec3 SpatiallyNestable::getPosition() const { +glm::vec3 SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; parentTransformDescaled.getMatrix(parentMat); @@ -176,7 +176,7 @@ const glm::vec3 SpatiallyNestable::getPosition() const { return glm::vec3(absPos); } -const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { +glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; @@ -184,7 +184,7 @@ const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { return jointInWorldFrame.getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3 position) { +void SpatiallyNestable::setPosition(glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -194,12 +194,12 @@ void SpatiallyNestable::setPosition(const glm::vec3 position) { }); } -const glm::quat SpatiallyNestable::getOrientation() const { +glm::quat SpatiallyNestable::getOrientation() const { Transform parentTransformDescaled = getParentTransform(); return parentTransformDescaled.getRotation() * getLocalOrientation(); } -const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { +glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; @@ -207,7 +207,7 @@ const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { return jointInWorldFrame.getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat orientation) { +void SpatiallyNestable::setOrientation(glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -241,7 +241,7 @@ void SpatiallyNestable::setTransform(const Transform transform) { }); } -const glm::vec3 SpatiallyNestable::getScale() const { +glm::vec3 SpatiallyNestable::getScale() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getScale(); @@ -249,12 +249,12 @@ const glm::vec3 SpatiallyNestable::getScale() const { return result; } -const glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { +glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { // XXX ... something with joints return getScale(); } -void SpatiallyNestable::setScale(const glm::vec3 scale) { +void SpatiallyNestable::setScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); @@ -274,7 +274,7 @@ void SpatiallyNestable::setLocalTransform(const Transform transform) { }); } -const glm::vec3 SpatiallyNestable::getLocalPosition() const { +glm::vec3 SpatiallyNestable::getLocalPosition() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getTranslation(); @@ -282,13 +282,13 @@ const glm::vec3 SpatiallyNestable::getLocalPosition() const { return result; } -void SpatiallyNestable::setLocalPosition(const glm::vec3 position) { +void SpatiallyNestable::setLocalPosition(glm::vec3 position) { _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); } -const glm::quat SpatiallyNestable::getLocalOrientation() const { +glm::quat SpatiallyNestable::getLocalOrientation() const { glm::quat result; _transformLock.withReadLock([&] { result = _transform.getRotation(); @@ -296,13 +296,13 @@ const glm::quat SpatiallyNestable::getLocalOrientation() const { return result; } -void SpatiallyNestable::setLocalOrientation(const glm::quat orientation) { +void SpatiallyNestable::setLocalOrientation(glm::quat orientation) { _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); } -const glm::vec3 SpatiallyNestable::getLocalScale() const { +glm::vec3 SpatiallyNestable::getLocalScale() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getScale(); @@ -310,7 +310,7 @@ const glm::vec3 SpatiallyNestable::getLocalScale() const { return result; } -void SpatiallyNestable::setLocalScale(const glm::vec3 scale) { +void SpatiallyNestable::setLocalScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index bbef61b93a..962399d080 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,11 +47,11 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - static glm::vec3 worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex); - static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex); // world frame virtual const Transform getTransform() const; @@ -59,33 +59,33 @@ public: virtual Transform getParentTransform() const; - virtual const glm::vec3 getPosition() const; - virtual void setPosition(const glm::vec3 position); + virtual glm::vec3 getPosition() const; + virtual void setPosition(glm::vec3 position); - virtual const glm::quat getOrientation() const; - virtual const glm::quat getOrientation(int jointIndex) const; - virtual void setOrientation(const glm::quat orientation); + virtual glm::quat getOrientation() const; + virtual glm::quat getOrientation(int jointIndex) const; + virtual void setOrientation(glm::quat orientation); - virtual const glm::vec3 getScale() const; - virtual void setScale(const glm::vec3 scale); + virtual glm::vec3 getScale() const; + virtual void setScale(glm::vec3 scale); // get world location of a specific joint virtual const Transform getTransform(int jointIndex) const; - virtual const glm::vec3 getPosition(int jointIndex) const; - virtual const glm::vec3 getScale(int jointIndex) const; + virtual glm::vec3 getPosition(int jointIndex) const; + virtual glm::vec3 getScale(int jointIndex) const; // object's parent's frame virtual const Transform getLocalTransform() const; virtual void setLocalTransform(const Transform transform); - virtual const glm::vec3 getLocalPosition() const; - virtual void setLocalPosition(const glm::vec3 position); + virtual glm::vec3 getLocalPosition() const; + virtual void setLocalPosition(glm::vec3 position); - virtual const glm::quat getLocalOrientation() const; - virtual void setLocalOrientation(const glm::quat orientation); + virtual glm::quat getLocalOrientation() const; + virtual void setLocalOrientation(glm::quat orientation); - virtual const glm::vec3 getLocalScale() const; - virtual void setLocalScale(const glm::vec3 scale); + virtual glm::vec3 getLocalScale() const; + virtual void setLocalScale(glm::vec3 scale); QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } From 941dfe5bd2dcb09f4a32878f0743432acc74be01 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 13:30:47 -0800 Subject: [PATCH 069/165] initialize _parentJointIndex --- libraries/shared/src/SpatiallyNestable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 962399d080..8805e72af5 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -99,7 +99,7 @@ protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - quint16 _parentJointIndex; // which joint of the parent is this relative to? + quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; From 89b78986d5b219bec205348840aa6e43f6306645 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:01:17 -0800 Subject: [PATCH 070/165] remove some more stray const --- interface/src/avatar/Avatar.h | 4 ++-- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/entities/src/EntityItem.h | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 51768e4e71..60040fd493 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -161,8 +161,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(const glm::vec3 position); - virtual void setOrientation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setOrientation(glm::quat orientation); public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8db0ef5897..0cdc285021 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(const glm::vec3 position); - virtual void setOrientation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setOrientation(glm::quat orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cd5f97bee2..bccfccc628 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -330,10 +330,10 @@ public: // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setPosition(const glm::vec3 position); - virtual void setLocalPosition(const glm::vec3 position); - virtual void setRotation(const glm::quat orientation); - virtual void setLocalRotation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setLocalPosition(glm::vec3 position); + virtual void setRotation(glm::quat orientation); + virtual void setLocalRotation(glm::quat orientation); // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); From 5c327edd5a8e1825e19a68a7cd5f81b3ca1cd0d4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:08:07 -0800 Subject: [PATCH 071/165] keep AvatarHashMap::findAvatar from creating bogus avatar entries. remove some more stray consts --- cmake/externals/quazip/CMakeLists.txt | 2 +- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- libraries/avatars/src/AvatarHashMap.cpp | 5 ++++- libraries/render-utils/src/AbstractViewStateInterface.h | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index ddac942692..eadbecd2ad 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD) include(ExternalProject) -string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +# string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) ExternalProject_Add( ${EXTERNAL_NAME} URL http://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.6.2.zip diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0220d2b56c..1fff97c916 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3329,7 +3329,7 @@ MyAvatar* Application::getMyAvatar() const { return DependencyManager::get()->getMyAvatar(); } -const glm::vec3 Application::getAvatarPosition() const { +glm::vec3 Application::getAvatarPosition() const { return getMyAvatar()->getPosition(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 0467926b47..e615eeaeaa 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -185,7 +185,7 @@ public: virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual PickRay computePickRay(float x, float y) const; - virtual const glm::vec3 getAvatarPosition() const; + virtual glm::vec3 getAvatarPosition() const; virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } virtual void endOverrideEnvironmentData() { _environment.endOverride(); } virtual qreal getDevicePixelRatio(); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index c195ab4c32..84fff8d114 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -65,7 +65,10 @@ AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) { QReadLocker locker(&_hashLock); - return _avatarHash.value(sessionUUID); + if (_avatarHash.contains(sessionUUID)) { + return _avatarHash.value(sessionUUID); + } + return nullptr; } void AvatarHashMap::processAvatarDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 2954c1fce4..39da33ee8f 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -45,7 +45,7 @@ public: virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; - virtual const glm::vec3 getAvatarPosition() const = 0; + virtual glm::vec3 getAvatarPosition() const = 0; virtual void postLambdaEvent(std::function f) = 0; virtual qreal getDevicePixelRatio() = 0; From aa383455f5967dfdcdf542fcf2fa29f4111f10ad Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:09:19 -0800 Subject: [PATCH 072/165] oops --- cmake/externals/quazip/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index eadbecd2ad..ddac942692 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD) include(ExternalProject) -# string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) ExternalProject_Add( ${EXTERNAL_NAME} URL http://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.6.2.zip From 4aaa9ca02f10f6d51c524e2423a5e59fa1889a62 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 15:23:49 -0800 Subject: [PATCH 073/165] Make OctreeElementBag safer to use --- .../src/octree/OctreeQueryNode.cpp | 6 ++-- .../src/octree/OctreeSendThread.cpp | 4 +-- libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/octree/src/Octree.cpp | 6 ++-- libraries/octree/src/Octree.h | 17 +++++------ libraries/octree/src/OctreeElement.h | 3 +- libraries/octree/src/OctreeElementBag.cpp | 28 +++++++++---------- libraries/octree/src/OctreeElementBag.h | 17 ++++++----- 9 files changed, 37 insertions(+), 48 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 10f1d2ec14..cff2c7ee2e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -336,8 +336,7 @@ void OctreeQueryNode::dumpOutOfView() { int stillInView = 0; int outOfView = 0; OctreeElementBag tempBag; - while (!elementBag.isEmpty()) { - OctreeElementPointer elementToCheck = elementBag.extract(); + while (OctreeElementPointer elementToCheck = elementBag.extract()) { if (elementToCheck->isInView(_currentViewFrustum)) { tempBag.insert(elementToCheck); stillInView++; @@ -346,8 +345,7 @@ void OctreeQueryNode::dumpOutOfView() { } } if (stillInView > 0) { - while (!tempBag.isEmpty()) { - OctreeElementPointer elementToKeepInBag = tempBag.extract(); + while (OctreeElementPointer elementToKeepInBag = tempBag.extract()) { if (elementToKeepInBag->isInView(_currentViewFrustum)) { elementBag.insert(elementToKeepInBag); } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 7c8d8f0e01..84caf9ce81 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -417,7 +417,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 startInside = usecTimestampNow(); bool lastNodeDidntFit = false; // assume each node fits - if (!nodeData->elementBag.isEmpty()) { + if (OctreeElementPointer subTree = nodeData->elementBag.extract()) { quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ @@ -425,8 +425,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); quint64 encodeStart = usecTimestampNow(); - OctreeElementPointer subTree = nodeData->elementBag.extract(); - /* TODO: Looking for a way to prevent locking and encoding a tree that is not // going to result in any packets being sent... // diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8403db8b2f..ff2e97e8fe 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -153,7 +153,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen -void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const { +void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) const { const bool wantDebug = false; if (wantDebug) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 57e0bea696..d8a182156d 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -122,7 +122,7 @@ public: virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const; virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const; virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const; - virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const; + virtual void elementEncodeComplete(EncodeBitstreamParams& params) const; bool alreadyFullyEncoded(EncodeBitstreamParams& params) const; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6f73be360f..c02a034778 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1736,7 +1736,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If our element is completed let the element know so it can do any cleanup it of extra wants if (elementAppendState == OctreeElement::COMPLETED) { - element->elementEncodeComplete(params, &bag); + element->elementEncodeComplete(params); } return bytesAtThisLevel; @@ -2104,9 +2104,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) int bytesWritten = 0; bool lastPacketWritten = false; - while (!elementBag.isEmpty()) { - OctreeElementPointer subTree = elementBag.extract(); - + while (OctreeElementPointer subTree = elementBag.extract()) { EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5ebb991d49..d9cf17d7de 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -18,16 +18,6 @@ #include #include -class CoverageMap; -class ReadBitstreamToTreeParams; -class Octree; -class OctreeElement; -class OctreeElementBag; -class OctreePacketData; -class Shape; -typedef std::shared_ptr OctreePointer; - - #include #include @@ -38,6 +28,13 @@ typedef std::shared_ptr OctreePointer; #include "OctreePacketData.h" #include "OctreeSceneStats.h" +class CoverageMap; +class ReadBitstreamToTreeParams; +class Octree; +class OctreeElement; +class OctreePacketData; +class Shape; +using OctreePointer = std::shared_ptr; extern QVector PERSIST_EXTENSIONS; diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index c686970c3a..3c25ec0850 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -32,7 +32,6 @@ using AtomicUIntStat = std::atomic; class EncodeBitstreamParams; class Octree; class OctreeElement; -class OctreeElementBag; class OctreePacketData; class ReadBitstreamToTreeParams; class Shape; @@ -91,7 +90,7 @@ public: virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { return true; } virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { } - virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const { } + virtual void elementEncodeComplete(EncodeBitstreamParams& params) const { } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. virtual AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index 167c3560d6..4634c05a06 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -13,29 +13,29 @@ #include void OctreeElementBag::deleteAll() { - _bagElements.clear(); + _bagElements = Bag(); +} + +bool OctreeElementBag::isEmpty() { + // Pop all expired front elements + while (!_bagElements.empty() && _bagElements.front().expired()) { + _bagElements.pop(); + } + + return _bagElements.empty(); } void OctreeElementBag::insert(OctreeElementPointer element) { - _bagElements.insert(element.get(), element); + _bagElements.push(element); } OctreeElementPointer OctreeElementBag::extract() { OctreeElementPointer result; // Find the first element still alive - while (!_bagElements.empty() && !result) { - auto it = _bagElements.begin(); - result = it->lock(); - _bagElements.erase(it); + while (!result && !_bagElements.empty()) { + result = _bagElements.front().lock(); // Grab head's shared_ptr + _bagElements.pop(); } return result; } - -bool OctreeElementBag::contains(OctreeElementPointer element) { - return _bagElements.contains(element.get()); -} - -void OctreeElementBag::remove(OctreeElementPointer element) { - _bagElements.remove(element.get()); -} diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index c0bfa15472..02423b640c 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -16,25 +16,24 @@ #ifndef hifi_OctreeElementBag_h #define hifi_OctreeElementBag_h +#include + #include "OctreeElement.h" -#include class OctreeElementBag { + using Bag = std::queue; + public: - void insert(OctreeElementPointer element); // put a element into the bag OctreeElementPointer extract(); // pull a element out of the bag (could come in any order) - bool contains(OctreeElementPointer element); // is this element in the bag? - void remove(OctreeElementPointer element); // remove a specific element from the bag - bool isEmpty() const { return _bagElements.isEmpty(); } - int count() const { return _bagElements.size(); } - + bool isEmpty(); + void deleteAll(); private: - QHash _bagElements; + Bag _bagElements; }; -typedef QMap OctreeElementExtraEncodeData; +using OctreeElementExtraEncodeData = QMap; #endif // hifi_OctreeElementBag_h From 9b54924524783b3731c2a09f562705902f6ad2a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 16:21:14 -0800 Subject: [PATCH 074/165] edit.js can now manipulate children without flipping the table --- .../entities/src/EntityItemProperties.cpp | 4 ++++ libraries/entities/src/EntityItemProperties.h | 2 ++ .../entities/src/EntityScriptingInterface.cpp | 23 ++++++++++++++++++- libraries/shared/src/SpatiallyNestable.cpp | 3 +++ libraries/shared/src/SpatiallyNestable.h | 2 +- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2ecb42a9ce..52f98be208 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1789,3 +1789,7 @@ QList EntityItemProperties::listChangedProperties() { return out; } + +bool EntityItemProperties::parentDependentPropertyChanged() { + return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged(); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6bb6b1914c..11d29c5d57 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -83,6 +83,8 @@ public: { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } EntityPropertyFlags getChangedProperties() const; + bool parentDependentPropertyChanged(); // was there a changed in a property that requires parent info to interpret? + AACube getMaximumAACube() const; AABox getAABox() const; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ca963aca6d..39da57f3a8 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -201,10 +201,31 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script bool updatedEntity = false; _entityTree->withWriteLock([&] { + if (scriptSideProperties.parentDependentPropertyChanged()) { + // if the script sets a location property but didn't include parent information, grab the needed + // properties from the entity. + bool recompute = false; + EntityItemPointer entity = nullptr; + if (!scriptSideProperties.parentIDChanged()) { + entity = _entityTree->findEntityByEntityItemID(entityID); + scriptSideProperties.setParentID(entity->getParentID()); + recompute = true; + } + if (!scriptSideProperties.parentJointIndexChanged()) { + if (!entity) { + entity = _entityTree->findEntityByEntityItemID(entityID); + } + scriptSideProperties.setParentJointIndex(entity->getParentJointIndex()); + recompute = true; + } + if (recompute) { + properties = convertLocationFromScriptSemantics(scriptSideProperties); + } + } + updatedEntity = _entityTree->updateEntity(entityID, properties); }); - if (!updatedEntity) { return QUuid(); } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 31a0dd5647..9b2e809063 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -218,6 +218,7 @@ void SpatiallyNestable::setOrientation(glm::quat orientation) { } const Transform SpatiallyNestable::getTransform() const { + // return a world-space transform for this object's location Transform parentTransform = getParentTransform(); Transform result; _transformLock.withReadLock([&] { @@ -227,6 +228,8 @@ const Transform SpatiallyNestable::getTransform() const { } const Transform SpatiallyNestable::getTransform(int jointIndex) const { + // this returns the world-space transform for this object. It find its parent's transform (which may + // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 8805e72af5..6e0afa24a5 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -69,7 +69,7 @@ public: virtual glm::vec3 getScale() const; virtual void setScale(glm::vec3 scale); - // get world location of a specific joint + // get world-frame values for a specific joint virtual const Transform getTransform(int jointIndex) const; virtual glm::vec3 getPosition(int jointIndex) const; virtual glm::vec3 getScale(int jointIndex) const; From 3402585d1ac2b053c4708025765afe9d40c5eb26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 16:54:29 -0800 Subject: [PATCH 075/165] fix a crash from previous commit --- libraries/avatars/src/AvatarData.cpp | 12 +++++++-- .../entities/src/EntityScriptingInterface.cpp | 26 +++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ec363756f6..a7a3e74663 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -90,8 +90,10 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - SpatiallyNestable::setPosition(position); - SpatiallyNestable::setOrientation(orientation); + Transform trans; + trans.setTranslation(position); + trans.setRotation(orientation); + SpatiallyNestable::setTransform(trans); avatarLock.unlock(); updateAttitude(); } @@ -478,6 +480,12 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // TODO is this safe? will the floats not exactly match? + // Andrew says: + // Yes, there is a possibility that the transmitted will not quite match the extracted despite being originally + // extracted from the exact same quaternion. I followed the code through and it appears the risk is that the + // avatar's SkeletonModel might fall into the CPU expensive part of Model::updateClusterMatrices() when otherwise it + // would not have required it. However, we know we can update many simultaneously animating avatars, and most + // avatars will be moving constantly anyway, so I don't think we need to worry. if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; glm::vec3 eulerAngles(pitch, yaw, roll); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 39da57f3a8..9cb816be1f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -191,7 +191,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit } QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) { - EntityItemProperties properties = convertLocationFromScriptSemantics(scriptSideProperties); + EntityItemProperties properties = scriptSideProperties; EntityItemID entityID(id); // If we have a local entity tree set, then also update it. if (!_entityTree) { @@ -204,25 +204,17 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script if (scriptSideProperties.parentDependentPropertyChanged()) { // if the script sets a location property but didn't include parent information, grab the needed // properties from the entity. - bool recompute = false; - EntityItemPointer entity = nullptr; - if (!scriptSideProperties.parentIDChanged()) { - entity = _entityTree->findEntityByEntityItemID(entityID); - scriptSideProperties.setParentID(entity->getParentID()); - recompute = true; - } - if (!scriptSideProperties.parentJointIndexChanged()) { - if (!entity) { - entity = _entityTree->findEntityByEntityItemID(entityID); + if (!scriptSideProperties.parentIDChanged() || !scriptSideProperties.parentJointIndexChanged()) { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (entity && !scriptSideProperties.parentIDChanged()) { + properties.setParentID(entity->getParentID()); + } + if (entity && !scriptSideProperties.parentJointIndexChanged()) { + properties.setParentJointIndex(entity->getParentJointIndex()); } - scriptSideProperties.setParentJointIndex(entity->getParentJointIndex()); - recompute = true; - } - if (recompute) { - properties = convertLocationFromScriptSemantics(scriptSideProperties); } } - + properties = convertLocationFromScriptSemantics(properties); updatedEntity = _entityTree->updateEntity(entityID, properties); }); From a94b6667b16f73d364c168b6f61a7c809b0ba420 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 27 Nov 2015 14:49:47 -0800 Subject: [PATCH 076/165] Moving most of GLCanvas to gl library --- interface/src/GLCanvas.cpp | 107 ++---------------------------- interface/src/GLCanvas.h | 26 ++------ libraries/gl/src/gl/GLHelpers.cpp | 40 ++++++++--- libraries/gl/src/gl/GLHelpers.h | 7 +- libraries/gl/src/gl/GLWidget.cpp | 107 ++++++++++++++++++++++++++++++ libraries/gl/src/gl/GLWidget.h | 36 ++++++++++ 6 files changed, 187 insertions(+), 136 deletions(-) create mode 100644 libraries/gl/src/gl/GLWidget.cpp create mode 100644 libraries/gl/src/gl/GLWidget.h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index d9cde868a9..0b4c6dde3d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -9,54 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// FIXME ordering of headers #include "Application.h" #include "GLCanvas.h" -#include -#include #include #include "MainWindow.h" #include "Menu.h" -static QGLFormat& getDesiredGLFormat() { - // Specify an OpenGL 3.3 format using the Core profile. - // That is, no old-school fixed pipeline functionality - static QGLFormat glFormat; - static std::once_flag once; - std::call_once(once, [] { - glFormat.setVersion(4, 1); - glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 - glFormat.setSampleBuffers(false); - glFormat.setDepth(false); - glFormat.setStencil(false); - }); - return glFormat; -} - -GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()) { -#ifdef Q_OS_LINUX - // Cause GLCanvas::eventFilter to be called. - // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. - qApp->installEventFilter(this); -#endif -} - -int GLCanvas::getDeviceWidth() const { - return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); -} - -int GLCanvas::getDeviceHeight() const { - return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); -} - -void GLCanvas::initializeGL() { - setAttribute(Qt::WA_AcceptTouchEvents); - setAcceptDrops(true); - // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. - setAutoBufferSwap(false); -} - void GLCanvas::paintGL() { PROFILE_RANGE(__FUNCTION__); @@ -74,68 +35,8 @@ void GLCanvas::resizeGL(int width, int height) { } bool GLCanvas::event(QEvent* event) { - switch (event->type()) { - case QEvent::MouseMove: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::KeyPress: - case QEvent::KeyRelease: - case QEvent::FocusIn: - case QEvent::FocusOut: - case QEvent::Resize: - case QEvent::TouchBegin: - case QEvent::TouchEnd: - case QEvent::TouchUpdate: - case QEvent::Wheel: - case QEvent::DragEnter: - case QEvent::Drop: - if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { - return true; - } - break; - case QEvent::Paint: - // Ignore paint events that occur after we've decided to quit - if (qApp->isAboutToQuit()) { - return true; - } - break; - - default: - break; + if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { + return true; } - return QGLWidget::event(event); -} - - -// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the -// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to -// receive keyPress events for the Alt (and Meta) key in a reliable manner. -// -// This filter catches events before QMenuBar can steal the keyboard focus. -// The idea was borrowed from -// http://www.archivum.info/qt-interest@trolltech.com/2006-09/00053/Re-(Qt4)-Alt-key-focus-QMenuBar-(solved).html - -bool GLCanvas::eventFilter(QObject*, QEvent* event) { - switch (event->type()) { - case QEvent::KeyPress: - case QEvent::KeyRelease: - case QEvent::ShortcutOverride: - { - QKeyEvent* keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta) { - if (event->type() == QEvent::KeyPress) { - keyPressEvent(keyEvent); - } else if (event->type() == QEvent::KeyRelease) { - keyReleaseEvent(keyEvent); - } else { - QGLWidget::event(event); - } - return true; - } - } - default: - break; - } - return false; + return GLWidget::event(event); } diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 73c5b5e8bf..0442159eeb 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -12,31 +12,15 @@ #ifndef hifi_GLCanvas_h #define hifi_GLCanvas_h -#include -#include -#include +#include /// customized canvas that simply forwards requests/events to the singleton application -class GLCanvas : public QGLWidget { +class GLCanvas : public GLWidget { Q_OBJECT - -public: - GLCanvas(); - - int getDeviceWidth() const; - int getDeviceHeight() const; - QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } - protected: - - virtual void initializeGL(); - virtual void paintGL(); - virtual void resizeGL(int width, int height); - virtual bool event(QEvent* event); - -private slots: - bool eventFilter(QObject*, QEvent* event); - + virtual void paintGL() override; + virtual void resizeGL(int width, int height) override; + virtual bool event(QEvent* event) override; }; diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index f67f9e9120..9022f0ffcc 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -1,15 +1,37 @@ #include "GLHelpers.h" +#include -QSurfaceFormat getDefaultOpenGlSurfaceFormat() { - QSurfaceFormat format; - // Qt Quick may need a depth and stencil buffer. Always make sure these are available. - format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); - format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); - format.setVersion(4, 1); +#include +#include + +const QSurfaceFormat& getDefaultOpenGlSurfaceFormat() { + static QSurfaceFormat format; + static std::once_flag once; + std::call_once(once, [] { + // Qt Quick may need a depth and stencil buffer. Always make sure these are available. + format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); + format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); + format.setVersion(4, 1); #ifdef DEBUG - format.setOption(QSurfaceFormat::DebugContext); + format.setOption(QSurfaceFormat::DebugContext); #endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - return format; + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + }); + return format; +} + +const QGLFormat& getDefaultGLFormat() { + // Specify an OpenGL 3.3 format using the Core profile. + // That is, no old-school fixed pipeline functionality + static QGLFormat glFormat; + static std::once_flag once; + std::call_once(once, [] { + glFormat.setVersion(4, 1); + glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 + glFormat.setSampleBuffers(false); + glFormat.setDepth(false); + glFormat.setStencil(false); + }); + return glFormat; } diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index dc9f0f3140..de9e8f5d85 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -10,14 +10,15 @@ #ifndef hifi_GLHelpers_h #define hifi_GLHelpers_h -#include - // 16 bits of depth precision #define DEFAULT_GL_DEPTH_BUFFER_BITS 16 // 8 bits of stencil buffer (typically you really only need 1 bit for functionality // but GL implementations usually just come with buffer sizes in multiples of 8) #define DEFAULT_GL_STENCIL_BUFFER_BITS 8 -QSurfaceFormat getDefaultOpenGlSurfaceFormat(); +class QSurfaceFormat; +class QGLFormat; +const QSurfaceFormat& getDefaultOpenGlSurfaceFormat(); +const QGLFormat& getDefaultGLFormat(); #endif diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp new file mode 100644 index 0000000000..b274b39da7 --- /dev/null +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -0,0 +1,107 @@ +// +// GLWidget.cpp +// interface/src +// +// Created by Stephen Birarda on 8/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLWidget.h" + +#include + +#include +#include +#include + +#include +#include + +#include "GLHelpers.h" + +GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) { +#ifdef Q_OS_LINUX + // Cause GLWidget::eventFilter to be called. + // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. + qApp->installEventFilter(this); +#endif +} + +int GLWidget::getDeviceWidth() const { + return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); +} + +int GLWidget::getDeviceHeight() const { + return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); +} + +void GLWidget::initializeGL() { + setAttribute(Qt::WA_AcceptTouchEvents); + setAcceptDrops(true); + // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. + setAutoBufferSwap(false); +} + +bool GLWidget::event(QEvent* event) { + switch (event->type()) { + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Resize: + case QEvent::TouchBegin: + case QEvent::TouchEnd: + case QEvent::TouchUpdate: + case QEvent::Wheel: + case QEvent::DragEnter: + case QEvent::Drop: + if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { + return true; + } + break; + + default: + break; + } + return QGLWidget::event(event); +} + + +// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the +// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to +// receive keyPress events for the Alt (and Meta) key in a reliable manner. +// +// This filter catches events before QMenuBar can steal the keyboard focus. +// The idea was borrowed from +// http://www.archivum.info/qt-interest@trolltech.com/2006-09/00053/Re-(Qt4)-Alt-key-focus-QMenuBar-(solved).html + +bool GLWidget::eventFilter(QObject*, QEvent* event) { + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::ShortcutOverride: + { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta) { + if (event->type() == QEvent::KeyPress) { + keyPressEvent(keyEvent); + } else if (event->type() == QEvent::KeyRelease) { + keyReleaseEvent(keyEvent); + } else { + QGLWidget::event(event); + } + return true; + } + } + default: + break; + } + return false; +} diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h new file mode 100644 index 0000000000..040ce542e9 --- /dev/null +++ b/libraries/gl/src/gl/GLWidget.h @@ -0,0 +1,36 @@ +// +// GLWidget.h +// interface/src +// +// Created by Stephen Birarda on 8/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GLWidget_h +#define hifi_GLWidget_h + +#include + +/// customized canvas that simply forwards requests/events to the singleton application +class GLWidget : public QGLWidget { + Q_OBJECT + +public: + GLWidget(); + int getDeviceWidth() const; + int getDeviceHeight() const; + QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } + +protected: + virtual void initializeGL() override; + virtual bool event(QEvent* event) override; + +private slots: + virtual bool eventFilter(QObject*, QEvent* event) override; +}; + + +#endif // hifi_GLCanvas_h From 0023c034c41a57e14bbe7322fd58bd471a367c7e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 29 Nov 2015 00:42:46 -0800 Subject: [PATCH 077/165] Fixing naming of GL classes --- interface/src/Application.cpp | 4 +-- interface/src/Application.h | 4 +-- .../display-plugins/OpenGLDisplayPlugin.cpp | 1 - .../openvr/OpenVrDisplayPlugin.cpp | 1 - .../stereo/InterleavedStereoDisplayPlugin.cpp | 11 +------- .../stereo/SideBySideStereoDisplayPlugin.cpp | 12 +------- libraries/gl/src/gl/GLEscrow.h | 8 +++++- libraries/gl/src/gl/GLWidget.cpp | 8 ++++++ libraries/gl/src/gl/GLWidget.h | 2 ++ .../gl/src/gl/{GlWindow.cpp => GLWindow.cpp} | 28 ++++++++++++------- .../gl/src/gl/{GlWindow.h => GLWindow.h} | 13 +++++---- ...reenGlCanvas.cpp => OffscreenGLCanvas.cpp} | 14 +++++----- ...ffscreenGlCanvas.h => OffscreenGLCanvas.h} | 14 +++++----- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 6 ++-- .../src/OculusLegacyDisplayPlugin.cpp | 1 - 15 files changed, 65 insertions(+), 62 deletions(-) rename libraries/gl/src/gl/{GlWindow.cpp => GLWindow.cpp} (69%) rename libraries/gl/src/gl/{GlWindow.h => GLWindow.h} (63%) rename libraries/gl/src/gl/{OffscreenGlCanvas.cpp => OffscreenGLCanvas.cpp} (86%) rename libraries/gl/src/gl/{OffscreenGlCanvas.h => OffscreenGLCanvas.h} (77%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ac14ac0ec..708f8ee5ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -78,7 +78,7 @@ #include #include #include -#include +#include #include #include #include @@ -616,7 +616,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); - _offscreenContext = new OffscreenGlCanvas(); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->makeCurrent(); initializeGL(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 730158c689..6e8df65032 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -65,7 +65,7 @@ #include "ui/ToolWindow.h" #include "UndoStackScriptingInterface.h" -class OffscreenGlCanvas; +class OffscreenGLCanvas; class GLCanvas; class FaceTracker; class MainWindow; @@ -421,7 +421,7 @@ private: bool _dependencyManagerIsSetup; - OffscreenGlCanvas* _offscreenContext { nullptr }; + OffscreenGLCanvas* _offscreenContext { nullptr }; DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 3ef882fe76..01cb0961e4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -10,7 +10,6 @@ #include #include -#include #include diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index bb39c7bb7a..4278165e25 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 6e14a158d4..72921b4f90 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -8,15 +8,6 @@ #include "InterleavedStereoDisplayPlugin.h" -#include -#include - -#include -#include -#include - -#include - static const char * INTERLEAVED_TEXTURED_VS = R"VS(#version 410 core #pragma line __LINE__ @@ -81,4 +72,4 @@ void InterleavedStereoDisplayPlugin::display( _program->Bind(); Uniform(*_program, "textureSize").SetValue(sceneSize); WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); -} \ No newline at end of file +} diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp index 5ba113420d..12865cf4cd 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp @@ -7,17 +7,7 @@ // #include "SideBySideStereoDisplayPlugin.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include +#include const QString SideBySideStereoDisplayPlugin::NAME("3D TV - Side by Side Stereo"); diff --git a/libraries/gl/src/gl/GLEscrow.h b/libraries/gl/src/gl/GLEscrow.h index 54b124ae3c..db9f033de8 100644 --- a/libraries/gl/src/gl/GLEscrow.h +++ b/libraries/gl/src/gl/GLEscrow.h @@ -87,6 +87,11 @@ public: _recycler = recycler; } + size_t depth() { + Lock lock(_mutex); + return _submits.size(); + } + // Submit a new resource from the producer context // returns the number of prior submissions that were // never consumed before becoming available. @@ -124,7 +129,7 @@ public: } return result; } - + // If fetch returns a non-zero value, it's the responsibility of the // client to release it at some point void release(T t, GLsync readSync = 0) { @@ -175,6 +180,7 @@ private: // May be called on any thread, but must be inside a locked section void pop(Deque& deque) { + Lock lock(_mutex); auto& item = deque.front(); _trash.push_front(item); deque.pop_front(); diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index b274b39da7..ec08d70e7a 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -45,6 +45,14 @@ void GLWidget::initializeGL() { setAutoBufferSwap(false); } +void GLWidget::paintEvent(QPaintEvent* event) { + QWidget::paintEvent(event); +} + +void GLWidget::resizeEvent(QResizeEvent* event) { + QWidget::resizeEvent(event); +} + bool GLWidget::event(QEvent* event) { switch (event->type()) { case QEvent::MouseMove: diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index 040ce542e9..5c4f4305cc 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -27,6 +27,8 @@ public: protected: virtual void initializeGL() override; virtual bool event(QEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; private slots: virtual bool eventFilter(QObject*, QEvent* event) override; diff --git a/libraries/gl/src/gl/GlWindow.cpp b/libraries/gl/src/gl/GLWindow.cpp similarity index 69% rename from libraries/gl/src/gl/GlWindow.cpp rename to libraries/gl/src/gl/GLWindow.cpp index 40a5bedf7e..42914fed59 100644 --- a/libraries/gl/src/gl/GlWindow.cpp +++ b/libraries/gl/src/gl/GLWindow.cpp @@ -6,17 +6,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GlWindow.h" +#include "GLWindow.h" #include #include #include "GLHelpers.h" -GlWindow::GlWindow(QOpenGLContext* shareContext) : GlWindow(getDefaultOpenGlSurfaceFormat(), shareContext) { +void GLWindow::createContext(QOpenGLContext* shareContext) { + createContext(getDefaultOpenGlSurfaceFormat(), shareContext); } -GlWindow::GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext) { +void GLWindow::createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext) { setSurfaceType(QSurface::OpenGLSurface); setFormat(format); _context = new QOpenGLContext; @@ -27,13 +28,15 @@ GlWindow::GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext) { _context->create(); } -GlWindow::~GlWindow() { - _context->doneCurrent(); - _context->deleteLater(); - _context = nullptr; +GLWindow::~GLWindow() { + if (_context) { + _context->doneCurrent(); + _context->deleteLater(); + _context = nullptr; + } } -bool GlWindow::makeCurrent() { +bool GLWindow::makeCurrent() { bool makeCurrentResult = _context->makeCurrent(this); Q_ASSERT(makeCurrentResult); @@ -49,11 +52,16 @@ bool GlWindow::makeCurrent() { return makeCurrentResult; } -void GlWindow::doneCurrent() { +void GLWindow::doneCurrent() { _context->doneCurrent(); } -void GlWindow::swapBuffers() { +void GLWindow::swapBuffers() { _context->swapBuffers(this); } +QOpenGLContext* GLWindow::context() const { + return _context; +} + + diff --git a/libraries/gl/src/gl/GlWindow.h b/libraries/gl/src/gl/GLWindow.h similarity index 63% rename from libraries/gl/src/gl/GlWindow.h rename to libraries/gl/src/gl/GLWindow.h index 4956177725..bccfcd7320 100644 --- a/libraries/gl/src/gl/GlWindow.h +++ b/libraries/gl/src/gl/GLWindow.h @@ -7,8 +7,8 @@ // #pragma once -#ifndef hifi_GlWindow_h -#define hifi_GlWindow_h +#ifndef hifi_GLWindow_h +#define hifi_GLWindow_h #include #include @@ -16,14 +16,15 @@ class QOpenGLContext; class QOpenGLDebugLogger; -class GlWindow : public QWindow { +class GLWindow : public QWindow { public: - GlWindow(QOpenGLContext* shareContext = nullptr); - GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext = nullptr); - virtual ~GlWindow(); + virtual ~GLWindow(); + void createContext(QOpenGLContext* shareContext = nullptr); + void createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext = nullptr); bool makeCurrent(); void doneCurrent(); void swapBuffers(); + QOpenGLContext* context() const; private: std::once_flag _reportOnce; QOpenGLContext* _context{ nullptr }; diff --git a/libraries/gl/src/gl/OffscreenGlCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp similarity index 86% rename from libraries/gl/src/gl/OffscreenGlCanvas.cpp rename to libraries/gl/src/gl/OffscreenGLCanvas.cpp index e5c1ee4c4a..b8c9b9e117 100644 --- a/libraries/gl/src/gl/OffscreenGlCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -1,5 +1,5 @@ // -// OffscreenGlCanvas.cpp +// OffscreenGLCanvas.cpp // interface/src/renderer // // Created by Bradley Austin Davis on 2014/04/09. @@ -10,7 +10,7 @@ // -#include "OffscreenGlCanvas.h" +#include "OffscreenGLCanvas.h" #include #include @@ -18,10 +18,10 @@ #include "GLHelpers.h" -OffscreenGlCanvas::OffscreenGlCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ +OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ } -OffscreenGlCanvas::~OffscreenGlCanvas() { +OffscreenGLCanvas::~OffscreenGLCanvas() { #ifdef DEBUG if (_logger) { makeCurrent(); @@ -32,7 +32,7 @@ OffscreenGlCanvas::~OffscreenGlCanvas() { _context->doneCurrent(); } -void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { +void OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { if (nullptr != sharedContext) { sharedContext->doneCurrent(); _context->setShareContext(sharedContext); @@ -45,7 +45,7 @@ void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { } -bool OffscreenGlCanvas::makeCurrent() { +bool OffscreenGLCanvas::makeCurrent() { bool result = _context->makeCurrent(_offscreenSurface); Q_ASSERT(result); @@ -72,7 +72,7 @@ bool OffscreenGlCanvas::makeCurrent() { return result; } -void OffscreenGlCanvas::doneCurrent() { +void OffscreenGLCanvas::doneCurrent() { _context->doneCurrent(); } diff --git a/libraries/gl/src/gl/OffscreenGlCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h similarity index 77% rename from libraries/gl/src/gl/OffscreenGlCanvas.h rename to libraries/gl/src/gl/OffscreenGLCanvas.h index 94014adf98..e278f550f0 100644 --- a/libraries/gl/src/gl/OffscreenGlCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -1,5 +1,5 @@ // -// OffscreenGlCanvas.h +// OffscreenGLCanvas.h // interface/src/renderer // // Created by Bradley Austin Davis on 2014/04/09. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #pragma once -#ifndef hifi_OffscreenGlCanvas_h -#define hifi_OffscreenGlCanvas_h +#ifndef hifi_OffscreenGLCanvas_h +#define hifi_OffscreenGLCanvas_h #include #include @@ -19,10 +19,10 @@ class QOpenGLContext; class QOffscreenSurface; class QOpenGLDebugLogger; -class OffscreenGlCanvas : public QObject { +class OffscreenGLCanvas : public QObject { public: - OffscreenGlCanvas(); - ~OffscreenGlCanvas(); + OffscreenGLCanvas(); + ~OffscreenGLCanvas(); void create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); @@ -40,4 +40,4 @@ protected: }; -#endif // hifi_OffscreenGlCanvas_h +#endif // hifi_OffscreenGLCanvas_h diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index e8a950a16b..f2eb112dc7 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -23,7 +23,7 @@ #include #include "GLEscrow.h" -#include "OffscreenGlCanvas.h" +#include "OffscreenGLCanvas.h" // FIXME move to threaded rendering with Qt 5.5 //#define QML_THREADED @@ -64,12 +64,12 @@ static const QEvent::Type STOP = QEvent::Type(QEvent::User + 4); static const QEvent::Type UPDATE = QEvent::Type(QEvent::User + 5); #endif -class OffscreenQmlRenderer : public OffscreenGlCanvas { +class OffscreenQmlRenderer : public OffscreenGLCanvas { friend class OffscreenQmlSurface; public: OffscreenQmlRenderer(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) { - OffscreenGlCanvas::create(shareContext); + OffscreenGLCanvas::create(shareContext); #ifdef QML_THREADED // Qt 5.5 _renderControl->prepareThread(_renderThread); diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index ddf251778f..f0398158b4 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From 1b197987ecd9a0a1241455243cc3a66e650fb14e Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 30 Nov 2015 18:34:40 -0800 Subject: [PATCH 078/165] MOnday spent on improving the Agent/Clint coordination, but still bugs --- examples/acScripts/AgentPoolControler.js | 285 +++++++++++++---------- examples/acScripts/playbackAgents.js | 25 +- examples/acScripts/playbackMaster.js | 61 +++-- 3 files changed, 217 insertions(+), 154 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 8965defe9c..c7ecd70ad1 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -14,8 +14,8 @@ function printDebug(message) { } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var SERVICE_CHANNEL = "com.highfidelity.playback.service"; + var COMMAND_CHANNEL = "com.highfidelity.playback.command"; // The time between alive messages on the command channel var ALIVE_PERIOD = 3; @@ -23,15 +23,15 @@ function printDebug(message) { // Service Actions var MASTER_ID = -1; - var AGENT_READY = "ready"; - var AGENT_LOST = "agentLost"; + var INVALID_AGENT = -2; - var INVALID_ACTOR = -2; + var BROADCAST_AGENTS = -3; - - var AGENTS_BROADCAST = -1; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; + var MASTER_ALIVE = "MASTER_ALIVE"; + var AGENT_ALIVE = "AGENT_ALIVE"; + var AGENT_READY = "READY"; + var MASTER_HIRE_AGENT = "HIRE" + var MASTER_FIRE_AGENT = "FIRE"; var makeUniqueUUID = function(SEUUID) { //return SEUUID + Math.random(); @@ -39,7 +39,7 @@ function printDebug(message) { return (Math.random() * 10000).toFixed(0); } - var packAnnounceMessage = function(dest, command, src) { + var packServiceMessage = function(dest, command, src) { var message = { dest: dest, command: command, @@ -48,7 +48,7 @@ function printDebug(message) { return JSON.stringify(message); }; - var unpackAnnounceMessage = function(message) { + var unpackServiceMessage = function(message) { return JSON.parse(message); }; @@ -68,13 +68,27 @@ function printDebug(message) { // Actor //--------------------------------- var Actor = function() { - this.agentID = INVALID_ACTOR; + this.agentID = INVALID_AGENT; + this.lastAliveCycle = 0; this.onHired = function(actor) {}; - this.onLost = function(actor) {}; + this.onFired = function(actor) {}; }; Actor.prototype.isConnected = function () { - return (this.agentID != INVALID_ACTOR); + return (this.agentID != INVALID_AGENT); + } + + Actor.prototype.alive = function () { + printDebug("Agent UUID =" + this.agentID + " Alive was " + this.lastAliveCycle); + this.lastAliveCycle = 0; + } + Actor.prototype.incrementAliveCycle = function () { + printDebug("Actor.prototype.incrementAliveCycle UUID =" + this.agentID + " Alive pre increment " + this.lastAliveCycle); + if (this.isConnected()) { + this.lastAliveCycle++; + printDebug("Agent UUID =" + this.agentID + " Alive incremented " + this.lastAliveCycle); + } + return this.lastAliveCycle; } this.Actor = Actor; @@ -91,7 +105,7 @@ function printDebug(message) { MasterController.prototype.destroy = function() { if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -102,11 +116,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } }); @@ -116,45 +130,59 @@ function printDebug(message) { printDebug("Master Started"); }; - MasterController.prototype._processAnnounceMessage = function(message, senderID) { - var message = unpackAnnounceMessage(message); + MasterController.prototype._processServiceMessage = function(message, senderID) { + var message = unpackServiceMessage(message); if (message.dest == MASTER_ID) { if (message.command == AGENT_READY) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex < 0) { - if (this.hiringAgentsQueue.length > 0) { - var hiringHandler = this.hiringAgentsQueue.pop(); - hiringHandler(message.src); - } else { - //No hiring in queue so bail - return; - } + this._onAgentAvailableForHiring(message.src); } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + this._removeAgent(agentIndex); } - } else if (message.command == AGENT_LOST) { + } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex >= 0) { - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + // yes so reset its alive beat + this.hiredActors[agentIndex].alive(); + return; } else { return; } } } }; - - MasterController.prototype.sendCommand = function(target, action, argument) { + + MasterController.prototype._onAgentAvailableForHiring = function(agentID) { + if (this.hiringAgentsQueue.length == 0) { + printDebug("No Actor on the hiring queue"); + return; + } + + printDebug("MasterController.prototype._onAgentAvailableForHiring " + agentID); + var newActor = this.hiringAgentsQueue.pop(); + + var indexOfNewAgent = this.knownAgents.push(agentID); + newActor.alive(); + newActor.agentID = agentID; + this.hiredActors.push(newActor); + + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("message sent calling the actor" + JSON.stringify(newActor) ); + + newActor.onHired(newActor); + } + + MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = packCommandMessage(target, action, argument); - Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + var command = packCommandMessage(target, action, argument); + printDebug(command); + Messages.sendMessage(COMMAND_CHANNEL, command); } }; @@ -162,7 +190,31 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { this.timeSinceLastAlive = 0; - this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); + + printDebug("checking the agents status"); + { + // Check for alive connected agents + var lostAgents = new Array(); + for (var i = 0; i < this.hiredActors.length; i++) { + var actor = this.hiredActors[i]; + printDebug("checking :" + JSON.stringify(actor)); + var lastAlive = actor.incrementAliveCycle() + if (lastAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Agent Lost, firing Agent"); + lostAgents.push(actor); + } + } + + // now fire gathered lost agents + if (lostAgents.length > 0) { + printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); + + for (var i = 0; i < lostAgents.length; i++) { + this.fireAgent(lostAgents[l]); + } + } + } } }; @@ -172,54 +224,51 @@ function printDebug(message) { printDebug("trying to hire an agent with a null actor, abort"); return; } - var localThis = this; - this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); - - var indexOfNewAgent = localThis.knownAgents.push(agentID) - actor.agentID = agentID; - localThis.hiredActors.push(actor); - - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - var hireMessage = "HIRE." + indexOfNewAgent; - var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); - Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - - printDebug("message sent calling the actor" + JSON.stringify(actor) ); - - actor.onHired(actor); - }) + if (actor.isConnected()) { + printDebug("trying to hire an agent already connected, abort"); + return; + } + this.hiringAgentsQueue.unshift(actor); }; MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + + var waitingIndex = this.hiringAgentsQueue.indexOf(actor); + if (waitingIndex >= 0) { + printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); + this.hiringAgentsQueue.splice(waitingIndex, 1); + } + var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - - var currentAgentID = actor.agentID; - this._clearAgent(actorIndex); - printDebug("fired actor found #" + actorIndex); - - if (currentAgentID != INVALID_ACTOR) { - printDebug("fired actor is still connected, send fire command"); - this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); - } + this._removeAgent(actorIndex); } } - MasterController.prototype._clearAgent = function(actorIndex) { + MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; this.hiredActors.splice(actorIndex, 1); - lostActor.agentID = INVALID_ACTOR; - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + var lostAgentID = lostActor.agentID; + lostActor.agentID = INVALID_AGENT; + + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + + if (lostAgentID != INVALID_AGENT) { + printDebug("fired actor is still connected, send fire command"); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(lostAgentID, MASTER_FIRE_AGENT, MASTER_ID)); + } + + lostActor.onFired(lostActor); } } @@ -238,18 +287,17 @@ function printDebug(message) { }; AgentController.prototype._init = function() { - this.actorIndex= INVALID_ACTOR; - this.notifyAlive = false; + this.isHired= false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; - this.actorUUID = makeUniqueUUID(Agent.sessionUUID); - printDebug("this.actorUUID = " + this.actorUUID); + this.agentUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.agentUUID = " + this.agentUUID); } AgentController.prototype.destroy = function() { if (this.subscribed) { this.fired(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -261,11 +309,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } if (channel == COMMAND_CHANNEL) { @@ -278,44 +326,39 @@ function printDebug(message) { printDebug("Client Started"); }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackAnnounceMessage(message); - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (announce.dest == this.actorUUID) { + AgentController.prototype._processServiceMessage = function(message, senderID) { + var announce = unpackServiceMessage(message); + //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); + if (announce.dest == this.agentUUID) { if (announce.command != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { + var parts = announce.command.split("."); + + // this is potnetially a message to hire me if i m not already + if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { printDebug(announce.command); + this.isHired = true; + printDebug("Client Hired by master UUID" + senderID); + this.onHired(); + return; + } - var parts = announce.command.split("."); - var commandPart0 = parts[0]; - var commandPart1 = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - // if (agentID == Agent.sessionUUID) { - this.actorIndex = commandPart1; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - // } + if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + printDebug("Client Fired by master UUID" + senderID); + this.fired(); + return; } } + } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + this.numCyclesWithoutAlive = 0; + return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { var command = unpackCommandMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); - - if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fired(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); } else { // ignored } @@ -326,17 +369,18 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + if (!this.isHired) { + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); + //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); } else { + + // Send alive beat + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); + + // Listen for master beat this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); + if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, self firing Agent"); this.fired(); } } @@ -348,12 +392,7 @@ function printDebug(message) { AgentController.prototype.fired = function() { // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - - // Post a last message to master in case it still listen to warn that this agent is losing it - if (wasHired) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); - } + var wasHired = this.isHired; // reset this._init(); @@ -366,6 +405,10 @@ function printDebug(message) { this.AgentController = AgentController; + + + + this.BROADCAST_AGENTS = BROADCAST_AGENTS; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index ec704e35e9..67fe8c733e 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -31,7 +31,6 @@ var totalTime = 0; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. -var ALIVE = -1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -45,11 +44,11 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(command) { +function agentCommand(command) { if(true) { // var command = JSON.parse(message); - print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + print("I'm the agent " + this.agentUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); switch(command.action_key) { case PLAY: @@ -82,13 +81,19 @@ function getAction(command) { } break; case LOAD: - print("Load"); - if(command.argument_key !== null) { + { + print("Load" + command.argument_key); + print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); + print("After Load" + command.argument_key); + + /*if(command.argument_key == null) { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); + } else *{ print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); - } else { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } + }*/ + } break; default: print("Unknown action: " + command.action_key); @@ -102,7 +107,7 @@ function agentHired() { print("Agent Hired from playbackAgents.js"); if (Recording.isPlaying()) { Recording.stopPlaying(); - } + } Recording.setPlayerLoop(false); } @@ -119,7 +124,7 @@ function update(deltaTime) { if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); - agentController.onCommand = getAction; + agentController.onCommand = agentCommand; agentController.onHired = agentHired; agentController.onFired = agentFired; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3cf24a6071..7486256f07 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -23,7 +23,6 @@ Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -149,10 +148,10 @@ Director.prototype.destroy = function () { Director.prototype.clearActors = function () { print("Director.prototype.clearActors") - for (var i = 0; i < this.actors.length; i++) { - print("Destroy actor #" + i) - this.actors[i].destroy(); + while (this.actors.length > 0) { + this.actors.pop().destroy(); } + this.actors = new Array();// Brand new actors } @@ -222,23 +221,40 @@ Director.prototype._buildUI = function () { } Director.prototype.onMousePressEvent = function(clickedOverlay) { - if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + print("master play"); + masterController.sendCommand(BROADCAST_AGENTS, PLAY); + } else if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { this.clearActors(); return true; - } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY); } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + masterController.sendCommand(BROADCAST_AGENTS, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, STOP); - } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(BROADCAST_AGENTS, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + var urlpartition = input_text.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } } } else { // Check individual controls @@ -270,19 +286,17 @@ Director.prototype.moveUI = function(pos) { } } -Director.prototype.onPerformanceLoaded = function(performanceData) { - var performanceJSON = JSON.parse(performanceData); +Director.prototype.onPerformanceLoaded = function(performanceJSON) { + // First fire all the current actors + this.clearActors(); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); if (performanceJSON.avatarClips != null) { var numClips = performanceJSON.avatarClips.length; print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); for (var i = 0; i < numClips; i++) { - if (i < this.actors.length) { - // load correct clip to actor - } else { - this.hireActor(performanceJSON.avatarClips[i]); - } + this.hireActor(performanceJSON.avatarClips[i]); } } @@ -309,13 +323,14 @@ Director.prototype.hireActor = function(clipURL) { } }; - newActor.onLost = function(actor) { - print("agent lost from playbackMaster! " + actor.agentID); + newActor.onFired = function(actor) { + print("agent fired from playbackMaster! " + actor.agentID); var index = localThis.actors.indexOf(actor); if (index >= 0) { localThis.actors.splice(index, 1); } actor.destroy(); + moveUI(); } newActor.resetClip(clipURL, function(actor) { From 921cd94c0794caace610ff3d0dcbbbf0723b19fb Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Tue, 1 Dec 2015 00:15:12 -0800 Subject: [PATCH 079/165] Finally a more stable api and playback use case --- examples/acScripts/AgentPoolControler.js | 20 ++++---------- examples/acScripts/playbackAgents.js | 35 ++++++------------------ examples/acScripts/playbackMaster.js | 15 ++++++---- 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index c7ecd70ad1..74ee12922a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -192,27 +192,22 @@ function printDebug(message) { this.timeSinceLastAlive = 0; Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); - printDebug("checking the agents status"); { // Check for alive connected agents var lostAgents = new Array(); for (var i = 0; i < this.hiredActors.length; i++) { var actor = this.hiredActors[i]; - printDebug("checking :" + JSON.stringify(actor)); var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent"); - lostAgents.push(actor); + printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + lostAgents.push(i); } } - // now fire gathered lost agents - if (lostAgents.length > 0) { + // now fire gathered lost agents from end to begin + while (lostAgents.length > 0) { printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); - - for (var i = 0; i < lostAgents.length; i++) { - this.fireAgent(lostAgents[l]); - } + this.fireAgent(this.hiredActors[lostAgents.pop()]); } } } @@ -251,7 +246,7 @@ function printDebug(message) { MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; @@ -259,9 +254,6 @@ function printDebug(message) { var lostAgentID = lostActor.agentID; lostActor.agentID = INVALID_AGENT; - - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) if (lostAgentID != INVALID_AGENT) { printDebug("fired actor is still connected, send fire command"); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 67fe8c733e..64c25ec0a8 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,9 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Agent is an avatar -Agent.isAvatar = true; - Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -34,8 +31,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; Recording.setPlayFromCurrentLocation(playFromCurrentLocation); @@ -71,28 +66,13 @@ function agentCommand(command) { Recording.stopPlaying(); } break; - case SHOW: - print("Show"); - break; - case HIDE: - print("Hide"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - break; case LOAD: { print("Load" + command.argument_key); print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); print("After Load" + command.argument_key); - - /*if(command.argument_key == null) { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } else *{ - print("Agent #" + id + " loading clip URL: " + command.argument_key); - Recording.loadRecording(command.argument_key); - }*/ + Recording.setPlayerTime(0); } break; default: @@ -105,17 +85,18 @@ function agentCommand(command) { function agentHired() { print("Agent Hired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Agent.isAvatar = true; + Recording.stopPlaying(); Recording.setPlayerLoop(false); + Recording.setPlayerTime(0); } function agentFired() { print("Agent Fired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Recording.stopPlaying(); + Recording.setPlayerTime(0); + Recording.setPlayerLoop(false); + Agent.isAvatar = false; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 7486256f07..d66a09d633 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -26,8 +26,6 @@ Tool.IMAGE_WIDTH /= 2; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; var windowDimensions = Controller.getViewportDimensions(); @@ -42,10 +40,6 @@ var TEXT_MARGIN = 3; // Add new features to Actor class: Actor.prototype.destroy = function() { print("Actor.prototype.destroy"); - - this.toolbar.cleanup(); - Overlays.deleteOverlay(this.nameOverlay); - print("Need to fire myself" + this.agentID); masterController.fireAgent(this); } @@ -123,6 +117,11 @@ Actor.prototype._buildUI = function() { }); } +Actor.prototype._destroyUI = function() { + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + Actor.prototype.moveUI = function(pos) { var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; this.toolbar.move(pos.x, pos.y); @@ -329,6 +328,9 @@ Director.prototype.hireActor = function(clipURL) { if (index >= 0) { localThis.actors.splice(index, 1); } + + actor._destroyUI(); + actor.destroy(); moveUI(); } @@ -338,6 +340,7 @@ Director.prototype.hireActor = function(clipURL) { masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); }); + masterController.hireAgent(newActor); newActor._buildUI(); From e25e6b5003a38ffc1a56035ec9a1b0e5ead2521c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Dec 2015 06:44:56 -0800 Subject: [PATCH 080/165] Test script with sliders for all reverb parameters --- examples/utilities/tools/reverbTest.js | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/utilities/tools/reverbTest.js diff --git a/examples/utilities/tools/reverbTest.js b/examples/utilities/tools/reverbTest.js new file mode 100644 index 0000000000..f399a40cc0 --- /dev/null +++ b/examples/utilities/tools/reverbTest.js @@ -0,0 +1,69 @@ +// +// reverbTest.js +// examples +// +// Created by Ken Cooke on 11/23/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("cookies.js"); + +var audioOptions = new AudioEffectOptions({ + maxRoomSize: 50, + roomSize: 50, + reverbTime: 4, + damping: 0.50, + inputBandwidth: 0.8, + earlyLevel: 0, + tailLevel: 0, + dryLevel: 0, + wetLevel: 0 +}); + +AudioDevice.setReverbOptions(audioOptions); +AudioDevice.setReverb(true); +print("Reverb is ON."); + +var panel = new Panel(10, 200); + +var parameters = [ + { name: "roomSize", min: 0, max: 100, units: " feet" }, + { name: "reverbTime", min: 0, max: 10, units: " sec" }, + { name: "damping", min: 0, max: 1, units: " " }, + { name: "inputBandwidth", min: 0, max: 1, units: " " }, + { name: "earlyLevel", min: -48, max: 0, units: " dB" }, + { name: "tailLevel", min: -48, max: 0, units: " dB" }, + { name: "wetLevel", min: -48, max: 0, units: " dB" }, +] + +function setter(name) { + return function(value) { audioOptions[name] = value; AudioDevice.setReverbOptions(audioOptions); } +} + +function getter(name) { + return function() { return audioOptions[name]; } +} + +function displayer(units) { + return function(value) { return (value).toFixed(1) + units; }; +} + +// create a slider for each parameter +for (var i = 0; i < parameters.length; i++) { + var p = parameters[i]; + panel.newSlider(p.name, p.min, p.max, setter(p.name), getter(p.name), displayer(p.units)); +} + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); +Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); + +function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); +} +Script.scriptEnding.connect(scriptEnding); From 27227181f0acb8f66f8b02601956b92b39671a2a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Dec 2015 10:40:43 -0800 Subject: [PATCH 081/165] fix for infinite loop in OctreeeInboundPacketProcessor --- .../src/octree/OctreeInboundPacketProcessor.cpp | 10 +++++++--- .../src/octree/OctreeInboundPacketProcessor.h | 3 ++- assignment-client/src/octree/OctreeServer.cpp | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 0cdc7f9921..e22f241453 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -43,6 +43,7 @@ void OctreeInboundPacketProcessor::resetStats() { _totalPackets = 0; _lastNackTime = usecTimestampNow(); + QWriteLocker locker(&_senderStatsLock); _singleSenderStats.clear(); } @@ -220,6 +221,8 @@ void OctreeInboundPacketProcessor::trackInboundPacket(const QUuid& nodeUUID, uns _totalElementsInPacket += editsInPacket; _totalPackets++; + QWriteLocker locker(&_senderStatsLock); + // find the individual senders stats and track them there too... // see if this is the first we've heard of this node... if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) { @@ -242,6 +245,8 @@ int OctreeInboundPacketProcessor::sendNackPackets() { int packetsSent = 0; int totalBytesSent = 0; + QWriteLocker locker(&_senderStatsLock); + NodeToSenderStatsMapIterator i = _singleSenderStats.begin(); while (i != _singleSenderStats.end()) { @@ -262,10 +267,9 @@ int OctreeInboundPacketProcessor::sendNackPackets() { } const SharedNodePointer& destinationNode = DependencyManager::get()->nodeWithUUID(nodeUUID); - // If the node no longer exists, wait until the ReceivedPacketProcessor has cleaned up the node - // to remove it from our stats list. - // FIXME Is it safe to clean it up here before ReceivedPacketProcess has? + // if the node no longer exists, remove its stats if (!destinationNode) { + i = _singleSenderStats.erase(i); continue; } diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 3ddb76b3fa..f95a402b15 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -72,7 +72,7 @@ public: void resetStats(); - NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } + NodeToSenderStatsMap getSingleSenderStats() { QReadLocker locker(&_senderStatsLock); return _singleSenderStats; } virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } @@ -101,6 +101,7 @@ private: quint64 _totalPackets; NodeToSenderStatsMap _singleSenderStats; + QReadWriteLock _senderStatsLock; quint64 _lastNackTime; bool _shuttingDown; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 297f872108..7cd3e59edf 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -711,7 +711,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url int senderNumber = 0; - NodeToSenderStatsMap& allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats(); + NodeToSenderStatsMap allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats(); for (NodeToSenderStatsMapConstIterator i = allSenderStats.begin(); i != allSenderStats.end(); i++) { senderNumber++; QUuid senderID = i.key(); From 557ab315d9f991ee4fba13a227101cfa4664980c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Dec 2015 10:51:52 -0800 Subject: [PATCH 082/165] make resettable stats atomic --- .../src/octree/OctreeInboundPacketProcessor.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index f95a402b15..83960abaa6 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -94,16 +94,16 @@ private: OctreeServer* _myServer; int _receivedPacketCount; - quint64 _totalTransitTime; - quint64 _totalProcessTime; - quint64 _totalLockWaitTime; - quint64 _totalElementsInPacket; - quint64 _totalPackets; + std::atomic _totalTransitTime; + std::atomic _totalProcessTime; + std::atomic _totalLockWaitTime; + std::atomic _totalElementsInPacket; + std::atomic _totalPackets; NodeToSenderStatsMap _singleSenderStats; QReadWriteLock _senderStatsLock; - quint64 _lastNackTime; + std::atomic _lastNackTime; bool _shuttingDown; }; #endif // hifi_OctreeInboundPacketProcessor_h From ab6367ff4e6e486643870c5d85a868663739210e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Dec 2015 11:13:01 -0800 Subject: [PATCH 083/165] remove debug option for disabling physics updates --- .../utilities/tools/developerMenuItems.js | 8 +----- libraries/entities/src/EntityItem.cpp | 1 - libraries/entities/src/EntityItem.h | 25 +------------------ .../entities/src/EntityScriptingInterface.cpp | 19 ++++---------- .../entities/src/EntityScriptingInterface.h | 3 --- libraries/physics/src/EntityMotionState.cpp | 20 ++++++--------- 6 files changed, 14 insertions(+), 62 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index ef8be8aaa9..477cbd671b 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -19,7 +19,6 @@ var createdStereoInputMenuItem = false; var DEVELOPER_MENU = "Developer"; var ENTITIES_MENU = DEVELOPER_MENU + " > Entities"; -var COLLISION_UPDATES_TO_SERVER = "Don't send collision updates to server"; var RENDER_MENU = DEVELOPER_MENU + " > Render"; var ENTITIES_ITEM = "Entities"; @@ -66,7 +65,6 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); */ - Menu.addMenuItem({ menuName: ENTITIES_MENU, menuItemName: COLLISION_UPDATES_TO_SERVER, isCheckable: true, isChecked: false }); } if (!Menu.menuExists(RENDER_MENU)) { @@ -112,11 +110,7 @@ function setupMenus() { Menu.menuItemEvent.connect(function (menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == COLLISION_UPDATES_TO_SERVER) { - var dontSendUpdates = Menu.isOptionChecked(COLLISION_UPDATES_TO_SERVER); - print(" dontSendUpdates... checked=" + dontSendUpdates); - Entities.setSendPhysicsUpdates(!dontSendUpdates); - } else if (menuItem == ENTITIES_ITEM) { + if (menuItem == ENTITIES_ITEM) { Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM); } else if (menuItem == AVATARS_ITEM) { Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 992b6a1bdd..a70a8c0428 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -32,7 +32,6 @@ #include "EntityActionFactoryInterface.h" -bool EntityItem::_sendPhysicsUpdates = true; int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d80de4d427..854acb7fe0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -48,25 +48,6 @@ namespace render { class PendingChanges; } -/* -// these thesholds determine what updates will be ignored (client and server) -const float IGNORE_POSITION_DELTA = 0.0001f; -const float IGNORE_DIMENSIONS_DELTA = 0.0005f; -const float IGNORE_ALIGNMENT_DOT = 0.99997f; -const float IGNORE_LINEAR_VELOCITY_DELTA = 0.001f; -const float IGNORE_DAMPING_DELTA = 0.001f; -const float IGNORE_GRAVITY_DELTA = 0.001f; -const float IGNORE_ANGULAR_VELOCITY_DELTA = 0.0002f; - -// these thresholds determine what updates will activate the physical object -const float ACTIVATION_POSITION_DELTA = 0.005f; -const float ACTIVATION_DIMENSIONS_DELTA = 0.005f; -const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; -const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; -const float ACTIVATION_GRAVITY_DELTA = 0.1f; -const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; -*/ - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -194,7 +175,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { return true; } @@ -387,9 +368,6 @@ public: EntityTreePointer getTree() const; bool wantTerseEditLogging(); - static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } - static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } - glm::mat4 getEntityToWorldMatrix() const; glm::mat4 getWorldToEntityMatrix() const; glm::vec3 worldToEntity(const glm::vec3& point) const; @@ -432,7 +410,6 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; QUuid _id; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index bc57f2c72c..611a484142 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -167,8 +167,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper if (hasTerseUpdateChanges) { entity->getAllTerseUpdateProperties(properties); } - // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object - // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update + // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object + // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update // and instead let the physics simulation decide when to send a terse update. This would remove // the "slide-no-rotate" glitch (and typical a double-update) that we see during the "poke rolling // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible @@ -333,15 +333,6 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const { return ZoneEntityItem::getDrawZoneBoundaries(); } -void EntityScriptingInterface::setSendPhysicsUpdates(bool value) { - EntityItem::setSendPhysicsUpdates(value); -} - -bool EntityScriptingInterface::getSendPhysicsUpdates() const { - return EntityItem::getSendPhysicsUpdates(); -} - - RayToEntityIntersectionResult::RayToEntityIntersectionResult() : intersects(false), accurate(true), // assume it's accurate @@ -548,16 +539,16 @@ bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& poin if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; } - + EntityTypes::EntityType entityType = entity->getType(); - + if (entityType == EntityTypes::Line) { return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool { return (LineEntityItem*)lineEntity.appendPoint(point); }); } - + return false; } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8a4414a596..84688ab24a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -127,9 +127,6 @@ public slots: Q_INVOKABLE void setDrawZoneBoundaries(bool value); Q_INVOKABLE bool getDrawZoneBoundaries() const; - Q_INVOKABLE void setSendPhysicsUpdates(bool value); - Q_INVOKABLE bool getSendPhysicsUpdates() const; - Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 34439e57ce..dead822994 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -492,20 +492,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; } - if (EntityItem::getSendPhysicsUpdates()) { - EntityItemID id(_entity->getID()); - EntityEditPacketSender* entityPacketSender = static_cast(packetSender); - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; - #endif + EntityItemID id(_entity->getID()); + EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + #ifdef WANT_DEBUG + qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; + #endif - entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties); - _entity->setLastBroadcast(usecTimestampNow()); - } else { - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... NOT sending update as requested."; - #endif - } + entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties); + _entity->setLastBroadcast(usecTimestampNow()); _lastStep = step; } From 4d84362757bbeb0fd7f6f86f5f6768f33ea835ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Dec 2015 11:30:56 -0800 Subject: [PATCH 084/165] Fix ScriptEngine setting _isFinished when it shouldn't --- libraries/script-engine/src/ScriptEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 995a92bf83..895a572434 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -673,7 +673,6 @@ void ScriptEngine::run() { } _isRunning = true; - _isFinished = false; if (_wantSignals) { emit runningStateChanged(); } From ff3ae852459e599dee20b69cd7ad4f83d578f9d2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 12:36:49 -0800 Subject: [PATCH 085/165] Separating the ui to get the url from the actual loading to maybe avoid playbackMaster.js crash? --- examples/acScripts/AgentPoolControler.js | 22 +++++---- examples/acScripts/playbackMaster.js | 59 ++++++++++++++++-------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 74ee12922a..e5917ea93e 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -141,7 +141,7 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeAgent(agentIndex); + this._removeHiredAgent(agentIndex); } } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent @@ -199,7 +199,7 @@ function printDebug(message) { var actor = this.hiredActors[i]; var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + printDebug("Agent Lost, firing Agent #" + i + " ID " + actor.agentID); lostAgents.push(i); } } @@ -228,25 +228,31 @@ function printDebug(message) { MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent - printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + printDebug("MasterController.prototype.fireAgent" + actor.agentID); + // Try the waiting list first var waitingIndex = this.hiringAgentsQueue.indexOf(actor); if (waitingIndex >= 0) { - printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); - this.hiringAgentsQueue.splice(waitingIndex, 1); + printDebug("fireAgent found actor on waiting queue #" + waitingIndex); + var lostActor = this.hiringAgentsQueue.splice(waitingIndex, 1); + if (lostActor.length) { + lostActor[0].onFired(lostActor[0]); + } + return; } + // then the hired agents var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - this._removeAgent(actorIndex); + this._removeHiredAgent(actorIndex); } } - MasterController.prototype._removeAgent = function(actorIndex) { + MasterController.prototype._removeHiredAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeHiredAgent #" + this.knownAgents[actorIndex]) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index d66a09d633..5115dc9871 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -61,6 +61,8 @@ Actor.prototype.onMousePressEvent = function(clickedOverlay) { masterController.sendCommand(this.agentID, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, STOP); + } else if (this.nameOverlay === clickedOverlay) { + print("Actor: " + JSON.stringify(this)); } else { return false; } @@ -136,6 +138,8 @@ Director = function() { this.actors = new Array(); this.toolbar = null; this._buildUI(); + this.requestPerformanceLoad = false; + this.performanceURL = ""; }; Director.prototype.destroy = function () { @@ -234,27 +238,11 @@ Director.prototype.onMousePressEvent = function(clickedOverlay) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - var urlpartition = input_text.split("."); - print(urlpartition[0]); - print(urlpartition[1]); - - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; - - print(JSON.stringify(oneClipPerformance)); - - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + this.requestPerformanceLoad = true; + this.performanceURL = input_text; } + } else if (this.nameOverlay === clickedOverlay) { + print("Director: " + JSON.stringify(this)); } else { // Check individual controls for (var i = 0; i < this.actors.length; i++) { @@ -285,6 +273,32 @@ Director.prototype.moveUI = function(pos) { } } + +Director.prototype.reloadPerformance = function() { + this.requestPerformanceLoad = false; + + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } +} + Director.prototype.onPerformanceLoaded = function(performanceJSON) { // First fire all the current actors this.clearActors(); @@ -377,6 +391,11 @@ function update(deltaTime) { moveUI(); } + if (director.requestPerformanceLoad) { + print("reloadPerformance " + director.performanceURL); + director.reloadPerformance(); + } + masterController.update(deltaTime); } From aca0fa7beb17c5157601b39ebf4f45ffed5b3961 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 1 Dec 2015 16:03:19 -0800 Subject: [PATCH 086/165] support disabling both hands --- examples/controllers/handControllerGrab.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 272c2903af..287f57ca30 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1266,10 +1266,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND) { + if (handToDisable !== LEFT_HAND && handToDisable!=='both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND) { + if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { rightController.update(); } } @@ -1279,13 +1279,18 @@ Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { - handToDisable = message; if (message === 'left') { handToDisable = LEFT_HAND; } if (message === 'right') { handToDisable = RIGHT_HAND; } + if(message==='both'){ + handToDisable='both'; + } + if(message==='none'){ + handToDisable='none'; + } } } From 386afa272c99193e377b0fc78197cdd66960d718 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 16:50:09 -0800 Subject: [PATCH 087/165] disable grab while attachment version of pistol script is running --- examples/example/games/exterminatorGame/pistol.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/example/games/exterminatorGame/pistol.js b/examples/example/games/exterminatorGame/pistol.js index 365e29fbe5..e1923835c3 100644 --- a/examples/example/games/exterminatorGame/pistol.js +++ b/examples/example/games/exterminatorGame/pistol.js @@ -18,6 +18,7 @@ Script.include("../../../libraries/constants.js"); var GUN_FORCE =20; +Messages.sendMessage('Hifi-Hand-Disabler', "both"); var gameName = "Kill All The Rats!" // var HOST = "localhost:5000" @@ -194,6 +195,7 @@ function fire(side, value) { function scriptEnding() { + Messages.sendMessage('Hifi-Hand-Disabler', 'none'); mapping.disable(); for (var i = 0; i < pointers.length; ++i) { Overlays.deleteOverlay(pointers[i]); From e4199439af6a89db8a19c1a856d839ddd34a6f37 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 17:00:43 -0800 Subject: [PATCH 088/165] added collision sounds to some toys --- examples/controllers/handControllerGrab.js | 1 - unpublishedScripts/hiddenEntityReset.js | 3 +++ unpublishedScripts/masterReset.js | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 287f57ca30..3902963a61 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1277,7 +1277,6 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index af914259a3..982c65fc08 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -241,6 +241,7 @@ gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { @@ -649,6 +650,7 @@ z: 0.08 }, collisionsWillMove: true, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav", gravity: { x: 0, y: -3.5, @@ -1185,6 +1187,7 @@ z: 0.07 }, collisionsWillMove: true, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', gravity: { x: 0, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 667dc3aa96..6e89e12d41 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -220,6 +220,7 @@ MasterReset = function() { gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { @@ -629,6 +630,7 @@ MasterReset = function() { z: 0.08 }, collisionsWillMove: true, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav", gravity: { x: 0, y: -3.5, @@ -1165,6 +1167,7 @@ MasterReset = function() { z: 0.07 }, collisionsWillMove: true, + collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', gravity: { x: 0, From 0fd1bdaec508c9edefc15989d4b1919065a97478 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 17:03:11 -0800 Subject: [PATCH 089/165] fixed accidental newline in handgrab --- examples/controllers/handControllerGrab.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 3902963a61..ebfa248f58 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1277,6 +1277,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; From 40fb45c6d39453126b94443369c4f907a2fe746a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 17:04:10 -0800 Subject: [PATCH 090/165] fixed accidental newline in handgrab --- examples/controllers/handControllerGrab.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ebfa248f58..3902963a61 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1277,7 +1277,6 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; From 34234da2d1de9b593d92687b125df6f80625fbd1 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Tue, 1 Dec 2015 17:05:51 -0800 Subject: [PATCH 091/165] fixed spacing --- examples/controllers/handControllerGrab.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 3902963a61..ebfa248f58 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1277,6 +1277,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; From 99065f10fa8eb9ce9987902fc8fcfccb2be023ce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Dec 2015 12:27:09 -0800 Subject: [PATCH 092/165] Avatar Warning fixes on linux --- interface/src/Application.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 5 ++++- interface/src/avatar/SkeletonModel.cpp | 6 ------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ac14ac0ec..f18c6c87ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2577,7 +2577,6 @@ void Application::setAvatarUpdateThreading(bool isThreaded) { return; } - auto myAvatar = getMyAvatar(); if (_avatarUpdate) { _avatarUpdate->terminate(); // Must be before we shutdown anim graph. } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 39b09fb9de..029aefcac4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1808,7 +1808,10 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { int neckIndex = _rig->indexOfJoint("Neck"); int hipsIndex = _rig->indexOfJoint("Hips"); - glm::vec3 rigMiddleEyePos = leftEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_RIG_MIDDLE_EYE_POS; + glm::vec3 rigMiddleEyePos = DEFAULT_RIG_MIDDLE_EYE_POS; + if (leftEyeIndex >= 0 && rightEyeIndex >= 0) { + rigMiddleEyePos = (_rig->getAbsoluteDefaultPose(leftEyeIndex).trans + _rig->getAbsoluteDefaultPose(rightEyeIndex).trans) / 2.0f; + } glm::vec3 rigNeckPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_RIG_NECK_POS; glm::vec3 rigHipsPos = hipsIndex != -1 ? _rig->getAbsoluteDefaultPose(hipsIndex).trans : DEFAULT_RIG_HIPS_POS; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d438e6f528..342f8315e1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -42,7 +42,6 @@ SkeletonModel::~SkeletonModel() { void SkeletonModel::initJointStates() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 geometryOffset = geometry.offset; glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->initJointStates(geometry, modelOffset); @@ -237,11 +236,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) { if (parentJointIndex == -1) { return; } - - // the palm's position must be transformed into the model-frame - glm::quat inverseRotation = glm::inverse(_rotation); - glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); - glm::quat palmRotation = inverseRotation * palm.getRotation(); } bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { From 86af28dbab66cd3558428000d5368252035998ee Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 18:18:18 -0800 Subject: [PATCH 093/165] Fighting for one hour with the ready message being misunderstood by master --- examples/acScripts/AgentPoolControler.js | 67 +++++++++++++----------- examples/acScripts/playbackMaster.js | 44 +++++++++------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index e5917ea93e..830a8fe1e3 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -131,21 +131,21 @@ function printDebug(message) { }; MasterController.prototype._processServiceMessage = function(message, senderID) { - var message = unpackServiceMessage(message); - if (message.dest == MASTER_ID) { - if (message.command == AGENT_READY) { + var service = unpackServiceMessage(message); + if (service.dest == MASTER_ID) { + if (service.command == AGENT_READY) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex < 0) { - this._onAgentAvailableForHiring(message.src); + this._onAgentAvailableForHiring(service.src); } else { // Master think the agent is hired but not the other way around, forget about it - printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeHiredAgent(agentIndex); + printDebug("New agent still sending ready ? " + service.src + " " + agentIndex + " Forgeting about it"); + // this._removeHiredAgent(agentIndex); } - } else if (message.command == AGENT_ALIVE) { + } else if (service.command == AGENT_ALIVE) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex >= 0) { // yes so reset its alive beat this.hiredActors[agentIndex].alive(); @@ -171,8 +171,10 @@ function printDebug(message) { newActor.agentID = agentID; this.hiredActors.push(newActor); - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var serviceMessage = packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID); + printDebug("serviceMessage = " + serviceMessage); + Messages.sendMessage(SERVICE_CHANNEL, serviceMessage); printDebug("message sent calling the actor" + JSON.stringify(newActor) ); newActor.onHired(newActor); @@ -276,7 +278,6 @@ function printDebug(message) { //--------------------------------- var AgentController = function() { this.subscribed = false; - this._init(); this.onHired = function() {}; @@ -325,40 +326,42 @@ function printDebug(message) { }; AgentController.prototype._processServiceMessage = function(message, senderID) { - var announce = unpackServiceMessage(message); - //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); - if (announce.dest == this.agentUUID) { - if (announce.command != AGENT_READY) { - var parts = announce.command.split("."); + var service = unpackServiceMessage(message); + printDebug("Client " + this.agentUUID + " Received message = " + message); + if (service.dest == this.agentUUID) { + if (service.command != AGENT_READY) { - // this is potnetially a message to hire me if i m not already - if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { - printDebug(announce.command); + // this is potentially a message to hire me if i m not already + if (!this.isHired && (service.command == MASTER_HIRE_AGENT)) { + printDebug(service.command); this.isHired = true; - printDebug("Client Hired by master UUID" + senderID); - this.onHired(); + printDebug("Client Hired by master UUID" + service.src); + this.onHired(); + this.alive(); return; } - if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + // Or maybe a message to fire me if i m not hired + if (this.isHired && (service.command == MASTER_FIRE_AGENT)) { printDebug("Client Fired by master UUID" + senderID); this.fired(); return; } } - } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + } else if ((service.src == MASTER_ID) && (service.command == MASTER_ALIVE)) { this.numCyclesWithoutAlive = 0; return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackCommandMessage(message); - if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { - printDebug("Command received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } else { - // ignored + // ONly work if hired + if (this.isHired) { + var command = unpackCommandMessage(message); + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } } }; @@ -370,9 +373,9 @@ function printDebug(message) { if (!this.isHired) { Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); - } else { - + } else { // Send alive beat + printDebug("beat !"); Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); // Listen for master beat diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 5115dc9871..a88b699bf8 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -275,28 +275,34 @@ Director.prototype.moveUI = function(pos) { Director.prototype.reloadPerformance = function() { - this.requestPerformanceLoad = false; - - var urlpartition = this.performanceURL.split("."); - print(urlpartition[0]); - print(urlpartition[1]); + this.requestPerformanceLoad = false; - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; + if (this.performanceURL[0] == '{') { + var jsonPerformance = JSON.parse(this.performanceURL); + this.onPerformanceLoaded(jsonPerformance); + } else { - print(JSON.stringify(oneClipPerformance)); + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } + } } Director.prototype.onPerformanceLoaded = function(performanceJSON) { From e67f372bcf12a251db32878feafb9a33a9707cf6 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 1 Dec 2015 18:24:13 -0800 Subject: [PATCH 094/165] make pistol shoot differently and not alter controller mappings --- examples/toybox/pistol/pistol.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index 4c8913086e..8ef26b94c1 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -22,6 +22,8 @@ Controller.Standard.LT, Controller.Standard.RT, ]; + var RELOAD_THRESHOLD = 0.95; + Pistol = function() { _this = this; this.equipped = false; @@ -45,6 +47,7 @@ }; Pistol.prototype = { + canShoot: false, startEquip: function(id, params) { this.equipped = true; @@ -62,6 +65,17 @@ }, toggleWithTriggerPressure: function() { this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); + + if (this.triggerValue < RELOAD_THRESHOLD) { + // print('RELOAD'); + this.canShoot = true; + } + if (this.canShoot === true && this.triggerValue === 1) { + // print('SHOOT'); + this.fire(); + this.canShoot = false; + } + if (this.triggerValue < DISABLE_LASER_THRESHOLD && this.showLaser === true) { this.showLaser = false; Overlays.editOverlay(this.laser, { @@ -74,6 +88,7 @@ }); } + }, updateLaser: function() { var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); @@ -101,7 +116,7 @@ preload: function(entityID) { this.entityID = entityID; - this.initControllerMapping(); + // this.initControllerMapping(); this.laser = Overlays.addOverlay("line3d", { start: ZERO_VECTOR, end: ZERO_VECTOR, @@ -150,22 +165,7 @@ } }, - initControllerMapping: function() { - this.mapping = Controller.newMapping(); - this.mapping.from(Controller.Standard.LT).hysteresis(0.0, 0.75).to(function(value) { - _this.triggerPress(0, value); - }); - - - this.mapping.from(Controller.Standard.RT).hysteresis(0.0, 0.75).to(function(value) { - _this.triggerPress(1, value); - }); - this.mapping.enable(); - - }, - unload: function() { - this.mapping.disable(); Overlays.deleteOverlay(this.laser); }, From 0bc914bf1986bb1792456795efe4e57fc6c0e3a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 19:33:44 -0800 Subject: [PATCH 095/165] Don't grab subTree outside lock --- assignment-client/src/octree/OctreeSendThread.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 84caf9ce81..b1fd37fe85 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -417,10 +417,15 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 startInside = usecTimestampNow(); bool lastNodeDidntFit = false; // assume each node fits - if (OctreeElementPointer subTree = nodeData->elementBag.extract()) { + if (!nodeData->elementBag.isEmpty()) { quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ + OctreeElementPointer subTree = nodeData->elementBag.extract(); + if (!subTree) { + return; + } + quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); quint64 encodeStart = usecTimestampNow(); From 9b6ec34f092d1ab80f765050f0f088a510513080 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 1 Dec 2015 20:50:03 -0800 Subject: [PATCH 096/165] Fixing avatar orientation in recordings --- libraries/avatars/src/AvatarData.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e25e4f243f..597c4c5986 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -116,7 +116,7 @@ void AvatarData::setOrientation(const glm::quat& orientation, bool overideRefere glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); _bodyPitch = eulerAngles.x; _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; + _bodyRoll = eulerAngles.z; } } @@ -1529,6 +1529,17 @@ QJsonObject AvatarData::toJson() const { } void AvatarData::fromJson(const QJsonObject& json) { + // The head setOrientation likes to overwrite the avatar orientation, + // so lets do the head first + // Most head data is relative to the avatar, and needs no basis correction, + // but the lookat vector does need correction + if (json.contains(JSON_AVATAR_HEAD)) { + if (!_headData) { + _headData = new HeadData(this); + } + _headData->fromJson(json[JSON_AVATAR_HEAD].toObject()); + } + if (json.contains(JSON_AVATAR_HEAD_MODEL)) { auto faceModelURL = json[JSON_AVATAR_HEAD_MODEL].toString(); if (faceModelURL != getFaceModelURL().toString()) { @@ -1600,15 +1611,6 @@ void AvatarData::fromJson(const QJsonObject& json) { } setRawJointData(jointArray); } - - // Most head data is relative to the avatar, and needs no basis correction, - // but the lookat vector does need correction - if (json.contains(JSON_AVATAR_HEAD)) { - if (!_headData) { - _headData = new HeadData(this); - } - _headData->fromJson(json[JSON_AVATAR_HEAD].toObject()); - } } // Every frame will store both a basis for the recording and a relative transform From be2f14cae580d675b1cea1c499a256f38aa91cc4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 1 Dec 2015 21:50:01 -0800 Subject: [PATCH 097/165] Review fix --- interface/src/avatar/Head.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b79e502bed..a22bbfca0b 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -261,8 +261,7 @@ void Head::calculateMouthShapes() { float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; if (audioDelta > _audioJawOpen) { _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } - else { + } else { _audioJawOpen *= JAW_CLOSE_RATE; } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); From f005afd7c021fe30570d9aa7394162091d597d9f Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 2 Dec 2015 09:33:47 -0800 Subject: [PATCH 098/165] Fix stdint.h includes --- libraries/audio/src/AudioReverb.h | 2 +- libraries/audio/src/AudioSRC.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h index 92e9c0009b..639d62d8ec 100644 --- a/libraries/audio/src/AudioReverb.h +++ b/libraries/audio/src/AudioReverb.h @@ -9,7 +9,7 @@ #ifndef hifi_AudioReverb_h #define hifi_AudioReverb_h -#include "stdint.h" +#include typedef struct ReverbParameters { diff --git a/libraries/audio/src/AudioSRC.h b/libraries/audio/src/AudioSRC.h index 5b00ca9e77..920ea8aef0 100644 --- a/libraries/audio/src/AudioSRC.h +++ b/libraries/audio/src/AudioSRC.h @@ -12,7 +12,7 @@ #ifndef hifi_AudioSRC_h #define hifi_AudioSRC_h -#include "stdint.h" +#include class AudioSRC { From c3e2d920ee4180fc6997fd661167bba80788c3ec Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Dec 2015 09:45:51 -0800 Subject: [PATCH 099/165] Move timing at the top --- assignment-client/src/octree/OctreeSendThread.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b1fd37fe85..94d82b463e 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -421,14 +421,14 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ + quint64 lockWaitEnd = usecTimestampNow(); + lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); + quint64 encodeStart = usecTimestampNow(); + OctreeElementPointer subTree = nodeData->elementBag.extract(); if (!subTree) { return; } - - quint64 lockWaitEnd = usecTimestampNow(); - lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - quint64 encodeStart = usecTimestampNow(); /* TODO: Looking for a way to prevent locking and encoding a tree that is not // going to result in any packets being sent... From b6398a79309889e6fb0f6e396c7dd8693d28ca5d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 09:51:52 -0800 Subject: [PATCH 100/165] fix PlayRecordingOnAC.js to use new API --- examples/acScripts/PlayRecordingOnAC.js | 27 +++++++++---------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/examples/acScripts/PlayRecordingOnAC.js b/examples/acScripts/PlayRecordingOnAC.js index b7ae2c7329..0961f65079 100644 --- a/examples/acScripts/PlayRecordingOnAC.js +++ b/examples/acScripts/PlayRecordingOnAC.js @@ -10,20 +10,17 @@ // -var filename = "http://your.recording.url"; +var recordingFile = "http://your.recording.url"; var playFromCurrentLocation = true; var loop = true; -Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/e21c0b95-e502-4d15-8c41-ea2fc40f1125/3585ddf674869a67d31d5964f7b52de1.fst?1427169998"; - // Set position here if playFromCurrentLocation is true Avatar.position = { x:1, y: 1, z: 1 }; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; - Agent.isAvatar = true; -Avatar.loadRecording(filename); +Recording.loadRecording(recordingFile); count = 300; // This is necessary to wait for the audio mixer to connect function update(event) { @@ -32,22 +29,18 @@ function update(event) { return; } if (count == 0) { - Avatar.setPlayFromCurrentLocation(playFromCurrentLocation); - Avatar.setPlayerLoop(loop); - Avatar.setPlayerUseDisplayName(true); - Avatar.setPlayerUseAttachments(true); - Avatar.setPlayerUseHeadModel(false); - Avatar.setPlayerUseSkeletonModel(true); - Avatar.startPlaying(); - Avatar.play(); + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerLoop(loop); + Recording.setPlayerUseDisplayName(true); + Recording.setPlayerUseAttachments(true); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(true); + Recording.startPlaying(); Vec3.print("Playing from ", Avatar.position); - count--; } - if (Avatar.isPlaying()) { - Avatar.play(); - } else { + if (!Recording.isPlaying()) { Script.update.disconnect(update); } } From 586ed51436aec549d011d97c8923b0ad1dd3bfc4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 09:56:16 -0800 Subject: [PATCH 101/165] rename AgentPoolCOntroller.js --- .../acScripts/{AgentPoolControler.js => AgentPoolController.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/acScripts/{AgentPoolControler.js => AgentPoolController.js} (100%) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolController.js similarity index 100% rename from examples/acScripts/AgentPoolControler.js rename to examples/acScripts/AgentPoolController.js From 0b05a341a842c89b3bef25ebb6034e08859850f0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 10:18:02 -0800 Subject: [PATCH 102/165] MyAvatar::reset() improvements Body should not orient under the HMD body without changing the HMD view point. It's more predictable and less likely to make you sick. It also should reset the height of the character to cancel out squatting, if the HMD position is low. --- interface/src/avatar/MyAvatar.cpp | 33 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 029aefcac4..eca39a0a44 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -232,30 +232,27 @@ void MyAvatar::reset(bool andReload) { setThrust(glm::vec3(0.0f)); if (andReload) { - // Get fresh data, in case we're really slow and out of wack. - _hmdSensorMatrix = qApp->getHMDSensorPose(); - _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); - _hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix); - - // Reset body position/orientation under the head. + // derive the desired body orientation from the *old* hmd orientation, before the sensor reset. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + + // transform this body into world space auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; - glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); - glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); - - // FIXME: Hack to retain the previous behavior wrt height. - // I'd like to make the body match head height, but that will have to wait for separate PR. - worldBodyPos.y = getPosition().y; + auto worldBodyPos = extractTranslation(worldBodyMatrix); + auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); + // this will become our new position. setPosition(worldBodyPos); setOrientation(worldBodyRot); - // If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor), - // we can make that right by setting _bodySensorMatrix = newBodySensorMatrix. - // However, doing so will make the head want to point to the previous body orientation, as cached above. - //_bodySensorMatrix = newBodySensorMatrix; - //updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - qApp->setRawAvatarUpdateThreading(); + // now sample the new hmd orientation AFTER sensor reset. + updateFromHMDSensorMatrix(qApp->getHMDSensorPose()); + + // update the body in sensor space using the new hmd sensor sample + _bodySensorMatrix = deriveBodyFromHMDSensor(); + + // rebuild the sensor to world matrix such that, the HMD will point in the desired orientation. + // i.e. the along avatar's current position and orientation. + updateSensorToWorldMatrix(); } } From 0ae70603168a54d18fd0f4b57f8abf0abc5c420b Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 10:23:31 -0800 Subject: [PATCH 103/165] the correct includes --- examples/acScripts/playbackAgents.js | 2 +- examples/acScripts/playbackMaster.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 64c25ec0a8..cf805623de 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); var agentController = new AgentController(); // Set the following variables to the values needed diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index a88b699bf8..dff0b1d852 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; From f18fc84c2df8140cbe5afbe10437b4563549456d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 2 Dec 2015 10:46:10 -0800 Subject: [PATCH 104/165] fix debug build --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4dff61cedc..83e2324080 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -725,7 +725,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const { const float HEAD_PROPORTION = 0.75f; float billboardSize = getBillboardSize(); - DEBUG_VALUE("_position =", _position); + DEBUG_VALUE("_position =", getPosition()); DEBUG_VALUE("billboardSize =", billboardSize); namePosition = getPosition() + bodyUpDirection * (billboardSize * HEAD_PROPORTION); } From fbd754943010c6746fd6a5f34b25dd1773f81f41 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 2 Dec 2015 11:05:06 -0800 Subject: [PATCH 105/165] Better reverb script defaults --- examples/utilities/tools/reverbTest.js | 4 ++-- libraries/audio/src/AudioEffectOptions.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/reverbTest.js b/examples/utilities/tools/reverbTest.js index f399a40cc0..32c28a993f 100644 --- a/examples/utilities/tools/reverbTest.js +++ b/examples/utilities/tools/reverbTest.js @@ -19,8 +19,8 @@ var audioOptions = new AudioEffectOptions({ inputBandwidth: 0.8, earlyLevel: 0, tailLevel: 0, - dryLevel: 0, - wetLevel: 0 + dryLevel: -6, + wetLevel: -6 }); AudioDevice.setReverbOptions(audioOptions); diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 97aac7c82c..be5e1cca5e 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -15,6 +15,8 @@ #include #include +#include "AudioReverb.h" + class AudioEffectOptions : public QObject { Q_OBJECT From 018050344746581d6b39a434dc3182027b093314 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 12:07:38 -0800 Subject: [PATCH 106/165] removed collision sound url --- unpublishedScripts/hiddenEntityReset.js | 1 - unpublishedScripts/masterReset.js | 1 - 2 files changed, 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 982c65fc08..0c15100aaa 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -241,7 +241,6 @@ gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, - collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6e89e12d41..2aa29eb94e 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -220,7 +220,6 @@ MasterReset = function() { gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, - collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { From 6d953a65dd2a44ee94906adc2e21424edcb0e205 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 12:09:21 -0800 Subject: [PATCH 107/165] changed restitution to 0 --- unpublishedScripts/hiddenEntityReset.js | 2 ++ unpublishedScripts/masterReset.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 0c15100aaa..48745715f9 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -655,6 +655,7 @@ y: -3.5, z: 0 }, + restitution: 0, velocity: { x: 0, y: -0.01, @@ -1188,6 +1189,7 @@ collisionsWillMove: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', + restitution: 0, gravity: { x: 0, y: -3.0, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 2aa29eb94e..6a870f988f 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -635,6 +635,7 @@ MasterReset = function() { y: -3.5, z: 0 }, + restitution: 0, velocity: { x: 0, y: -0.01, @@ -1173,6 +1174,7 @@ MasterReset = function() { y: -3.0, z: 0 }, + restitution: 0, velocity: { x: 0, y: -1, From 861393910a47a367799567e0641769731ecc4e00 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 2 Dec 2015 12:12:57 -0800 Subject: [PATCH 108/165] Add an avatar LOD preference called "Minimum Avatar Display Distance" --- interface/src/avatar/AvatarManager.cpp | 13 ++++- interface/src/avatar/AvatarManager.h | 4 +- interface/src/ui/PreferencesDialog.cpp | 2 + interface/ui/preferencesDialog.ui | 79 ++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 9df597109c..e094f2e263 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include "Application.h" @@ -35,7 +37,6 @@ #include "Menu.h" #include "MyAvatar.h" #include "SceneScriptingInterface.h" -#include // 70 times per second - target is 60hz, but this helps account for any small deviations // in the update loop @@ -75,6 +76,13 @@ AvatarManager::AvatarManager(QObject* parent) : packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket"); } +const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters +Setting::Handle avatarRenderDistanceHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); +void AvatarManager::setRenderDistanceHighLimit(float newValue) { + avatarRenderDistanceHighLimit.set(newValue); + _renderDistanceController.setControlledValueHighLimit(newValue); +} + void AvatarManager::init() { _myAvatar->init(); { @@ -93,8 +101,7 @@ void AvatarManager::init() { const float target_fps = qApp->getTargetFrameRate(); _renderDistanceController.setMeasuredValueSetpoint(target_fps); - const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters - _renderDistanceController.setControlledValueHighLimit(1.0f / SMALLEST_REASONABLE_HORIZON); + _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceHighLimit.get()); _renderDistanceController.setControlledValueLowLimit(1.0f / (float) TREE_SCALE); // Advice for tuning parameters: // See PIDController.h. There's a section on tuning in the reference. diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 96383b7e60..ddc40d8490 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,6 +70,8 @@ public: // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } + Q_INVOKABLE float getRenderDistanceLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } + Q_INVOKABLE float getRenderDistanceHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } Q_INVOKABLE int getNumberInRenderRange() { return _renderedAvatarCount; } Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); } Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); } @@ -77,7 +79,7 @@ public: Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); } Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } Q_INVOKABLE void setRenderDistanceLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } - Q_INVOKABLE void setRenderDistanceHighLimit(float newValue) { _renderDistanceController.setControlledValueHighLimit(newValue); } + Q_INVOKABLE void setRenderDistanceHighLimit(float newValue); public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index c37755b823..69ece359e9 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -204,6 +204,7 @@ void PreferencesDialog::loadPreferences() { auto lodManager = DependencyManager::get(); ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS()); ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS()); + ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceHighLimit()); } void PreferencesDialog::savePreferences() { @@ -294,4 +295,5 @@ void PreferencesDialog::savePreferences() { auto lodManager = DependencyManager::get(); lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value()); lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value()); + DependencyManager::get()->setRenderDistanceHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); } diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index a1137a2bf2..e6a5e2228d 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -912,6 +912,85 @@ + + + + 0 + + + 7 + + + 0 + + + 7 + + + + + + Arial + + + + + + + Minimum Avatar Display Distance + + + 0 + + + + + + + + Arial + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 100 + 0 + + + + + 95 + 36 + + + + + Arial + + + + 5 + + + 32768 + + + + + From a9438490fe4ef4cf7a2ba60c0c2d981ada3b6f6a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 2 Dec 2015 12:53:19 -0800 Subject: [PATCH 109/165] update butterfly model --- examples/example/entities/butterflies.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/example/entities/butterflies.js b/examples/example/entities/butterflies.js index 3a78a2fc1c..9d53fc0ebf 100644 --- a/examples/example/entities/butterflies.js +++ b/examples/example/entities/butterflies.js @@ -32,7 +32,7 @@ function randVector(a, b) { var startTimeInSeconds = new Date().getTime() / 1000; -var NATURAL_SIZE_OF_BUTTERFLY = { x: 1.0, y: 0.4, z: 0.2 }; +var NATURAL_SIZE_OF_BUTTERFLY = { x:0.5, y: 0.2, z: 0.1 }; var lifeTime = 3600; // One hour lifespan var range = 7.0; // Over what distance in meters do you want the flock to fly around @@ -65,8 +65,8 @@ function addButterfly() { var color = { red: 100, green: 100, blue: 100 }; var size = 0; - var MINSIZE = 0.06; - var RANGESIZE = 0.2; + var MINSIZE = 0.01; + var RANGESIZE = 0.05; var maxSize = MINSIZE + RANGESIZE; size = MINSIZE + Math.random() * RANGESIZE; @@ -74,7 +74,7 @@ function addButterfly() { var dimensions = Vec3.multiply(NATURAL_SIZE_OF_BUTTERFLY, (size / maxSize)); var GRAVITY = -0.2; - var newFrameRate = 20 + Math.random() * 30; + var newFrameRate = 29 + Math.random() * 30; var properties = { type: "Model", lifetime: lifeTime, @@ -86,17 +86,13 @@ function addButterfly() { dimensions: dimensions, color: color, animation: { - url: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx", - firstFrame: 0, + url: "http://hifi-content.s3.amazonaws.com/james/butterfly/butterfly.fbx", fps: newFrameRate, - currentFrame: 0, - hold: false, - lastFrame: 10000, loop: true, running: true, startAutomatically:false }, - modelURL: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx" + modelURL: "http://hifi-content.s3.amazonaws.com/james/butterfly/butterfly.fbx" }; butterflies.push(Entities.addEntity(properties)); } From 08ba535c384a62a09ca67583409405694038e9df Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 13:43:05 -0800 Subject: [PATCH 110/165] add some basic send tracking --- .../src/entities/EntityServer.cpp | 46 +++++++++++++++++++ assignment-client/src/entities/EntityServer.h | 6 +++ .../src/octree/OctreeSendThread.cpp | 6 +++ assignment-client/src/octree/OctreeServer.cpp | 5 ++ assignment-client/src/octree/OctreeServer.h | 2 + libraries/entities/src/EntityItem.cpp | 5 ++ libraries/octree/src/Octree.h | 2 + 7 files changed, 72 insertions(+) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 6508f09f72..28e852af6a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -266,3 +266,49 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setWantEditLogging(wantEditLogging); tree->setWantTerseEditLogging(wantTerseEditLogging); } + +void EntityServer::trackSend(const QUuid& dataID, const QUuid& viewerNode) { + QWriteLocker locker(&_viewerSendingStatsLock); + _viewerSendingStats[viewerNode] = usecTimestampNow(); +} + + +QString EntityServer::serverSubclassStats() { + QLocale locale(QLocale::English); + QString statsString; + + // display memory usage stats + statsString += "Entity Server Memory Statistics\r\n"; + statsString += QString().sprintf("EntityTreeElement size... %ld bytes\r\n", sizeof(EntityTreeElement)); + statsString += QString().sprintf(" EntityItem size... %ld bytes\r\n", sizeof(EntityItem)); + statsString += "\r\n\r\n"; + + statsString += "Entity Server Sending to Viewer Statistics\r\n"; + statsString += "----- Viewer Node ID ----------------- ---------- Last Sent To ----------\r\n"; + + int viewers = 0; + const int COLUMN_WIDTH = 24; + + { + QReadLocker locker(&_viewerSendingStatsLock); + quint64 now = usecTimestampNow(); + + for (auto key : _viewerSendingStats.keys()) { + quint64 lastSentAt = _viewerSendingStats[key]; + quint64 elapsed = now - lastSentAt; + double msecsAgo = (double)(elapsed / USECS_PER_MSEC); + statsString += key.toString(); + statsString += " "; + statsString += QString("%1 msecs ago\r\n") + .arg(locale.toString((double)msecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + + viewers++; + } + } + if (viewers < 1) { + statsString += " no viewers... \r\n"; + } + statsString += "\r\n\r\n"; + + return statsString; +} diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d9795316c4..ab7ca038cf 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,6 +44,9 @@ public: virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; + virtual QString serverSubclassStats(); + + virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode); public slots: void pruneDeletedEntities(); @@ -57,6 +60,9 @@ private slots: private: EntitySimulation* _entitySimulation; QTimer* _pruneDeletedEntitiesTimer = nullptr; + + QReadWriteLock _viewerSendingStatsLock; + QMap _viewerSendingStats; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 94d82b463e..fc3731f063 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -467,6 +467,12 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); + // Our trackSend() function is implemented by the server subclass, and will be called back + // during the encodeTreeBitstream() as new entities/data elements are sent + params.trackSend = [this](const QUuid& id) { + _myServer->trackSend(id, _nodeUUID); + }; + // TODO: should this include the lock time or not? This stat is sent down to the client, // it seems like it may be a good idea to include the lock time as part of the encode time // are reported to client. Since you can encode without the lock diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 7cd3e59edf..c5072d0175 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -821,6 +821,11 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url .arg(locale.toString((uint)checkSum).rightJustified(16, ' ')); statsString += "\r\n\r\n"; + + statsString += serverSubclassStats(); + + statsString += "\r\n\r\n"; + statsString += "\r\n"; statsString += ""; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 1aea9c960e..6c11a53bd2 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -79,6 +79,8 @@ public: virtual void beforeRun() { } virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) { return false; } virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } + virtual QString serverSubclassStats() { return QString(); } + virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a70a8c0428..cde1012fb0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -311,6 +311,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet entityTreeElementExtraEncodeData->entities.insert(getEntityItemID(), propertiesDidntFit); } + // if any part of our entity was sent, call trackSend + if (appendState != OctreeElement::NONE) { + params.trackSend(getID()); + } + return appendState; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index d9cf17d7de..118ea79b6e 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -176,6 +176,8 @@ public: case OCCLUDED: return QString("OCCLUDED"); break; } } + + std::function trackSend { [](const QUuid&){} }; }; class ReadElementBufferToTreeArgs { From 9c0b4bc2a2be713a32fd4b269e03d377896cdf18 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 14:09:47 -0800 Subject: [PATCH 111/165] Fix for model entities with non-uniform scaled mesh Logic which extracted rotations from a non-uniformly scaled matrices was sometimes incorrect. This should fix the roads in Qbit as well as the blocks in toybox. --- libraries/animation/src/AnimPose.cpp | 5 ++++- libraries/render-utils/src/Model.cpp | 2 +- libraries/shared/src/GLMHelpers.cpp | 11 +++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 5914031a3a..0c6af2d5bd 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -11,6 +11,7 @@ #include "AnimPose.h" #include #include +#include const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), glm::quat(), @@ -18,7 +19,9 @@ const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), AnimPose::AnimPose(const glm::mat4& mat) { scale = extractScale(mat); - rot = glmExtractRotation(mat); + // quat_cast doesn't work so well with scaled matrices, so cancel it out. + glm::mat4 tmp = glm::scale(mat, 1.0f / scale); + rot = glm::normalize(glm::quat_cast(tmp)); trans = extractTranslation(mat); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0070b99591..7ab1129e2e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -928,7 +928,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { //virtual void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _needsUpdateClusterMatrices = true; - _rig->updateAnimations(deltaTime, parentTransform); + _rig->updateAnimations(deltaTime, parentTransform); } void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 7c5ba6bb48..e6fbe5e5cc 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -279,14 +279,9 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { glm::quat glmExtractRotation(const glm::mat4& matrix) { glm::vec3 scale = extractScale(matrix); - float maxScale = std::max(std::max(scale.x, scale.y), scale.z); - if (maxScale > 1.01f || maxScale <= 0.99f) { - // quat_cast doesn't work so well with scaled matrices, so cancel it out. - glm::mat4 tmp = glm::scale(matrix, 1.0f / scale); - return glm::normalize(glm::quat_cast(tmp)); - } else { - return glm::normalize(glm::quat_cast(matrix)); - } + // quat_cast doesn't work so well with scaled matrices, so cancel it out. + glm::mat4 tmp = glm::scale(matrix, 1.0f / scale); + return glm::normalize(glm::quat_cast(tmp)); } glm::vec3 extractScale(const glm::mat4& matrix) { From 1e51a902046304ea8f6619e79a319ef1578c440e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 14:37:41 -0800 Subject: [PATCH 112/165] add edit times and entity ids to the viewer stats --- .../src/entities/EntityServer.cpp | 41 ++++++++++++++----- assignment-client/src/entities/EntityServer.h | 10 ++++- .../src/octree/OctreeSendThread.cpp | 4 +- assignment-client/src/octree/OctreeServer.h | 2 +- libraries/entities/src/EntityItem.cpp | 2 +- libraries/octree/src/Octree.h | 2 +- 6 files changed, 43 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 28e852af6a..2b53cc9314 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -267,9 +267,14 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setWantTerseEditLogging(wantTerseEditLogging); } -void EntityServer::trackSend(const QUuid& dataID, const QUuid& viewerNode) { + +// FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad +// set of stats to have, but we'd probably want a different data-structure if we keep it very long. +// Since this version uses a single shared QMap for all senders, there can be a fair amount of lock +// contention on this QWriteLocker +void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats[viewerNode] = usecTimestampNow(); + _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; } @@ -284,7 +289,8 @@ QString EntityServer::serverSubclassStats() { statsString += "\r\n\r\n"; statsString += "Entity Server Sending to Viewer Statistics\r\n"; - statsString += "----- Viewer Node ID ----------------- ---------- Last Sent To ----------\r\n"; + statsString += "----- Viewer Node ID ----------------- ----- Entity ID ---------------------- " + "---------- Last Sent To ---------- ---------- Last Edited -----------\r\n"; int viewers = 0; const int COLUMN_WIDTH = 24; @@ -293,15 +299,28 @@ QString EntityServer::serverSubclassStats() { QReadLocker locker(&_viewerSendingStatsLock); quint64 now = usecTimestampNow(); - for (auto key : _viewerSendingStats.keys()) { - quint64 lastSentAt = _viewerSendingStats[key]; - quint64 elapsed = now - lastSentAt; - double msecsAgo = (double)(elapsed / USECS_PER_MSEC); - statsString += key.toString(); - statsString += " "; - statsString += QString("%1 msecs ago\r\n") - .arg(locale.toString((double)msecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + for (auto viewerID : _viewerSendingStats.keys()) { + statsString += viewerID.toString() + "\r\n"; + auto viewerData = _viewerSendingStats[viewerID]; + for (auto entityID : viewerData.keys()) { + ViewerSendingStats stats = viewerData[entityID]; + + quint64 elapsedSinceSent = now - stats.lastSent; + double sentMsecsAgo = (double)(elapsedSinceSent / USECS_PER_MSEC); + + quint64 elapsedSinceEdit = now - stats.lastEdited; + double editMsecsAgo = (double)(elapsedSinceEdit / USECS_PER_MSEC); + + statsString += " "; // the viewerID spacing + statsString += entityID.toString(); + statsString += " "; + statsString += QString("%1 msecs ago") + .arg(locale.toString((double)sentMsecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + statsString += QString("%1 msecs ago") + .arg(locale.toString((double)editMsecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + statsString += "\r\n"; + } viewers++; } } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index ab7ca038cf..d39e966430 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -21,6 +21,12 @@ #include "EntityTree.h" /// Handles assignments of type EntityServer - sending entities to various clients. + +struct ViewerSendingStats { + quint64 lastSent; + quint64 lastEdited; +}; + class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: @@ -46,7 +52,7 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; virtual QString serverSubclassStats(); - virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode); + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); public slots: void pruneDeletedEntities(); @@ -62,7 +68,7 @@ private: QTimer* _pruneDeletedEntitiesTimer = nullptr; QReadWriteLock _viewerSendingStatsLock; - QMap _viewerSendingStats; + QMap> _viewerSendingStats; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index fc3731f063..0a32f574de 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -469,8 +469,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Our trackSend() function is implemented by the server subclass, and will be called back // during the encodeTreeBitstream() as new entities/data elements are sent - params.trackSend = [this](const QUuid& id) { - _myServer->trackSend(id, _nodeUUID); + params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { + _myServer->trackSend(dataID, dataEdited, _nodeUUID); }; // TODO: should this include the lock time or not? This stat is sent down to the client, diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 6c11a53bd2..9876f5147c 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -80,7 +80,7 @@ public: virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) { return false; } virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } virtual QString serverSubclassStats() { return QString(); } - virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode) { } + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index cde1012fb0..0120b7c0ca 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -313,7 +313,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // if any part of our entity was sent, call trackSend if (appendState != OctreeElement::NONE) { - params.trackSend(getID()); + params.trackSend(getID(), getLastEdited()); } return appendState; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 118ea79b6e..514a9b391b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -177,7 +177,7 @@ public: } } - std::function trackSend { [](const QUuid&){} }; + std::function trackSend { [](const QUuid&, quint64){} }; }; class ReadElementBufferToTreeArgs { From 4497d21aecde9b69babd1434252c599ed76f1f56 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 14:49:04 -0800 Subject: [PATCH 113/165] remove nodes that disconnect from out viewer stats --- assignment-client/src/entities/EntityServer.cpp | 10 +++++++--- assignment-client/src/entities/EntityServer.h | 1 + assignment-client/src/octree/OctreeServer.cpp | 2 ++ assignment-client/src/octree/OctreeServer.h | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 2b53cc9314..f37e8cf3f7 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -269,14 +269,18 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio // FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad -// set of stats to have, but we'd probably want a different data-structure if we keep it very long. -// Since this version uses a single shared QMap for all senders, there can be a fair amount of lock -// contention on this QWriteLocker +// set of stats to have, but we'd probably want a different data structure if we keep it very long. +// Since this version uses a single shared QMap for all senders, there could be some lock contention +// on this QWriteLocker void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { QWriteLocker locker(&_viewerSendingStatsLock); _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; } +void EntityServer::trackViewerGone(const QUuid& viewerNode) { + QWriteLocker locker(&_viewerSendingStatsLock); + _viewerSendingStats.remove(viewerNode); +} QString EntityServer::serverSubclassStats() { QLocale locale(QLocale::English); diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d39e966430..89b445c449 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -53,6 +53,7 @@ public: virtual QString serverSubclassStats(); virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); + virtual void trackViewerGone(const QUuid& viewerNode); public slots: void pruneDeletedEntities(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c5072d0175..dead61d65a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1184,6 +1184,8 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { if (usecsElapsed > 1000) { qDebug() << qPrintable(_safeServerName) << "server nodeKilled() took: " << usecsElapsed << " usecs for node:" << *node; } + + trackViewerGone(node->getUUID()); } void OctreeServer::forceNodeShutdown(SharedNodePointer node) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 9876f5147c..f3a5191335 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -81,6 +81,7 @@ public: virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } virtual QString serverSubclassStats() { return QString(); } virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { } + virtual void trackViewerGone(const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times From b56cf58e337550094b6f811caa1bbec106acb7e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 16:55:04 -0800 Subject: [PATCH 114/165] Fix for mirrored transforms in FBX models extractScale will now return negative scale for left-handed matrices. --- libraries/shared/src/GLMHelpers.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index e6fbe5e5cc..257ef2f00e 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -285,7 +285,14 @@ glm::quat glmExtractRotation(const glm::mat4& matrix) { } glm::vec3 extractScale(const glm::mat4& matrix) { - return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); + glm::mat3 m(matrix); + float det = glm::determinant(m); + if (det < 0) { + // left handed matrix, flip sign to compensate. + return glm::vec3(-glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } else { + return glm::vec3(glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } } float extractUniformScale(const glm::mat4& matrix) { From 4f836568ad43ed2a0b8833fbbf35acad7f5c2f52 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 17:26:32 -0800 Subject: [PATCH 115/165] Tests to verify AnimPose decomposition is working. --- tests/animation/src/AnimTests.cpp | 91 +++++++++++++++++++++++++++---- tests/animation/src/AnimTests.h | 1 + 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 1b5bb4739a..64db3f6154 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -194,10 +194,7 @@ void AnimTests::testVariant() { auto floatVarNegative = AnimVariant(-1.0f); auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f)); auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f)); - auto mat4Var = AnimVariant(glm::mat4(glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), - glm::vec4(5.0f, 6.0f, -7.0f, 8.0f), - glm::vec4(9.0f, 10.0f, 11.0f, 12.0f), - glm::vec4(13.0f, 14.0f, 15.0f, 16.0f))); + QVERIFY(defaultVar.isBool()); QVERIFY(defaultVar.getBool() == false); @@ -232,12 +229,6 @@ void AnimTests::testVariant() { QVERIFY(q.x == 2.0f); QVERIFY(q.y == -3.0f); QVERIFY(q.z == 4.0f); - - QVERIFY(mat4Var.isMat4()); - auto m = mat4Var.getMat4(); - QVERIFY(m[0].x == 1.0f); - QVERIFY(m[1].z == -7.0f); - QVERIFY(m[3].w == 16.0f); } void AnimTests::testAccumulateTime() { @@ -323,3 +314,83 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop"); triggers.clear(); } + + +void AnimTests::testAnimPose() { + const float PI = (float)M_PI; + const glm::quat ROT_X_90 = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat ROT_Y_180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0, 0.0f)); + const glm::quat ROT_Z_30 = glm::angleAxis(PI / 6.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + std::vector scaleVec = { + glm::vec3(1), + glm::vec3(2.0f, 1.0f, 1.0f), + glm::vec3(1.0f, 0.5f, 1.0f), + glm::vec3(1.0f, 1.0f, 1.5f), + glm::vec3(2.0f, 0.5f, 1.5f), + glm::vec3(-2.0f, 0.5f, 1.5f), + glm::vec3(2.0f, -0.5f, 1.5f), + glm::vec3(2.0f, 0.5f, -1.5f), + glm::vec3(-2.0f, -0.5f, -1.5f), + }; + + std::vector rotVec = { + glm::quat(), + ROT_X_90, + ROT_Y_180, + ROT_Z_30, + ROT_X_90 * ROT_Y_180 * ROT_Z_30, + -ROT_Y_180 + }; + + std::vector transVec = { + glm::vec3(), + glm::vec3(10.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 5.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 7.5f), + glm::vec3(10.0f, 5.0f, 7.5f), + glm::vec3(-10.0f, 5.0f, 7.5f), + glm::vec3(10.0f, -5.0f, 7.5f), + glm::vec3(10.0f, 5.0f, -7.5f) + }; + + const float EPSILON = 0.001f; + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to build a matrix by parts. + AnimPose pose(scale, rot, trans); + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to decompse a matrix into parts + AnimPose pose(rawMat); + + // now build a new matrix from those parts. + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } +} diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index 7bd05369c7..a07217b91a 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -26,6 +26,7 @@ private slots: void testLoader(); void testVariant(); void testAccumulateTime(); + void testAnimPose(); }; #endif // hifi_AnimTests_h From dec4cd012e62fdf62d5fed843f087d7084d66d26 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 18:26:09 -0800 Subject: [PATCH 116/165] made ping pong gun have restitution of 0 --- unpublishedScripts/hiddenEntityReset.js | 1 + unpublishedScripts/masterReset.js | 1 + 2 files changed, 2 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 48745715f9..7e1391780d 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1027,6 +1027,7 @@ y: -9.8, z: 0 }, + restitution: 0, dimensions: { x: 0.08, y: 0.21, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6a870f988f..2fbeb94865 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1007,6 +1007,7 @@ MasterReset = function() { y: -9.8, z: 0 }, + restitution: 0, dimensions: { x: 0.08, y: 0.21, From 7a05a664f4e05d1d6334d625060afd2353a6c001 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 2 Dec 2015 16:47:48 -0800 Subject: [PATCH 117/165] Updating GPU for 64 bit --- libraries/gpu/src/gpu/Batch.cpp | 6 +- libraries/gpu/src/gpu/Batch.h | 16 ++-- libraries/gpu/src/gpu/Format.h | 2 +- libraries/gpu/src/gpu/GLBackend.cpp | 46 +++++----- libraries/gpu/src/gpu/GLBackend.h | 90 ++++++++++---------- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 2 +- libraries/gpu/src/gpu/GLBackendInput.cpp | 18 ++-- libraries/gpu/src/gpu/GLBackendOutput.cpp | 6 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 6 +- libraries/gpu/src/gpu/GLBackendQuery.cpp | 6 +- libraries/gpu/src/gpu/GLBackendState.cpp | 4 +- libraries/gpu/src/gpu/GLBackendTransform.cpp | 22 ++--- libraries/gpu/src/gpu/Resource.h | 4 +- libraries/gpu/src/gpu/Stream.h | 15 ++-- 14 files changed, 121 insertions(+), 122 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 2e3ea7fc36..80b3a4f158 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -80,9 +80,9 @@ void Batch::clear() { _framebuffers.clear(); } -uint32 Batch::cacheData(uint32 size, const void* data) { - uint32 offset = _data.size(); - uint32 numBytes = size; +size_t Batch::cacheData(size_t size, const void* data) { + size_t offset = _data.size(); + size_t numBytes = size; _data.resize(offset + numBytes); memcpy(_data.data() + offset, data, size); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 8397f92da6..258f6d6488 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -334,7 +334,7 @@ public: NUM_COMMANDS, }; typedef std::vector Commands; - typedef std::vector CommandOffsets; + typedef std::vector CommandOffsets; const Commands& getCommands() const { return _commands; } const CommandOffsets& getCommandOffsets() const { return _commandOffsets; } @@ -342,11 +342,13 @@ public: class Param { public: union { + size_t _size; int32 _int; uint32 _uint; - float _float; - char _chars[4]; + float _float; + char _chars[sizeof(size_t)]; }; + Param(size_t val) : _size(val) {} Param(int32 val) : _int(val) {} Param(uint32 val) : _uint(val) {} Param(float val) : _float(val) {} @@ -370,8 +372,8 @@ public: std::vector< Cache > _items; size_t size() const { return _items.size(); } - uint32 cache(const Data& data) { - uint32 offset = _items.size(); + size_t cache(const Data& data) { + size_t offset = _items.size(); _items.push_back(Cache(data)); return offset; } @@ -403,8 +405,8 @@ public: // FOr example Mat4s are going there typedef unsigned char Byte; typedef std::vector Bytes; - uint32 cacheData(uint32 size, const void* data); - Byte* editData(uint32 offset) { + size_t cacheData(size_t size, const void* data); + Byte* editData(size_t offset) { if (offset >= _data.size()) { return 0; } diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index ff0fd9faea..3022f47b51 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -33,7 +33,7 @@ typedef char int8; typedef unsigned char Byte; -typedef uint32 Offset; +typedef size_t Offset; typedef glm::mat4 Mat4; typedef glm::mat3 Mat3; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index e49a3ba6c0..d4f3c5c4b3 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -304,7 +304,7 @@ void GLBackend::syncCache() { glEnable(GL_LINE_SMOOTH); } -void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { +void GLBackend::do_draw(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -317,7 +317,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -336,7 +336,7 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -351,7 +351,7 @@ void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -378,7 +378,7 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) { #if (GPU_INPUT_PROFILE == GPU_CORE_43) updateInput(); updateTransform(); @@ -387,7 +387,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { uint commandCount = batch._params[paramOffset + 0]._uint; GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; - glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, _input._indirectBufferStride); + glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); #else // FIXME implement the slow path #endif @@ -395,7 +395,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) { #if (GPU_INPUT_PROFILE == GPU_CORE_43) updateInput(); updateTransform(); @@ -405,7 +405,7 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; GLenum indexType = _elementTypeToGLType[_input._indexBufferType]; - glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, _input._indirectBufferStride); + glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); #else // FIXME implement the slow path #endif @@ -413,11 +413,11 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) { +void GLBackend::do_resetStages(Batch& batch, size_t paramOffset) { resetStages(); } -void GLBackend::do_runLambda(Batch& batch, uint32 paramOffset) { +void GLBackend::do_runLambda(Batch& batch, size_t paramOffset) { std::function f = batch._lambdas.get(batch._params[paramOffset]._uint); f(); } @@ -455,7 +455,7 @@ void Batch::_glActiveBindTexture(GLenum unit, GLenum target, GLuint texture) { DO_IT_NOW(_glActiveBindTexture, 3); } -void GLBackend::do_glActiveBindTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glActiveBindTexture(Batch& batch, size_t paramOffset) { glActiveTexture(batch._params[paramOffset + 2]._uint); glBindTexture( batch._params[paramOffset + 1]._uint, @@ -474,7 +474,7 @@ void Batch::_glUniform1i(GLint location, GLint v0) { DO_IT_NOW(_glUniform1i, 1); } -void GLBackend::do_glUniform1i(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -497,7 +497,7 @@ void Batch::_glUniform1f(GLint location, GLfloat v0) { DO_IT_NOW(_glUniform1f, 1); } -void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform1f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -521,7 +521,7 @@ void Batch::_glUniform2f(GLint location, GLfloat v0, GLfloat v1) { DO_IT_NOW(_glUniform2f, 1); } -void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform2f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -546,7 +546,7 @@ void Batch::_glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { DO_IT_NOW(_glUniform3f, 1); } -void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform3f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -575,7 +575,7 @@ void Batch::_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLf } -void GLBackend::do_glUniform4f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -601,7 +601,7 @@ void Batch::_glUniform3fv(GLint location, GLsizei count, const GLfloat* value) { DO_IT_NOW(_glUniform3fv, 3); } -void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform3fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -627,7 +627,7 @@ void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) { DO_IT_NOW(_glUniform4fv, 3); } -void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -653,7 +653,7 @@ void Batch::_glUniform4iv(GLint location, GLsizei count, const GLint* value) { DO_IT_NOW(_glUniform4iv, 3); } -void GLBackend::do_glUniform4iv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -679,7 +679,7 @@ void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpo DO_IT_NOW(_glUniformMatrix4fv, 4); } -void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -704,7 +704,7 @@ void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DO_IT_NOW(_glColor4f, 4); } -void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glColor4f(Batch& batch, size_t paramOffset) { glm::vec4 newColor( batch._params[paramOffset + 3]._float, @@ -720,14 +720,14 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_pushProfileRange(Batch& batch, uint32 paramOffset) { +void GLBackend::do_pushProfileRange(Batch& batch, size_t paramOffset) { #if defined(NSIGHT_FOUND) auto name = batch._profileRanges.get(batch._params[paramOffset]._uint); nvtxRangePush(name.c_str()); #endif } -void GLBackend::do_popProfileRange(Batch& batch, uint32 paramOffset) { +void GLBackend::do_popProfileRange(Batch& batch, size_t paramOffset) { #if defined(NSIGHT_FOUND) nvtxRangePop(); #endif diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 9f1e17205c..f44fbe6c0d 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -195,17 +195,17 @@ public: static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; - uint32 getNumInputBuffers() const { return _input._invalidBuffers.size(); } + size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_UNIFORM_BUFFERS = 12; - uint32 getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } + size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_RESOURCE_TEXTURES = 16; - uint32 getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } + size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } // The State setters called by the GLState::Commands when a new state is assigned void do_setStateFillMode(int32 mode); @@ -248,18 +248,18 @@ protected: Stats _stats; // Draw Stage - void do_draw(Batch& batch, uint32 paramOffset); - void do_drawIndexed(Batch& batch, uint32 paramOffset); - void do_drawInstanced(Batch& batch, uint32 paramOffset); - void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); - void do_multiDrawIndirect(Batch& batch, uint32 paramOffset); - void do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset); + void do_draw(Batch& batch, size_t paramOffset); + void do_drawIndexed(Batch& batch, size_t paramOffset); + void do_drawInstanced(Batch& batch, size_t paramOffset); + void do_drawIndexedInstanced(Batch& batch, size_t paramOffset); + void do_multiDrawIndirect(Batch& batch, size_t paramOffset); + void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset); // Input Stage - void do_setInputFormat(Batch& batch, uint32 paramOffset); - void do_setInputBuffer(Batch& batch, uint32 paramOffset); - void do_setIndexBuffer(Batch& batch, uint32 paramOffset); - void do_setIndirectBuffer(Batch& batch, uint32 paramOffset); + void do_setInputFormat(Batch& batch, size_t paramOffset); + void do_setInputBuffer(Batch& batch, size_t paramOffset); + void do_setIndexBuffer(Batch& batch, size_t paramOffset); + void do_setIndirectBuffer(Batch& batch, size_t paramOffset); void initInput(); void killInput(); @@ -310,11 +310,11 @@ protected: } _input; // Transform Stage - void do_setModelTransform(Batch& batch, uint32 paramOffset); - void do_setViewTransform(Batch& batch, uint32 paramOffset); - void do_setProjectionTransform(Batch& batch, uint32 paramOffset); - void do_setViewportTransform(Batch& batch, uint32 paramOffset); - void do_setDepthRangeTransform(Batch& batch, uint32 paramOffset); + void do_setModelTransform(Batch& batch, size_t paramOffset); + void do_setViewTransform(Batch& batch, size_t paramOffset); + void do_setProjectionTransform(Batch& batch, size_t paramOffset); + void do_setViewportTransform(Batch& batch, size_t paramOffset); + void do_setDepthRangeTransform(Batch& batch, size_t paramOffset); void initTransform(); void killTransform(); @@ -362,7 +362,7 @@ protected: // Uniform Stage - void do_setUniformBuffer(Batch& batch, uint32 paramOffset); + void do_setUniformBuffer(Batch& batch, size_t paramOffset); void releaseUniformBuffer(uint32_t slot); void resetUniformStage(); @@ -375,7 +375,7 @@ protected: } _uniform; // Resource Stage - void do_setResourceTexture(Batch& batch, uint32 paramOffset); + void do_setResourceTexture(Batch& batch, size_t paramOffset); void releaseResourceTexture(uint32_t slot); void resetResourceStage(); @@ -390,9 +390,9 @@ protected: size_t _commandIndex{ 0 }; // Pipeline Stage - void do_setPipeline(Batch& batch, uint32 paramOffset); - void do_setStateBlendFactor(Batch& batch, uint32 paramOffset); - void do_setStateScissorRect(Batch& batch, uint32 paramOffset); + void do_setPipeline(Batch& batch, size_t paramOffset); + void do_setStateBlendFactor(Batch& batch, size_t paramOffset); + void do_setStateScissorRect(Batch& batch, size_t paramOffset); // Standard update pipeline check that the current Program and current State or good to go for a void updatePipeline(); @@ -429,9 +429,9 @@ protected: } _pipeline; // Output stage - void do_setFramebuffer(Batch& batch, uint32 paramOffset); - void do_clearFramebuffer(Batch& batch, uint32 paramOffset); - void do_blit(Batch& batch, uint32 paramOffset); + void do_setFramebuffer(Batch& batch, size_t paramOffset); + void do_clearFramebuffer(Batch& batch, size_t paramOffset); + void do_blit(Batch& batch, size_t paramOffset); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); @@ -446,9 +446,9 @@ protected: } _output; // Query section - void do_beginQuery(Batch& batch, uint32 paramOffset); - void do_endQuery(Batch& batch, uint32 paramOffset); - void do_getQuery(Batch& batch, uint32 paramOffset); + void do_beginQuery(Batch& batch, size_t paramOffset); + void do_endQuery(Batch& batch, size_t paramOffset); + void do_getQuery(Batch& batch, size_t paramOffset); void resetQueryStage(); struct QueryStageState { @@ -456,33 +456,33 @@ protected: }; // Reset stages - void do_resetStages(Batch& batch, uint32 paramOffset); + void do_resetStages(Batch& batch, size_t paramOffset); - void do_runLambda(Batch& batch, uint32 paramOffset); + void do_runLambda(Batch& batch, size_t paramOffset); void resetStages(); // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - void do_glActiveBindTexture(Batch& batch, uint32 paramOffset); + void do_glActiveBindTexture(Batch& batch, size_t paramOffset); - void do_glUniform1i(Batch& batch, uint32 paramOffset); - void do_glUniform1f(Batch& batch, uint32 paramOffset); - void do_glUniform2f(Batch& batch, uint32 paramOffset); - void do_glUniform3f(Batch& batch, uint32 paramOffset); - void do_glUniform4f(Batch& batch, uint32 paramOffset); - void do_glUniform3fv(Batch& batch, uint32 paramOffset); - void do_glUniform4fv(Batch& batch, uint32 paramOffset); - void do_glUniform4iv(Batch& batch, uint32 paramOffset); - void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset); + void do_glUniform1i(Batch& batch, size_t paramOffset); + void do_glUniform1f(Batch& batch, size_t paramOffset); + void do_glUniform2f(Batch& batch, size_t paramOffset); + void do_glUniform3f(Batch& batch, size_t paramOffset); + void do_glUniform4f(Batch& batch, size_t paramOffset); + void do_glUniform3fv(Batch& batch, size_t paramOffset); + void do_glUniform4fv(Batch& batch, size_t paramOffset); + void do_glUniform4iv(Batch& batch, size_t paramOffset); + void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset); - void do_glColor4f(Batch& batch, uint32 paramOffset); + void do_glColor4f(Batch& batch, size_t paramOffset); - void do_pushProfileRange(Batch& batch, uint32 paramOffset); - void do_popProfileRange(Batch& batch, uint32 paramOffset); + void do_pushProfileRange(Batch& batch, size_t paramOffset); + void do_popProfileRange(Batch& batch, size_t paramOffset); - typedef void (GLBackend::*CommandCall)(Batch&, uint32); + typedef void (GLBackend::*CommandCall)(Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; }; diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 3eeedc5dc3..49aeeca38e 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -46,7 +46,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); object->_stamp = buffer.getSysmem().getStamp(); - object->_size = buffer.getSysmem().getSize(); + object->_size = (GLuint)buffer.getSysmem().getSize(); //} (void) CHECK_GL_ERROR(); diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index 5cdcf0adc6..75f4be3cbe 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -12,7 +12,7 @@ using namespace gpu; -void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) { Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); if (format != _input._format) { @@ -21,7 +21,7 @@ void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setInputBuffer(Batch& batch, size_t paramOffset) { Offset stride = batch._params[paramOffset + 0]._uint; Offset offset = batch._params[paramOffset + 1]._uint; BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); @@ -232,14 +232,14 @@ void GLBackend::updateInput() { GLenum type = _elementTypeToGLType[attrib._element.getType()]; // GLenum perLocationStride = strides[bufferNum]; GLenum perLocationStride = attrib._element.getLocationSize(); - GLuint stride = strides[bufferNum]; - GLuint pointer = attrib._offset + offsets[bufferNum]; + GLuint stride = (GLuint)strides[bufferNum]; + GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]); GLboolean isNormalized = attrib._element.isNormalized(); for (size_t locNum = 0; locNum < locationCount; ++locNum) { - glVertexAttribPointer(slot + locNum, count, type, isNormalized, stride, - reinterpret_cast(pointer + perLocationStride * locNum)); - glVertexAttribDivisor(slot + locNum, attrib._frequency); + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); } // TODO: Support properly the IAttrib version @@ -287,7 +287,7 @@ void GLBackend::resetInputStage() { } -void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) { _input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint; _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; @@ -304,7 +304,7 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_setIndirectBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setIndirectBuffer(Batch& batch, size_t paramOffset) { _input._indirectBufferOffset = batch._params[paramOffset + 1]._uint; _input._indirectBufferStride = batch._params[paramOffset + 2]._uint; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 2bcd7e31d8..3ae8ee5435 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -196,7 +196,7 @@ void GLBackend::resetOutputStage() { } } -void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) { auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); if (_output._framebuffer != framebuffer) { auto newFBO = getFramebufferID(framebuffer); @@ -208,7 +208,7 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_clearFramebuffer(Batch& batch, size_t paramOffset) { if (_stereo._enable && !_pipeline._stateCache.scissorEnable) { qWarning("Clear without scissor in stereo mode"); } @@ -298,7 +298,7 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_blit(Batch& batch, uint32 paramOffset) { +void GLBackend::do_blit(Batch& batch, size_t paramOffset) { auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); Vec4i srcvp; for (size_t i = 0; i < 4; ++i) { diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 8dd5242c3a..8601c7512b 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -57,7 +57,7 @@ GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) { return object; } -void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) { PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint); if (_pipeline._pipeline == pipeline) { @@ -168,7 +168,7 @@ void GLBackend::resetUniformStage() { } } -void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 3]._uint; BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); GLintptr rangeStart = batch._params[paramOffset + 1]._uint; @@ -237,7 +237,7 @@ void GLBackend::resetResourceStage() { } } -void GLBackend::do_setResourceTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 1]._uint; TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index 5772a09943..0a76d38963 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -60,7 +60,7 @@ GLuint GLBackend::getQueryID(const QueryPointer& query) { } } -void GLBackend::do_beginQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { @@ -74,7 +74,7 @@ void GLBackend::do_beginQuery(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_endQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { @@ -88,7 +88,7 @@ void GLBackend::do_endQuery(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_getQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 895d0a0027..64bd87c876 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -763,7 +763,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) { } -void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) { Vec4 factor(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float, @@ -774,7 +774,7 @@ void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_setStateScissorRect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setStateScissorRect(Batch& batch, size_t paramOffset) { Vec4i rect; memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 963cab778f..686b52296f 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -15,22 +15,22 @@ using namespace gpu; // Transform Stage -void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setModelTransform(Batch& batch, size_t paramOffset) { _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidModel = true; } -void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setViewTransform(Batch& batch, size_t paramOffset) { _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidView = true; } -void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setProjectionTransform(Batch& batch, size_t paramOffset) { memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4)); _transform._invalidProj = true; } -void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) { memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); ivec4& vp = _transform._viewport; @@ -49,7 +49,7 @@ void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) { _transform._invalidViewport = true; } -void GLBackend::do_setDepthRangeTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) { Vec2 depthRange(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float); @@ -142,7 +142,8 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo } void GLBackend::TransformStageState::transfer() const { - static QByteArray bufferData; + // FIXME not thread safe + static std::vector bufferData; if (!_cameras.empty()) { glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer); bufferData.resize(_cameraUboSize * _cameras.size()); @@ -168,22 +169,23 @@ void GLBackend::TransformStageState::transfer() const { } void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const { - int offset = -1; + static const size_t INVALID_OFFSET = (size_t)-1; + size_t offset = INVALID_OFFSET; while ((_objectsItr != _objectOffsets.end()) && (commandIndex >= (*_objectsItr).first)) { offset = (*_objectsItr).second; ++_objectsItr; } - if (offset >= 0) { + if (offset != INVALID_OFFSET) { glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _objectBuffer, offset, sizeof(Backend::TransformObject)); } - offset = -1; + offset = INVALID_OFFSET; while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) { offset = (*_camerasItr).second; ++_camerasItr; } - if (offset >= 0) { + if (offset != INVALID_OFFSET) { // We include both camera offsets for stereo if (stereo._enable && stereo._pass) { offset += _cameraUboSize; diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 8d53d6e2e7..794ee680f4 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -26,9 +26,9 @@ namespace gpu { class Resource { public: - typedef unsigned int Size; + typedef size_t Size; - static const Size NOT_ALLOCATED = -1; + static const Size NOT_ALLOCATED = (Size)-1; // The size in bytes of data stored in the resource virtual Size getSize() const = 0; diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 492af5f62a..4fff3b651d 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -93,19 +93,14 @@ public: }; typedef std::map< Slot, ChannelInfo > ChannelMap; - Format() : - _attributes(), - _elementTotalSize(0) {} - ~Format() {} - - uint32 getNumAttributes() const { return _attributes.size(); } + size_t getNumAttributes() const { return _attributes.size(); } const AttributeMap& getAttributes() const { return _attributes; } - uint8 getNumChannels() const { return _channels.size(); } + size_t getNumChannels() const { return _channels.size(); } const ChannelMap& getChannels() const { return _channels; } Offset getChannelStride(Slot channel) const { return _channels.at(channel)._stride; } - uint32 getElementTotalSize() const { return _elementTotalSize; } + size_t getElementTotalSize() const { return _elementTotalSize; } bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX); bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX); @@ -115,7 +110,7 @@ public: protected: AttributeMap _attributes; ChannelMap _channels; - uint32 _elementTotalSize; + uint32 _elementTotalSize { 0 }; void evaluateCache(); }; @@ -140,7 +135,7 @@ public: const Buffers& getBuffers() const { return _buffers; } const Offsets& getOffsets() const { return _offsets; } const Strides& getStrides() const { return _strides; } - uint32 getNumBuffers() const { return _buffers.size(); } + size_t getNumBuffers() const { return _buffers.size(); } BufferStream makeRangedStream(uint32 offset, uint32 count = -1) const; From 55799403c99dffebddcf4ecafed0423d20bbcad4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 2 Dec 2015 21:52:06 -0800 Subject: [PATCH 118/165] 64 bit support for Leap Motion on windows --- cmake/modules/FindLeapMotion.cmake | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/modules/FindLeapMotion.cmake b/cmake/modules/FindLeapMotion.cmake index eafb031a07..b5d6fe1b69 100644 --- a/cmake/modules/FindLeapMotion.cmake +++ b/cmake/modules/FindLeapMotion.cmake @@ -18,10 +18,16 @@ hifi_library_search_hints("leapmotion") find_path(LEAPMOTION_INCLUDE_DIRS Leap.h PATH_SUFFIXES include HINTS ${LEAPMOTION_SEARCH_DIRS}) if (WIN32) - find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) - find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) - - find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64") + else() + set(ARCH_DIR "x86") + endif() + + find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) + find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) + find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) elseif (APPLE) find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib HINTS ${LEAPMOTION_SEARCH_DIRS}) endif () From b122586ea5d5144661b9ad89fb7772f4ba5d85b6 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 08:08:04 -0800 Subject: [PATCH 119/165] remove camera cycle and context menu from standard mapping --- interface/resources/controllers/standard.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index d4988fc00d..e3f7726755 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -32,9 +32,6 @@ { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" }, { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" }, - { "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" }, - { "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" }, - { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" }, From 2d804555dec92c105bea303d13630c8b3e3740a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 08:59:15 -0800 Subject: [PATCH 120/165] minor cleanups --- libraries/shared/src/SpatiallyNestable.cpp | 37 ++++++++-------------- libraries/shared/src/SpatiallyNestable.h | 2 ++ 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 9b2e809063..688ed831e3 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -40,18 +40,17 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } - SpatiallyNestableConstPointer constThisPointer = shared_from_this(); - SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! - if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date if (!_parentKnowsMe) { - parent->beParentOfChild(thisPointer); + parent->beParentOfChild(getThisPointer()); _parentKnowsMe = true; } return parent; } + SpatiallyNestablePointer thisPointer = getThisPointer(); + if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. parent->forgetChild(thisPointer); @@ -167,21 +166,12 @@ glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, return result.getRotation(); } - glm::vec3 SpatiallyNestable::getPosition() const { - Transform parentTransformDescaled = getParentTransform(); - glm::mat4 parentMat; - parentTransformDescaled.getMatrix(parentMat); - glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); - return glm::vec3(absPos); + return getTransform().getTranslation(); } glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { - Transform worldTransform = getTransform(); - Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); - Transform jointInWorldFrame; - Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); - return jointInWorldFrame.getTranslation(); + return getTransform(jointIndex).getTranslation(); } void SpatiallyNestable::setPosition(glm::vec3 position) { @@ -195,16 +185,11 @@ void SpatiallyNestable::setPosition(glm::vec3 position) { } glm::quat SpatiallyNestable::getOrientation() const { - Transform parentTransformDescaled = getParentTransform(); - return parentTransformDescaled.getRotation() * getLocalOrientation(); + return getTransform().getRotation(); } glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { - Transform worldTransform = getTransform(); - Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); - Transform jointInWorldFrame; - Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); - return jointInWorldFrame.getRotation(); + return getTransform(jointIndex).getRotation(); } void SpatiallyNestable::setOrientation(glm::quat orientation) { @@ -228,7 +213,7 @@ const Transform SpatiallyNestable::getTransform() const { } const Transform SpatiallyNestable::getTransform(int jointIndex) const { - // this returns the world-space transform for this object. It find its parent's transform (which may + // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); @@ -341,3 +326,9 @@ const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex jointInObjectFrame.setTranslation(position); return jointInObjectFrame; } + +SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const { + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); + SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! + return thisPointer; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6e0afa24a5..b7c04e8563 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -95,6 +95,8 @@ public: virtual glm::quat getJointRotation(int index) const = 0; virtual glm::vec3 getJointTranslation(int index) const = 0; + SpatiallyNestablePointer getThisPointer() const; + protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; From c0bd54e8a25786d904d81648cf82d3dcc148427c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 09:05:26 -0800 Subject: [PATCH 121/165] change hydra secondary thumb to 0 button --- interface/resources/controllers/hydra.json | 9 ++++----- interface/resources/controllers/standard.json | 3 +++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index b517d1bad5..0193612d27 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -13,12 +13,11 @@ { "from": "Hydra.RB", "to": "Standard.RB" }, { "from": "Hydra.RS", "to": "Standard.RS" }, - { "from": [ "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftSecondaryThumb" }, - - { "from": [ "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.L0" ], "to": "Standard.LeftSecondaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.R0" ], "to": "Standard.RightSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index e3f7726755..d4988fc00d 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -32,6 +32,9 @@ { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" }, { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" }, + { "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" }, + { "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" }, + { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" }, From 38545237872ecb47ed7a2528c8b6ecd7cf80a52d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 09:17:41 -0800 Subject: [PATCH 122/165] Fixing 32 bit build breakage --- libraries/gpu/src/gpu/Batch.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 258f6d6488..da1f13151e 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -342,13 +342,17 @@ public: class Param { public: union { +#if (QT_POINTER_SIZE == 8) size_t _size; +#endif int32 _int; uint32 _uint; float _float; char _chars[sizeof(size_t)]; }; +#if (QT_POINTER_SIZE == 8) Param(size_t val) : _size(val) {} +#endif Param(int32 val) : _int(val) {} Param(uint32 val) : _uint(val) {} Param(float val) : _float(val) {} From 667d2b728e6d7e6ce977b20831ec9399040f3c08 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 3 Dec 2015 09:52:56 -0800 Subject: [PATCH 123/165] Fix uninitialized xColor value when converting script value --- libraries/entities/src/EntityItemPropertiesMacros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index b3299b6fe6..ca67aadbd6 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -257,7 +257,7 @@ inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isVal } inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - xColor newValue; + xColor newValue { 255, 255, 255 }; isValid = false; /// assume it can't be converted QScriptValue r = v.property("red"); QScriptValue g = v.property("green"); From 0c05ffe9cea631efba6cc8479c3bc4bbe406593a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 10:20:04 -0800 Subject: [PATCH 124/165] remove coverage map and occulusion culling, since it was always disabled --- .../src/octree/OctreeQueryNode.h | 2 - .../src/octree/OctreeSendThread.cpp | 7 +- interface/src/Application.cpp | 1 - libraries/octree/src/CoverageMap.cpp | 542 ------------------ libraries/octree/src/CoverageMap.h | 120 ---- libraries/octree/src/CoverageMapV2.cpp | 251 -------- libraries/octree/src/CoverageMapV2.h | 72 --- libraries/octree/src/Octree.cpp | 101 +--- libraries/octree/src/Octree.h | 9 - libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 5 +- 12 files changed, 6 insertions(+), 1107 deletions(-) delete mode 100644 libraries/octree/src/CoverageMap.cpp delete mode 100644 libraries/octree/src/CoverageMap.h delete mode 100644 libraries/octree/src/CoverageMapV2.cpp delete mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 0c691a06a2..75c841851f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -55,7 +54,6 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; - CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 0a32f574de..f873ee4808 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -350,7 +350,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } - nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -451,9 +450,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ - bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); - CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); @@ -462,7 +458,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, + boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -634,7 +630,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef10ad4464..68a809688a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3076,7 +3076,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp deleted file mode 100644 index 626d4bcf1a..0000000000 --- a/libraries/octree/src/CoverageMap.cpp +++ /dev/null @@ -1,542 +0,0 @@ -// -// CoverageMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMap.h" - -int CoverageMap::_mapCount = 0; -int CoverageMap::_checkMapRootCalls = 0; -int CoverageMap::_notAllInView = 0; -bool CoverageMap::wantDebugging = false; - -const int MAX_POLYGONS_PER_REGION = 50; - -const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); - -CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), - _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), - _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), - _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), - _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) -{ - _mapCount++; - init(); -}; - -CoverageMap::~CoverageMap() { - erase(); -}; - -void CoverageMap::printStats() { - qCDebug(octree, "CoverageMap::printStats()..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); - qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); - qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); - qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); - qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); - qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); - qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); - qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); -} - -void CoverageMap::erase() { - // tell our regions to erase() - _topHalf.erase(); - _bottomHalf.erase(); - _leftHalf.erase(); - _rightHalf.erase(); - _remainder.erase(); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMap last to be deleted..."); - printStats(); - - CoverageRegion::_maxPolygonsUsed = 0; - CoverageRegion::_totalPolygons = 0; - CoverageRegion::_occlusionTests = 0; - CoverageRegion::_regionSkips = 0; - CoverageRegion::_tooSmallSkips = 0; - CoverageRegion::_regionFullSkips = 0; - CoverageRegion::_outOfOrderPolygon = 0; - CoverageRegion::_clippedPolygons = 0; - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMap::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, right -// 1 = bottom, left -// 2 = top, right -// 3 = top, left -BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { - const int LEFT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "left" bit is set, then add size.x to the corner - if ((childIndex & LEFT_BIT) == LEFT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -int CoverageMap::getPolygonCount() const { - return (_topHalf.getPolygonCount() + - _bottomHalf.getPolygonCount() + - _leftHalf.getPolygonCount() + - _rightHalf.getPolygonCount() + - _remainder.getPolygonCount()); -} - -OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { - int base = 0; - if ((index - base) < _topHalf.getPolygonCount()) { - return _topHalf.getPolygon((index - base)); - } - base += _topHalf.getPolygonCount(); - - if ((index - base) < _bottomHalf.getPolygonCount()) { - return _bottomHalf.getPolygon((index - base)); - } - base += _bottomHalf.getPolygonCount(); - - if ((index - base) < _leftHalf.getPolygonCount()) { - return _leftHalf.getPolygon((index - base)); - } - base += _leftHalf.getPolygonCount(); - - if ((index - base) < _rightHalf.getPolygonCount()) { - return _rightHalf.getPolygon((index - base)); - } - base += _rightHalf.getPolygonCount(); - - if ((index - base) < _remainder.getPolygonCount()) { - return _remainder.getPolygon((index - base)); - } - return NULL; -} - - - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { - - if (_isRoot) { - _checkMapRootCalls++; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return DOESNT_FIT; - } - - BoundingBox polygonBox(polygon->getBoundingBox()); - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - - CoverageMapStorageResult result = NOT_STORED; - CoverageRegion* storeIn = &_remainder; - - // Check each half of the box independently - const bool useRegions = true; // for now we will continue to use regions - if (useRegions) { - if (_topHalf.contains(polygonBox)) { - result = _topHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_topHalf; - } else if (_bottomHalf.contains(polygonBox)) { - result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_bottomHalf; - } else if (_leftHalf.contains(polygonBox)) { - result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_leftHalf; - } else if (_rightHalf.contains(polygonBox)) { - result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_rightHalf; - } - } - - // if we got this far, there are one of two possibilities, either a polygon doesn't fit - // in one of the halves, or it did fit, but it wasn't occluded by anything only in that - // half. In either of these cases, we want to check our remainder region to see if its - // occluded by anything there - if (!(result == STORED || result == OCCLUDED)) { - result = _remainder.checkRegion(polygon, polygonBox, storeIt); - } - - // It's possible that this first set of checks might have resulted in an out of order polygon - // in which case we just return.. - if (result == STORED || result == OCCLUDED) { - - /* - if (result == STORED) - qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); - else - qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); - */ - - return result; - } - - // if we made it here, then it means the polygon being stored is not occluded - // at this level of the quad tree, so we can continue to insert it into the map. - // First we check to see if it fits in any of our sub maps - const bool useChildMaps = true; // for now we will continue to use child maps - if (useChildMaps) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - if (childMapBoundingBox.contains(polygon->getBoundingBox())) { - // if no child map exists yet, then create it - if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); - } - result = _childMaps[i]->checkMap(polygon, storeIt); - - /* - switch (result) { - case STORED: - qCDebug(octree, "checkMap() = STORED\n"); - break; - case NOT_STORED: - qCDebug(octree, "checkMap() = NOT_STORED\n"); - break; - case OCCLUDED: - qCDebug(octree, "checkMap() = OCCLUDED\n"); - break; - default: - qCDebug(octree, "checkMap() = ????? \n"); - break; - } - */ - - return result; - } - } - } - // if we got this far, then the polygon is in our bounding box, but doesn't fit in - // any of our child bounding boxes, so we should add it here. - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeIn->storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - CoverageRegion::_tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - return DOESNT_FIT; -} - - -CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _regionName(regionName) -{ - init(); -}; - -CoverageRegion::~CoverageRegion() { - erase(); -}; - -void CoverageRegion::init() { - _polygonCount = 0; - _polygonArraySize = 0; - _polygons = NULL; - _polygonDistances = NULL; - _polygonSizes = NULL; -} - - -void CoverageRegion::erase() { - -/** - if (_polygonCount) { - qCDebug(octree, "CoverageRegion::erase()...\n"); - qCDebug(octree, "_polygonCount=%d\n",_polygonCount); - _myBoundingBox.printDebugDetails(getRegionName()); - //for (int i = 0; i < _polygonCount; i++) { - // qCDebug(octree, "_polygons[%d]=",i); - // _polygons[i]->getBoundingBox().printDebugDetails(); - //} - } -**/ - // If we're in charge of managing the polygons, then clean them up first - if (_polygons && _managePolygons) { - for (int i = 0; i < _polygonCount; i++) { - delete _polygons[i]; - _polygons[i] = NULL; // do we need to do this? - } - } - - // Now, clean up our local storage - _polygonCount = 0; - _polygonArraySize = 0; - if (_polygons) { - delete[] _polygons; - _polygons = NULL; - } - if (_polygonDistances) { - delete[] _polygonDistances; - _polygonDistances = NULL; - } - if (_polygonSizes) { - delete[] _polygonSizes; - _polygonSizes = NULL; - } -} - -void CoverageRegion::growPolygonArray() { - OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - - - if (_polygons) { - memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); - delete[] _polygons; - memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); - delete[] _polygonDistances; - memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); - delete[] _polygonSizes; - } - _polygons = newPolygons; - _polygonDistances = newDistances; - _polygonSizes = newSizes; - _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -} - -const char* CoverageRegion::getRegionName() const { - switch (_regionName) { - case TOP_HALF: - return "TOP_HALF"; - case BOTTOM_HALF: - return "BOTTOM_HALF"; - case LEFT_HALF: - return "LEFT_HALF"; - case RIGHT_HALF: - return "RIGHT_HALF"; - default: - case REMAINDER: - return "REMAINDER"; - } - return "REMAINDER"; -} - -int CoverageRegion::_maxPolygonsUsed = 0; -int CoverageRegion::_totalPolygons = 0; -int CoverageRegion::_occlusionTests = 0; -int CoverageRegion::_regionSkips = 0; -int CoverageRegion::_tooSmallSkips = 0; -int CoverageRegion::_regionFullSkips = 0; -int CoverageRegion::_outOfOrderPolygon = 0; -int CoverageRegion::_clippedPolygons = 0; - - -bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* otherPolygon = _polygons[i]; - if (otherPolygon->canMerge(*seed)) { - otherPolygon->merge(*seed); - - if (seedInArray) { - int* IGNORED_ADDRESS = NULL; - // remove this otherOtherPolygon for our polygon array - _polygonCount = removeFromSortedArrays((void*)seed, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - _totalPolygons--; - } - - // clean up - if (_managePolygons) { - delete seed; - } - - // Now run again using our newly merged polygon as the seed - mergeItemsInArray(otherPolygon, true); - - return true; - } - } - return false; -} - -// just handles storage in the array, doesn't test for occlusion or -// determining if this is the correct map to store in! -void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { - - _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); - - - // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing - // polygons already in our array. - if (mergeItemsInArray(polygon, false)) { - return; // exit early - } - - // only after we attempt to merge! - _totalPolygons++; - - if (_polygonArraySize < _polygonCount + 1) { - growPolygonArray(); - } - - // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order - // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier - // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since - // sometimes things come out of order. - const bool SORT_BY_SIZE = false; - const int IGNORED = 0; - int* IGNORED_ADDRESS = NULL; - if (SORT_BY_SIZE) { - // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to - // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the - // insertion point in this array, and shift the array accordingly - float area = polygon->getBoundingBox().area(); - float reverseArea = 4.0f - area; - _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, - (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } else { - _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } - - // Debugging and Optimization Tuning code. - if (_polygonCount > _maxPolygonsUsed) { - _maxPolygonsUsed = _polygonCount; - } -} - - - -CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { - - CoverageMapStorageResult result = DOESNT_FIT; - - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - result = NOT_STORED; // if we got here, then we DO fit... - - // only actually check the polygons if this polygon is in the covered bounds for this region - if (!_currentCoveredBounds.contains(polygonBox)) { - _regionSkips += _polygonCount; - } else { - // check to make sure this polygon isn't occluded by something at this level - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; - - // Check to make sure that the polygon in question is "behind" the polygon in the list - // otherwise, we don't need to test it's occlusion (although, it means we've potentially - // added an item previously that may be occluded??? Is that possible? Maybe not, because two - // voxels can't have the exact same outline. So one occludes the other, they can't both occlude - // each other. - - _occlusionTests++; - if (polygonAtThisLevel->occludes(*polygon)) { - // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't - // want to report our inserted one as occluded, but we do want to add our inserted one. - if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { - _outOfOrderPolygon++; - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - _tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - // this polygon is occluded by a closer polygon, so don't store it, and let the caller know - return OCCLUDED; - } - } - } - } - return result; -} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h deleted file mode 100644 index bff6bb1078..0000000000 --- a/libraries/octree/src/CoverageMap.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// CoverageMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CoverageMap_h -#define hifi_CoverageMap_h - -#include -#include "OctreeProjectedPolygon.h" - -typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; -typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; - -class CoverageRegion { - -public: - - CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); - ~CoverageRegion(); - - CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); - void storeInArray(OctreeProjectedPolygon* polygon); - - bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; - void erase(); // erase the coverage region - - static int _maxPolygonsUsed; - static int _totalPolygons; - static int _occlusionTests; - static int _regionSkips; - static int _tooSmallSkips; - static int _regionFullSkips; - static int _outOfOrderPolygon; - static int _clippedPolygons; - - - const char* getRegionName() const; - - int getPolygonCount() const { return _polygonCount; }; - OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon - bool _managePolygons; // will the coverage map delete the polygons on destruct - RegionName _regionName; - int _polygonCount; // how many polygons at this level - int _polygonArraySize; // how much room is there to store polygons at this level - OctreeProjectedPolygon** _polygons; - - // we will use one or the other of these depending on settings in the code. - float* _polygonDistances; - float* _polygonSizes; - void growPolygonArray(); - static const int DEFAULT_GROW_SIZE = 100; - - bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); - -}; - -class CoverageMap { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT=false; - static const bool IS_ROOT=true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - - CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); - ~CoverageMap(); - - CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - - void erase(); // erase the coverage map - void printStats(); - - static bool wantDebugging; - - int getPolygonCount() const; - OctreeProjectedPolygon* getPolygon(int index) const; - CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; - bool _managePolygons; // will the coverage map delete the polygons on destruct - - // We divide the map into 5 regions representing each possible half of the map, and the whole map - // this allows us to keep the list of polygons shorter - CoverageRegion _topHalf; - CoverageRegion _bottomHalf; - CoverageRegion _leftHalf; - CoverageRegion _rightHalf; - CoverageRegion _remainder; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp deleted file mode 100644 index 8467ea1ee9..0000000000 --- a/libraries/octree/src/CoverageMapV2.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// CoverageMapV2.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMapV2.h" - -int CoverageMapV2::_mapCount = 0; -int CoverageMapV2::_checkMapRootCalls = 0; -int CoverageMapV2::_notAllInView = 0; -bool CoverageMapV2::wantDebugging = false; - -const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); -const float CoverageMapV2::NOT_COVERED = FLT_MAX; -const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly - - -CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _isCovered(isCovered), - _coveredDistance(coverageDistance) -{ - _mapCount++; - init(); -}; - -CoverageMapV2::~CoverageMapV2() { - erase(); -}; - -void CoverageMapV2::erase() { - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMapV2 last to be deleted..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMapV2::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, left -// 1 = bottom, right -// 2 = top, left -// 3 = top, right -BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { - const int RIGHT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "right" bit is set, then add size.x to the corner - if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { - assert(_isRoot); // you can only call this on the root map!!! - _checkMapRootCalls++; - - // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our - // covered depth, then this polygon is occluded! - if (_isCovered && _coveredDistance < polygon->getDistance()) { - return V2_OCCLUDED; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return V2_DOESNT_FIT; - } - - // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. - // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered - // state of the polygon. - // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map - // items is not covered, then our polygon is not covered. - bool seenOccludedMapNodes = false; - bool allOccludedMapNodesCovered = false; - - recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon - // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon - if (allOccludedMapNodesCovered) { - return V2_OCCLUDED; - } - if (storeIt) { - return V2_STORED; // otherwise report that we STORED it - } - return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't -} - -void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { - - // if we are really small, then we act like we don't intersect, this allows us to stop - // recusing as we get to the smalles edge of the polygon - if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { - return; // stop recursion, we're done! - } - - // Determine if this map node intersects the polygon and/or is fully covered by the polygon - // There are a couple special cases: If we're the root, we are assumed to intersect with all - // polygons. Also, any map node that is fully occluded also intersects. - bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); - bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); - - // If we don't intersect, then we can just return, we're done recursing - if (!nodeIsIntersectedByPolygon) { - return; // stop recursion, we're done! - } - - // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it - // as if the node was fully covered, because this allows us to short circuit further recursion... - if (_isCovered && _coveredDistance < polygon->getDistance()) { - nodeIsCoveredByPolygon = true; // fake it till you make it - } - - // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but - // we do need to do some bookkeeping. - if (nodeIsCoveredByPolygon) { - // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered - // to be our current covered state. This has the following effect: if this node isn't already covered, then by - // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. - if (!seenOccludedMapNodes) { - allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); - // We need to mark that we've seen at least one node of our polygon! ;) - seenOccludedMapNodes = true; - } else { - // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state - allOccludedMapNodesCovered = allOccludedMapNodesCovered && - (_isCovered && _coveredDistance < polygon->getDistance()); - } - - // if we're in store mode then we want to record that this node is covered. - if (storeIt) { - _isCovered = true; - // store the minimum distance of our previous known distance, or our current polygon's distance. This is because - // we know that we're at least covered at this distance, but if we had previously identified that we're covered - // at a shallower distance, then we want to maintain that distance - _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); - - // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because - // we're trying to maintain the known distances in the lower portion of the tree. - } - - // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map - // nodes will also be covered. - return; - } - - // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect - // with the polygon. - - // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. - // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered - bool allChildrenOccluded = true; - float maxChildCoveredDepth = NOT_COVERED; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - // if no child map exists yet, then create it - if (!_childMaps[i]) { - // children get created with the coverage state of their parent. - _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); - } - - _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // if so far, all of our children are covered, then record our furthest coverage distance - if (allChildrenOccluded && _childMaps[i]->_isCovered) { - maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); - } else { - // otherwise, at least one of our children is not covered, so not all are covered - allChildrenOccluded = false; - } - } - // if all the children are covered, this makes our quad tree "shallower" because it records that - // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through - // we won't assume its occluded - if (allChildrenOccluded && storeIt) { - _isCovered = true; - _coveredDistance = maxChildCoveredDepth; - } - - // normal exit case... return... -} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h deleted file mode 100644 index fc9a3ea70e..0000000000 --- a/libraries/octree/src/CoverageMapV2.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// CoverageMapV2.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CoverageMapV2_h -#define hifi_CoverageMapV2_h - -#include - -#include "OctreeProjectedPolygon.h" - -typedef enum { - V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, - V2_INTERSECT, V2_NO_INTERSECT, - V2_OCCLUDED, V2_NOT_OCCLUDED -} CoverageMapV2StorageResult; - -class CoverageMapV2 { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT = false; - static const bool IS_ROOT = true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - static const float NOT_COVERED; - static const float MINIMUM_OCCLUSION_CHECK_AREA; - static bool wantDebugging; - - CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, - bool isCovered = false, float coverageDistance = NOT_COVERED); - ~CoverageMapV2(); - - CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; - CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; - bool isCovered() const { return _isCovered; }; - - void erase(); // erase the coverage map - - void render(); - - -private: - void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); - - void init(); - - bool _isRoot; - BoundingBox _myBoundingBox; - CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; - - bool _isCovered; - float _coveredDistance; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c02a034778..1960537ced 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,7 +41,6 @@ #include #include -#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -1103,31 +1102,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } - - // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. - // leaf occlusion is handled down below when we check child nodes - if (params.wantOcclusionCulling && !element->isLeaf()) { - OctreeProjectedPolygon* voxelPolygon = - new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); - delete voxelPolygon; // cleanup - if (result == OCCLUDED) { - if (params.stats) { - params.stats->skippedOccluded(element); - } - params.stopReason = EncodeBitstreamParams::OCCLUDED; - return bytesAtThisLevel; - } - } else { - // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but - // we do need to clean up memory and proceed as normal... - delete voxelPolygon; - } - } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1190,20 +1164,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - if (params.wantOcclusionCulling) { - if (childElement) { - float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - - currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, - sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); - } - } else { - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; - } + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; // track stats // must check childElement here, because it could be we got here with no childElement @@ -1255,36 +1219,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded - // If the user also asked for occlusion culling, check if this element is occluded - if (params.wantOcclusionCulling && childElement->isLeaf()) { - // Don't check occlusion here, just add them to our distance ordered array... - - // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. - OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( - params.viewFrustum->getProjectedPolygon(childElement->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); - - // In all cases where the shadow wasn't stored, we need to free our own memory. - // In the case where it is stored, the CoverageMap will free memory for us later. - if (result != STORED) { - delete voxelPolygon; - } - - // If while attempting to add this voxel's shadow, we determined it was occluded, then - // we don't need to process it further and we can exit early. - if (result == OCCLUDED) { - childIsOccluded = true; - } - } else { - delete voxelPolygon; - } - } // wants occlusion culling & isLeaf() - - bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1613,33 +1547,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for - - // reshuffle here... - if (continueThisLevel && params.wantOcclusionCulling) { - unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; - - unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination - - // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree - // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them - // back into original distance order - for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - int thisSliceSize = recursiveSliceSizes[originalIndex]; - const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; - - memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); - tempBufferTo += thisSliceSize; - } - } - - // now that all slices are back in the correct order, copy them to the correct output buffer - continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 514a9b391b..5f5aa1432a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,7 +28,6 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" -class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -57,8 +56,6 @@ const bool NO_COLOR = false; const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; -const bool NO_OCCLUSION_CULLING = false; -const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -80,13 +77,11 @@ public: int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; - bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; - CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -113,8 +108,6 @@ public: int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, - bool wantOcclusionCulling = NO_OCCLUSION_CULLING, - CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -130,13 +123,11 @@ public: chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), - wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), - map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 88a77a4c53..b18f219d4d 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -53,7 +53,6 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index e8beb0404c..2739b4a0d1 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -43,7 +43,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -86,7 +85,6 @@ int OctreeQuery::parseData(NLPacket& packet) { _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 86474ffc02..9605cbfb5d 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -37,7 +37,7 @@ typedef unsigned long long quint64; const int WANT_LOW_RES_MOVING_BIT = 0; const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int WANT_OCCLUSION_CULLING_BIT = 3; +const int UNUSED_BIT = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -74,7 +74,6 @@ public: bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } @@ -84,7 +83,6 @@ public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } @@ -104,7 +102,6 @@ protected: bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantOcclusionCulling = false; bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations From 2cea593fbdaa4cb2f673cfed9b82d60372d5e556 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 10:20:40 -0800 Subject: [PATCH 125/165] Remove RealSense & MIDI --- cmake/modules/FindRSSDK.cmake | 33 ---- cmake/modules/FindRtMidi.cmake | 30 --- interface/CMakeLists.txt | 9 +- interface/external/rssdk/readme.txt | 9 - interface/external/rtmidi/readme.txt | 43 ----- interface/src/Application.cpp | 14 -- interface/src/Menu.cpp | 7 - interface/src/Menu.h | 1 - interface/src/devices/MIDIManager.cpp | 73 -------- interface/src/devices/MIDIManager.h | 58 ------ interface/src/devices/RealSense.cpp | 259 -------------------------- interface/src/devices/RealSense.h | 65 ------- 12 files changed, 1 insertion(+), 600 deletions(-) delete mode 100644 cmake/modules/FindRSSDK.cmake delete mode 100644 cmake/modules/FindRtMidi.cmake delete mode 100644 interface/external/rssdk/readme.txt delete mode 100644 interface/external/rtmidi/readme.txt delete mode 100644 interface/src/devices/MIDIManager.cpp delete mode 100644 interface/src/devices/MIDIManager.h delete mode 100644 interface/src/devices/RealSense.cpp delete mode 100644 interface/src/devices/RealSense.h diff --git a/cmake/modules/FindRSSDK.cmake b/cmake/modules/FindRSSDK.cmake deleted file mode 100644 index c31b0efcd9..0000000000 --- a/cmake/modules/FindRSSDK.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# Try to find the RSSDK library -# -# You must provide a RSSDK_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# RSSDK_FOUND - system found RSSDK -# RSSDK_INCLUDE_DIRS - the RSSDK include directory -# RSSDK_LIBRARIES - Link this to use RSSDK -# -# Created on 12/7/2014 by Thijs Wenker -# Copyright (c) 2014 High Fidelity -# - -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("rssdk") - -find_path(RSSDK_INCLUDE_DIRS pxcbase.h PATH_SUFFIXES include HINTS ${RSSDK_SEARCH_DIRS}) - -if (WIN32) - find_library(RSSDK_LIBRARY_DEBUG libpxc_d PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS}) - find_library(RSSDK_LIBRARY_RELEASE libpxc PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS}) -endif () - -include(SelectLibraryConfigurations) -select_library_configurations(RSSDK) - -set(RSSDK_LIBRARIES "${RSSDK_LIBRARY}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RSSDK DEFAULT_MSG RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES) - -mark_as_advanced(RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES RSSDK_SEARCH_DIRS) diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake deleted file mode 100644 index 213c990b52..0000000000 --- a/cmake/modules/FindRtMidi.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# -# FindRtMidi.cmake -# -# Try to find the RtMidi library -# -# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# RTMIDI_FOUND - system found RtMidi -# RTMIDI_INCLUDE_DIRS - the RtMidi include directory -# RTMIDI_LIBRARIES - link to this to use RtMidi -# -# Created on 6/30/2014 by Stephen Birarda -# Copyright 2014 High Fidelity, Inc. -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("rtmidi") - -find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS}) -find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) - -mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS) \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 67ce3f3df8..573fc1ce1e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "LeapMotion" "RtMidi" "RSSDK") +set(OPTIONAL_EXTERNALS "LeapMotion") if(WIN32) list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient") @@ -161,13 +161,6 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) endif () endforeach() -# special OS X modifications for RtMidi library -if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE) - find_library(CoreMIDI CoreMIDI) - add_definitions(-D__MACOSX_CORE__) - target_link_libraries(${TARGET_NAME} ${CoreMIDI}) -endif () - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src") diff --git a/interface/external/rssdk/readme.txt b/interface/external/rssdk/readme.txt deleted file mode 100644 index fe2246e32a..0000000000 --- a/interface/external/rssdk/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ - -Instructions for adding the Intel Realsense (RSSDK) to Interface -Thijs Wenker, December 19, 2014 - -This is Windows only for now. - -1. Download the SDK at https://software.intel.com/en-us/intel-realsense-sdk/download - -2. Copy the `lib` and `include` folder inside this directory \ No newline at end of file diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt deleted file mode 100644 index 3b9d6603a9..0000000000 --- a/interface/external/rtmidi/readme.txt +++ /dev/null @@ -1,43 +0,0 @@ - -Instructions for adding the RtMidi library to Interface -Stephen Birarda, June 30, 2014 - -1. Download the RtMidi tarball from High Fidelity S3. - http://public.highfidelity.io/dependencies/rtmidi-2.1.0.tar.gz - -2. Copy RtMidi.h to externals/rtmidi/include. - -3. Compile the RtMidi library. - -3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib - -4. Delete your build directory, run cmake and build, and you should be all set. - -========================= - -RtMidi: realtime MIDI i/o C++ classes
-Copyright (c) 2003-2014 Gary P. Scavone - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -Any person wishing to distribute modifications to the Software is -asked to send the modifications to the original developer so that -they can be incorporated into the canonical version. This is, -however, not a binding provision of this license. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef10ad4464..0c913bfaef 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -110,8 +110,6 @@ #include "devices/EyeTracker.h" #include "devices/Faceshift.h" #include "devices/Leapmotion.h" -#include "devices/MIDIManager.h" -#include "devices/RealSense.h" #include "DiscoverabilityManager.h" #include "GLCanvas.h" #include "InterfaceActionFactory.h" @@ -719,12 +717,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // set the local loopback interface for local sounds from audio scripts AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data()); -#ifdef HAVE_RTMIDI - // setup the MIDIManager - MIDIManager& midiManagerInstance = MIDIManager::getInstance(); - midiManagerInstance.openDefaultPort(); -#endif - this->installEventFilter(this); // initialize our face trackers after loading the menu settings @@ -970,7 +962,6 @@ Application::~Application() { nodeThread->wait(); Leapmotion::destroy(); - RealSense::destroy(); #if 0 ConnexionClient::getInstance().destroy(); @@ -2519,7 +2510,6 @@ void Application::init() { qCDebug(interfaceapp) << "Loaded settings"; Leapmotion::init(); - RealSense::init(); // fire off an immediate domain-server check in now that settings are loaded DependencyManager::get()->sendDomainServerCheckIn(); @@ -4069,10 +4059,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget()); - -#ifdef HAVE_RTMIDI - scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); -#endif } bool Application::canAcceptURL(const QString& urlString) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d0c8b502c5..48204464fc 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -29,7 +29,6 @@ #include "avatar/AvatarManager.h" #include "devices/DdeFaceTracker.h" #include "devices/Faceshift.h" -#include "devices/RealSense.h" #include "input-plugins/SpacemouseManager.h" #include "MainWindow.h" #include "scripting/MenuScriptingInterface.h" @@ -462,12 +461,6 @@ Menu::Menu() { MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); -#ifdef HAVE_RSSDK - MenuWrapper* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense"); - addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0, - RealSense::getInstance(), SLOT(loadRSSDKFile())); -#endif - MenuWrapper* networkMenu = developerMenu->addMenu("Network"); addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b51987479..a30c5d434b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -211,7 +211,6 @@ namespace MenuOption { const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; const QString LoadScriptURL = "Open and Run Script from URL..."; - const QString LoadRSSDKFile = "Load .rssdk file"; const QString LodTools = "LOD Tools"; const QString Login = "Login"; const QString Log = "Log"; diff --git a/interface/src/devices/MIDIManager.cpp b/interface/src/devices/MIDIManager.cpp deleted file mode 100644 index a21f5d49f5..0000000000 --- a/interface/src/devices/MIDIManager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// MIDIManager.cpp -// -// -// Created by Stephen Birarda on 2014-06-30. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "InterfaceLogging.h" -#include "MIDIManager.h" - -MIDIManager& MIDIManager::getInstance() { - static MIDIManager sharedInstance; - return sharedInstance; -} - -void MIDIManager::midiCallback(double deltaTime, std::vector* message, void* userData) { -#ifdef HAVE_RTMIDI - - MIDIEvent callbackEvent; - callbackEvent.deltaTime = deltaTime; - - callbackEvent.type = message->at(0); - - if (message->size() > 1) { - callbackEvent.data1 = message->at(1); - } - - if (message->size() > 2) { - callbackEvent.data2 = message->at(2); - } - - emit getInstance().midiEvent(callbackEvent); -#endif -} - -MIDIManager::~MIDIManager() { -#ifdef HAVE_RTMIDI - delete _midiInput; -#endif -} - -#ifdef HAVE_RTMIDI -const int DEFAULT_MIDI_PORT = 0; -#endif - -void MIDIManager::openDefaultPort() { -#ifdef HAVE_RTMIDI - if (!_midiInput) { - _midiInput = new RtMidiIn(); - - if (_midiInput->getPortCount() > 0) { - qCDebug(interfaceapp) << "MIDIManager opening port" << DEFAULT_MIDI_PORT; - - _midiInput->openPort(DEFAULT_MIDI_PORT); - - // don't ignore sysex, timing, or active sensing messages - _midiInput->ignoreTypes(false, false, false); - - _midiInput->setCallback(&MIDIManager::midiCallback); - } else { - qCDebug(interfaceapp) << "MIDIManager openDefaultPort called but there are no ports available."; - delete _midiInput; - _midiInput = NULL; - } - } -#endif -} diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h deleted file mode 100644 index 9fc55d11da..0000000000 --- a/interface/src/devices/MIDIManager.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// MIDIManager.h -// interface/src/devices -// -// Created by Stephen Birarda on 2014-06-30. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_MIDIManager_h -#define hifi_MIDIManager_h - -#include -#include - -#include - -#ifdef HAVE_RTMIDI -#include -#endif - -class MIDIManager : public QObject { - Q_OBJECT - - Q_PROPERTY(unsigned int NoteOn READ NoteOn) - Q_PROPERTY(unsigned int NoteOff READ NoteOff) - Q_PROPERTY(unsigned int ModWheel READ ModWheel) - Q_PROPERTY(unsigned int PitchWheel READ PitchWheel) - -public: - static MIDIManager& getInstance(); - static void midiCallback(double deltaTime, std::vector* message, void* userData); - - ~MIDIManager(); - - void openDefaultPort(); -#ifdef HAVE_RTMIDI - bool hasDevice() const { return !!_midiInput; } -#endif -public slots: - unsigned int NoteOn() const { return 144; } - unsigned int NoteOff() const { return 128; } - unsigned int ModWheel() const { return 176; } - unsigned int PitchWheel() const { return 224; } -signals: - void midiEvent(const MIDIEvent& event); - -private: -#ifdef HAVE_RTMIDI - RtMidiIn* _midiInput; -#endif -}; - - -#endif // hifi_MIDIManager_h - diff --git a/interface/src/devices/RealSense.cpp b/interface/src/devices/RealSense.cpp deleted file mode 100644 index ce28e40f2b..0000000000 --- a/interface/src/devices/RealSense.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// -// RealSense.cpp -// interface/src/devices -// -// Created by Thijs Wenker on 12/10/14 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Application.h" -#include "RealSense.h" -#include "MainWindow.h" -#include "Menu.h" -#include "SharedUtil.h" - -#ifdef HAVE_RSSDK -const int PALMROOT_NUM_JOINTS = 3; -const int FINGER_NUM_JOINTS = 4; -#endif // HAVE_RSSDK - -const DeviceTracker::Name RealSense::NAME = "RealSense"; - -// find the index of a joint from -// the side: true = right -// the finger & the bone: -// finger in [0..4] : bone in [0..3] a finger phalange -// [-1] up the hand branch : bone in [0..1] <=> [ hand, forearm] -MotionTracker::Index evalRealSenseJointIndex(bool isRightSide, int finger, int bone) { -#ifdef HAVE_RSSDK - MotionTracker::Index offset = 1 // start after root - + (int(isRightSide) * PXCHandData::NUMBER_OF_JOINTS) // then offset for side - + PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain - if (finger >= 0) { - // from there go down in the correct finger and bone - return offset + (finger * FINGER_NUM_JOINTS) + bone; - } else { - // or go back up for the correct root bone - return offset - 1 - bone; - } -#else - return -1; -#endif // HAVE_RSSDK -} - -// static -void RealSense::init() { - DeviceTracker* device = DeviceTracker::getDevice(NAME); - if (!device) { - // create a new RealSense and register it - RealSense* realSense = new RealSense(); - DeviceTracker::registerDevice(NAME, realSense); - } -} - -// static -void RealSense::destroy() { - DeviceTracker::destroyDevice(NAME); -} - -// static -RealSense* RealSense::getInstance() { - DeviceTracker* device = DeviceTracker::getDevice(NAME); - if (!device) { - // create a new RealSense and register it - RealSense* realSense = new RealSense(); - DeviceTracker::registerDevice(NAME, realSense); - } - return dynamic_cast< RealSense* > (device); -} - -RealSense::RealSense() : - MotionTracker(), - _active(false) -{ -#ifdef HAVE_RSSDK - _handData = NULL; - _session = PXCSession_Create(); - initSession(false, NULL); - - // Create the RealSense joint hierarchy - std::vector< Semantic > sides; - sides.push_back("joint_L_"); - sides.push_back("joint_R_"); - - std::vector< Semantic > rootBones; - rootBones.push_back("wrist"); - rootBones.push_back("hand"); - - std::vector< Semantic > fingers; - fingers.push_back("thumb"); - fingers.push_back("index"); - fingers.push_back("middle"); - fingers.push_back("ring"); - fingers.push_back("pinky"); - - std::vector< Semantic > fingerBones; - fingerBones.push_back("1"); - fingerBones.push_back("2"); - fingerBones.push_back("3"); - fingerBones.push_back("4"); - - std::vector< Index > palms; - for (unsigned int s = 0; s < sides.size(); s++) { - Index rootJoint = 0; - for (unsigned int rb = 0; rb < rootBones.size(); rb++) { - rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint); - } - - // capture the hand index for debug - palms.push_back(rootJoint); - - for (unsigned int f = 0; f < fingers.size(); f++) { - for (unsigned int b = 0; b < fingerBones.size(); b++) { - rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint); - } - } - } -#endif // HAVE_RSSDK -} - -RealSense::~RealSense() { -#ifdef HAVE_RSSDK - _manager->Release(); -#endif // HAVE_RSSDK -} - -void RealSense::initSession(bool playback, QString filename) { -#ifdef HAVE_RSSDK - _active = false; - _properlyInitialized = false; - if (_handData != NULL) { - _handData->Release(); - _handController->Release(); - _session->Release(); - _config->Release(); - } - _manager = _session->CreateSenseManager(); - if (playback) { - _manager->QueryCaptureManager()->SetFileName(filename.toStdWString().c_str(), false); - } - _manager->QueryCaptureManager()->SetRealtime(!playback); - _manager->EnableHand(0); - _handController = _manager->QueryHand(); - - if (_manager->Init() == PXC_STATUS_NO_ERROR) { - _handData = _handController->CreateOutput(); - - PXCCapture::Device *device = _manager->QueryCaptureManager()->QueryDevice(); - PXCCapture::DeviceInfo dinfo; - _manager->QueryCaptureManager()->QueryDevice()->QueryDeviceInfo(&dinfo); - if (dinfo.model == PXCCapture::DEVICE_MODEL_IVCAM) - { - device->SetDepthConfidenceThreshold(1); - device->SetMirrorMode(PXCCapture::Device::MIRROR_MODE_DISABLED); - device->SetIVCAMFilterOption(6); - } - _properlyInitialized = true; - } - - _config = _handController->CreateActiveConfiguration(); - _config->EnableStabilizer(true); - _config->SetTrackingMode(PXCHandData::TRACKING_MODE_FULL_HAND); - _config->ApplyChanges(); -#endif // HAVE_RSSDK -} - -#ifdef HAVE_RSSDK -glm::quat quatFromPXCPoint4DF32(const PXCPoint4DF32& basis) { - return glm::normalize(glm::quat(basis.w, basis.x, basis.y, basis.z) * glm::quat(glm::vec3(0, M_PI, 0))); -} - -glm::vec3 vec3FromPXCPoint3DF32(const PXCPoint3DF32& vec) { - return glm::vec3(-vec.x, vec.y, -vec.z); -} -#endif // HAVE_RSSDK - -void RealSense::update() { -#ifdef HAVE_RSSDK - bool wasActive = _active; - _active = _manager->IsConnected() && _properlyInitialized; - if (_active || wasActive) { - // Go through all the joints and increment their counter since last update. - // Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive. - // TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) { - for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) { - (*jointIt).tickNewFrame(); - } - } - - if (!_active) { - return; - } - - pxcStatus sts = _manager->AcquireFrame(true); - _handData->Update(); - PXCHandData::JointData nodes[2][PXCHandData::NUMBER_OF_JOINTS] = {}; - PXCHandData::ExtremityData extremitiesPointsNodes[2][PXCHandData::NUMBER_OF_EXTREMITIES] = {}; - for (pxcI32 i = 0; i < _handData->QueryNumberOfHands(); i++) { - PXCHandData::IHand* handData; - if (_handData->QueryHandData(PXCHandData::ACCESS_ORDER_BY_TIME, i, handData) == PXC_STATUS_NO_ERROR) { - int rightSide = handData->QueryBodySide() == PXCHandData::BODY_SIDE_RIGHT; - PXCHandData::JointData jointData; - JointTracker* parentJointTracker = _jointsArray.data(); - //Iterate Joints - int rootBranchIndex = -1; - JointTracker* palmJoint = NULL; - for (int j = 0; j < PXCHandData::NUMBER_OF_JOINTS; j++) { - handData->QueryTrackedJoint((PXCHandData::JointType)j, jointData); - nodes[i][j] = jointData; - if (j == PXCHandData::JOINT_WRIST) { - JointTracker* wrist = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 1)); // 1 is the index of the wrist joint - wrist->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - wrist->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - wrist->updateLocFromAbsTransform(parentJointTracker); - wrist->activeFrame(); - parentJointTracker = wrist; - continue; - } else if (j == PXCHandData::JOINT_CENTER) { - palmJoint = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 0)); // 0 is the index of the palm joint - palmJoint->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - palmJoint->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - palmJoint->updateLocFromAbsTransform(parentJointTracker); - palmJoint->activeFrame(); - parentJointTracker = palmJoint; - continue; - } - int finger_index = j - PALMROOT_NUM_JOINTS; - int finger = finger_index / FINGER_NUM_JOINTS; - int finger_bone = finger_index % FINGER_NUM_JOINTS; - JointTracker* ljointTracker = editJointTracker(evalRealSenseJointIndex(rightSide, finger, finger_bone)); - if (jointData.confidence > 0) { - ljointTracker->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - ljointTracker->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - ljointTracker->updateLocFromAbsTransform(parentJointTracker); - ljointTracker->activeFrame(); - } - if (finger_bone == (FINGER_NUM_JOINTS - 1)) { - parentJointTracker = palmJoint; - continue; - } - parentJointTracker = ljointTracker; - } - } - } - _manager->ReleaseFrame(); -#endif // HAVE_RSSDK -} - -void RealSense::loadRSSDKFile() { - QString locationDir(QStandardPaths::displayName(QStandardPaths::DesktopLocation)); - QString fileNameString = QFileDialog::getOpenFileName(qApp->getWindow(), tr("Open RSSDK clip"), - locationDir, - tr("RSSDK Recordings (*.rssdk)")); - if (!fileNameString.isEmpty()) { - initSession(true, fileNameString); - } -} diff --git a/interface/src/devices/RealSense.h b/interface/src/devices/RealSense.h deleted file mode 100644 index c958ab1e53..0000000000 --- a/interface/src/devices/RealSense.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// RealSense.h -// interface/src/devices -// -// Created by Thijs Wenker on 12/10/14 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_RealSense_h -#define hifi_RealSense_h - -#include - -#include "MotionTracker.h" - -#ifdef HAVE_RSSDK -#include -#include -#include -#include -#include -#endif - -/// Handles interaction with the RealSense skeleton tracking suit. -class RealSense : public QObject, public MotionTracker { - Q_OBJECT - -public: - static const Name NAME; - - static void init(); - static void destroy(); - - /// RealSense MotionTracker factory - static RealSense* getInstance(); - - bool isActive() const { return _active; } - - virtual void update(); - -public slots: - void loadRSSDKFile(); - -protected: - RealSense(); - virtual ~RealSense(); - - void initSession(bool playback, QString filename); - -private: -#ifdef HAVE_RSSDK - PXCSession* _session; - PXCSenseManager* _manager; - PXCHandModule* _handController; - PXCHandData* _handData; - PXCHandConfiguration* _config; -#endif - bool _properlyInitialized; - bool _active; -}; - -#endif // hifi_RealSense_h From 6f79b381f96abf39682d985e1a67370e4dbef4cb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 11:00:06 -0800 Subject: [PATCH 126/165] working toward making children of avatar joints work --- libraries/entities/src/EntityItem.cpp | 77 +++------------------- libraries/entities/src/EntityItem.h | 15 ++--- libraries/shared/src/SpatiallyNestable.cpp | 41 +++++++++++- libraries/shared/src/SpatiallyNestable.h | 9 ++- 4 files changed, 59 insertions(+), 83 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f169554a2c..e286275fed 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1319,9 +1319,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } if (getLocalPosition() != value) { setLocalPosition(value); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->_dirtyFlags |= Simulation::DIRTY_POSITION; - }); } } @@ -1337,10 +1334,12 @@ void EntityItem::updateRotation(const glm::quat& rotation) { return; } if (getLocalOrientation() != rotation) { - setLocalRotation(rotation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; - if (this->getID() != entity->getID()) { + setLocalOrientation(rotation); + _dirtyFlags |= Simulation::DIRTY_ROTATION; + forEachDescendant([&](SpatiallyNestablePointer object) { + if (object->getNestableType() == NestableTypes::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; entity->_dirtyFlags |= Simulation::DIRTY_POSITION; } }); @@ -1838,65 +1837,7 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG return result; } -void EntityItem::forSelfAndEachChildEntity(std::function actor) { - QQueue toProcess; - toProcess.enqueue(shared_from_this()); - - while (!toProcess.empty()) { - EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - actor(entity); - foreach (SpatiallyNestablePointer child, entity->getChildren()) { - if (child && child->getNestableType() == NestableTypes::Entity) { - toProcess.enqueue(child); - } - } - } -} - -void EntityItem::parentChanged() { - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setTransform(const Transform transform) { - SpatiallyNestable::setTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalTransform(const Transform transform) { - SpatiallyNestable::setLocalTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setPosition(const glm::vec3 position) { - SpatiallyNestable::setPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalPosition(const glm::vec3 position) { - SpatiallyNestable::setLocalPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setRotation(const glm::quat orientation) { - SpatiallyNestable::setOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalRotation(const glm::quat orientation) { - SpatiallyNestable::setLocalOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); +void EntityItem::locationChanged() { + requiresRecalcBoxes(); + SpatiallyNestable::locationChanged(); // tell all the children, also } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cbaa152c7f..761208cb06 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -306,15 +306,9 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } - virtual void setTransform(const Transform transform); - virtual void setLocalTransform(const Transform transform); - // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } - virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - - virtual void setPosition(glm::vec3 position); - virtual void setLocalPosition(glm::vec3 position); - virtual void setRotation(glm::quat orientation); - virtual void setLocalRotation(glm::quat orientation); + // these are only needed because the names don't match + virtual const glm::quat getRotation() const { return getOrientation(); } + virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); @@ -393,8 +387,7 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - void forSelfAndEachChildEntity(std::function actor); - virtual void parentChanged(); + virtual void locationChanged(); EntityTypes::EntityType _type; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, // and physics changes diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 688ed831e3..a0280943de 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "DependencyManager.h" #include "SpatiallyNestable.h" @@ -91,6 +93,7 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { _parentID = parentID; _parentKnowsMe = false; } + parentChanged(); } glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { @@ -182,6 +185,7 @@ void SpatiallyNestable::setPosition(glm::vec3 position) { myWorldTransform.setTranslation(position); Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); + locationChanged(); } glm::quat SpatiallyNestable::getOrientation() const { @@ -200,6 +204,7 @@ void SpatiallyNestable::setOrientation(glm::quat orientation) { myWorldTransform.setRotation(orientation); Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); + locationChanged(); } const Transform SpatiallyNestable::getTransform() const { @@ -227,6 +232,7 @@ void SpatiallyNestable::setTransform(const Transform transform) { _transformLock.withWriteLock([&] { Transform::inverseMult(_transform, parentTransform, transform); }); + locationChanged(); } glm::vec3 SpatiallyNestable::getScale() const { @@ -246,6 +252,7 @@ void SpatiallyNestable::setScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); + dimensionsChanged(); } const Transform SpatiallyNestable::getLocalTransform() const { @@ -260,6 +267,7 @@ void SpatiallyNestable::setLocalTransform(const Transform transform) { _transformLock.withWriteLock([&] { _transform = transform; }); + locationChanged(); } glm::vec3 SpatiallyNestable::getLocalPosition() const { @@ -274,6 +282,7 @@ void SpatiallyNestable::setLocalPosition(glm::vec3 position) { _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); + locationChanged(); } glm::quat SpatiallyNestable::getLocalOrientation() const { @@ -288,6 +297,7 @@ void SpatiallyNestable::setLocalOrientation(glm::quat orientation) { _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); + locationChanged(); } glm::vec3 SpatiallyNestable::getLocalScale() const { @@ -302,12 +312,13 @@ void SpatiallyNestable::setLocalScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); + dimensionsChanged(); } QList SpatiallyNestable::getChildren() const { QList children; _childrenLock.withReadLock([&] { - foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + foreach(SpatiallyNestableWeakPointer childWP, _children.values()) { SpatiallyNestablePointer child = childWP.lock(); if (child) { children << child; @@ -317,7 +328,6 @@ QList SpatiallyNestable::getChildren() const { return children; } - const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { Transform jointInObjectFrame; glm::vec3 position = getJointTranslation(jointIndex); @@ -332,3 +342,30 @@ SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const { SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! return thisPointer; } + +void SpatiallyNestable::forEachChild(std::function actor) { + foreach(SpatiallyNestablePointer child, getChildren()) { + actor(child); + } +} + +void SpatiallyNestable::forEachDescendant(std::function actor) { + QQueue toProcess; + foreach(SpatiallyNestablePointer child, getChildren()) { + toProcess.enqueue(child); + } + + while (!toProcess.empty()) { + SpatiallyNestablePointer object = toProcess.dequeue(); + actor(object); + foreach (SpatiallyNestablePointer child, object->getChildren()) { + toProcess.enqueue(child); + } + } +} + +void SpatiallyNestable::locationChanged() { + forEachChild([&](SpatiallyNestablePointer object) { + object->locationChanged(); + }); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index b7c04e8563..f750860037 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,8 +92,8 @@ public: // this object's frame virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; - virtual glm::quat getJointRotation(int index) const = 0; - virtual glm::vec3 getJointTranslation(int index) const = 0; + virtual glm::quat getJointRotation(int index) const { assert(false); } + virtual glm::vec3 getJointTranslation(int index) const { assert(false); } SpatiallyNestablePointer getThisPointer() const; @@ -112,6 +112,11 @@ protected: mutable QHash _children; virtual void parentChanged() {} // called when parent pointer is updated + virtual void locationChanged(); // called when a this object's location has changed + virtual void dimensionsChanged() {} // called when a this object's dimensions have changed + + void forEachChild(std::function actor); + void forEachDescendant(std::function actor); private: mutable ReadWriteLockable _transformLock; From cf5c8c08e25c21aea9930e2180ea16ae31a3df79 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 3 Dec 2015 11:10:22 -0800 Subject: [PATCH 127/165] update toys to be inverted while held --- examples/toybox/doll/createDoll.js | 21 +++++++++++++++---- .../toybox/flashlight/createFlashlight.js | 21 +++++++++++++++---- .../toybox/ping_pong_gun/createPingPongGun.js | 7 ++++++- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/examples/toybox/doll/createDoll.js b/examples/toybox/doll/createDoll.js index ffd840f4ea..52ba5a5291 100644 --- a/examples/toybox/doll/createDoll.js +++ b/examples/toybox/doll/createDoll.js @@ -15,12 +15,20 @@ function createDoll() { var scriptURL = Script.resolvePath("doll.js"); - var center = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); + var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 + }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); - var naturalDimensions = { x: 1.63, y: 1.67, z: 0.26}; + var naturalDimensions = { + x: 1.63, + y: 1.67, + z: 0.26 + }; var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15); - + var doll = Entities.addEntity({ type: "Model", name: "doll", @@ -39,7 +47,12 @@ function createDoll() { y: 0, z: 0 }, - collisionsWillMove: true + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); return doll; } diff --git a/examples/toybox/flashlight/createFlashlight.js b/examples/toybox/flashlight/createFlashlight.js index b049d2632e..108d519d3e 100644 --- a/examples/toybox/flashlight/createFlashlight.js +++ b/examples/toybox/flashlight/createFlashlight.js @@ -18,14 +18,27 @@ var scriptURL = Script.resolvePath('flashlight.js'); var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"; -var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); +var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 +}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); var flashlight = Entities.addEntity({ type: "Model", modelURL: modelURL, position: center, - dimensions: { x: 0.08, y: 0.30, z: 0.08}, + dimensions: { + x: 0.08, + y: 0.30, + z: 0.08 + }, collisionsWillMove: true, shapeType: 'box', - script: scriptURL -}); + script: scriptURL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) +}); \ No newline at end of file diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 705671e784..4b93842896 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -35,7 +35,12 @@ var pingPongGun = Entities.addEntity({ z: 0.47 }, collisionsWillMove: true, - collisionSoundURL: COLLISION_SOUND_URL + collisionSoundURL: COLLISION_SOUND_URL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); function cleanUp() { From 849a8707d2a1a91faa57ad4f809435e8904b8531 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 11:05:28 -0800 Subject: [PATCH 128/165] remove wantsColor support since its always true and required for entities --- .../src/octree/OctreeQueryNode.cpp | 1 - .../src/octree/OctreeQueryNode.h | 2 +- .../src/octree/OctreeSendThread.cpp | 3 +- interface/src/Application.cpp | 1 - libraries/octree/src/Octree.cpp | 115 ++++++++---------- libraries/octree/src/Octree.h | 10 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 7 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 ---- libraries/shared/src/OctalCode.h | 2 - 14 files changed, 62 insertions(+), 115 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cff2c7ee2e..06e9834804 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,7 +179,6 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsColor = getWantColor(); _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; if (_currentPacketIsColor) { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 75c841851f..4140d42a5f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -78,7 +78,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + return (getCurrentPacketIsCompressed() == getWantCompression()); } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index f873ee4808..efc81d6a21 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantColor = nodeData->getWantColor(); bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color @@ -456,7 +455,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 68a809688a..4b3775933d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 1960537ced..64a2eaccc4 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -950,9 +950,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { + if (suppressEmptySubtrees() && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1293,7 +1293,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... NOTE: includeColor means include element data + // write the child element data... // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,65 +1303,63 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - if (params.includeColor) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); - } + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); } } } @@ -1500,17 +1498,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } - // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem - // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else - // about not attempting to add this optimization back in, without solving the element deletion case. - // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree - //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { - // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees - //} bytesAtThisLevel += childTreeBytesOut; @@ -1530,7 +1521,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); + params.stats->childBitsRemoved(params.includeExistsBits); } if (!continueThisLevel) { @@ -1825,7 +1816,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1864,7 +1855,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -2012,7 +2003,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5f5aa1432a..3ca8528a2f 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -52,8 +52,6 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; -const bool NO_COLOR = false; -const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; @@ -72,7 +70,6 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; - bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; @@ -103,7 +100,6 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, @@ -118,7 +114,6 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), - includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), @@ -181,7 +176,6 @@ public: class ReadBitstreamToTreeParams { public: - bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -192,14 +186,12 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : - includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -306,7 +298,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName, bool wantColorRandomizer); + void loadOctreeFile(const char* fileName); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index b18f219d4d..f1c2172d86 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); // TODO: should be on by default diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 2739b4a0d1..c431d66bf2 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } - if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 9605cbfb5d..71c9361e68 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,9 +35,9 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int WANT_COLOR_AT_BIT = 1; +const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT = 3; // unused... available for new feature +const int UNUSED_BIT_3 = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -71,7 +71,6 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantCompression() const { return _wantCompression; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } - void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } @@ -99,7 +97,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; bool _wantCompression = false; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index b7be4cf3e7..c65359f12f 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 22352fbe3b..c70e0e4935 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,14 +371,12 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - if (includesColors) { - _colorBitsWritten--; - } + _colorBitsWritten--; _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index bdb4ef206a..f8ecf93106 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits, bool includesColors); + void childBitsRemoved(bool includesExistsBits); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 0b77683d4c..1fa18903cb 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,29 +264,6 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace) { - - int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); - int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); - int newCodeLength = newParentCodeLength + oldCodeLength; - int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); - unsigned char* newCode = new unsigned char[bufferLength]; - *newCode = newCodeLength; // set the length byte - - // copy parent code section first - for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { - char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); - setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); - } - // copy original code section next - for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { - char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); - setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); - } - return newCode; -} - bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 9229157c3d..09766b685a 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,8 +36,6 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From fbca1c975402624ffec58bdf282838995ca5a17b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 3 Dec 2015 11:12:28 -0800 Subject: [PATCH 129/165] another toy --- examples/toybox/basketball/createSingleBasketball.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/toybox/basketball/createSingleBasketball.js b/examples/toybox/basketball/createSingleBasketball.js index a1e0140553..6765e5e075 100644 --- a/examples/toybox/basketball/createSingleBasketball.js +++ b/examples/toybox/basketball/createSingleBasketball.js @@ -47,7 +47,12 @@ function makeBasketball() { modelURL: basketballURL, restitution: 1.0, damping: 0.00001, - shapeType: "sphere" + shapeType: "sphere", + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); originalPosition = position; } From e5b1cfa920d5a09b2e2b1375a0f797f4d21cf9a9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 11:15:04 -0800 Subject: [PATCH 130/165] fix windows build --- libraries/shared/src/SpatiallyNestable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index f750860037..f3056d9a4f 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,8 +92,8 @@ public: // this object's frame virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; - virtual glm::quat getJointRotation(int index) const { assert(false); } - virtual glm::vec3 getJointTranslation(int index) const { assert(false); } + virtual glm::quat getJointRotation(int index) const { assert(false); return glm::quat(); } + virtual glm::vec3 getJointTranslation(int index) const { assert(false); return glm::vec3(); } SpatiallyNestablePointer getThisPointer() const; From 1a5bc5d11148185e67ca09a69a427ac7773796fa Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 12:40:24 -0800 Subject: [PATCH 131/165] removing optional compression --- assignment-client/src/octree/OctreeQueryNode.cpp | 9 ++------- assignment-client/src/octree/OctreeQueryNode.h | 4 +--- assignment-client/src/octree/OctreeSendThread.cpp | 14 ++++---------- interface/src/Application.cpp | 1 - libraries/entities/src/EntityItemProperties.cpp | 4 +++- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreePacketData.cpp | 9 +++++---- libraries/octree/src/OctreePacketData.h | 6 +++--- libraries/octree/src/OctreeQuery.cpp | 2 -- libraries/octree/src/OctreeQuery.h | 5 +---- 10 files changed, 19 insertions(+), 36 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 06e9834804..cafba8c083 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,14 +179,9 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; - if (_currentPacketIsColor) { - setAtBit(flags, PACKET_IS_COLOR_BIT); - } - if (_currentPacketIsCompressed) { - setAtBit(flags, PACKET_IS_COMPRESSED_BIT); - } + setAtBit(flags, PACKET_IS_COLOR_BIT); + setAtBit(flags, PACKET_IS_COMPRESSED_BIT); _octreePacket->reset(); diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4140d42a5f..67298296e9 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -77,9 +77,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsCompressed() == getWantCompression()); - } + bool getCurrentPacketFormatMatches() { return (getCurrentPacketIsCompressed() == true); } // FIXME bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index efc81d6a21..d01117dff6 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. @@ -332,10 +331,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } - _packetData.changeSettings(wantCompression, targetSize); + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + _packetData.changeSettings(targetSize); } const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -551,10 +548,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); - - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. // but we've finalized the _packetData, so we want to start a new section, we will do that by @@ -564,7 +558,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset + _packetData.changeSettings(targetSize); // will do reset } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4b3775933d..053ef5b7a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3075,7 +3075,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 78a4f3e8b6..30bee83482 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -790,7 +790,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue // bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer) { - OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. + + // FIXME - remove non-compressed OctreePacketData and handle compressed edit packets + OctreePacketData ourDataPacket(buffer.size(), false); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro bool success = true; // assume the best diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index f1c2172d86..7b80d315f1 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -52,7 +52,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 811e96fcf4..f4fbf9bd97 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -23,12 +23,13 @@ AtomicUIntStat OctreePacketData::_totalBytesOfValues { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 }; -OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) { - changeSettings(enableCompression, targetSize); // does reset... +OctreePacketData::OctreePacketData(int targetSize, bool enableCompression) { + changeSettings(targetSize); // does reset... + _enableCompression = enableCompression; // FIXME } -void OctreePacketData::changeSettings(bool enableCompression, unsigned int targetSize) { - _enableCompression = enableCompression; +void OctreePacketData::changeSettings(unsigned int targetSize) { + _enableCompression = true; // FIXME _targetSize = std::min(MAX_OCTREE_UNCOMRESSED_PACKET_SIZE, targetSize); reset(); } diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 2c86d518ad..fb53b3472f 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -83,11 +83,11 @@ private: /// Handles packing of the data portion of PacketType_OCTREE_DATA messages. class OctreePacketData { public: - OctreePacketData(bool enableCompression = false, int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE); + OctreePacketData(int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE, bool enableCompression = true); ~OctreePacketData(); /// change compression and target size settings - void changeSettings(bool enableCompression = false, unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); + void changeSettings(unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); /// reset completely, all data is discarded void reset(); @@ -262,7 +262,7 @@ private: bool append(unsigned char byte); unsigned int _targetSize; - bool _enableCompression; + bool _enableCompression { true }; // FIXME - these will always be compressed, so remove this option unsigned char _uncompressed[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index c431d66bf2..8449e3083a 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -42,7 +42,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 71c9361e68..962a8e1425 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -38,7 +38,7 @@ const int WANT_LOW_RES_MOVING_BIT = 0; const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int WANT_COMPRESSION = 4; // 5th bit +const int UNUSED_BIT_4 = 4; // 5th bit, unused... available for new feature class OctreeQuery : public NodeData { Q_OBJECT @@ -73,7 +73,6 @@ public: // related to Octree Sending strategies bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -99,7 +97,6 @@ protected: // octree server sending items bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations From cc80dfb9e17d0dfae836eb13f8fa018fa51c28eb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 11:08:56 -0800 Subject: [PATCH 132/165] Fixing case on gl surface format helper --- libraries/gl/src/gl/GLHelpers.cpp | 2 +- libraries/gl/src/gl/GLHelpers.h | 2 +- libraries/gl/src/gl/GLWidget.cpp | 7 +++---- libraries/gl/src/gl/GLWidget.h | 8 +++----- libraries/gl/src/gl/GLWindow.cpp | 2 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 2 +- tests/shaders/src/main.cpp | 2 +- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 9022f0ffcc..6ad7f816b8 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -5,7 +5,7 @@ #include #include -const QSurfaceFormat& getDefaultOpenGlSurfaceFormat() { +const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { static QSurfaceFormat format; static std::once_flag once; std::call_once(once, [] { diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index de9e8f5d85..335272d991 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -19,6 +19,6 @@ class QSurfaceFormat; class QGLFormat; -const QSurfaceFormat& getDefaultOpenGlSurfaceFormat(); +const QSurfaceFormat& getDefaultOpenGLSurfaceFormat(); const QGLFormat& getDefaultGLFormat(); #endif diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index ec08d70e7a..310675c01f 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -1,9 +1,8 @@ // -// GLWidget.cpp -// interface/src // -// Created by Stephen Birarda on 8/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/12/03 +// Derived from interface/src/GLCanvas.cpp created by Stephen Birarda on 8/14/13. +// Copyright 2013-2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index 5c4f4305cc..df4a73ac50 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -1,9 +1,7 @@ // -// GLWidget.h -// interface/src -// -// Created by Stephen Birarda on 8/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/12/03 +// Derived from interface/src/GLCanvas.h created by Stephen Birarda on 8/14/13. +// Copyright 2013-2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/libraries/gl/src/gl/GLWindow.cpp b/libraries/gl/src/gl/GLWindow.cpp index 42914fed59..78c7666d25 100644 --- a/libraries/gl/src/gl/GLWindow.cpp +++ b/libraries/gl/src/gl/GLWindow.cpp @@ -14,7 +14,7 @@ #include "GLHelpers.h" void GLWindow::createContext(QOpenGLContext* shareContext) { - createContext(getDefaultOpenGlSurfaceFormat(), shareContext); + createContext(getDefaultOpenGLSurfaceFormat(), shareContext); } void GLWindow::createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext) { diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index b8c9b9e117..640c8ed5f5 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -37,7 +37,7 @@ void OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { sharedContext->doneCurrent(); _context->setShareContext(sharedContext); } - _context->setFormat(getDefaultOpenGlSurfaceFormat()); + _context->setFormat(getDefaultOpenGLSurfaceFormat()); _context->create(); _offscreenSurface->setFormat(_context->format()); diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 3edff67d66..f65cd9b5aa 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -128,7 +128,7 @@ protected: public: QTestWindow() { setSurfaceType(QSurface::OpenGLSurface); - QSurfaceFormat format = getDefaultOpenGlSurfaceFormat(); + QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); setFormat(format); _context = new QOpenGLContext; _context->setFormat(format); From 4a8649c202b5b02f49be6ee4f55f6328d4d466f0 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 3 Dec 2015 14:23:16 -0800 Subject: [PATCH 133/165] Change get/setRenderDistanceLow/HighLimit and avatarRenderDistanceHighLimit to get/setRenderDistanceInverseLow/HighLimit and avatarRenderDistanceInverseHighLimit. --- interface/src/avatar/AvatarManager.cpp | 8 ++++---- interface/src/avatar/AvatarManager.h | 8 ++++---- interface/src/ui/PreferencesDialog.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e094f2e263..eeb5bbd55f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -77,9 +77,9 @@ AvatarManager::AvatarManager(QObject* parent) : } const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters -Setting::Handle avatarRenderDistanceHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); -void AvatarManager::setRenderDistanceHighLimit(float newValue) { - avatarRenderDistanceHighLimit.set(newValue); +Setting::Handle avatarRenderDistanceInverseHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); +void AvatarManager::setRenderDistanceInverseHighLimit(float newValue) { + avatarRenderDistanceInverseHighLimit.set(newValue); _renderDistanceController.setControlledValueHighLimit(newValue); } @@ -101,7 +101,7 @@ void AvatarManager::init() { const float target_fps = qApp->getTargetFrameRate(); _renderDistanceController.setMeasuredValueSetpoint(target_fps); - _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceHighLimit.get()); + _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceInverseHighLimit.get()); _renderDistanceController.setControlledValueLowLimit(1.0f / (float) TREE_SCALE); // Advice for tuning parameters: // See PIDController.h. There's a section on tuning in the reference. diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index ddc40d8490..84a4bc44b8 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,16 +70,16 @@ public: // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } - Q_INVOKABLE float getRenderDistanceLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } - Q_INVOKABLE float getRenderDistanceHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } + Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } + Q_INVOKABLE float getRenderDistanceInverseHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } Q_INVOKABLE int getNumberInRenderRange() { return _renderedAvatarCount; } Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); } Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); } Q_INVOKABLE void setRenderDistanceKP(float newValue) { _renderDistanceController.setKP(newValue); } Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); } Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } - Q_INVOKABLE void setRenderDistanceLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } - Q_INVOKABLE void setRenderDistanceHighLimit(float newValue); + Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } + Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue); public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 69ece359e9..5d01893873 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -204,7 +204,7 @@ void PreferencesDialog::loadPreferences() { auto lodManager = DependencyManager::get(); ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS()); ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS()); - ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceHighLimit()); + ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceInverseHighLimit()); } void PreferencesDialog::savePreferences() { @@ -295,5 +295,5 @@ void PreferencesDialog::savePreferences() { auto lodManager = DependencyManager::get(); lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value()); lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value()); - DependencyManager::get()->setRenderDistanceHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); + DependencyManager::get()->setRenderDistanceInverseHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); } From 3da80f58610be08f3a2551f9a243687c34c8784c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 24 Nov 2015 09:28:48 -0800 Subject: [PATCH 134/165] gpu::Shader::create* return shared_ptr --- interface/src/Stars.cpp | 16 +++---- .../RenderableParticleEffectEntityItem.cpp | 19 ++++----- .../src/RenderablePolyLineEntityItem.cpp | 8 ++-- .../src/RenderablePolyVoxEntityItem.cpp | 8 ++-- libraries/gpu/src/gpu/Pipeline.cpp | 8 ++-- libraries/gpu/src/gpu/Pipeline.h | 6 ++- libraries/gpu/src/gpu/Shader.cpp | 22 ++++------ libraries/gpu/src/gpu/Shader.h | 6 +-- libraries/gpu/src/gpu/StandardShaderLib.cpp | 16 +++---- libraries/model/src/model/Skybox.cpp | 8 ++-- .../procedural/src/procedural/Procedural.cpp | 8 ++-- .../src/AmbientOcclusionEffect.cpp | 32 +++++++------- libraries/render-utils/src/AnimDebugDraw.cpp | 8 ++-- .../render-utils/src/AntialiasingEffect.cpp | 16 +++---- .../src/DeferredLightingEffect.cpp | 22 +++++----- libraries/render-utils/src/Environment.cpp | 8 ++-- libraries/render-utils/src/GeometryCache.cpp | 12 +++--- libraries/render-utils/src/HitEffect.cpp | 8 ++-- libraries/render-utils/src/ModelRender.cpp | 42 +++++++++---------- .../render-utils/src/RenderDeferredTask.cpp | 14 +++---- libraries/render-utils/src/text/Font.cpp | 8 ++-- libraries/render/src/render/DrawStatus.cpp | 16 +++---- tests/gpu-test/src/main.cpp | 8 ++-- tests/render-utils/src/main.cpp | 6 +-- tests/shaders/src/main.cpp | 6 +-- 25 files changed, 163 insertions(+), 168 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 6145529b52..c8fd5188e2 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -130,9 +130,9 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { std::call_once(once, [&] { { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(starsGrid_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(starsGrid_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); _timeSlot = program->getBuffers().findLocation(UNIFORM_TIME_NAME); if (_timeSlot == gpu::Shader::INVALID_LOCATION) { @@ -143,12 +143,12 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { state->setDepthTest(gpu::State::DepthTest(false)); state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _gridPipeline.reset(gpu::Pipeline::create(program, state)); + _gridPipeline = gpu::Pipeline::create(program, state); } { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(stars_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(stars_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(stars_vert)); + auto ps = gpu::Shader::createPixel(std::string(stars_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = gpu::StatePointer(new gpu::State()); // enable decal blend @@ -156,7 +156,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _starsPipeline.reset(gpu::Pipeline::create(program, state)); + _starsPipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 05fca343fd..787b04811b 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -334,10 +334,10 @@ void RenderableParticleEffectEntityItem::createPipelines() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, destinationColorBlendArg, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(untextured_particle_vert))); - auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(untextured_particle_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _untexturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert)); + auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag)); + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _untexturedPipeline = gpu::Pipeline::create(program, state); } if (!_texturedPipeline) { auto state = std::make_shared(); @@ -349,17 +349,16 @@ void RenderableParticleEffectEntityItem::createPipelines() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, destinationColorBlendArg, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert))); + auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert)); gpu::ShaderPointer fragShader; if (_additiveBlending) { - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag))); + fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag)); } else { //If we are sorting and have no additive blending, we want to discard pixels with low alpha to avoid inter-particle entity artifacts - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag))); + fragShader = gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag)); } - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _texturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _texturedPipeline = gpu::Pipeline::create(program, state); } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 036d37a95b..30b1544e15 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -50,9 +50,9 @@ void RenderablePolyLineEntityItem::createPipeline() { _format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET); _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET); - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(paintStroke_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert)); + auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; PAINTSTROKE_GPU_SLOT = 0; @@ -64,7 +64,7 @@ void RenderablePolyLineEntityItem::createPipeline() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } void RenderablePolyLineEntityItem::updateGeometry() { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 16252eb453..c38378fc7c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -477,8 +477,8 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { _meshLock.unlock(); if (!_pipeline) { - gpu::ShaderPointer vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(polyvox_vert))); - gpu::ShaderPointer pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(polyvox_frag))); + gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert)); + gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag)); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); @@ -486,14 +486,14 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } gpu::Batch& batch = *args->_batch; diff --git a/libraries/gpu/src/gpu/Pipeline.cpp b/libraries/gpu/src/gpu/Pipeline.cpp index 501cb3fea4..e5d991f181 100755 --- a/libraries/gpu/src/gpu/Pipeline.cpp +++ b/libraries/gpu/src/gpu/Pipeline.cpp @@ -15,9 +15,7 @@ using namespace gpu; -Pipeline::Pipeline(): - _program(), - _state() +Pipeline::Pipeline() { } @@ -25,8 +23,8 @@ Pipeline::~Pipeline() { } -Pipeline* Pipeline::create(const ShaderPointer& program, const StatePointer& state) { - Pipeline* pipeline = new Pipeline(); +Pipeline::Pointer Pipeline::create(const ShaderPointer& program, const StatePointer& state) { + auto pipeline = Pointer(new Pipeline()); pipeline->_program = program; pipeline->_state = state; diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index 73e9a29913..adc65a0c66 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -22,7 +22,9 @@ namespace gpu { class Pipeline { public: - static Pipeline* create(const ShaderPointer& program, const StatePointer& state); + using Pointer = std::shared_ptr< Pipeline >; + + static Pointer create(const ShaderPointer& program, const StatePointer& state); ~Pipeline(); const ShaderPointer& getProgram() const { return _program; } @@ -44,7 +46,7 @@ protected: friend class Backend; }; -typedef std::shared_ptr< Pipeline > PipelinePointer; +typedef Pipeline::Pointer PipelinePointer; typedef std::vector< PipelinePointer > Pipelines; }; diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 60bcbdaed0..ddb3a0d755 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -36,24 +36,20 @@ Shader::~Shader() { } -Shader* Shader::createVertex(const Source& source) { - Shader* shader = new Shader(VERTEX, source); - return shader; +Shader::Pointer Shader::createVertex(const Source& source) { + return Pointer(new Shader(VERTEX, source)); } -Shader* Shader::createPixel(const Source& source) { - Shader* shader = new Shader(PIXEL, source); - return shader; +Shader::Pointer Shader::createPixel(const Source& source) { + return Pointer(new Shader(PIXEL, source)); } -Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { - if (vertexShader && vertexShader->getType() == VERTEX) { - if (pixelShader && pixelShader->getType() == PIXEL) { - Shader* shader = new Shader(PROGRAM, vertexShader, pixelShader); - return shader; - } +Shader::Pointer Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { + if (vertexShader && vertexShader->getType() == VERTEX && + pixelShader && pixelShader->getType() == PIXEL) { + return Pointer(new Shader(PROGRAM, vertexShader, pixelShader)); } - return nullptr; + return Pointer(); } void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 55812c6166..bceb00c71e 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -108,10 +108,10 @@ public: PROGRAM, }; - static Shader* createVertex(const Source& source); - static Shader* createPixel(const Source& source); + static Pointer createVertex(const Source& source); + static Pointer createPixel(const Source& source); - static Shader* createProgram(Pointer& vertexShader, Pointer& pixelShader); + static Pointer createProgram(Pointer& vertexShader, Pointer& pixelShader); ~Shader(); diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 864bff08c9..81500347fd 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -39,7 +39,7 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) { } else { auto vs = (getVS)(); auto ps = (getPS)(); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto program = gpu::Shader::createProgram(vs, ps); if (program) { // Program created, let's try to make it if (gpu::Shader::makeProgram((*program))) { @@ -59,42 +59,42 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) { ShaderPointer StandardShaderLib::getDrawUnitQuadTexcoordVS() { if (!_drawUnitQuadTexcoordVS) { - _drawUnitQuadTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert))); + _drawUnitQuadTexcoordVS = gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert)); } return _drawUnitQuadTexcoordVS; } ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() { if (!_drawTransformUnitQuadVS) { - _drawTransformUnitQuadVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawTransformUnitQuad_vert))); + _drawTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTransformUnitQuad_vert)); } return _drawTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS() { if (!_drawTexcoordRectTransformUnitQuadVS) { - _drawTexcoordRectTransformUnitQuadVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert))); + _drawTexcoordRectTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert)); } return _drawTexcoordRectTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() { if (!_drawViewportQuadTransformTexcoordVS) { - _drawViewportQuadTransformTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert))); + _drawViewportQuadTransformTexcoordVS = gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert)); } return _drawViewportQuadTransformTexcoordVS; } ShaderPointer StandardShaderLib::getDrawTexturePS() { if (!_drawTexturePS) { - _drawTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawTexture_frag))); + _drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag)); } return _drawTexturePS; } ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { if (!_drawTextureOpaquePS) { - _drawTextureOpaquePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag))); + _drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag)); } return _drawTextureOpaquePS; } @@ -103,7 +103,7 @@ ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { ShaderPointer StandardShaderLib::getDrawColoredTexturePS() { if (!_drawColoredTexturePS) { - _drawColoredTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawColoredTexture_frag))); + _drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)); } return _drawColoredTexturePS; } diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 21b40a54c8..3e445933fa 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -88,9 +88,9 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky } { - auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); - auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag))); - auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS)); + auto skyVS = gpu::Shader::createVertex(std::string(Skybox_vert)); + auto skyFS = gpu::Shader::createPixel(std::string(Skybox_frag)); + auto skyShader = gpu::Shader::createProgram(skyVS, skyFS); gpu::Shader::BindingSet bindings; bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), SKYBOX_SKYMAP_SLOT)); @@ -102,7 +102,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky auto skyState = std::make_shared(); skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); + thePipeline = gpu::Pipeline::create(skyShader, skyState); } }); diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index a0020d21f3..69a433d5e1 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -170,7 +170,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm if (!_pipeline || _pipelineDirty) { _pipelineDirty = true; if (!_vertexShader) { - _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(_vertexSource)); + _vertexShader = gpu::Shader::createVertex(_vertexSource); } // Build the fragment shader @@ -193,8 +193,8 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); } //qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str(); - _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource)); - _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); + _fragmentShader = gpu::Shader::createPixel(fragmentShaderSource); + _shader = gpu::Shader::createProgram(_vertexShader, _fragmentShader); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0)); @@ -203,7 +203,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3)); gpu::Shader::makeProgram(*_shader, slotBindings); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state)); + _pipeline = gpu::Pipeline::create(_shader, _state); for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) { const std::string& name = STANDARD_UNIFORM_NAMES[i]; _standardUniformSlots[i] = _shader->getUniforms().findLocation(name); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 456a6430a7..e54f55fc94 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -37,9 +37,9 @@ AmbientOcclusion::AmbientOcclusion() { const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { if (!_occlusionPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(ambient_occlusion_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); + auto ps = gpu::Shader::createPixel(std::string(ambient_occlusion_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); @@ -78,16 +78,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _occlusionPipeline.reset(gpu::Pipeline::create(program, state)); + _occlusionPipeline = gpu::Pipeline::create(program, state); } return _occlusionPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { if (!_vBlurPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -111,16 +111,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _vBlurPipeline.reset(gpu::Pipeline::create(program, state)); + _vBlurPipeline = gpu::Pipeline::create(program, state); } return _vBlurPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { if (!_hBlurPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -144,16 +144,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _hBlurPipeline.reset(gpu::Pipeline::create(program, state)); + _hBlurPipeline = gpu::Pipeline::create(program, state); } return _hBlurPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_blend_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); + auto ps = gpu::Shader::createPixel(std::string(occlusion_blend_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); @@ -169,7 +169,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { gpu::State::INV_SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::SRC_ALPHA); // Good to go add the brand new pipeline - _blendPipeline.reset(gpu::Pipeline::create(program, state)); + _blendPipeline = gpu::Pipeline::create(program, state); } return _blendPipeline; } diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index d110576c0d..d17676fe90 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -95,10 +95,10 @@ AnimDebugDraw::AnimDebugDraw() : state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(animdebugdraw_vert))); - auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(animdebugdraw_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto vertShader = gpu::Shader::createVertex(std::string(animdebugdraw_vert)); + auto fragShader = gpu::Shader::createPixel(std::string(animdebugdraw_frag)); + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _pipeline = gpu::Pipeline::create(program, state); _animDebugDrawData = std::make_shared(); _animDebugDrawPayload = std::make_shared(_animDebugDrawData); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index aaef67542f..d4707c172d 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -34,9 +34,9 @@ Antialiasing::Antialiasing() { const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { if (!_antialiasingPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); + auto ps = gpu::Shader::createPixel(std::string(fxaa_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); @@ -59,7 +59,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _antialiasingPipeline.reset(gpu::Pipeline::create(program, state)); + _antialiasingPipeline = gpu::Pipeline::create(program, state); } int w = DependencyManager::get()->getFrameBufferSize().width(); @@ -73,9 +73,9 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_blend_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); + auto ps = gpu::Shader::createPixel(std::string(fxaa_blend_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); @@ -87,7 +87,7 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { state->setDepthTest(false, false, gpu::LESS_EQUAL); // Good to go add the brand new pipeline - _blendPipeline.reset(gpu::Pipeline::create(program, state)); + _blendPipeline = gpu::Pipeline::create(program, state); } return _blendPipeline; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 57e3129ef8..342471454d 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -87,18 +87,18 @@ gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); _simplePrograms.insert(config, pipeline); return pipeline; } void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); - auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); + auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)); - _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); + _simpleShader = gpu::Shader::createProgram(VS, PS); + _emissiveShader = gpu::Shader::createProgram(VS, PSEmissive); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); @@ -150,7 +150,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); blitState->setColorWriteMask(true, true, true, false); - _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); + _blitLightBuffer = gpu::Pipeline::create(blitProgram, blitState); } // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light @@ -721,10 +721,10 @@ void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferU } static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); + auto VS = gpu::Shader::createVertex(std::string(vertSource)); + auto PS = gpu::Shader::createPixel(std::string(fragSource)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); @@ -769,7 +769,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo } else { state->setCullMode(gpu::State::CULL_BACK); } - pipeline.reset(gpu::Pipeline::create(program, state)); + pipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/render-utils/src/Environment.cpp b/libraries/render-utils/src/Environment.cpp index b26d402fa3..f7327a2b72 100644 --- a/libraries/render-utils/src/Environment.cpp +++ b/libraries/render-utils/src/Environment.cpp @@ -51,10 +51,10 @@ void Environment::init() { void Environment::setupAtmosphereProgram(const char* vertSource, const char* fragSource, gpu::PipelinePointer& pipeline, int* locations) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); + auto VS = gpu::Shader::createVertex(std::string(vertSource)); + auto PS = gpu::Shader::createPixel(std::string(fragSource)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -67,7 +67,7 @@ void Environment::setupAtmosphereProgram(const char* vertSource, const char* fra gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + pipeline = gpu::Pipeline::create(program, state); locations[CAMERA_POS_LOCATION] = program->getUniforms().findLocation("v3CameraPos"); locations[LIGHT_POS_LOCATION] = program->getUniforms().findLocation("v3LightPos"); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index eed52fccbc..75b3b91c10 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1701,9 +1701,9 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = std::make_shared(); @@ -1712,14 +1712,14 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { // enable decal blend state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _standardDrawPipeline.reset(gpu::Pipeline::create(program, state)); + _standardDrawPipeline = gpu::Pipeline::create(program, state); auto stateNoBlend = std::make_shared(); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); - auto programNoBlend = gpu::ShaderPointer(gpu::Shader::createProgram(vs, noBlendPS)); + auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); gpu::Shader::makeProgram((*programNoBlend)); - _standardDrawPipelineNoBlend.reset(gpu::Pipeline::create(programNoBlend, stateNoBlend)); + _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); } if (noBlend) { batch.setPipeline(_standardDrawPipelineNoBlend); diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index 06bd07b456..7e8b5f5fa0 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -36,9 +36,9 @@ HitEffect::HitEffect() { const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { if (!_hitEffectPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(hit_effect_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(hit_effect_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(hit_effect_vert)); + auto ps = gpu::Shader::createPixel(std::string(hit_effect_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -54,7 +54,7 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); // Good to go add the brand new pipeline - _hitEffectPipeline.reset(gpu::Pipeline::create(program, state)); + _hitEffectPipeline = gpu::Pipeline::create(program, state); } return _hitEffectPipeline; } diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp index c614fae67a..73f3d715b6 100644 --- a/libraries/render-utils/src/ModelRender.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -42,26 +42,26 @@ ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib; const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() { if (_renderPipelineLib.empty()) { // Vertex shaders - auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); - auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); - auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); - auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); - auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); - auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); - auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); - auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); + auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); + auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); // Pixel shaders - auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); - auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); - auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); - auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); - auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); - auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); - auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); - auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); - auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); - auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); + auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); + auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); + auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); // Fill the renderPipelineLib @@ -181,7 +181,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); @@ -209,7 +209,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); // Good to go add the brand new pipeline - auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto pipeline = gpu::Pipeline::create(program, state); insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); @@ -221,7 +221,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke wireframeState->setFillMode(gpu::State::FILL_LINE); // create a new RenderPipeline with the same shader side and the wireframe state - auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); } } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e65018ad3d..1430651c86 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -231,16 +231,16 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const gpu::PipelinePointer DrawOverlay3D::_opaquePipeline; const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { if (!_opaquePipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(overlay3D_vert)); + auto ps = gpu::Shader::createPixel(std::string(overlay3D_frag)); + auto program = gpu::Shader::createProgram(vs, ps); auto state = std::make_shared(); state->setDepthTest(false); // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _opaquePipeline.reset(gpu::Pipeline::create(program, state)); + _opaquePipeline = gpu::Pipeline::create(program, state); } return _opaquePipeline; } @@ -307,8 +307,8 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() { if (!_opaquePipeline) { const gpu::int8 STENCIL_OPAQUE = 1; auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto ps = gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); @@ -318,7 +318,7 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); state->setColorWriteMask(0); - _opaquePipeline.reset(gpu::Pipeline::create(program, state)); + _opaquePipeline = gpu::Pipeline::create(program, state); } return _opaquePipeline; } diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 0157d873d3..5587185ead 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -216,9 +216,9 @@ void Font::setupGPU() { // Setup render pipeline { - auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text3D_vert))); - auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text3D_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert)); + auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -233,7 +233,7 @@ void Font::setupGPU() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } // Sanity checks diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 5e8fd74e5f..3f37ce378b 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -31,9 +31,9 @@ using namespace render; const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { if (!_drawItemBoundsPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -51,16 +51,16 @@ const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); // Good to go add the brand new pipeline - _drawItemBoundsPipeline.reset(gpu::Pipeline::create(program, state)); + _drawItemBoundsPipeline = gpu::Pipeline::create(program, state); } return _drawItemBoundsPipeline; } const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { if (!_drawItemStatusPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(drawItemStatus_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemStatus_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("iconStatusMap"), 0)); @@ -81,7 +81,7 @@ const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); // Good to go add the brand new pipeline - _drawItemStatusPipeline.reset(gpu::Pipeline::create(program, state)); + _drawItemStatusPipeline = gpu::Pipeline::create(program, state); } return _drawItemStatusPipeline; } diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index 80c2dbf8e9..47ed582f3c 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -85,9 +85,9 @@ public: uint32_t toCompactColor(const glm::vec4& color); gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(vertexShaderSrc)); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSrc)); - auto shader = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(vertexShaderSrc); + auto fs = gpu::Shader::createPixel(fragmentShaderSrc); + auto shader = gpu::Shader::createProgram(vs, fs); if (!gpu::Shader::makeProgram(*shader, bindings)) { printf("Could not compile shader\n"); exit(-1); @@ -172,7 +172,7 @@ public: auto state = std::make_shared(); state->setMultisampleEnable(true); state->setDepthTest(gpu::State::DepthTest { true }); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); + _pipeline = gpu::Pipeline::create(shader, state); _instanceLocation = _pipeline->getProgram()->getUniforms().findLocation("Instanced"); // Clear screen diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 0fa261db8d..7ae2bd1166 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -170,9 +170,9 @@ static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { void testShaderBuild(const char* vs_src, const char * fs_src) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vs_src))); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fs_src))); - auto pr = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(std::string(vs_src)); + auto fs = gpu::Shader::createPixel(std::string(fs_src)); + auto pr = gpu::Shader::createProgram(vs, fs); gpu::Shader::makeProgram(*pr); } diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 3edff67d66..f162aae89a 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -160,9 +160,9 @@ public: }; void testShaderBuild(const char* vs_src, const char * fs_src) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vs_src))); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fs_src))); - auto pr = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(std::string(vs_src)); + auto fs = gpu::Shader::createPixel(std::string(fs_src)); + auto pr = gpu::Shader::createProgram(vs, fs); if (!gpu::Shader::makeProgram(*pr)) { throw std::runtime_error("Failed to compile shader"); } From a600df5ea646c0e41639e5aed07ac550aad672b4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 16:04:39 -0800 Subject: [PATCH 135/165] try a different method of exagerating hand motion onto distanly held object --- examples/controllers/handControllerGrab.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ebfa248f58..5763115bfc 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -34,7 +34,7 @@ var BUMPER_ON_VALUE = 0.5; // distant manipulation // -var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did @@ -659,6 +659,12 @@ function MyController(hand) { this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); this.handPreviousRotation = handRotation; + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + this.actionID = NULL_ACTION_ID; this.actionID = Entities.addAction("spring", this.grabbedEntity, { targetPosition: this.currentObjectPosition, @@ -689,8 +695,6 @@ function MyController(hand) { this.currentAvatarOrientation = MyAvatar.orientation; this.overlayLineOff(); - - }; this.continueDistanceHolding = function() { @@ -719,8 +723,12 @@ function MyController(hand) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * - DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR); + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + // how far did avatar move this timestep? var currentPosition = MyAvatar.position; var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); @@ -751,11 +759,11 @@ function MyController(hand) { var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); this.handRelativePreviousPosition = handToAvatar; - // magnify the hand movement but not the change from avatar movement & rotation + // magnify the hand movement but not the change from avatar movement & rotation handMoved = Vec3.subtract(handMoved, handMovementFromTurning); var superHandMoved = Vec3.multiply(handMoved, radius); - // Move the object by the magnified amount and then by amount from avatar movement & rotation + // Move the object by the magnified amount and then by amount from avatar movement & rotation var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); From 1b42c5a172267efe7e4b7ba92ff586e675e49ded Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 3 Dec 2015 16:16:01 -0800 Subject: [PATCH 136/165] Make MyAvatar.get/setAnimGraphUrl take a url(!), and make setting it actually do something. --- interface/src/avatar/MyAvatar.cpp | 18 +++++++++++++++--- interface/src/avatar/MyAvatar.h | 6 +++--- interface/src/ui/PreferencesDialog.cpp | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index eca39a0a44..1b1dc563c9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1283,6 +1283,15 @@ void MyAvatar::initHeadBones() { } } +void MyAvatar::setAnimGraphUrl(const QUrl& url) { + if (_animGraphUrl == url) { + return; + } + destroyAnimGraph(); + _animGraphUrl = url; + initAnimGraph(); +} + void MyAvatar::initAnimGraph() { // avatar.json // https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9 @@ -1299,16 +1308,19 @@ void MyAvatar::initAnimGraph() { // or run a local web-server // python -m SimpleHTTPServer& //auto graphUrl = QUrl("http://localhost:8000/avatar.json"); - auto graphUrl = QUrl(_animGraphUrl.isEmpty() ? - QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : - _animGraphUrl); + auto graphUrl =_animGraphUrl.isEmpty() ? + QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : + QUrl(_animGraphUrl); + qCDebug(interfaceapp) << "*** FIXME initAnimGraph" << graphUrl.toString(); _rig->initAnimGraph(graphUrl); _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + qCDebug(interfaceapp) << "*** FIXME initAnimGraph ready" << graphUrl.toString(); } void MyAvatar::destroyAnimGraph() { + qCDebug(interfaceapp) << "*** FIXME destroyAnimGraph" << _animGraphUrl.toString(); _rig->destroyAnimGraph(); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 13575388e3..3698ac02dc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -253,13 +253,13 @@ public slots: virtual void rebuildSkeletonBody() override; - const QString& getAnimGraphUrl() const { return _animGraphUrl; } + Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; } void setEnableDebugDrawDefaultPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled); void setEnableDebugDrawPosition(bool isEnabled); void setEnableMeshVisible(bool isEnabled); - void setAnimGraphUrl(const QString& url) { _animGraphUrl = url; } + Q_INVOKABLE void setAnimGraphUrl(const QUrl& url); glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); @@ -360,7 +360,7 @@ private: // Avatar Preferences QUrl _fullAvatarURLFromPreferences; QString _fullAvatarModelName; - QString _animGraphUrl {""}; + QUrl _animGraphUrl {""}; // cache of the current HMD sensor position and orientation // in sensor space. diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index c37755b823..a82fb39be7 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -190,7 +190,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); ui.avatarScaleSpin->setValue(myAvatar->getScale()); - ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl()); + ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); From 1d01f083240b38796871c83b8fef333a48c0827c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Dec 2015 16:27:35 -0800 Subject: [PATCH 137/165] Fix compiler warnings --- libraries/audio/src/AudioReverb.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index f06bbe76ed..f9e891ec30 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -34,6 +34,7 @@ inline static int MULHI(int a, int b) { #endif static const float PHI = 0.6180339887f; // maximum allpass diffusion +static const float TWOPI = 6.283185307f; static const double PI = 3.14159265358979323846; static const double SQRT2 = 1.41421356237309504880; @@ -383,7 +384,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { // Biquad Peaking EQ using analog matching. // Supports full range of w0. // -static void BQPeak(double coef[5], double w0, double dbgain, double Q) { +void BQPeak(double coef[5], double w0, double dbgain, double Q) { w0 = MAX(w0, 0.0); // allow w0 > pi Q = MIN(MAX(Q, 1.0e-6), 1.0e+6); @@ -402,7 +403,7 @@ static void BQPeak(double coef[5], double w0, double dbgain, double Q) { // // Biquad Shelf using analog matching. // -static void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { +void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { double G, G1; double wpi, wn, wd; double wna, wda; @@ -499,7 +500,7 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, // Biquad Lowpass/Highpass using analog matching. // Q = sqrt(0.5) = 2nd order Butterworth // -static void BQFilter(double coef[5], double w0, int isHigh) { +void BQFilter(double coef[5], double w0, int isHigh) { double G1; double wpi, wn, wd; double wna, wda; @@ -587,7 +588,7 @@ static void BQFilter(double coef[5], double w0, int isHigh) { // PoleZero Shelf. For Lowpass/Highpass, setCoef dbgain to -100dB. // NOTE: w0 always sets the pole frequency (3dB corner from unity gain) // -static void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { +void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { double G, G0, G1; double b0, b1, a0, a1; double temp, scale; @@ -653,7 +654,7 @@ public: // lowpass filter, -3dB @ freq double coef[5]; - BQFilter(coef, PI * freq / (0.5 * sampleRate), 0); + BQFilter(coef, TWOPI * freq / sampleRate, 0); _b0 = (float)coef[0]; _b1 = (float)coef[1]; _b2 = (float)coef[2]; @@ -661,7 +662,7 @@ public: _a2 = (float)coef[4]; // DC-blocking filter, -3dB @ 10Hz - _alpha = (float)(1.0 - exp(-PI * 10.0 / (0.5 * sampleRate))); + _alpha = 1.0f - expf(-TWOPI * 10.0f / sampleRate); } void process(float input0, float input1, float& output0, float& output1) { @@ -807,11 +808,13 @@ public: freq = MIN(freq, 1/16.0f * sampleRate); freq = MAX(freq, 1/16777216.0f * sampleRate); - // amplitude slightly less than 1.0 - _y0 = (int32_t)(0.000 * FIXQ31); - _y1 = (int32_t)(0.999 * cos(PI * freq / sampleRate) * FIXQ31); + double w = PI * (double)freq / (double)sampleRate; - _k = (int32_t)(2.0 * sin(PI * freq / sampleRate) * FIXQ32); + // amplitude slightly less than 1.0 + _y0 = 0; + _y1 = (int32_t)(0.999 * cos(w) * FIXQ31); + + _k = (int32_t)(2.0 * sin(w) * FIXQ32); } void setGain(int32_t gain) { @@ -985,8 +988,8 @@ public: freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); double coefLo[3], coefHi[3]; - PZShelf(coefLo, PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf - PZShelf(coefHi, PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + PZShelf(coefLo, TWOPI * freq0 / sampleRate, dBgain0, 0); // low shelf + PZShelf(coefHi, TWOPI * freq1 / sampleRate, dBgain1, 1); // high shelf // convolve into a single biquad _b0 = (float)(coefLo[0] * coefHi[0]); @@ -1407,7 +1410,7 @@ void ReverbImpl::setParameters(ReverbParameters *p) { // Modulation _lfo.setFreq(p->modRate, sampleRate); - _lfo.setGain((int32_t)MIN(MAX(p->modDepth * (1/100.0) * FIXQ31, 0.0), 0X7fffffff)); + _lfo.setGain((int32_t)MIN(MAX((double)p->modDepth * (1/100.0) * FIXQ31, 0.0), (double)0x7fffffff)); // // Set delays From 187c213f416bb2a29d9e5f40ea916b3dc863c281 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 3 Dec 2015 16:42:57 -0800 Subject: [PATCH 138/165] reset skeleton --- interface/src/avatar/MyAvatar.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1b1dc563c9..2ccaf2d1c8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1288,6 +1288,7 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { return; } destroyAnimGraph(); + _skeletonModel.reset(); // Why is this necessary? Without this, we crash in the next render. _animGraphUrl = url; initAnimGraph(); } @@ -1311,16 +1312,13 @@ void MyAvatar::initAnimGraph() { auto graphUrl =_animGraphUrl.isEmpty() ? QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : QUrl(_animGraphUrl); - qCDebug(interfaceapp) << "*** FIXME initAnimGraph" << graphUrl.toString(); _rig->initAnimGraph(graphUrl); _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - qCDebug(interfaceapp) << "*** FIXME initAnimGraph ready" << graphUrl.toString(); } void MyAvatar::destroyAnimGraph() { - qCDebug(interfaceapp) << "*** FIXME destroyAnimGraph" << _animGraphUrl.toString(); _rig->destroyAnimGraph(); } From 528b8e5d3f452937dba766f4fcb5f28bb06d9afe Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 16:45:01 -0800 Subject: [PATCH 139/165] fix warnings --- libraries/octree/src/Octree.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 64a2eaccc4..6da59f00a3 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1438,15 +1438,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); - // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the - // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, - // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make - // a single recursive pass in distance sorted order, but retain standard order in our encoded packet - int recursiveSliceSizes[NUMBER_OF_CHILDREN]; - const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); - int allSlicesSize = 0; - // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { @@ -1456,9 +1447,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; - // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); - int childTreeBytesOut = 0; // NOTE: some octree styles (like models and particles) will store content in parent elements, and child @@ -1478,10 +1466,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - // remember this for reshuffling - recursiveSliceSizes[originalIndex] = childTreeBytesOut; - allSlicesSize += childTreeBytesOut; - // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. From 17b5ade9c039b7d76a4bc4f8a42c1f810cc8f22f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 16:45:46 -0800 Subject: [PATCH 140/165] allow moving distantly grabbed objects with head --- examples/controllers/handControllerGrab.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5763115bfc..bcb76716d9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -37,6 +37,7 @@ var BUMPER_ON_VALUE = 0.5; var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = false; // experimental head-controll of distantly held objects var NO_INTERSECT_COLOR = { red: 10, @@ -658,6 +659,7 @@ function MyController(hand) { this.currentObjectTime = now; this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); @@ -785,6 +787,16 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); + var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, From 5a75a1717437c60f750503f3f42274462837687a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 17:40:41 -0800 Subject: [PATCH 141/165] Revert "Cruft removal" --- .../src/octree/OctreeQueryNode.cpp | 10 +- .../src/octree/OctreeQueryNode.h | 6 +- .../src/octree/OctreeSendThread.cpp | 24 +- interface/src/Application.cpp | 3 + .../entities/src/EntityItemProperties.cpp | 4 +- libraries/octree/src/CoverageMap.cpp | 542 ++++++++++++++++++ libraries/octree/src/CoverageMap.h | 120 ++++ libraries/octree/src/CoverageMapV2.cpp | 251 ++++++++ libraries/octree/src/CoverageMapV2.h | 72 +++ libraries/octree/src/Octree.cpp | 232 ++++++-- libraries/octree/src/Octree.h | 19 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 3 + libraries/octree/src/OctreePacketData.cpp | 9 +- libraries/octree/src/OctreePacketData.h | 6 +- libraries/octree/src/OctreeQuery.cpp | 6 + libraries/octree/src/OctreeQuery.h | 15 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 + libraries/shared/src/OctalCode.h | 2 + 21 files changed, 1272 insertions(+), 85 deletions(-) create mode 100644 libraries/octree/src/CoverageMap.cpp create mode 100644 libraries/octree/src/CoverageMap.h create mode 100644 libraries/octree/src/CoverageMapV2.cpp create mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cafba8c083..cff2c7ee2e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,9 +179,15 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. + _currentPacketIsColor = getWantColor(); + _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; - setAtBit(flags, PACKET_IS_COLOR_BIT); - setAtBit(flags, PACKET_IS_COMPRESSED_BIT); + if (_currentPacketIsColor) { + setAtBit(flags, PACKET_IS_COLOR_BIT); + } + if (_currentPacketIsCompressed) { + setAtBit(flags, PACKET_IS_COMPRESSED_BIT); + } _octreePacket->reset(); diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 67298296e9..0c691a06a2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -54,6 +55,7 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; + CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } @@ -77,7 +79,9 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { return (getCurrentPacketIsCompressed() == true); } // FIXME + bool getCurrentPacketFormatMatches() { + return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d01117dff6..0a32f574de 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,6 +321,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. + bool wantColor = nodeData->getWantColor(); + bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. @@ -331,8 +333,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - _packetData.changeSettings(targetSize); + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + } + _packetData.changeSettings(wantCompression, targetSize); } const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -346,6 +350,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } + nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -446,15 +451,18 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ + bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); + CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; + float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - boundaryLevelAdjust, octreeSizeScale, + wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -548,7 +556,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + } } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. // but we've finalized the _packetData, so we want to start a new section, we will do that by @@ -558,7 +569,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - _packetData.changeSettings(targetSize); // will do reset + _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); @@ -623,6 +634,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); + nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 199fdecb8e..e6678c8758 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); + _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); + _octreeQuery.setWantOcclusionCulling(false); + _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 30bee83482..78a4f3e8b6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -790,9 +790,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue // bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer) { - - // FIXME - remove non-compressed OctreePacketData and handle compressed edit packets - OctreePacketData ourDataPacket(buffer.size(), false); // create a packetData object to add out packet details too. + OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro bool success = true; // assume the best diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp new file mode 100644 index 0000000000..626d4bcf1a --- /dev/null +++ b/libraries/octree/src/CoverageMap.cpp @@ -0,0 +1,542 @@ +// +// CoverageMap.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include + +#include + +#include "OctreeLogging.h" +#include "CoverageMap.h" + +int CoverageMap::_mapCount = 0; +int CoverageMap::_checkMapRootCalls = 0; +int CoverageMap::_notAllInView = 0; +bool CoverageMap::wantDebugging = false; + +const int MAX_POLYGONS_PER_REGION = 50; + +const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); + +// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. +// +// (0,0) (windowWidth, 0) +// -1,1 1,1 +// +-----------------------+ +// | | | +// | | | +// | -1,0 | | +// |-----------+-----------| +// | 0,0 | +// | | | +// | | | +// | | | +// +-----------------------+ +// -1,-1 1,-1 +// (0,windowHeight) (windowWidth,windowHeight) +// + +// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide +// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically +// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" +// then we can calculate a reasonable polygon area +const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; +const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; +const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); +const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * + (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); + +CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _managePolygons(managePolygons), + _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), + _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), + _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), + _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), + _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) +{ + _mapCount++; + init(); +}; + +CoverageMap::~CoverageMap() { + erase(); +}; + +void CoverageMap::printStats() { + qCDebug(octree, "CoverageMap::printStats()..."); + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); + qCDebug(octree, "_mapCount=%d",_mapCount); + qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); + qCDebug(octree, "_notAllInView=%d",_notAllInView); + qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); + qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); + qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); + qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); + qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); + qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); + qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); + qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); +} + +void CoverageMap::erase() { + // tell our regions to erase() + _topHalf.erase(); + _bottomHalf.erase(); + _leftHalf.erase(); + _rightHalf.erase(); + _remainder.erase(); + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (_childMaps[i]) { + delete _childMaps[i]; + _childMaps[i] = NULL; + } + } + + if (_isRoot && wantDebugging) { + qCDebug(octree, "CoverageMap last to be deleted..."); + printStats(); + + CoverageRegion::_maxPolygonsUsed = 0; + CoverageRegion::_totalPolygons = 0; + CoverageRegion::_occlusionTests = 0; + CoverageRegion::_regionSkips = 0; + CoverageRegion::_tooSmallSkips = 0; + CoverageRegion::_regionFullSkips = 0; + CoverageRegion::_outOfOrderPolygon = 0; + CoverageRegion::_clippedPolygons = 0; + _mapCount = 0; + _checkMapRootCalls = 0; + _notAllInView = 0; + } +} + +void CoverageMap::init() { + memset(_childMaps,0,sizeof(_childMaps)); +} + +// 0 = bottom, right +// 1 = bottom, left +// 2 = top, right +// 3 = top, left +BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { + const int LEFT_BIT = 1; + const int TOP_BIT = 2; + // initialize to our corner, and half our size + BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); + // if our "left" bit is set, then add size.x to the corner + if ((childIndex & LEFT_BIT) == LEFT_BIT) { + result.corner.x += result.size.x; + } + // if our "top" bit is set, then add size.y to the corner + if ((childIndex & TOP_BIT) == TOP_BIT) { + result.corner.y += result.size.y; + } + return result; +} + +int CoverageMap::getPolygonCount() const { + return (_topHalf.getPolygonCount() + + _bottomHalf.getPolygonCount() + + _leftHalf.getPolygonCount() + + _rightHalf.getPolygonCount() + + _remainder.getPolygonCount()); +} + +OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { + int base = 0; + if ((index - base) < _topHalf.getPolygonCount()) { + return _topHalf.getPolygon((index - base)); + } + base += _topHalf.getPolygonCount(); + + if ((index - base) < _bottomHalf.getPolygonCount()) { + return _bottomHalf.getPolygon((index - base)); + } + base += _bottomHalf.getPolygonCount(); + + if ((index - base) < _leftHalf.getPolygonCount()) { + return _leftHalf.getPolygon((index - base)); + } + base += _leftHalf.getPolygonCount(); + + if ((index - base) < _rightHalf.getPolygonCount()) { + return _rightHalf.getPolygon((index - base)); + } + base += _rightHalf.getPolygonCount(); + + if ((index - base) < _remainder.getPolygonCount()) { + return _remainder.getPolygon((index - base)); + } + return NULL; +} + + + +// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT +CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { + + if (_isRoot) { + _checkMapRootCalls++; + } + + // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is + // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. + if (!polygon->getAllInView()) { + _notAllInView++; + return DOESNT_FIT; + } + + BoundingBox polygonBox(polygon->getBoundingBox()); + if (_isRoot || _myBoundingBox.contains(polygonBox)) { + + CoverageMapStorageResult result = NOT_STORED; + CoverageRegion* storeIn = &_remainder; + + // Check each half of the box independently + const bool useRegions = true; // for now we will continue to use regions + if (useRegions) { + if (_topHalf.contains(polygonBox)) { + result = _topHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_topHalf; + } else if (_bottomHalf.contains(polygonBox)) { + result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_bottomHalf; + } else if (_leftHalf.contains(polygonBox)) { + result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_leftHalf; + } else if (_rightHalf.contains(polygonBox)) { + result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_rightHalf; + } + } + + // if we got this far, there are one of two possibilities, either a polygon doesn't fit + // in one of the halves, or it did fit, but it wasn't occluded by anything only in that + // half. In either of these cases, we want to check our remainder region to see if its + // occluded by anything there + if (!(result == STORED || result == OCCLUDED)) { + result = _remainder.checkRegion(polygon, polygonBox, storeIt); + } + + // It's possible that this first set of checks might have resulted in an out of order polygon + // in which case we just return.. + if (result == STORED || result == OCCLUDED) { + + /* + if (result == STORED) + qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); + else + qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); + */ + + return result; + } + + // if we made it here, then it means the polygon being stored is not occluded + // at this level of the quad tree, so we can continue to insert it into the map. + // First we check to see if it fits in any of our sub maps + const bool useChildMaps = true; // for now we will continue to use child maps + if (useChildMaps) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + BoundingBox childMapBoundingBox = getChildBoundingBox(i); + if (childMapBoundingBox.contains(polygon->getBoundingBox())) { + // if no child map exists yet, then create it + if (!_childMaps[i]) { + _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); + } + result = _childMaps[i]->checkMap(polygon, storeIt); + + /* + switch (result) { + case STORED: + qCDebug(octree, "checkMap() = STORED\n"); + break; + case NOT_STORED: + qCDebug(octree, "checkMap() = NOT_STORED\n"); + break; + case OCCLUDED: + qCDebug(octree, "checkMap() = OCCLUDED\n"); + break; + default: + qCDebug(octree, "checkMap() = ????? \n"); + break; + } + */ + + return result; + } + } + } + // if we got this far, then the polygon is in our bounding box, but doesn't fit in + // any of our child bounding boxes, so we should add it here. + if (storeIt) { + if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { + if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { + storeIn->storeInArray(polygon); + return STORED; + } else { + CoverageRegion::_regionFullSkips++; + return NOT_STORED; + } + } else { + CoverageRegion::_tooSmallSkips++; + return NOT_STORED; + } + } else { + return NOT_STORED; + } + } + return DOESNT_FIT; +} + + +CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _managePolygons(managePolygons), + _regionName(regionName) +{ + init(); +}; + +CoverageRegion::~CoverageRegion() { + erase(); +}; + +void CoverageRegion::init() { + _polygonCount = 0; + _polygonArraySize = 0; + _polygons = NULL; + _polygonDistances = NULL; + _polygonSizes = NULL; +} + + +void CoverageRegion::erase() { + +/** + if (_polygonCount) { + qCDebug(octree, "CoverageRegion::erase()...\n"); + qCDebug(octree, "_polygonCount=%d\n",_polygonCount); + _myBoundingBox.printDebugDetails(getRegionName()); + //for (int i = 0; i < _polygonCount; i++) { + // qCDebug(octree, "_polygons[%d]=",i); + // _polygons[i]->getBoundingBox().printDebugDetails(); + //} + } +**/ + // If we're in charge of managing the polygons, then clean them up first + if (_polygons && _managePolygons) { + for (int i = 0; i < _polygonCount; i++) { + delete _polygons[i]; + _polygons[i] = NULL; // do we need to do this? + } + } + + // Now, clean up our local storage + _polygonCount = 0; + _polygonArraySize = 0; + if (_polygons) { + delete[] _polygons; + _polygons = NULL; + } + if (_polygonDistances) { + delete[] _polygonDistances; + _polygonDistances = NULL; + } + if (_polygonSizes) { + delete[] _polygonSizes; + _polygonSizes = NULL; + } +} + +void CoverageRegion::growPolygonArray() { + OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; + float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; + float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; + + + if (_polygons) { + memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); + delete[] _polygons; + memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); + delete[] _polygonDistances; + memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); + delete[] _polygonSizes; + } + _polygons = newPolygons; + _polygonDistances = newDistances; + _polygonSizes = newSizes; + _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; +} + +const char* CoverageRegion::getRegionName() const { + switch (_regionName) { + case TOP_HALF: + return "TOP_HALF"; + case BOTTOM_HALF: + return "BOTTOM_HALF"; + case LEFT_HALF: + return "LEFT_HALF"; + case RIGHT_HALF: + return "RIGHT_HALF"; + default: + case REMAINDER: + return "REMAINDER"; + } + return "REMAINDER"; +} + +int CoverageRegion::_maxPolygonsUsed = 0; +int CoverageRegion::_totalPolygons = 0; +int CoverageRegion::_occlusionTests = 0; +int CoverageRegion::_regionSkips = 0; +int CoverageRegion::_tooSmallSkips = 0; +int CoverageRegion::_regionFullSkips = 0; +int CoverageRegion::_outOfOrderPolygon = 0; +int CoverageRegion::_clippedPolygons = 0; + + +bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { + for (int i = 0; i < _polygonCount; i++) { + OctreeProjectedPolygon* otherPolygon = _polygons[i]; + if (otherPolygon->canMerge(*seed)) { + otherPolygon->merge(*seed); + + if (seedInArray) { + int* IGNORED_ADDRESS = NULL; + // remove this otherOtherPolygon for our polygon array + _polygonCount = removeFromSortedArrays((void*)seed, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + _totalPolygons--; + } + + // clean up + if (_managePolygons) { + delete seed; + } + + // Now run again using our newly merged polygon as the seed + mergeItemsInArray(otherPolygon, true); + + return true; + } + } + return false; +} + +// just handles storage in the array, doesn't test for occlusion or +// determining if this is the correct map to store in! +void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { + + _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); + + + // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing + // polygons already in our array. + if (mergeItemsInArray(polygon, false)) { + return; // exit early + } + + // only after we attempt to merge! + _totalPolygons++; + + if (_polygonArraySize < _polygonCount + 1) { + growPolygonArray(); + } + + // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order + // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier + // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since + // sometimes things come out of order. + const bool SORT_BY_SIZE = false; + const int IGNORED = 0; + int* IGNORED_ADDRESS = NULL; + if (SORT_BY_SIZE) { + // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to + // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the + // insertion point in this array, and shift the array accordingly + float area = polygon->getBoundingBox().area(); + float reverseArea = 4.0f - area; + _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, + (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + } else { + _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + } + + // Debugging and Optimization Tuning code. + if (_polygonCount > _maxPolygonsUsed) { + _maxPolygonsUsed = _polygonCount; + } +} + + + +CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { + + CoverageMapStorageResult result = DOESNT_FIT; + + if (_isRoot || _myBoundingBox.contains(polygonBox)) { + result = NOT_STORED; // if we got here, then we DO fit... + + // only actually check the polygons if this polygon is in the covered bounds for this region + if (!_currentCoveredBounds.contains(polygonBox)) { + _regionSkips += _polygonCount; + } else { + // check to make sure this polygon isn't occluded by something at this level + for (int i = 0; i < _polygonCount; i++) { + OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; + + // Check to make sure that the polygon in question is "behind" the polygon in the list + // otherwise, we don't need to test it's occlusion (although, it means we've potentially + // added an item previously that may be occluded??? Is that possible? Maybe not, because two + // voxels can't have the exact same outline. So one occludes the other, they can't both occlude + // each other. + + _occlusionTests++; + if (polygonAtThisLevel->occludes(*polygon)) { + // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't + // want to report our inserted one as occluded, but we do want to add our inserted one. + if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { + _outOfOrderPolygon++; + if (storeIt) { + if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { + if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { + storeInArray(polygon); + return STORED; + } else { + CoverageRegion::_regionFullSkips++; + return NOT_STORED; + } + } else { + _tooSmallSkips++; + return NOT_STORED; + } + } else { + return NOT_STORED; + } + } + // this polygon is occluded by a closer polygon, so don't store it, and let the caller know + return OCCLUDED; + } + } + } + } + return result; +} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h new file mode 100644 index 0000000000..bff6bb1078 --- /dev/null +++ b/libraries/octree/src/CoverageMap.h @@ -0,0 +1,120 @@ +// +// CoverageMap.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CoverageMap_h +#define hifi_CoverageMap_h + +#include +#include "OctreeProjectedPolygon.h" + +typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; +typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; + +class CoverageRegion { + +public: + + CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); + ~CoverageRegion(); + + CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); + void storeInArray(OctreeProjectedPolygon* polygon); + + bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; + void erase(); // erase the coverage region + + static int _maxPolygonsUsed; + static int _totalPolygons; + static int _occlusionTests; + static int _regionSkips; + static int _tooSmallSkips; + static int _regionFullSkips; + static int _outOfOrderPolygon; + static int _clippedPolygons; + + + const char* getRegionName() const; + + int getPolygonCount() const { return _polygonCount; }; + OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; + +private: + void init(); + + bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT + BoundingBox _myBoundingBox; + BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon + bool _managePolygons; // will the coverage map delete the polygons on destruct + RegionName _regionName; + int _polygonCount; // how many polygons at this level + int _polygonArraySize; // how much room is there to store polygons at this level + OctreeProjectedPolygon** _polygons; + + // we will use one or the other of these depending on settings in the code. + float* _polygonDistances; + float* _polygonSizes; + void growPolygonArray(); + static const int DEFAULT_GROW_SIZE = 100; + + bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); + +}; + +class CoverageMap { + +public: + static const int NUMBER_OF_CHILDREN = 4; + static const bool NOT_ROOT=false; + static const bool IS_ROOT=true; + static const BoundingBox ROOT_BOUNDING_BOX; + static const float MINIMUM_POLYGON_AREA_TO_STORE; + + CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); + ~CoverageMap(); + + CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); + + BoundingBox getChildBoundingBox(int childIndex); + + void erase(); // erase the coverage map + void printStats(); + + static bool wantDebugging; + + int getPolygonCount() const; + OctreeProjectedPolygon* getPolygon(int index) const; + CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; + +private: + void init(); + + bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT + BoundingBox _myBoundingBox; + CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; + bool _managePolygons; // will the coverage map delete the polygons on destruct + + // We divide the map into 5 regions representing each possible half of the map, and the whole map + // this allows us to keep the list of polygons shorter + CoverageRegion _topHalf; + CoverageRegion _bottomHalf; + CoverageRegion _leftHalf; + CoverageRegion _rightHalf; + CoverageRegion _remainder; + + static int _mapCount; + static int _checkMapRootCalls; + static int _notAllInView; +}; + + +#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp new file mode 100644 index 0000000000..8467ea1ee9 --- /dev/null +++ b/libraries/octree/src/CoverageMapV2.cpp @@ -0,0 +1,251 @@ +// +// CoverageMapV2.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include + +#include + +#include + +#include "OctreeLogging.h" +#include "CoverageMapV2.h" + +int CoverageMapV2::_mapCount = 0; +int CoverageMapV2::_checkMapRootCalls = 0; +int CoverageMapV2::_notAllInView = 0; +bool CoverageMapV2::wantDebugging = false; + +const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); + +// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. +// +// (0,0) (windowWidth, 0) +// -1,1 1,1 +// +-----------------------+ +// | | | +// | | | +// | -1,0 | | +// |-----------+-----------| +// | 0,0 | +// | | | +// | | | +// | | | +// +-----------------------+ +// -1,-1 1,-1 +// (0,windowHeight) (windowWidth,windowHeight) +// + +// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide +// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically +// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" +// then we can calculate a reasonable polygon area +const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; +const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; +const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); +const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * + (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); +const float CoverageMapV2::NOT_COVERED = FLT_MAX; +const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly + + +CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _isCovered(isCovered), + _coveredDistance(coverageDistance) +{ + _mapCount++; + init(); +}; + +CoverageMapV2::~CoverageMapV2() { + erase(); +}; + +void CoverageMapV2::erase() { + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (_childMaps[i]) { + delete _childMaps[i]; + _childMaps[i] = NULL; + } + } + + if (_isRoot && wantDebugging) { + qCDebug(octree, "CoverageMapV2 last to be deleted..."); + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); + qCDebug(octree, "_mapCount=%d",_mapCount); + qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); + qCDebug(octree, "_notAllInView=%d",_notAllInView); + _mapCount = 0; + _checkMapRootCalls = 0; + _notAllInView = 0; + } +} + +void CoverageMapV2::init() { + memset(_childMaps,0,sizeof(_childMaps)); +} + +// 0 = bottom, left +// 1 = bottom, right +// 2 = top, left +// 3 = top, right +BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { + const int RIGHT_BIT = 1; + const int TOP_BIT = 2; + // initialize to our corner, and half our size + BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); + // if our "right" bit is set, then add size.x to the corner + if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { + result.corner.x += result.size.x; + } + // if our "top" bit is set, then add size.y to the corner + if ((childIndex & TOP_BIT) == TOP_BIT) { + result.corner.y += result.size.y; + } + return result; +} + +// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT +CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { + assert(_isRoot); // you can only call this on the root map!!! + _checkMapRootCalls++; + + // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our + // covered depth, then this polygon is occluded! + if (_isCovered && _coveredDistance < polygon->getDistance()) { + return V2_OCCLUDED; + } + + // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is + // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. + if (!polygon->getAllInView()) { + _notAllInView++; + return V2_DOESNT_FIT; + } + + // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. + // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered + // state of the polygon. + // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map + // items is not covered, then our polygon is not covered. + bool seenOccludedMapNodes = false; + bool allOccludedMapNodesCovered = false; + + recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); + + // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon + // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon + if (allOccludedMapNodesCovered) { + return V2_OCCLUDED; + } + if (storeIt) { + return V2_STORED; // otherwise report that we STORED it + } + return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't +} + +void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, + bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { + + // if we are really small, then we act like we don't intersect, this allows us to stop + // recusing as we get to the smalles edge of the polygon + if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { + return; // stop recursion, we're done! + } + + // Determine if this map node intersects the polygon and/or is fully covered by the polygon + // There are a couple special cases: If we're the root, we are assumed to intersect with all + // polygons. Also, any map node that is fully occluded also intersects. + bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); + bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); + + // If we don't intersect, then we can just return, we're done recursing + if (!nodeIsIntersectedByPolygon) { + return; // stop recursion, we're done! + } + + // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it + // as if the node was fully covered, because this allows us to short circuit further recursion... + if (_isCovered && _coveredDistance < polygon->getDistance()) { + nodeIsCoveredByPolygon = true; // fake it till you make it + } + + // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but + // we do need to do some bookkeeping. + if (nodeIsCoveredByPolygon) { + // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered + // to be our current covered state. This has the following effect: if this node isn't already covered, then by + // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. + if (!seenOccludedMapNodes) { + allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); + // We need to mark that we've seen at least one node of our polygon! ;) + seenOccludedMapNodes = true; + } else { + // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state + allOccludedMapNodesCovered = allOccludedMapNodesCovered && + (_isCovered && _coveredDistance < polygon->getDistance()); + } + + // if we're in store mode then we want to record that this node is covered. + if (storeIt) { + _isCovered = true; + // store the minimum distance of our previous known distance, or our current polygon's distance. This is because + // we know that we're at least covered at this distance, but if we had previously identified that we're covered + // at a shallower distance, then we want to maintain that distance + _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); + + // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because + // we're trying to maintain the known distances in the lower portion of the tree. + } + + // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map + // nodes will also be covered. + return; + } + + // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect + // with the polygon. + + // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. + // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered + bool allChildrenOccluded = true; + float maxChildCoveredDepth = NOT_COVERED; + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + BoundingBox childMapBoundingBox = getChildBoundingBox(i); + // if no child map exists yet, then create it + if (!_childMaps[i]) { + // children get created with the coverage state of their parent. + _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); + } + + _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); + + // if so far, all of our children are covered, then record our furthest coverage distance + if (allChildrenOccluded && _childMaps[i]->_isCovered) { + maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); + } else { + // otherwise, at least one of our children is not covered, so not all are covered + allChildrenOccluded = false; + } + } + // if all the children are covered, this makes our quad tree "shallower" because it records that + // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through + // we won't assume its occluded + if (allChildrenOccluded && storeIt) { + _isCovered = true; + _coveredDistance = maxChildCoveredDepth; + } + + // normal exit case... return... +} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h new file mode 100644 index 0000000000..fc9a3ea70e --- /dev/null +++ b/libraries/octree/src/CoverageMapV2.h @@ -0,0 +1,72 @@ +// +// CoverageMapV2.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CoverageMapV2_h +#define hifi_CoverageMapV2_h + +#include + +#include "OctreeProjectedPolygon.h" + +typedef enum { + V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, + V2_INTERSECT, V2_NO_INTERSECT, + V2_OCCLUDED, V2_NOT_OCCLUDED +} CoverageMapV2StorageResult; + +class CoverageMapV2 { + +public: + static const int NUMBER_OF_CHILDREN = 4; + static const bool NOT_ROOT = false; + static const bool IS_ROOT = true; + static const BoundingBox ROOT_BOUNDING_BOX; + static const float MINIMUM_POLYGON_AREA_TO_STORE; + static const float NOT_COVERED; + static const float MINIMUM_OCCLUSION_CHECK_AREA; + static bool wantDebugging; + + CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, + bool isCovered = false, float coverageDistance = NOT_COVERED); + ~CoverageMapV2(); + + CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); + + BoundingBox getChildBoundingBox(int childIndex); + const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; + CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; + bool isCovered() const { return _isCovered; }; + + void erase(); // erase the coverage map + + void render(); + + +private: + void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, + bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); + + void init(); + + bool _isRoot; + BoundingBox _myBoundingBox; + CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; + + bool _isCovered; + float _coveredDistance; + + static int _mapCount; + static int _checkMapRootCalls; + static int _notAllInView; +}; + + +#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6da59f00a3..c02a034778 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,6 +41,7 @@ #include #include +#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -950,9 +951,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && childBytesWritten == 2) { + if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1102,6 +1103,31 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } + + // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. + // leaf occlusion is handled down below when we check child nodes + if (params.wantOcclusionCulling && !element->isLeaf()) { + OctreeProjectedPolygon* voxelPolygon = + new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion + // culling and proceed as normal + if (voxelPolygon->getAllInView()) { + CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); + delete voxelPolygon; // cleanup + if (result == OCCLUDED) { + if (params.stats) { + params.stats->skippedOccluded(element); + } + params.stopReason = EncodeBitstreamParams::OCCLUDED; + return bytesAtThisLevel; + } + } else { + // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but + // we do need to clean up memory and proceed as normal... + delete voxelPolygon; + } + } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1164,10 +1190,20 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; + if (params.wantOcclusionCulling) { + if (childElement) { + float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; + + currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, + sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + } + } else { + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; + } // track stats // must check childElement here, because it could be we got here with no childElement @@ -1219,6 +1255,36 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded + // If the user also asked for occlusion culling, check if this element is occluded + if (params.wantOcclusionCulling && childElement->isLeaf()) { + // Don't check occlusion here, just add them to our distance ordered array... + + // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. + OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( + params.viewFrustum->getProjectedPolygon(childElement->getAACube())); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion + // culling and proceed as normal + if (voxelPolygon->getAllInView()) { + CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); + + // In all cases where the shadow wasn't stored, we need to free our own memory. + // In the case where it is stored, the CoverageMap will free memory for us later. + if (result != STORED) { + delete voxelPolygon; + } + + // If while attempting to add this voxel's shadow, we determined it was occluded, then + // we don't need to process it further and we can exit early. + if (result == OCCLUDED) { + childIsOccluded = true; + } + } else { + delete voxelPolygon; + } + } // wants occlusion culling & isLeaf() + + bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1293,7 +1359,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... + // write the child element data... NOTE: includeColor means include element data // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,63 +1369,65 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + if (params.includeColor) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); + } } } } @@ -1438,6 +1506,15 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); + // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the + // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, + // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make + // a single recursive pass in distance sorted order, but retain standard order in our encoded packet + int recursiveSliceSizes[NUMBER_OF_CHILDREN]; + const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; + int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); + int allSlicesSize = 0; + // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { @@ -1447,6 +1524,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; + // remember this for reshuffling + recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); + int childTreeBytesOut = 0; // NOTE: some octree styles (like models and particles) will store content in parent elements, and child @@ -1466,6 +1546,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } + // remember this for reshuffling + recursiveSliceSizes[originalIndex] = childTreeBytesOut; + allSlicesSize += childTreeBytesOut; + // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -1482,10 +1566,17 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } + // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem + // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else + // about not attempting to add this optimization back in, without solving the element deletion case. + // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree + //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { + // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees + //} bytesAtThisLevel += childTreeBytesOut; @@ -1505,7 +1596,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits); + params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); } if (!continueThisLevel) { @@ -1522,6 +1613,33 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for + + // reshuffle here... + if (continueThisLevel && params.wantOcclusionCulling) { + unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; + + unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination + + // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree + // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them + // back into original distance order + for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { + if (oneAtBit(childrenExistInPacketBits, originalIndex)) { + int thisSliceSize = recursiveSliceSizes[originalIndex]; + const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; + + memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); + tempBufferTo += thisSliceSize; + } + } + + // now that all slices are back in the correct order, copy them to the correct output buffer + continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); + if (!continueThisLevel) { + qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; + qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; + } + } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root @@ -1800,7 +1918,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1839,7 +1957,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1987,7 +2105,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 3ca8528a2f..514a9b391b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,6 +28,7 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" +class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -52,8 +53,12 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; +const bool NO_COLOR = false; +const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; +const bool NO_OCCLUSION_CULLING = false; +const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -70,15 +75,18 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; + bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; + bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; + CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -100,10 +108,13 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, + bool wantOcclusionCulling = NO_OCCLUSION_CULLING, + CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -114,15 +125,18 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), + includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), + wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), + map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) @@ -176,6 +190,7 @@ public: class ReadBitstreamToTreeParams { public: + bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -186,12 +201,14 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : + includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -298,7 +315,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName); + void loadOctreeFile(const char* fileName, bool wantColorRandomizer); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 7b80d315f1..88a77a4c53 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,10 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); + _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); + _octreeQuery.setWantOcclusionCulling(false); + _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index f4fbf9bd97..811e96fcf4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -23,13 +23,12 @@ AtomicUIntStat OctreePacketData::_totalBytesOfValues { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 }; -OctreePacketData::OctreePacketData(int targetSize, bool enableCompression) { - changeSettings(targetSize); // does reset... - _enableCompression = enableCompression; // FIXME +OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) { + changeSettings(enableCompression, targetSize); // does reset... } -void OctreePacketData::changeSettings(unsigned int targetSize) { - _enableCompression = true; // FIXME +void OctreePacketData::changeSettings(bool enableCompression, unsigned int targetSize) { + _enableCompression = enableCompression; _targetSize = std::min(MAX_OCTREE_UNCOMRESSED_PACKET_SIZE, targetSize); reset(); } diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index fb53b3472f..2c86d518ad 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -83,11 +83,11 @@ private: /// Handles packing of the data portion of PacketType_OCTREE_DATA messages. class OctreePacketData { public: - OctreePacketData(int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE, bool enableCompression = true); + OctreePacketData(bool enableCompression = false, int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE); ~OctreePacketData(); /// change compression and target size settings - void changeSettings(unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); + void changeSettings(bool enableCompression = false, unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); /// reset completely, all data is discarded void reset(); @@ -262,7 +262,7 @@ private: bool append(unsigned char byte); unsigned int _targetSize; - bool _enableCompression { true }; // FIXME - these will always be compressed, so remove this option + bool _enableCompression; unsigned char _uncompressed[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 8449e3083a..e8beb0404c 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,10 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } + if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } + if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } + if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -81,7 +84,10 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); + _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); + _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); + _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 962a8e1425..86474ffc02 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,10 +35,10 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int UNUSED_BIT_1 = 1; // unused... available for new feature +const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int UNUSED_BIT_4 = 4; // 5th bit, unused... available for new feature +const int WANT_OCCLUSION_CULLING_BIT = 3; +const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { Q_OBJECT @@ -71,15 +71,21 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies + bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } + bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } + bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } + void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } + void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } + void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -95,8 +101,11 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items + bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; + bool _wantOcclusionCulling = false; + bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index c65359f12f..b7be4cf3e7 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index c70e0e4935..22352fbe3b 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,12 +371,14 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - _colorBitsWritten--; + if (includesColors) { + _colorBitsWritten--; + } _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index f8ecf93106..bdb4ef206a 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits); + void childBitsRemoved(bool includesExistsBits, bool includesColors); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 1fa18903cb..0b77683d4c 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,6 +264,29 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, + bool includeColorSpace) { + + int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); + int newCodeLength = newParentCodeLength + oldCodeLength; + int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); + unsigned char* newCode = new unsigned char[bufferLength]; + *newCode = newCodeLength; // set the length byte + + // copy parent code section first + for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { + char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); + setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); + } + // copy original code section next + for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); + setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); + } + return newCode; +} + bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 09766b685a..9229157c3d 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,6 +36,8 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, + bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From aad4743bf0bdc860fcba4caeef65e7b7999c80d3 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Dec 2015 18:06:50 -0800 Subject: [PATCH 142/165] Completely remove Gverb from cmake --- cmake/externals/gverb/CMakeLists.txt | 31 --------------------------- libraries/audio-client/CMakeLists.txt | 5 ----- 2 files changed, 36 deletions(-) delete mode 100644 cmake/externals/gverb/CMakeLists.txt diff --git a/cmake/externals/gverb/CMakeLists.txt b/cmake/externals/gverb/CMakeLists.txt deleted file mode 100644 index 4da19e1d31..0000000000 --- a/cmake/externals/gverb/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -set(EXTERNAL_NAME gverb) - -if (ANDROID) - set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") -endif () - -include(ExternalProject) -ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/gverb-master.zip - URL_MD5 8b16d586390a2102804e46b87820dfc6 - CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= - BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 -) - -# Hide this external target (for ide users) -set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - -ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to gverb include directory") - -if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/gverb.lib CACHE FILEPATH "List of gverb libraries") -else () - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libgverb.a CACHE FILEPATH "List of gverb libraries") -endif () \ No newline at end of file diff --git a/libraries/audio-client/CMakeLists.txt b/libraries/audio-client/CMakeLists.txt index 90937edc5d..2c0fc0a9cd 100644 --- a/libraries/audio-client/CMakeLists.txt +++ b/libraries/audio-client/CMakeLists.txt @@ -6,11 +6,6 @@ link_hifi_libraries(audio) target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src") # have CMake grab externals for us -add_dependency_external_projects(gverb) -find_package(Gverb REQUIRED) -target_link_libraries(${TARGET_NAME} ${GVERB_LIBRARIES}) -target_include_directories(${TARGET_NAME} PRIVATE ${GVERB_INCLUDE_DIRS}) - if (APPLE) find_library(CoreAudio CoreAudio) find_library(CoreFoundation CoreFoundation) From 81fb4476bc1621d78aa20a5d10018bd4974e8dac Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 10:20:04 -0800 Subject: [PATCH 143/165] remove coverage map and occulusion culling, since it was always disabled --- .../src/octree/OctreeQueryNode.h | 2 - .../src/octree/OctreeSendThread.cpp | 7 +- interface/src/Application.cpp | 1 - libraries/octree/src/CoverageMap.cpp | 542 ------------------ libraries/octree/src/CoverageMap.h | 120 ---- libraries/octree/src/CoverageMapV2.cpp | 251 -------- libraries/octree/src/CoverageMapV2.h | 72 --- libraries/octree/src/Octree.cpp | 101 +--- libraries/octree/src/Octree.h | 9 - libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 5 +- 12 files changed, 6 insertions(+), 1107 deletions(-) delete mode 100644 libraries/octree/src/CoverageMap.cpp delete mode 100644 libraries/octree/src/CoverageMap.h delete mode 100644 libraries/octree/src/CoverageMapV2.cpp delete mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 0c691a06a2..75c841851f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -55,7 +54,6 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; - CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 0a32f574de..f873ee4808 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -350,7 +350,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } - nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -451,9 +450,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ - bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); - CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); @@ -462,7 +458,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, + boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -634,7 +630,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e6678c8758..67a220311b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3076,7 +3076,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp deleted file mode 100644 index 626d4bcf1a..0000000000 --- a/libraries/octree/src/CoverageMap.cpp +++ /dev/null @@ -1,542 +0,0 @@ -// -// CoverageMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMap.h" - -int CoverageMap::_mapCount = 0; -int CoverageMap::_checkMapRootCalls = 0; -int CoverageMap::_notAllInView = 0; -bool CoverageMap::wantDebugging = false; - -const int MAX_POLYGONS_PER_REGION = 50; - -const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); - -CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), - _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), - _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), - _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), - _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) -{ - _mapCount++; - init(); -}; - -CoverageMap::~CoverageMap() { - erase(); -}; - -void CoverageMap::printStats() { - qCDebug(octree, "CoverageMap::printStats()..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); - qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); - qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); - qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); - qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); - qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); - qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); - qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); -} - -void CoverageMap::erase() { - // tell our regions to erase() - _topHalf.erase(); - _bottomHalf.erase(); - _leftHalf.erase(); - _rightHalf.erase(); - _remainder.erase(); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMap last to be deleted..."); - printStats(); - - CoverageRegion::_maxPolygonsUsed = 0; - CoverageRegion::_totalPolygons = 0; - CoverageRegion::_occlusionTests = 0; - CoverageRegion::_regionSkips = 0; - CoverageRegion::_tooSmallSkips = 0; - CoverageRegion::_regionFullSkips = 0; - CoverageRegion::_outOfOrderPolygon = 0; - CoverageRegion::_clippedPolygons = 0; - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMap::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, right -// 1 = bottom, left -// 2 = top, right -// 3 = top, left -BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { - const int LEFT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "left" bit is set, then add size.x to the corner - if ((childIndex & LEFT_BIT) == LEFT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -int CoverageMap::getPolygonCount() const { - return (_topHalf.getPolygonCount() + - _bottomHalf.getPolygonCount() + - _leftHalf.getPolygonCount() + - _rightHalf.getPolygonCount() + - _remainder.getPolygonCount()); -} - -OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { - int base = 0; - if ((index - base) < _topHalf.getPolygonCount()) { - return _topHalf.getPolygon((index - base)); - } - base += _topHalf.getPolygonCount(); - - if ((index - base) < _bottomHalf.getPolygonCount()) { - return _bottomHalf.getPolygon((index - base)); - } - base += _bottomHalf.getPolygonCount(); - - if ((index - base) < _leftHalf.getPolygonCount()) { - return _leftHalf.getPolygon((index - base)); - } - base += _leftHalf.getPolygonCount(); - - if ((index - base) < _rightHalf.getPolygonCount()) { - return _rightHalf.getPolygon((index - base)); - } - base += _rightHalf.getPolygonCount(); - - if ((index - base) < _remainder.getPolygonCount()) { - return _remainder.getPolygon((index - base)); - } - return NULL; -} - - - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { - - if (_isRoot) { - _checkMapRootCalls++; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return DOESNT_FIT; - } - - BoundingBox polygonBox(polygon->getBoundingBox()); - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - - CoverageMapStorageResult result = NOT_STORED; - CoverageRegion* storeIn = &_remainder; - - // Check each half of the box independently - const bool useRegions = true; // for now we will continue to use regions - if (useRegions) { - if (_topHalf.contains(polygonBox)) { - result = _topHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_topHalf; - } else if (_bottomHalf.contains(polygonBox)) { - result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_bottomHalf; - } else if (_leftHalf.contains(polygonBox)) { - result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_leftHalf; - } else if (_rightHalf.contains(polygonBox)) { - result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_rightHalf; - } - } - - // if we got this far, there are one of two possibilities, either a polygon doesn't fit - // in one of the halves, or it did fit, but it wasn't occluded by anything only in that - // half. In either of these cases, we want to check our remainder region to see if its - // occluded by anything there - if (!(result == STORED || result == OCCLUDED)) { - result = _remainder.checkRegion(polygon, polygonBox, storeIt); - } - - // It's possible that this first set of checks might have resulted in an out of order polygon - // in which case we just return.. - if (result == STORED || result == OCCLUDED) { - - /* - if (result == STORED) - qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); - else - qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); - */ - - return result; - } - - // if we made it here, then it means the polygon being stored is not occluded - // at this level of the quad tree, so we can continue to insert it into the map. - // First we check to see if it fits in any of our sub maps - const bool useChildMaps = true; // for now we will continue to use child maps - if (useChildMaps) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - if (childMapBoundingBox.contains(polygon->getBoundingBox())) { - // if no child map exists yet, then create it - if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); - } - result = _childMaps[i]->checkMap(polygon, storeIt); - - /* - switch (result) { - case STORED: - qCDebug(octree, "checkMap() = STORED\n"); - break; - case NOT_STORED: - qCDebug(octree, "checkMap() = NOT_STORED\n"); - break; - case OCCLUDED: - qCDebug(octree, "checkMap() = OCCLUDED\n"); - break; - default: - qCDebug(octree, "checkMap() = ????? \n"); - break; - } - */ - - return result; - } - } - } - // if we got this far, then the polygon is in our bounding box, but doesn't fit in - // any of our child bounding boxes, so we should add it here. - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeIn->storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - CoverageRegion::_tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - return DOESNT_FIT; -} - - -CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _regionName(regionName) -{ - init(); -}; - -CoverageRegion::~CoverageRegion() { - erase(); -}; - -void CoverageRegion::init() { - _polygonCount = 0; - _polygonArraySize = 0; - _polygons = NULL; - _polygonDistances = NULL; - _polygonSizes = NULL; -} - - -void CoverageRegion::erase() { - -/** - if (_polygonCount) { - qCDebug(octree, "CoverageRegion::erase()...\n"); - qCDebug(octree, "_polygonCount=%d\n",_polygonCount); - _myBoundingBox.printDebugDetails(getRegionName()); - //for (int i = 0; i < _polygonCount; i++) { - // qCDebug(octree, "_polygons[%d]=",i); - // _polygons[i]->getBoundingBox().printDebugDetails(); - //} - } -**/ - // If we're in charge of managing the polygons, then clean them up first - if (_polygons && _managePolygons) { - for (int i = 0; i < _polygonCount; i++) { - delete _polygons[i]; - _polygons[i] = NULL; // do we need to do this? - } - } - - // Now, clean up our local storage - _polygonCount = 0; - _polygonArraySize = 0; - if (_polygons) { - delete[] _polygons; - _polygons = NULL; - } - if (_polygonDistances) { - delete[] _polygonDistances; - _polygonDistances = NULL; - } - if (_polygonSizes) { - delete[] _polygonSizes; - _polygonSizes = NULL; - } -} - -void CoverageRegion::growPolygonArray() { - OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - - - if (_polygons) { - memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); - delete[] _polygons; - memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); - delete[] _polygonDistances; - memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); - delete[] _polygonSizes; - } - _polygons = newPolygons; - _polygonDistances = newDistances; - _polygonSizes = newSizes; - _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -} - -const char* CoverageRegion::getRegionName() const { - switch (_regionName) { - case TOP_HALF: - return "TOP_HALF"; - case BOTTOM_HALF: - return "BOTTOM_HALF"; - case LEFT_HALF: - return "LEFT_HALF"; - case RIGHT_HALF: - return "RIGHT_HALF"; - default: - case REMAINDER: - return "REMAINDER"; - } - return "REMAINDER"; -} - -int CoverageRegion::_maxPolygonsUsed = 0; -int CoverageRegion::_totalPolygons = 0; -int CoverageRegion::_occlusionTests = 0; -int CoverageRegion::_regionSkips = 0; -int CoverageRegion::_tooSmallSkips = 0; -int CoverageRegion::_regionFullSkips = 0; -int CoverageRegion::_outOfOrderPolygon = 0; -int CoverageRegion::_clippedPolygons = 0; - - -bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* otherPolygon = _polygons[i]; - if (otherPolygon->canMerge(*seed)) { - otherPolygon->merge(*seed); - - if (seedInArray) { - int* IGNORED_ADDRESS = NULL; - // remove this otherOtherPolygon for our polygon array - _polygonCount = removeFromSortedArrays((void*)seed, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - _totalPolygons--; - } - - // clean up - if (_managePolygons) { - delete seed; - } - - // Now run again using our newly merged polygon as the seed - mergeItemsInArray(otherPolygon, true); - - return true; - } - } - return false; -} - -// just handles storage in the array, doesn't test for occlusion or -// determining if this is the correct map to store in! -void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { - - _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); - - - // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing - // polygons already in our array. - if (mergeItemsInArray(polygon, false)) { - return; // exit early - } - - // only after we attempt to merge! - _totalPolygons++; - - if (_polygonArraySize < _polygonCount + 1) { - growPolygonArray(); - } - - // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order - // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier - // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since - // sometimes things come out of order. - const bool SORT_BY_SIZE = false; - const int IGNORED = 0; - int* IGNORED_ADDRESS = NULL; - if (SORT_BY_SIZE) { - // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to - // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the - // insertion point in this array, and shift the array accordingly - float area = polygon->getBoundingBox().area(); - float reverseArea = 4.0f - area; - _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, - (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } else { - _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } - - // Debugging and Optimization Tuning code. - if (_polygonCount > _maxPolygonsUsed) { - _maxPolygonsUsed = _polygonCount; - } -} - - - -CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { - - CoverageMapStorageResult result = DOESNT_FIT; - - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - result = NOT_STORED; // if we got here, then we DO fit... - - // only actually check the polygons if this polygon is in the covered bounds for this region - if (!_currentCoveredBounds.contains(polygonBox)) { - _regionSkips += _polygonCount; - } else { - // check to make sure this polygon isn't occluded by something at this level - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; - - // Check to make sure that the polygon in question is "behind" the polygon in the list - // otherwise, we don't need to test it's occlusion (although, it means we've potentially - // added an item previously that may be occluded??? Is that possible? Maybe not, because two - // voxels can't have the exact same outline. So one occludes the other, they can't both occlude - // each other. - - _occlusionTests++; - if (polygonAtThisLevel->occludes(*polygon)) { - // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't - // want to report our inserted one as occluded, but we do want to add our inserted one. - if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { - _outOfOrderPolygon++; - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - _tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - // this polygon is occluded by a closer polygon, so don't store it, and let the caller know - return OCCLUDED; - } - } - } - } - return result; -} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h deleted file mode 100644 index bff6bb1078..0000000000 --- a/libraries/octree/src/CoverageMap.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// CoverageMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CoverageMap_h -#define hifi_CoverageMap_h - -#include -#include "OctreeProjectedPolygon.h" - -typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; -typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; - -class CoverageRegion { - -public: - - CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); - ~CoverageRegion(); - - CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); - void storeInArray(OctreeProjectedPolygon* polygon); - - bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; - void erase(); // erase the coverage region - - static int _maxPolygonsUsed; - static int _totalPolygons; - static int _occlusionTests; - static int _regionSkips; - static int _tooSmallSkips; - static int _regionFullSkips; - static int _outOfOrderPolygon; - static int _clippedPolygons; - - - const char* getRegionName() const; - - int getPolygonCount() const { return _polygonCount; }; - OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon - bool _managePolygons; // will the coverage map delete the polygons on destruct - RegionName _regionName; - int _polygonCount; // how many polygons at this level - int _polygonArraySize; // how much room is there to store polygons at this level - OctreeProjectedPolygon** _polygons; - - // we will use one or the other of these depending on settings in the code. - float* _polygonDistances; - float* _polygonSizes; - void growPolygonArray(); - static const int DEFAULT_GROW_SIZE = 100; - - bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); - -}; - -class CoverageMap { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT=false; - static const bool IS_ROOT=true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - - CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); - ~CoverageMap(); - - CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - - void erase(); // erase the coverage map - void printStats(); - - static bool wantDebugging; - - int getPolygonCount() const; - OctreeProjectedPolygon* getPolygon(int index) const; - CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; - bool _managePolygons; // will the coverage map delete the polygons on destruct - - // We divide the map into 5 regions representing each possible half of the map, and the whole map - // this allows us to keep the list of polygons shorter - CoverageRegion _topHalf; - CoverageRegion _bottomHalf; - CoverageRegion _leftHalf; - CoverageRegion _rightHalf; - CoverageRegion _remainder; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp deleted file mode 100644 index 8467ea1ee9..0000000000 --- a/libraries/octree/src/CoverageMapV2.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// CoverageMapV2.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMapV2.h" - -int CoverageMapV2::_mapCount = 0; -int CoverageMapV2::_checkMapRootCalls = 0; -int CoverageMapV2::_notAllInView = 0; -bool CoverageMapV2::wantDebugging = false; - -const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); -const float CoverageMapV2::NOT_COVERED = FLT_MAX; -const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly - - -CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _isCovered(isCovered), - _coveredDistance(coverageDistance) -{ - _mapCount++; - init(); -}; - -CoverageMapV2::~CoverageMapV2() { - erase(); -}; - -void CoverageMapV2::erase() { - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMapV2 last to be deleted..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMapV2::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, left -// 1 = bottom, right -// 2 = top, left -// 3 = top, right -BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { - const int RIGHT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "right" bit is set, then add size.x to the corner - if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { - assert(_isRoot); // you can only call this on the root map!!! - _checkMapRootCalls++; - - // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our - // covered depth, then this polygon is occluded! - if (_isCovered && _coveredDistance < polygon->getDistance()) { - return V2_OCCLUDED; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return V2_DOESNT_FIT; - } - - // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. - // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered - // state of the polygon. - // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map - // items is not covered, then our polygon is not covered. - bool seenOccludedMapNodes = false; - bool allOccludedMapNodesCovered = false; - - recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon - // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon - if (allOccludedMapNodesCovered) { - return V2_OCCLUDED; - } - if (storeIt) { - return V2_STORED; // otherwise report that we STORED it - } - return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't -} - -void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { - - // if we are really small, then we act like we don't intersect, this allows us to stop - // recusing as we get to the smalles edge of the polygon - if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { - return; // stop recursion, we're done! - } - - // Determine if this map node intersects the polygon and/or is fully covered by the polygon - // There are a couple special cases: If we're the root, we are assumed to intersect with all - // polygons. Also, any map node that is fully occluded also intersects. - bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); - bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); - - // If we don't intersect, then we can just return, we're done recursing - if (!nodeIsIntersectedByPolygon) { - return; // stop recursion, we're done! - } - - // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it - // as if the node was fully covered, because this allows us to short circuit further recursion... - if (_isCovered && _coveredDistance < polygon->getDistance()) { - nodeIsCoveredByPolygon = true; // fake it till you make it - } - - // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but - // we do need to do some bookkeeping. - if (nodeIsCoveredByPolygon) { - // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered - // to be our current covered state. This has the following effect: if this node isn't already covered, then by - // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. - if (!seenOccludedMapNodes) { - allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); - // We need to mark that we've seen at least one node of our polygon! ;) - seenOccludedMapNodes = true; - } else { - // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state - allOccludedMapNodesCovered = allOccludedMapNodesCovered && - (_isCovered && _coveredDistance < polygon->getDistance()); - } - - // if we're in store mode then we want to record that this node is covered. - if (storeIt) { - _isCovered = true; - // store the minimum distance of our previous known distance, or our current polygon's distance. This is because - // we know that we're at least covered at this distance, but if we had previously identified that we're covered - // at a shallower distance, then we want to maintain that distance - _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); - - // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because - // we're trying to maintain the known distances in the lower portion of the tree. - } - - // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map - // nodes will also be covered. - return; - } - - // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect - // with the polygon. - - // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. - // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered - bool allChildrenOccluded = true; - float maxChildCoveredDepth = NOT_COVERED; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - // if no child map exists yet, then create it - if (!_childMaps[i]) { - // children get created with the coverage state of their parent. - _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); - } - - _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // if so far, all of our children are covered, then record our furthest coverage distance - if (allChildrenOccluded && _childMaps[i]->_isCovered) { - maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); - } else { - // otherwise, at least one of our children is not covered, so not all are covered - allChildrenOccluded = false; - } - } - // if all the children are covered, this makes our quad tree "shallower" because it records that - // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through - // we won't assume its occluded - if (allChildrenOccluded && storeIt) { - _isCovered = true; - _coveredDistance = maxChildCoveredDepth; - } - - // normal exit case... return... -} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h deleted file mode 100644 index fc9a3ea70e..0000000000 --- a/libraries/octree/src/CoverageMapV2.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// CoverageMapV2.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CoverageMapV2_h -#define hifi_CoverageMapV2_h - -#include - -#include "OctreeProjectedPolygon.h" - -typedef enum { - V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, - V2_INTERSECT, V2_NO_INTERSECT, - V2_OCCLUDED, V2_NOT_OCCLUDED -} CoverageMapV2StorageResult; - -class CoverageMapV2 { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT = false; - static const bool IS_ROOT = true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - static const float NOT_COVERED; - static const float MINIMUM_OCCLUSION_CHECK_AREA; - static bool wantDebugging; - - CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, - bool isCovered = false, float coverageDistance = NOT_COVERED); - ~CoverageMapV2(); - - CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; - CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; - bool isCovered() const { return _isCovered; }; - - void erase(); // erase the coverage map - - void render(); - - -private: - void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); - - void init(); - - bool _isRoot; - BoundingBox _myBoundingBox; - CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; - - bool _isCovered; - float _coveredDistance; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c02a034778..1960537ced 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,7 +41,6 @@ #include #include -#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -1103,31 +1102,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } - - // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. - // leaf occlusion is handled down below when we check child nodes - if (params.wantOcclusionCulling && !element->isLeaf()) { - OctreeProjectedPolygon* voxelPolygon = - new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); - delete voxelPolygon; // cleanup - if (result == OCCLUDED) { - if (params.stats) { - params.stats->skippedOccluded(element); - } - params.stopReason = EncodeBitstreamParams::OCCLUDED; - return bytesAtThisLevel; - } - } else { - // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but - // we do need to clean up memory and proceed as normal... - delete voxelPolygon; - } - } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1190,20 +1164,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - if (params.wantOcclusionCulling) { - if (childElement) { - float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - - currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, - sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); - } - } else { - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; - } + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; // track stats // must check childElement here, because it could be we got here with no childElement @@ -1255,36 +1219,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded - // If the user also asked for occlusion culling, check if this element is occluded - if (params.wantOcclusionCulling && childElement->isLeaf()) { - // Don't check occlusion here, just add them to our distance ordered array... - - // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. - OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( - params.viewFrustum->getProjectedPolygon(childElement->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); - - // In all cases where the shadow wasn't stored, we need to free our own memory. - // In the case where it is stored, the CoverageMap will free memory for us later. - if (result != STORED) { - delete voxelPolygon; - } - - // If while attempting to add this voxel's shadow, we determined it was occluded, then - // we don't need to process it further and we can exit early. - if (result == OCCLUDED) { - childIsOccluded = true; - } - } else { - delete voxelPolygon; - } - } // wants occlusion culling & isLeaf() - - bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1613,33 +1547,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for - - // reshuffle here... - if (continueThisLevel && params.wantOcclusionCulling) { - unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; - - unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination - - // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree - // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them - // back into original distance order - for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - int thisSliceSize = recursiveSliceSizes[originalIndex]; - const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; - - memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); - tempBufferTo += thisSliceSize; - } - } - - // now that all slices are back in the correct order, copy them to the correct output buffer - continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 514a9b391b..5f5aa1432a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,7 +28,6 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" -class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -57,8 +56,6 @@ const bool NO_COLOR = false; const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; -const bool NO_OCCLUSION_CULLING = false; -const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -80,13 +77,11 @@ public: int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; - bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; - CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -113,8 +108,6 @@ public: int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, - bool wantOcclusionCulling = NO_OCCLUSION_CULLING, - CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -130,13 +123,11 @@ public: chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), - wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), - map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 88a77a4c53..b18f219d4d 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -53,7 +53,6 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index e8beb0404c..2739b4a0d1 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -43,7 +43,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -86,7 +85,6 @@ int OctreeQuery::parseData(NLPacket& packet) { _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 86474ffc02..9605cbfb5d 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -37,7 +37,7 @@ typedef unsigned long long quint64; const int WANT_LOW_RES_MOVING_BIT = 0; const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int WANT_OCCLUSION_CULLING_BIT = 3; +const int UNUSED_BIT = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -74,7 +74,6 @@ public: bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } @@ -84,7 +83,6 @@ public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } @@ -104,7 +102,6 @@ protected: bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantOcclusionCulling = false; bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations From f472b515c3e39397f1705be2b8915d8eb379055b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 11:05:28 -0800 Subject: [PATCH 144/165] remove wantsColor support since its always true and required for entities --- .../src/octree/OctreeQueryNode.cpp | 1 - .../src/octree/OctreeQueryNode.h | 2 +- .../src/octree/OctreeSendThread.cpp | 3 +- interface/src/Application.cpp | 1 - libraries/octree/src/Octree.cpp | 115 ++++++++---------- libraries/octree/src/Octree.h | 10 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 7 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 ---- libraries/shared/src/OctalCode.h | 2 - 14 files changed, 62 insertions(+), 115 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cff2c7ee2e..06e9834804 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,7 +179,6 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsColor = getWantColor(); _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; if (_currentPacketIsColor) { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 75c841851f..4140d42a5f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -78,7 +78,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + return (getCurrentPacketIsCompressed() == getWantCompression()); } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index f873ee4808..efc81d6a21 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantColor = nodeData->getWantColor(); bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color @@ -456,7 +455,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 67a220311b..627f48f7cc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 1960537ced..64a2eaccc4 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -950,9 +950,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { + if (suppressEmptySubtrees() && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1293,7 +1293,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... NOTE: includeColor means include element data + // write the child element data... // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,65 +1303,63 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - if (params.includeColor) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); - } + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); } } } @@ -1500,17 +1498,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } - // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem - // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else - // about not attempting to add this optimization back in, without solving the element deletion case. - // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree - //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { - // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees - //} bytesAtThisLevel += childTreeBytesOut; @@ -1530,7 +1521,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); + params.stats->childBitsRemoved(params.includeExistsBits); } if (!continueThisLevel) { @@ -1825,7 +1816,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1864,7 +1855,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -2012,7 +2003,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5f5aa1432a..3ca8528a2f 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -52,8 +52,6 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; -const bool NO_COLOR = false; -const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; @@ -72,7 +70,6 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; - bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; @@ -103,7 +100,6 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, @@ -118,7 +114,6 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), - includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), @@ -181,7 +176,6 @@ public: class ReadBitstreamToTreeParams { public: - bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -192,14 +186,12 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : - includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -306,7 +298,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName, bool wantColorRandomizer); + void loadOctreeFile(const char* fileName); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index b18f219d4d..f1c2172d86 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); // TODO: should be on by default diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 2739b4a0d1..c431d66bf2 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } - if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 9605cbfb5d..71c9361e68 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,9 +35,9 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int WANT_COLOR_AT_BIT = 1; +const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT = 3; // unused... available for new feature +const int UNUSED_BIT_3 = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -71,7 +71,6 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantCompression() const { return _wantCompression; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } - void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } @@ -99,7 +97,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; bool _wantCompression = false; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index b7be4cf3e7..c65359f12f 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 22352fbe3b..c70e0e4935 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,14 +371,12 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - if (includesColors) { - _colorBitsWritten--; - } + _colorBitsWritten--; _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index bdb4ef206a..f8ecf93106 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits, bool includesColors); + void childBitsRemoved(bool includesExistsBits); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 0b77683d4c..1fa18903cb 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,29 +264,6 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace) { - - int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); - int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); - int newCodeLength = newParentCodeLength + oldCodeLength; - int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); - unsigned char* newCode = new unsigned char[bufferLength]; - *newCode = newCodeLength; // set the length byte - - // copy parent code section first - for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { - char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); - setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); - } - // copy original code section next - for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { - char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); - setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); - } - return newCode; -} - bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 9229157c3d..09766b685a 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,8 +36,6 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From 18e62290f3b7ea9a71afa8b65f1ff0f46d4fd365 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 08:37:46 -0800 Subject: [PATCH 145/165] fix warnings --- libraries/octree/src/Octree.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 64a2eaccc4..aacb57f31d 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1442,10 +1442,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make // a single recursive pass in distance sorted order, but retain standard order in our encoded packet - int recursiveSliceSizes[NUMBER_OF_CHILDREN]; - const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); - int allSlicesSize = 0; // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children @@ -1456,8 +1452,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; - // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); int childTreeBytesOut = 0; @@ -1478,10 +1472,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - // remember this for reshuffling - recursiveSliceSizes[originalIndex] = childTreeBytesOut; - allSlicesSize += childTreeBytesOut; - // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. From cd26422ca0a11d05ad467d667108817cacf4a229 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Dec 2015 13:17:11 -0800 Subject: [PATCH 146/165] Fix warnings on OS X --- libraries/audio/src/AudioReverb.cpp | 74 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index f06bbe76ed..ff286d780b 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -1324,64 +1324,64 @@ static int scaleDelay(float delay, float sampleRate) { // input clamped to [0.0f, 100.0f] // static const float earlyMix0Table[][2] = { - 0.0000f, 0.6000f, - 63.3333f, 0.0800f, - 83.3333f, 0.0200f, - 93.3333f, 0.0048f, - 100.0000f, 0.0048f, + {0.0000f, 0.6000f}, + {63.3333f, 0.0800f}, + {83.3333f, 0.0200f}, + {93.3333f, 0.0048f}, + {100.0000f, 0.0048f}, }; static const float earlyMix1Table[][2] = { - 0.0000f, 0.3360f, - 20.0000f, 0.6000f, - 100.0000f, 0.0240f, + {0.0000f, 0.3360f}, + {20.0000f, 0.6000f}, + {100.0000f, 0.0240f}, }; static const float earlyMix2Table[][2] = { - 0.0000f, 0.0480f, - 13.3333f, 0.0960f, - 53.3333f, 0.9600f, - 100.0000f, 0.1200f, + {0.0000f, 0.0480f}, + {13.3333f, 0.0960f}, + {53.3333f, 0.9600f}, + {100.0000f, 0.1200f}, }; static const float lateMix0Table[][2] = { - 0.0000f, 0.1250f, - 13.3333f, 0.1875f, - 66.6666f, 0.7500f, - 100.0000f, 0.8750f, + {0.0000f, 0.1250f}, + {13.3333f, 0.1875f}, + {66.6666f, 0.7500f}, + {100.0000f, 0.8750f}, }; static const float lateMix1Table[][2] = { - 0.0000f, 0.9990f, - 33.3333f, 0.5000f, - 66.6666f, 0.9990f, - 93.3333f, 0.6000f, - 100.0000f, 0.6000f, + {0.0000f, 0.9990f}, + {33.3333f, 0.5000f}, + {66.6666f, 0.9990f}, + {93.3333f, 0.6000f}, + {100.0000f, 0.6000f}, }; static const float lateMix2Table[][2] = { - 0.0000f, 0.9990f, - 33.3333f, 0.9990f, - 63.3333f, 0.4500f, - 100.0000f, 0.9990f, + {0.0000f, 0.9990f}, + {33.3333f, 0.9990f}, + {63.3333f, 0.4500f}, + {100.0000f, 0.9990f}, }; static const float diffusionCoefTable[][2] = { - 0.0000f, 0.0000f, - 20.0000f, 0.0470f, - 33.3333f, 0.0938f, - 46.6666f, 0.1563f, - 60.0000f, 0.2344f, - 73.3333f, 0.3125f, - 93.3333f, 0.5000f, - 100.0000f, PHI, + {0.0000f, 0.0000f}, + {20.0000f, 0.0470f}, + {33.3333f, 0.0938f}, + {46.6666f, 0.1563f}, + {60.0000f, 0.2344f}, + {73.3333f, 0.3125f}, + {93.3333f, 0.5000f}, + {100.0000f, PHI}, }; static const float roomSizeTable[][2] = { - 0.0000f, 0.1500f, - 25.0000f, 0.3000f, - 50.0000f, 0.5000f, - 100.0000f, 1.0000f, + {0.0000f, 0.1500f}, + {25.0000f, 0.3000f}, + {50.0000f, 0.5000f}, + {100.0000f, 1.0000f}, }; static float interpolateTable(const float table[][2], float x) { From cb758ca6b4256391a68b2d603b2a8e21854483e9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 08:55:43 -0800 Subject: [PATCH 147/165] Fix override warnings on XCode 7 --- assignment-client/src/entities/EntityServer.h | 6 ++-- .../impl/endpoints/ActionEndpoint.h | 4 +-- .../impl/endpoints/InputEndpoint.h | 6 ++-- .../controllers/impl/filters/PulseFilter.h | 2 +- .../controllers/impl/filters/ScaleFilter.h | 2 +- .../src/RenderableModelEntityItem.h | 30 +++++++++---------- .../recording/src/recording/impl/ArrayClip.h | 4 +-- .../src/recording/impl/PointerClip.h | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 89b445c449..241c4c4d4f 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -50,10 +50,10 @@ public: virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; - virtual QString serverSubclassStats(); + virtual QString serverSubclassStats() override; - virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); - virtual void trackViewerGone(const QUuid& viewerNode); + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override; + virtual void trackViewerGone(const QUuid& viewerNode) override; public slots: void pruneDeletedEntities(); diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h index e07dc9e4c8..1073dc6593 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h @@ -23,10 +23,10 @@ class ActionEndpoint : public Endpoint { public: ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { } - virtual float peek() const { return _currentValue; } + virtual float peek() const override { return _currentValue; } virtual void apply(float newValue, const Pointer& source) override; - virtual Pose peekPose() const { return _currentPose; } + virtual Pose peekPose() const override { return _currentPose; } virtual void apply(const Pose& value, const Pointer& source) override; virtual void reset() override; diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h index 663168bedc..7e4560dcf9 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h @@ -28,9 +28,9 @@ public: virtual Pose pose() override; virtual void apply(const Pose& value, const Pointer& source) override { } - virtual bool writeable() const { return false; } - virtual bool readable() const { return !_read; } - virtual void reset() { _read = false; } + virtual bool writeable() const override { return false; } + virtual bool readable() const override { return !_read; } + virtual void reset() override { _read = false; } private: bool _read { false }; diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h index dbe2eba81b..271f4a04f6 100644 --- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h @@ -23,7 +23,7 @@ public: virtual float apply(float value) const override; - virtual bool parseParameters(const QJsonValue& parameters); + virtual bool parseParameters(const QJsonValue& parameters) override; private: static const float DEFAULT_LAST_EMIT_TIME; diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h index 39c5edd4e5..670da53fe8 100644 --- a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h @@ -23,7 +23,7 @@ public: virtual float apply(float value) const override { return value * _scale; } - virtual bool parseParameters(const QJsonValue& parameters); + virtual bool parseParameters(const QJsonValue& parameters) override; private: float _scale = 1.0f; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index c4e36c240a..b791373bde 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -30,42 +30,42 @@ public: virtual void setDimensions(const glm::vec3& value) override; - virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; - virtual bool setProperties(const EntityItemProperties& properties); + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; + virtual bool setProperties(const EntityItemProperties& properties) override; virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged); + bool& somethingChanged) override; - virtual void somethingChangedNotification() { + virtual void somethingChangedNotification() override { // FIX ME: this is overly aggressive. We only really need to simulate() if something about // the world space transform has changed and/or if some animation is occurring. _needsInitialSimulation = true; } virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr); - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - virtual void render(RenderArgs* args); - virtual bool supportsDetailedRayIntersection() const { return true; } + virtual void render(RenderArgs* args) override; + virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - void** intersectedObject, bool precisionPicking) const; + void** intersectedObject, bool precisionPicking) const override; Model* getModel(EntityTreeRenderer* renderer); - virtual bool needsToCallUpdate() const; - virtual void update(const quint64& now); + virtual bool needsToCallUpdate() const override; + virtual void update(const quint64& now) override; - virtual void setCompoundShapeURL(const QString& url); + virtual void setCompoundShapeURL(const QString& url) override; - bool isReadyToComputeShape(); - void computeShapeInfo(ShapeInfo& info); + virtual bool isReadyToComputeShape() override; + virtual void computeShapeInfo(ShapeInfo& info) override; - virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point) const override; private: void remapTextures(); diff --git a/libraries/recording/src/recording/impl/ArrayClip.h b/libraries/recording/src/recording/impl/ArrayClip.h index 10b3580228..165842d24a 100644 --- a/libraries/recording/src/recording/impl/ArrayClip.h +++ b/libraries/recording/src/recording/impl/ArrayClip.h @@ -32,7 +32,7 @@ public: return _frames.size(); } - Clip::Pointer duplicate() const { + virtual Clip::Pointer duplicate() const override { auto result = newClip(); Locker lock(_mutex); for (size_t i = 0; i < _frames.size(); ++i) { @@ -41,7 +41,7 @@ public: return result; } - virtual void seekFrameTime(Frame::Time offset) { + virtual void seekFrameTime(Frame::Time offset) override { Locker lock(_mutex); auto itr = std::lower_bound(_frames.begin(), _frames.end(), offset, [](const T& a, Frame::Time b)->bool { diff --git a/libraries/recording/src/recording/impl/PointerClip.h b/libraries/recording/src/recording/impl/PointerClip.h index f5c0dd6bc4..48d4e4cbc8 100644 --- a/libraries/recording/src/recording/impl/PointerClip.h +++ b/libraries/recording/src/recording/impl/PointerClip.h @@ -45,7 +45,7 @@ public: // FIXME move to frame? static const qint64 MINIMUM_FRAME_SIZE = sizeof(FrameType) + sizeof(Frame::Time) + sizeof(FrameSize); protected: - void reset(); + void reset() override; virtual FrameConstPointer readFrame(size_t index) const override; QJsonDocument _header; uchar* _data { nullptr }; From a455cb880f0d0571f9590f2d4012884f6bd0e5a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 09:23:16 -0800 Subject: [PATCH 148/165] Fix typeid warning --- interface/src/ui/overlays/Overlays.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 96553843c8..f6e6851c38 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -533,15 +533,13 @@ bool Overlays::isLoaded(unsigned int id) { QSizeF Overlays::textSize(unsigned int id, const QString& text) const { Overlay::Pointer thisOverlay = _overlaysHUD[id]; if (thisOverlay) { - if (typeid(*thisOverlay) == typeid(TextOverlay)) { - return std::dynamic_pointer_cast(thisOverlay)->textSize(text); + if (auto textOverlay = std::dynamic_pointer_cast(thisOverlay)) { + return textOverlay->textSize(text); } } else { thisOverlay = _overlaysWorld[id]; - if (thisOverlay) { - if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { - return std::dynamic_pointer_cast(thisOverlay)->textSize(text); - } + if (auto text3dOverlay = std::dynamic_pointer_cast(thisOverlay)) { + return text3dOverlay->textSize(text); } } return QSizeF(0.0f, 0.0f); From 07387ab8c0a7d4240f99f3b13ad7d99b3510ddb9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 10:01:43 -0800 Subject: [PATCH 149/165] Fix most OpenGL warnings --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp | 1 - .../src/display-plugins/WindowOpenGLDisplayPlugin.cpp | 1 - libraries/gpu/src/gpu/GLBackendShared.h | 2 ++ libraries/render-utils/src/FboCache.h | 1 - plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 1 - 5 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 01cb0961e4..09f4ba9897 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -6,7 +6,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OpenGLDisplayPlugin.h" -#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index 6ddc791503..e6fb2be2f5 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -8,7 +8,6 @@ #include "WindowOpenGLDisplayPlugin.h" #include -#include #include "plugins/PluginContainer.h" diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 21bd10a33a..59da9ab9e9 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -11,6 +11,8 @@ #ifndef hifi_gpu_GLBackend_Shared_h #define hifi_gpu_GLBackend_Shared_h +#include + #include #include "GPULogging.h" diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 78c3194eb5..cedc4bff82 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -12,7 +12,6 @@ #ifndef hifi_FboCache_h #define hifi_FboCache_h -#include #include #include #include diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index f0398158b4..8cfe061e37 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include From 786e241a29bbd0e86f34060e6c4fc3bb4d05c092 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 4 Dec 2015 10:14:40 -0800 Subject: [PATCH 150/165] blocks dont collide when held --- unpublishedScripts/hiddenEntityReset.js | 4 ++++ unpublishedScripts/masterReset.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 48745715f9..259cdd066c 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1366,7 +1366,11 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey; { + invertSolidWhileHeld: true } + }) }); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6a870f988f..2034bd9601 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1346,6 +1346,9 @@ MasterReset = function() { userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); From b9ace94ff1fa8e0b86603c10afe3f20eb050d7ae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 30 Nov 2015 09:35:18 -0800 Subject: [PATCH 151/165] Prototyping threaded present --- interface/resources/qml/Stats.qml | 7 +- interface/src/Application.cpp | 83 +++--- interface/src/Application.h | 6 + interface/src/GLCanvas.cpp | 21 -- interface/src/GLCanvas.h | 2 - interface/src/PluginContainerProxy.cpp | 87 ++++-- interface/src/PluginContainerProxy.h | 7 +- interface/src/avatar/AvatarUpdate.cpp | 3 +- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/Stats.cpp | 8 +- interface/src/ui/Stats.h | 6 +- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 80 +++--- .../Basic2DWindowOpenGLDisplayPlugin.h | 9 +- .../src/display-plugins/DisplayPlugin.cpp | 30 +- .../src/display-plugins/NullDisplayPlugin.cpp | 13 +- .../src/display-plugins/NullDisplayPlugin.h | 6 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 258 +++++++++++++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 66 +++-- .../WindowOpenGLDisplayPlugin.cpp | 28 +- .../WindowOpenGLDisplayPlugin.h | 12 +- .../openvr/OpenVrDisplayPlugin.cpp | 40 +-- .../openvr/OpenVrDisplayPlugin.h | 6 +- .../stereo/InterleavedStereoDisplayPlugin.cpp | 8 +- .../stereo/InterleavedStereoDisplayPlugin.h | 3 +- libraries/gl/src/gl/GLEscrow.h | 24 +- libraries/plugins/src/plugins/DisplayPlugin.h | 30 +- .../plugins/src/plugins/PluginContainer.h | 11 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 28 +- plugins/oculus/src/OculusBaseDisplayPlugin.h | 8 +- .../oculus/src/OculusDebugDisplayPlugin.cpp | 10 - plugins/oculus/src/OculusDebugDisplayPlugin.h | 3 - plugins/oculus/src/OculusDisplayPlugin.cpp | 60 ++-- plugins/oculus/src/OculusDisplayPlugin.h | 11 +- plugins/oculus/src/OculusHelpers.cpp | 1 - .../src/OculusLegacyDisplayPlugin.h | 1 - tests/controllers/src/main.cpp | 7 +- 37 files changed, 600 insertions(+), 387 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 84381cc754..56d4f9c14b 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -45,7 +45,12 @@ Item { Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Framerate: " + root.framerate + text: "Render Rate: " + root.renderrate + } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + text: "Present Rate: " + root.presentrate } Text { color: root.fontColor; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c552feb51b..581fdbec5a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -150,6 +150,8 @@ #include "InterfaceParentFinder.h" +#include +#include // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -1089,6 +1091,7 @@ void Application::paintGL() { // update fps once a second if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) { _fps = _framesPerSecond.getAverage(); + qDebug() << QString::number(_fps, 'g', 4); _lastFramesPerSecondUpdate = now; } @@ -1136,7 +1139,7 @@ void Application::paintGL() { _lastInstantaneousFps = instantaneousFps; auto displayPlugin = getActiveDisplayPlugin(); - displayPlugin->preRender(); + // FIXME not needed anymore? _offscreenContext->makeCurrent(); // update the avatar with a fresh HMD pose @@ -1304,6 +1307,13 @@ void Application::paintGL() { auto baseProjection = renderArgs._viewFrustum->getProjection(); auto hmdInterface = DependencyManager::get(); float IPDScale = hmdInterface->getIPDScale(); + + // Tell the plugin what pose we're using to render. In this case we're just using the + // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it + // for rotational timewarp. If we move to support positonal timewarp, we need to + // ensure this contains the full pose composed with the eye offsets. + mat4 headPose = displayPlugin->getHeadPose(_frameCount); + // FIXME we probably don't need to set the projection matrix every frame, // only when the display plugin changes (or in non-HMD modes when the user // changes the FOV manually, which right now I don't think they can. @@ -1319,12 +1329,7 @@ void Application::paintGL() { mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); eyeOffsets[eye] = eyeOffsetTransform; - // Tell the plugin what pose we're using to render. In this case we're just using the - // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it - // for rotational timewarp. If we move to support positonal timewarp, we need to - // ensure this contains the full pose composed with the eye offsets. - mat4 headPose = displayPlugin->getHeadPose(); - displayPlugin->setEyeRenderPose(eye, headPose); + displayPlugin->setEyeRenderPose(_frameCount, eye, headPose); eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); @@ -1367,44 +1372,35 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); - GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); - // Ensure the rendering context commands are completed when rendering - GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - // Ensure the sync object is flushed to the driver thread before releasing the context - // CRITICAL for the mac driver apparently. - glFlush(); - _offscreenContext->doneCurrent(); - - // Switches to the display plugin context - displayPlugin->preDisplay(); - // Ensure all operations from the previous context are complete before we try to read the fbo - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(sync); uint64_t displayStart = usecTimestampNow(); + auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); + auto scratchFramebuffer = framebufferCache->getFramebuffer(); + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i rect; + rect.z = size.width(); + rect.w = size.height(); + batch.setFramebuffer(scratchFramebuffer); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + batch.blit(primaryFramebuffer, rect, scratchFramebuffer, rect); + batch.setFramebuffer(nullptr); + }); + auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); + GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); - { - PROFILE_RANGE(__FUNCTION__ "/pluginDisplay"); - PerformanceTimer perfTimer("pluginDisplay"); - displayPlugin->display(finalTexture, toGlm(size)); - } + Q_ASSERT(0 != finalTexture); + Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); + _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); + displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); - { - PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); - PerformanceTimer perfTimer("bufferSwap"); - displayPlugin->finishFrame(); - } uint64_t displayEnd = usecTimestampNow(); const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs _lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND; - } { - PerformanceTimer perfTimer("makeCurrent"); - _offscreenContext->makeCurrent(); Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages // Back to the default framebuffer; gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { @@ -2612,7 +2608,7 @@ void Application::updateMyAvatarLookAtPosition() { lookAtPosition.x = -lookAtPosition.x; } if (isHMD) { - glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(_frameCount); glm::quat hmdRotation = glm::quat_cast(headPose); lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition); } else { @@ -4503,6 +4499,7 @@ void Application::toggleLogDialog() { } void Application::takeSnapshot() { +#if 0 QMediaPlayer* player = new QMediaPlayer(); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); @@ -4519,7 +4516,7 @@ void Application::takeSnapshot() { _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); } _snapshotShareDialog->show(); - +#endif } float Application::getRenderResolutionScale() const { @@ -4702,10 +4699,6 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const { return ((Application*)this)->getActiveDisplayPlugin(); } -bool _activatingDisplayPlugin{ false }; -QVector> _currentDisplayPluginActions; -QVector> _currentInputPluginActions; - static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); @@ -4735,9 +4728,9 @@ void Application::updateDisplayMode() { bool first = true; foreach(auto displayPlugin, displayPlugins) { addDisplayPluginToMenu(displayPlugin, first); - QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [this] { - paintGL(); - }); + QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, + this, &Application::paintGL, Qt::QueuedConnection); + QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { resizeGL(); }); @@ -4917,7 +4910,7 @@ mat4 Application::getEyeOffset(int eye) const { mat4 Application::getHMDSensorPose() const { if (isHMDMode()) { - return getActiveDisplayPlugin()->getHeadPose(); + return getActiveDisplayPlugin()->getHeadPose(_frameCount); } return mat4(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index e2445f7f22..1af252de95 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -158,6 +158,7 @@ public: bool isForeground() const { return _isForeground; } + uint32_t getFrameCount() { return _frameCount; } float getFps() const { return _fps; } float const HMD_TARGET_FRAME_RATE = 75.0f; float const DESKTOP_TARGET_FRAME_RATE = 60.0f; @@ -425,6 +426,11 @@ private: DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; + bool _activatingDisplayPlugin { false }; + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; + QMap _lockedFramebufferMap; + MainWindow* _window; ToolWindow* _toolWindow; diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0b4c6dde3d..ec96f7c5d4 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,27 +13,6 @@ #include "Application.h" #include "GLCanvas.h" -#include - -#include "MainWindow.h" -#include "Menu.h" - -void GLCanvas::paintGL() { - PROFILE_RANGE(__FUNCTION__); - - // FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near - // the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL() - // in this case, since the display plugins eventually handle all the painting - bool isThrottleFPSEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ThrottleFPSIfNotFocus); - if (!qApp->getWindow()->isMinimized() || !isThrottleFPSEnabled) { - qApp->paintGL(); - } -} - -void GLCanvas::resizeGL(int width, int height) { - qApp->resizeGL(); -} - bool GLCanvas::event(QEvent* event) { if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { return true; diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 0442159eeb..f707046c7c 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -18,8 +18,6 @@ class GLCanvas : public GLWidget { Q_OBJECT protected: - virtual void paintGL() override; - virtual void resizeGL(int width, int height) override; virtual bool event(QEvent* event) override; }; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 2e5c883897..8774eecd77 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -1,17 +1,23 @@ #include "PluginContainerProxy.h" -#include -#include +#include +#include #include #include #include +#include +#include +#include #include "Application.h" #include "MainWindow.h" #include "GLCanvas.h" #include "ui/DialogsManager.h" +#include +#include + PluginContainerProxy::PluginContainerProxy() { } @@ -36,30 +42,31 @@ extern QVector> _currentInputPluginActions; std::map _exclusiveGroups; QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - auto menu = Menu::getInstance(); - MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - if (!groupName.isEmpty()) { - QActionGroup* group{ nullptr }; - if (!_exclusiveGroups.count(groupName)) { - group = _exclusiveGroups[groupName] = new QActionGroup(menu); - group->setExclusive(true); - } else { - group = _exclusiveGroups[groupName]; - } - group->addAction(action); - } - connect(action, &QAction::triggered, [=] { - onClicked(action->isChecked()); - }); - action->setCheckable(checkable); - action->setChecked(checked); - if (_activatingDisplayPlugin) { - _currentDisplayPluginActions.push_back({ path, name }); - } else { - _currentInputPluginActions.push_back({ path, name }); - } - return action; + //auto menu = Menu::getInstance(); + //MenuWrapper* parentItem = menu->getMenu(path); + //QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + //if (!groupName.isEmpty()) { + // QActionGroup* group{ nullptr }; + // if (!_exclusiveGroups.count(groupName)) { + // group = _exclusiveGroups[groupName] = new QActionGroup(menu); + // group->setExclusive(true); + // } else { + // group = _exclusiveGroups[groupName]; + // } + // group->addAction(action); + //} + //connect(action, &QAction::triggered, [=] { + // onClicked(action->isChecked()); + //}); + //action->setCheckable(checkable); + //action->setChecked(checked); + //if (_activatingDisplayPlugin) { + // _currentDisplayPluginActions.push_back({ path, name }); + //} else { + // _currentInputPluginActions.push_back({ path, name }); + //} + //return action; + return nullptr; } void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { @@ -150,10 +157,36 @@ void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); } -QGLWidget* PluginContainerProxy::getPrimarySurface() { +QGLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } +QWindow* PluginContainerProxy::getPrimaryWindow() { + return qApp->_glWidget->windowHandle(); +} + +QOpenGLContext* PluginContainerProxy::getPrimaryContext() { + return qApp->_glWidget->context()->contextHandle(); +} + const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const { return qApp->getActiveDisplayPlugin(); } + +bool PluginContainerProxy::makeRenderingContextCurrent() { + return qApp->_offscreenContext->makeCurrent(); +} + +void PluginContainerProxy::releaseSceneTexture(uint32_t texture) { + Q_ASSERT(QThread::currentThread() == qApp->thread()); + auto& framebufferMap = qApp->_lockedFramebufferMap; + Q_ASSERT(framebufferMap.contains(texture)); + auto framebufferPointer = framebufferMap[texture]; + framebufferMap.remove(texture); + auto framebufferCache = DependencyManager::get(); + framebufferCache->releaseFramebuffer(framebufferPointer); +} + +void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { + +} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 79f8287b66..5cc1cc8583 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -22,7 +22,12 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; virtual void requestReset() override; - virtual QGLWidget* getPrimarySurface() override; + virtual bool makeRenderingContextCurrent() override; + virtual void releaseSceneTexture(uint32_t texture) override; + virtual void releaseOverlayTexture(uint32_t texture) override; + virtual QGLWidget* getPrimaryWidget() override; + virtual QWindow* getPrimaryWindow() override; + virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; virtual const DisplayPlugin* getActiveDisplayPlugin() const override; diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 52fa568879..99e5d2acaa 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -30,7 +30,8 @@ void AvatarUpdate::synchronousProcess() { // Keep our own updated value, so that our asynchronous code can consult it. _isHMDMode = qApp->isHMDMode(); - _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + auto frameCount = qApp->getFrameCount(); + _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(frameCount); if (_updateBillboard) { DependencyManager::get()->getMyAvatar()->doUpdateBillboard(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5f43b834ec..1a098ec5f6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1200,7 +1200,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (qApp->isHMDMode()) { glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(qApp->getFrameCount()); glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); leftEyePose = leftEyePose * headPose; glm::vec3 leftEyePosition = extractTranslation(leftEyePose); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index eb43b9d864..4cee190a47 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -287,7 +287,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int mat4 camMat; _cameraBaseTransform.getMatrix(camMat); auto displayPlugin = qApp->getActiveDisplayPlugin(); - auto headPose = displayPlugin->getHeadPose(); + auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount()); auto eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye); camMat = (headPose * eyeToHead) * camMat; batch.setViewportTransform(renderArgs->_viewport); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 12692698e7..358dc49bdb 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "BandwidthRecorder.h" #include "Menu.h" @@ -118,7 +119,12 @@ void Stats::updateStats(bool force) { STAT_UPDATE(avatarRenderableCount, avatarManager->getNumberInRenderRange()); STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating STAT_UPDATE(serverCount, nodeList->size()); - STAT_UPDATE(framerate, (int)qApp->getFps()); + STAT_UPDATE(renderrate, (int)qApp->getFps()); + if (qApp->getActiveDisplayPlugin()) { + STAT_UPDATE(presentrate, (int)qApp->getActiveDisplayPlugin()->presentRate()); + } else { + STAT_UPDATE(presentrate, -1); + } STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond()); STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index d1c0dd19d7..eb28883001 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -32,7 +32,8 @@ class Stats : public QQuickItem { Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream) STATS_PROPERTY(int, serverCount, 0) - STATS_PROPERTY(int, framerate, 0) + STATS_PROPERTY(int, renderrate, 0) + STATS_PROPERTY(int, presentrate, 0) STATS_PROPERTY(int, simrate, 0) STATS_PROPERTY(int, avatarSimrate, 0) STATS_PROPERTY(int, avatarCount, 0) @@ -115,7 +116,8 @@ signals: void expandedChanged(); void timingExpandedChanged(); void serverCountChanged(); - void framerateChanged(); + void renderrateChanged(); + void presentrateChanged(); void simrateChanged(); void avatarSimrateChanged(); void avatarCountChanged(); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 9366ec4403..36216f8912 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -30,44 +30,41 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { return NAME; } -std::vector _framerateActions; -QAction* _vsyncAction{ nullptr }; - void Basic2DWindowOpenGLDisplayPlugin::activate() { - _framerateActions.clear(); - _container->addMenuItem(MENU_PATH(), FULLSCREEN, - [this](bool clicked) { - if (clicked) { - _container->setFullscreen(getFullscreenTarget()); - } else { - _container->unsetFullscreen(); - } - }, true, false); - _container->addMenu(FRAMERATE); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, - [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_60, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_50, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_40, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_30, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.clear(); + //_container->addMenuItem(MENU_PATH(), FULLSCREEN, + // [this](bool clicked) { + // if (clicked) { + // _container->setFullscreen(getFullscreenTarget()); + // } else { + // _container->unsetFullscreen(); + // } + // }, true, false); + //_container->addMenu(FRAMERATE); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, + // [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_60, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_50, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_40, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_30, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); WindowOpenGLDisplayPlugin::activate(); - // Vsync detection happens in the parent class activate, so we need to check after that - if (_vsyncSupported) { - _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - } else { - _vsyncAction = nullptr; - } + //// Vsync detection happens in the parent class activate, so we need to check after that + //if (_vsyncSupported) { + // _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); + //} else { + // _vsyncAction = nullptr; + //} updateFramerate(); } @@ -76,19 +73,18 @@ void Basic2DWindowOpenGLDisplayPlugin::deactivate() { WindowOpenGLDisplayPlugin::deactivate(); } -void Basic2DWindowOpenGLDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) { +void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { if (_vsyncAction) { - bool wantVsync = _vsyncAction->isChecked(); - bool vsyncEnabed = isVsyncEnabled(); - if (vsyncEnabed ^ wantVsync) { - enableVsync(wantVsync); - } + _wantVsync = _vsyncAction->isChecked(); + //bool vsyncEnabed = isVsyncEnabled(); + //if (vsyncEnabed ^ wantVsync) { + // enableVsync(wantVsync); + //} } - WindowOpenGLDisplayPlugin::display(sceneTexture, sceneSize); + WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } - int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index f4655ab79f..80aebf9efc 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -10,6 +10,8 @@ #include "WindowOpenGLDisplayPlugin.h" class QScreen; +class QAction; + class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin { Q_OBJECT @@ -19,7 +21,7 @@ public: virtual void activate() override; virtual void deactivate() override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual bool isThrottled() const override; @@ -31,6 +33,9 @@ private: void updateFramerate(); static const QString NAME; QScreen* getFullscreenTarget(); - uint32_t _framerateTarget{ 0 }; + std::vector _framerateActions; + QAction* _vsyncAction { nullptr }; + uint32_t _framerateTarget { 0 }; int _fullscreenTarget{ -1 }; + bool _wantVsync { true }; }; diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 8155d69826..85e832abdd 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -25,22 +25,22 @@ const QString& DisplayPlugin::MENU_PATH() { DisplayPluginList getDisplayPlugins() { DisplayPlugin* PLUGIN_POOL[] = { new Basic2DWindowOpenGLDisplayPlugin(), -#ifdef DEBUG new NullDisplayPlugin(), -#endif - - // Stereo modes - - // SBS left/right - new SideBySideStereoDisplayPlugin(), - // Interleaved left/right - new InterleavedStereoDisplayPlugin(), - - // HMDs -#ifdef Q_OS_WIN - // SteamVR SDK - new OpenVrDisplayPlugin(), -#endif +//#ifdef DEBUG +//#endif +// +// // Stereo modes +// +// // SBS left/right +// new SideBySideStereoDisplayPlugin(), +// // Interleaved left/right +// new InterleavedStereoDisplayPlugin(), +// +// // HMDs +//#ifdef Q_OS_WIN +// // SteamVR SDK +// new OpenVrDisplayPlugin(), +//#endif nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index ce512962ff..b0f02b1149 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -9,6 +9,7 @@ // #include "NullDisplayPlugin.h" +#include const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); const QString & NullDisplayPlugin::getName() const { @@ -23,8 +24,12 @@ bool NullDisplayPlugin::hasFocus() const { return false; } -void NullDisplayPlugin::preRender() {} -void NullDisplayPlugin::preDisplay() {} -void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {} -void NullDisplayPlugin::finishFrame() {} +void NullDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + _container->releaseSceneTexture(sceneTexture); +} + +void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) { + _container->releaseOverlayTexture(overlayTexture); +} + void NullDisplayPlugin::stop() {} diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index 8cd5c2bc37..c4052f38dd 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -19,10 +19,8 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override; virtual bool hasFocus() const override; - virtual void preRender() override; - virtual void preDisplay() override; - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override; - virtual void finishFrame() override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; private: static const QString NAME; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 09f4ba9897..e18cc6c82f 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -6,71 +6,167 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OpenGLDisplayPlugin.h" -#include +#include +#include +#include + +#include +#include + +#include +#include +#include #include +#include #include +class PresentThread : public QThread, public Dependency { + using Mutex = std::mutex; + using Lock = std::unique_lock; + friend class OpenGLDisplayPlugin; +public: + + ~PresentThread() { + _shutdown = true; + wait(); + } + + void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) { + Lock lock(_mutex); + _newPlugin = plugin; + } + + virtual void run() override { + Q_ASSERT(_context); + while (!_shutdown) { + // Check before lock + if (_newPlugin != nullptr) { + Lock lock(_mutex); + // Check if we have a new plugin to activate + if (_newPlugin != nullptr) { + // Deactivate the old plugin + if (_activePlugin != nullptr) { + _activePlugin->uncustomizeContext(); + } + + _newPlugin->customizeContext(); + _activePlugin = _newPlugin; + _newPlugin = nullptr; + _context->doneCurrent(); + } + lock.unlock(); + } + + // If there's no active plugin, just sleep + if (_activePlugin == nullptr) { + QThread::usleep(100); + continue; + } + + // take the latest texture and present it + _activePlugin->present(); + + } + _context->doneCurrent(); + _context->moveToThread(qApp->thread()); + } + + +private: + bool _shutdown { false }; + Mutex _mutex; + QThread* _mainThread { nullptr }; + OpenGLDisplayPlugin* _newPlugin { nullptr }; + OpenGLDisplayPlugin* _activePlugin { nullptr }; + QOpenGLContext* _context { nullptr }; +}; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { + _sceneTextureEscrow.setRecycler([this](GLuint texture){ + cleanupForSceneTexture(texture); + _container->releaseSceneTexture(texture); + }); + + _overlayTextureEscrow.setRecycler([this](GLuint texture) { + _container->releaseOverlayTexture(texture); + }); + connect(&_timer, &QTimer::timeout, this, [&] { - if (_active) { + if (_active && _sceneTextureEscrow.depth() < 1) { emit requestRender(); } }); } -OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { +void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture)); + _sceneTextureToFrameIndexMap.remove(sceneTexture); } -void OpenGLDisplayPlugin::preDisplay() { - makeCurrent(); -}; - -void OpenGLDisplayPlugin::preRender() { - // NOOP -} - -void OpenGLDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; - -void OpenGLDisplayPlugin::customizeContext() { - using namespace oglplus; - // TODO: write the poper code for linux -#if defined(Q_OS_WIN) - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); -#endif - - Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); - Context::Disable(Capability::Blend); - Context::Disable(Capability::DepthTest); - Context::Disable(Capability::CullFace); - - - _program = loadDefaultShader(); - _plane = loadPlane(_program); - - enableVsync(); -} void OpenGLDisplayPlugin::activate() { + _timer.start(2); + + // Start the present thread if necessary + auto presentThread = DependencyManager::get(); + if (!presentThread) { + DependencyManager::set(); + presentThread = DependencyManager::get(); + auto widget = _container->getPrimaryWidget(); + auto glContext = widget->context(); + auto context = glContext->contextHandle(); + glContext->moveToThread(presentThread.data()); + context->moveToThread(presentThread.data()); + + // Move the OpenGL context to the present thread + presentThread->_context = context; + + // Start execution + presentThread->start(); + } + presentThread->setNewDisplayPlugin(this); DisplayPlugin::activate(); - _timer.start(1); + emit requestRender(); } void OpenGLDisplayPlugin::stop() { - DisplayPlugin::activate(); _timer.stop(); } void OpenGLDisplayPlugin::deactivate() { - _active = false; _timer.stop(); + DisplayPlugin::deactivate(); +} +void OpenGLDisplayPlugin::customizeContext() { + auto presentThread = DependencyManager::get(); + Q_ASSERT(thread() == presentThread->thread()); + + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + + // TODO: write the proper code for linux +#if defined(Q_OS_WIN) + _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); +#endif + enableVsync(); + + using namespace oglplus; + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::Blend); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + + _program = loadDefaultShader(); + _plane = loadPlane(_program); + + doneCurrent(); +} + +void OpenGLDisplayPlugin::uncustomizeContext() { makeCurrent(); - Q_ASSERT(0 == glGetError()); _program.reset(); _plane.reset(); doneCurrent(); @@ -118,13 +214,74 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) { return false; } -void OpenGLDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { +void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + { + Lock lock(_mutex); + _sceneTextureToFrameIndexMap[sceneTexture] = frameIndex; + } + + // Submit it to the presentation thread via escrow + _sceneTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::submitOverlayTexture(GLuint sceneTexture, const glm::uvec2& sceneSize) { + // Submit it to the presentation thread via escrow + _overlayTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::updateTextures() { + _currentSceneTexture = _sceneTextureEscrow.fetchAndRelease(_currentSceneTexture); + _currentOverlayTexture = _overlayTextureEscrow.fetchAndRelease(_currentOverlayTexture); +} + +void OpenGLDisplayPlugin::updateFramerate() { + uint64_t now = usecTimestampNow(); + static uint64_t lastSwapEnd { now }; + uint64_t diff = now - lastSwapEnd; + lastSwapEnd = now; + if (diff != 0) { + Lock lock(_mutex); + _usecsPerFrame.updateAverage(diff); + } +} + + +void OpenGLDisplayPlugin::internalPresent() { using namespace oglplus; - uvec2 size = getSurfaceSize(); + uvec2 size = getSurfacePixels(); Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + Context::Clear().DepthBuffer(); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); drawUnitQuad(); + swapBuffers(); + updateFramerate(); +} + +void OpenGLDisplayPlugin::present() { + auto makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + if (!makeCurrentResult) { + qDebug() << "Failed to make current"; + return; + } + + updateTextures(); + if (_currentSceneTexture) { + internalPresent(); + updateFramerate(); + } + doneCurrent(); +} + +float OpenGLDisplayPlugin::presentRate() { + float result { -1.0f }; + { + Lock lock(_mutex); + result = _usecsPerFrame.getAverage(); + result = 1.0f / result; + result *= USECS_PER_SECOND; + } + return result; } void OpenGLDisplayPlugin::drawUnitQuad() { @@ -151,3 +308,20 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() { return true; #endif } +bool OpenGLDisplayPlugin::makeCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->makeCurrent(); + auto result = widget->context()->contextHandle() == QOpenGLContext::currentContext(); + Q_ASSERT(result); + return result; +} + +void OpenGLDisplayPlugin::doneCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->doneCurrent(); +} + +void OpenGLDisplayPlugin::swapBuffers() { + static auto widget = _container->getPrimaryWidget(); + widget->swapBuffers(); +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 43d8e5af6b..4426bfd5ef 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -9,42 +9,74 @@ #include "DisplayPlugin.h" -#include -#include +#include -class GlWindow; -class QOpenGLContext; +#include +#include +#include +#include class OpenGLDisplayPlugin : public DisplayPlugin { +protected: + using Mutex = std::recursive_mutex; + using Lock = std::unique_lock; public: OpenGLDisplayPlugin(); - virtual ~OpenGLDisplayPlugin(); - virtual void preRender() override; - virtual void preDisplay() override; - virtual void finishFrame() override; - virtual void activate() override; virtual void deactivate() override; virtual void stop() override; virtual bool eventFilter(QObject* receiver, QEvent* event) override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; + virtual float presentRate() override; + + virtual glm::uvec2 getRecommendedRenderSize() const { + return getSurfacePixels(); + } + + virtual glm::uvec2 getRecommendedUiSize() const { + return getSurfaceSize(); + } protected: - virtual void customizeContext(); - virtual void drawUnitQuad(); - virtual glm::uvec2 getSurfaceSize() const = 0; - virtual void makeCurrent() = 0; - virtual void doneCurrent() = 0; - virtual void swapBuffers() = 0; + friend class PresentThread; + virtual glm::uvec2 getSurfaceSize() const = 0; + virtual glm::uvec2 getSurfacePixels() const = 0; + + // FIXME make thread safe? virtual bool isVsyncEnabled(); virtual void enableVsync(bool enable = true); + // These functions must only be called on the presentation thread + virtual void customizeContext(); + virtual void uncustomizeContext(); + virtual void cleanupForSceneTexture(uint32_t sceneTexture); + void present(); + void updateTextures(); + void updateFramerate(); + void drawUnitQuad(); + bool makeCurrent(); + void doneCurrent(); + void swapBuffers(); + // Plugin specific functionality to composite the scene and overlay and present the result + virtual void internalPresent(); + mutable QTimer _timer; ProgramPtr _program; ShapeWrapperPtr _plane; - bool _vsyncSupported{ false }; + bool _vsyncSupported { false }; + + Mutex _mutex; + SimpleMovingAverage _usecsPerFrame { 10 }; + QMap _sceneTextureToFrameIndexMap; + + GLuint _currentSceneTexture { 0 }; + GLuint _currentOverlayTexture { 0 }; + + GLTextureEscrow _overlayTextureEscrow; + GLTextureEscrow _sceneTextureEscrow; }; diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index e6fb2be2f5..b215b19b15 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -11,14 +11,7 @@ #include "plugins/PluginContainer.h" -WindowOpenGLDisplayPlugin::WindowOpenGLDisplayPlugin() { -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedRenderSize() const { - return getSurfaceSize(); -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfacePixels() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size() * _window->devicePixelRatio()); @@ -26,8 +19,7 @@ glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { return result; } - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedUiSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size()); @@ -40,11 +32,8 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const { } void WindowOpenGLDisplayPlugin::activate() { + _window = _container->getPrimaryWidget(); OpenGLDisplayPlugin::activate(); - _window = _container->getPrimarySurface(); - _window->makeCurrent(); - customizeContext(); - _window->doneCurrent(); } void WindowOpenGLDisplayPlugin::deactivate() { @@ -52,14 +41,3 @@ void WindowOpenGLDisplayPlugin::deactivate() { _window = nullptr; } -void WindowOpenGLDisplayPlugin::makeCurrent() { - _window->makeCurrent(); -} - -void WindowOpenGLDisplayPlugin::doneCurrent() { - _window->doneCurrent(); -} - -void WindowOpenGLDisplayPlugin::swapBuffers() { - _window->swapBuffers(); -} diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h index fc7691fc56..51e5d32503 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h @@ -9,21 +9,17 @@ #include "OpenGLDisplayPlugin.h" -class QGLWidget; +class QWidget; class WindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin { public: - WindowOpenGLDisplayPlugin(); - virtual glm::uvec2 getRecommendedRenderSize() const override; - virtual glm::uvec2 getRecommendedUiSize() const override; virtual bool hasFocus() const override; virtual void activate() override; virtual void deactivate() override; protected: virtual glm::uvec2 getSurfaceSize() const override final; - virtual void makeCurrent() override; - virtual void doneCurrent() override; - virtual void swapBuffers() override; - QGLWidget* _window{ nullptr }; + virtual glm::uvec2 getSurfacePixels() const override final; + + QWidget* _window { nullptr }; }; diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index 4278165e25..68a711a847 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -152,7 +152,7 @@ glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return _eyesData[eye]._eyeOffset; } -glm::mat4 OpenVrDisplayPlugin::getHeadPose() const { +glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { return _trackedDevicePoseMat4[0]; } @@ -160,26 +160,26 @@ void OpenVrDisplayPlugin::customizeContext() { WindowOpenGLDisplayPlugin::customizeContext(); } -void OpenVrDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - // Flip y-axis since GL UV coords are backwards. - static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; - static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; - _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); - _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); - glFinish(); -} +//void OpenVrDisplayPlugin::display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) { +// // Flip y-axis since GL UV coords are backwards. +// static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; +// static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; +// _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); +// _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); +// glFinish(); +//} -void OpenVrDisplayPlugin::finishFrame() { -// swapBuffers(); - doneCurrent(); - _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { - _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); - } - openvr_for_each_eye([&](vr::Hmd_Eye eye) { - _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; - }); -}; +//void OpenVrDisplayPlugin::finishFrame() { +//// swapBuffers(); +// doneCurrent(); +// _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); +// for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { +// _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); +// } +// openvr_for_each_eye([&](vr::Hmd_Eye eye) { +// _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; +// }); +//}; #endif diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h index 15d37d9de8..c8887276b7 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h @@ -31,13 +31,11 @@ public: virtual void resetSensors() override; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; - virtual glm::mat4 getHeadPose() const override; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; +// virtual void display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: vr::IVRSystem* _hmd { nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 72921b4f90..4332c53d81 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -66,10 +66,6 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const { return result; } -void InterleavedStereoDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { - using namespace oglplus; - _program->Bind(); - Uniform(*_program, "textureSize").SetValue(sceneSize); - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); +void InterleavedStereoDisplayPlugin::internalPresent() { + // FIXME } diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index 3044d91247..b9b3566349 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -19,7 +19,8 @@ public: virtual void customizeContext() override; virtual glm::uvec2 getRecommendedRenderSize() const override; - void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + + void internalPresent() override; private: static const QString NAME; diff --git a/libraries/gl/src/gl/GLEscrow.h b/libraries/gl/src/gl/GLEscrow.h index db9f033de8..d860f1239c 100644 --- a/libraries/gl/src/gl/GLEscrow.h +++ b/libraries/gl/src/gl/GLEscrow.h @@ -76,7 +76,7 @@ public: } }; - using Mutex = std::mutex; + using Mutex = std::recursive_mutex; using Lock = std::unique_lock; using Recycler = std::function; // deque gives us random access, double ended push & pop and size, all in constant time @@ -130,6 +130,21 @@ public: return result; } + // Returns the next available resource provided by the submitter, + // or if none is available (which could mean either the submission + // list is empty or that the first item on the list isn't yet signaled + // Also releases any previous texture held by the caller + T fetchAndRelease(T oldValue) { + T result = fetch(); + if (!result) { + return oldValue; + } + if (oldValue) { + release(oldValue); + } + return result; + } + // If fetch returns a non-zero value, it's the responsibility of the // client to release it at some point void release(T t, GLsync readSync = 0) { @@ -162,7 +177,12 @@ private: pop(_releases); } - trash.swap(_trash); + { + // FIXME I don't think this lock should be necessary, only the submitting thread + // touches the trash + Lock lock(_mutex); + trash.swap(_trash); + } } // FIXME maybe doing a timing on the deleters and warn if it's taking excessive time? diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 5b00391f09..928b72970b 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -65,29 +65,15 @@ public: // processing messages in the middle of submitFrame virtual void stop() = 0; - /** - * Called by the application before the frame rendering. Can be used for - * render timing related calls (for instance, the Oculus begin frame timing - * call) - */ - virtual void preRender() = 0; - /** - * Called by the application immediately before calling the display function. - * For OpenGL based plugins, this is the best place to put activate the output - * OpenGL context - */ - virtual void preDisplay() = 0; - /** * Sends the scene texture to the display plugin. */ - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; /** - * Called by the application immeidately after display. For OpenGL based - * displays, this is the best place to put the buffer swap - */ - virtual void finishFrame() = 0; + * Sends the scene texture to the display plugin. + */ + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) = 0; // Does the rendering surface have current focus? virtual bool hasFocus() const = 0; @@ -116,12 +102,12 @@ public: static const glm::mat4 transform; return transform; } - virtual glm::mat4 getHeadPose() const { + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const { static const glm::mat4 pose; return pose; } // Needed for timewarp style features - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) { + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { // NOOP } @@ -129,8 +115,8 @@ public: virtual void abandonCalibration() {} virtual void resetSensors() {} - virtual float devicePixelRatio() { return 1.0; } - + virtual float devicePixelRatio() { return 1.0f; } + virtual float presentRate() { return -1.0f; } static const QString& MENU_PATH(); signals: diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index f013bfe3bf..25c2bcb11f 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -8,11 +8,15 @@ #pragma once #include +#include #include class QAction; class QGLWidget; class QScreen; +class QOpenGLContext; +class QWindow; + class DisplayPlugin; class PluginContainer { @@ -30,7 +34,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; virtual void requestReset() = 0; - virtual QGLWidget* getPrimarySurface() = 0; + virtual bool makeRenderingContextCurrent() = 0; + virtual void releaseSceneTexture(uint32_t texture) = 0; + virtual void releaseOverlayTexture(uint32_t texture) = 0; + virtual QGLWidget* getPrimaryWidget() = 0; + virtual QWindow* getPrimaryWindow() = 0; + virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 7fd956a08f..805ad75e95 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -15,13 +15,6 @@ uvec2 OculusBaseDisplayPlugin::getRecommendedRenderSize() const { return _desiredFramebufferSize; } -void OculusBaseDisplayPlugin::preRender() { -#if (OVR_MAJOR_VERSION >= 6) - ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex); - _trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds); -#endif -} - glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const { return _eyeProjections[eye]; } @@ -29,7 +22,6 @@ glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseP void OculusBaseDisplayPlugin::resetSensors() { #if (OVR_MAJOR_VERSION >= 6) ovr_RecenterPose(_hmd); - preRender(); #endif } @@ -37,15 +29,14 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return glm::translate(mat4(), toGlm(_eyeOffsets[eye])); } -glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const { - return toGlm(_trackingState.HeadPose.ThePose); +glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const { +#if (OVR_MAJOR_VERSION >= 6) + auto frameTiming = ovr_GetFrameTiming(_hmd, frameIndex); + auto trackingState = ovr_GetTrackingState(_hmd, frameTiming.DisplayMidpointSeconds); + return toGlm(trackingState.HeadPose.ThePose); +#endif } -void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) { - _eyePoses[eye] = ovrPoseFromGlm(pose); -} - - bool OculusBaseDisplayPlugin::isSupported() const { #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { @@ -64,9 +55,11 @@ bool OculusBaseDisplayPlugin::isSupported() const { // DLL based display plugins MUST initialize GLEW inside the DLL code. void OculusBaseDisplayPlugin::customizeContext() { + makeCurrent(); glewExperimental = true; GLenum err = glewInit(); glGetError(); + doneCurrent(); WindowOpenGLDisplayPlugin::customizeContext(); } @@ -123,8 +116,6 @@ void OculusBaseDisplayPlugin::activate() { eyeSizes[0].x + eyeSizes[1].x, std::max(eyeSizes[0].y, eyeSizes[1].y)); - _frameIndex = 0; - if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { qFatal("Could not attach to sensor device"); @@ -159,9 +150,6 @@ void OculusBaseDisplayPlugin::deactivate() { #endif } -void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - ++_frameIndex; -} float OculusBaseDisplayPlugin::getIPD() const { float result = OVR_DEFAULT_IPD; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index ba1924bfff..711be6aa5e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -30,24 +30,18 @@ public: virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); } virtual void resetSensors() override final; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final; - virtual glm::mat4 getHeadPose() const override final; - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final; virtual float getIPD() const override final; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: virtual void customizeContext() override; - virtual void preRender() override final; - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; protected: - ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; uvec2 _desiredFramebufferSize; - ovrTrackingState _trackingState; - unsigned int _frameIndex{ 0 }; #if (OVR_MAJOR_VERSION >= 6) ovrHmd _hmd; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 7a8b355ddd..26bb3cf9b2 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -28,13 +28,3 @@ void OculusDebugDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); enableVsync(false); } - -void OculusDebugDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); - OculusBaseDisplayPlugin::display(finalTexture, sceneSize); -} - -void OculusDebugDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h index d23c6ba567..04b68704cc 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.h +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.h @@ -15,10 +15,7 @@ public: virtual bool isSupported() const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: static const QString NAME; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 923b8bde6e..bcb39f5100 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -144,7 +144,6 @@ static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; void OculusDisplayPlugin::activate() { - _container->addMenuItem(MENU_PATH(), MONO_PREVIEW, [this](bool clicked) { _monoPreview = clicked; @@ -155,6 +154,8 @@ void OculusDisplayPlugin::activate() { void OculusDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); #if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo->Init(getRecommendedRenderSize()); @@ -168,20 +169,24 @@ void OculusDisplayPlugin::customizeContext() { enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); + doneCurrent(); } -void OculusDisplayPlugin::deactivate() { +void OculusDisplayPlugin::uncustomizeContext() { #if (OVR_MAJOR_VERSION >= 6) makeCurrent(); _sceneFbo.reset(); doneCurrent(); #endif - - OculusBaseDisplayPlugin::deactivate(); + OculusBaseDisplayPlugin::uncustomizeContext(); } -void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { +void OculusDisplayPlugin::internalPresent() { #if (OVR_MAJOR_VERSION >= 6) + if (!_currentSceneTexture) { + return; + } + using namespace oglplus; // Need to make sure only the display plugin is responsible for // controlling vsync @@ -196,7 +201,7 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } else { Context::Viewport(windowSize.x, windowSize.y); } - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); Q_ASSERT(0 == err); drawUnitQuad(); @@ -205,16 +210,24 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi _sceneFbo->Bound([&] { auto size = _sceneFbo->size; Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); drawUnitQuad(); }); - ovr_for_each_eye([&](ovrEyeType eye) { - _sceneLayer.RenderPose[eye] = _eyePoses[eye]; - }); + uint32_t frameIndex { 0 }; + EyePoses eyePoses; + { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(_currentSceneTexture)); + frameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; + Q_ASSERT(_frameEyePoses.contains(frameIndex)); + eyePoses = _frameEyePoses[frameIndex]; + } + + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = eyePoses.first; + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = eyePoses.second; - auto windowSize = toGlm(_window->size()); { ovrViewScaleDesc viewScaleDesc; viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; @@ -228,19 +241,26 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } } _sceneFbo->Increment(); - - ++_frameIndex; #endif -} -/* + /* The swapbuffer call here is only required if we want to mirror the content to the screen. - However, it should only be done if we can reliably disable v-sync on the mirror surface, + However, it should only be done if we can reliably disable v-sync on the mirror surface, otherwise the swapbuffer delay will interefere with the framerate of the headset -*/ -void OculusDisplayPlugin::finishFrame() { + */ if (_enablePreview) { swapBuffers(); } - doneCurrent(); -}; +} + +void OculusDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { + auto ovrPose = ovrPoseFromGlm(pose); + { + Lock lock(_mutex); + if (eye == Eye::Left) { + _frameEyePoses[frameIndex].first = ovrPose; + } else { + _frameEyePoses[frameIndex].second = ovrPose; + } + } +} diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index c1224ecf3a..5509715b9f 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -15,22 +15,21 @@ using SwapFboPtr = QSharedPointer; class OculusDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual void activate() override; - virtual void deactivate() override; virtual const QString & getName() const override; + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + virtual void internalPresent() override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; + virtual void uncustomizeContext() override; private: + using EyePoses = std::pair; static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; + QMap _frameEyePoses; -#if (OVR_MAJOR_VERSION >= 6) SwapFboPtr _sceneFbo; -#endif }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index f93580e5a3..37c560e9ad 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -11,7 +11,6 @@ namespace Oculus { ovrHmd _hmd; - unsigned int _frameIndex{ 0 }; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 6e3f864aee..ccf1ffdb57 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -46,7 +46,6 @@ private: static const QString NAME; ovrHmd _hmd; - unsigned int _frameIndex; ovrTrackingState _trackingState; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 664a894e44..c5c038fde3 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -91,7 +91,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {} virtual void showDisplayPluginsTools() override {} virtual void requestReset() override {} - virtual QGLWidget* getPrimarySurface() override { return nullptr; } + virtual bool makeRenderingContextCurrent() override { return true; } + virtual void releaseSceneTexture(uint32_t texture) override {} + virtual void releaseOverlayTexture(uint32_t texture) override {} + virtual QGLWidget* getPrimaryWidget() override { return nullptr; } + virtual QWindow* getPrimaryWindow() override { return nullptr; } + virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } virtual bool isForeground() override { return true; } virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } }; From d8bb9f8d183fe8cfa2a064276e50feed05689ce4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 13:00:36 -0800 Subject: [PATCH 152/165] Fixing screenshot functionality --- interface/src/Application.cpp | 23 +++--- .../src/display-plugins/NullDisplayPlugin.cpp | 6 ++ .../src/display-plugins/NullDisplayPlugin.h | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 77 +++++++++++++++++-- .../src/display-plugins/OpenGLDisplayPlugin.h | 10 ++- libraries/plugins/src/plugins/DisplayPlugin.h | 4 + 6 files changed, 105 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 581fdbec5a..2c58156d2a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -44,6 +44,9 @@ #include +#include +#include + #include #include #include @@ -150,8 +153,6 @@ #include "InterfaceParentFinder.h" -#include -#include // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -1091,7 +1092,6 @@ void Application::paintGL() { // update fps once a second if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) { _fps = _framesPerSecond.getAverage(); - qDebug() << QString::number(_fps, 'g', 4); _lastFramesPerSecondUpdate = now; } @@ -1344,6 +1344,7 @@ void Application::paintGL() { } // Overlay Composition, needs to occur after screen space effects have completed + // FIXME migrate composition into the display plugins { PROFILE_RANGE(__FUNCTION__ "/compositor"); PerformanceTimer perfTimer("compositor"); @@ -1372,7 +1373,6 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - uint64_t displayStart = usecTimestampNow(); auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); auto scratchFramebuffer = framebufferCache->getFramebuffer(); gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { @@ -1386,12 +1386,18 @@ void Application::paintGL() { }); auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); - Q_ASSERT(0 != finalTexture); + Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + + uint64_t displayStart = usecTimestampNow(); Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); - displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + { + PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene"); + PerformanceTimer perfTimer("pluginSubmitScene"); + displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + } Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); uint64_t displayEnd = usecTimestampNow(); @@ -4499,13 +4505,12 @@ void Application::toggleLogDialog() { } void Application::takeSnapshot() { -#if 0 QMediaPlayer* player = new QMediaPlayer(); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); player->play(); - QString fileName = Snapshot::saveSnapshot(_glWidget->grabFrameBuffer()); + QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot()); AccountManager& accountManager = AccountManager::getInstance(); if (!accountManager.isLoggedIn()) { @@ -4516,7 +4521,6 @@ void Application::takeSnapshot() { _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); } _snapshotShareDialog->show(); -#endif } float Application::getRenderResolutionScale() const { @@ -4728,6 +4732,7 @@ void Application::updateDisplayMode() { bool first = true; foreach(auto displayPlugin, displayPlugins) { addDisplayPluginToMenu(displayPlugin, first); + // This must be a queued connection to avoid a deadlock QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, this, &Application::paintGL, Qt::QueuedConnection); diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index b0f02b1149..f780534bc9 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -9,7 +9,9 @@ // #include "NullDisplayPlugin.h" +#include #include + const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); const QString & NullDisplayPlugin::getName() const { @@ -33,3 +35,7 @@ void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm: } void NullDisplayPlugin::stop() {} + +QImage NullDisplayPlugin::getScreenshot() const { + return QImage(); +} diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index c4052f38dd..23e23e2c4e 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -21,7 +21,7 @@ public: virtual bool hasFocus() const override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; - + virtual QImage getScreenshot() const override; private: static const QString NAME; }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e18cc6c82f..22adeb8447 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -7,12 +7,15 @@ // #include "OpenGLDisplayPlugin.h" +#include + #include #include #include #include #include +#include #include #include @@ -23,7 +26,9 @@ class PresentThread : public QThread, public Dependency { using Mutex = std::mutex; + using Condition = std::condition_variable; using Lock = std::unique_lock; + friend class OpenGLDisplayPlugin; public: @@ -40,6 +45,25 @@ public: virtual void run() override { Q_ASSERT(_context); while (!_shutdown) { + if (_pendingMainThreadOperation) { + { + Lock lock(_mutex); + // Move the context to the main thread + _context->moveToThread(qApp->thread()); + _widgetContext->moveToThread(qApp->thread()); + _pendingMainThreadOperation = false; + // Release the main thread to do it's action + _condition.notify_one(); + } + + + { + // Main thread does it's thing while we wait on the lock to release + Lock lock(_mutex); + _condition.wait(lock, [&] { return _finishedMainThreadOperation; }); + } + } + // Check before lock if (_newPlugin != nullptr) { Lock lock(_mutex); @@ -69,17 +93,43 @@ public: } _context->doneCurrent(); + _widgetContext->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread()); } + void withMainThreadContext(std::function f) { + // Signal to the thread that there is work to be done on the main thread + Lock lock(_mutex); + _pendingMainThreadOperation = true; + _finishedMainThreadOperation = false; + _condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); + + _widgetContext->makeCurrent(); + f(); + _widgetContext->doneCurrent(); + + // restore control of the context to the presentation thread and signal + // the end of the operation + _widgetContext->moveToThread(this); + _context->moveToThread(this); + _finishedMainThreadOperation = true; + lock.unlock(); + _condition.notify_one(); + } + private: bool _shutdown { false }; Mutex _mutex; + // Used to allow the main thread to perform context operations + Condition _condition; + bool _pendingMainThreadOperation { false }; + bool _finishedMainThreadOperation { false }; QThread* _mainThread { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _activePlugin { nullptr }; QOpenGLContext* _context { nullptr }; + QGLContext* _widgetContext { nullptr }; }; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { @@ -114,14 +164,16 @@ void OpenGLDisplayPlugin::activate() { if (!presentThread) { DependencyManager::set(); presentThread = DependencyManager::get(); + presentThread->setObjectName("Presentation Thread"); + auto widget = _container->getPrimaryWidget(); - auto glContext = widget->context(); - auto context = glContext->contextHandle(); - glContext->moveToThread(presentThread.data()); - context->moveToThread(presentThread.data()); // Move the OpenGL context to the present thread - presentThread->_context = context; + // Extra code because of the widget 'wrapper' context + presentThread->_widgetContext = widget->context(); + presentThread->_widgetContext->moveToThread(presentThread.data()); + presentThread->_context = presentThread->_widgetContext->contextHandle(); + presentThread->_context->moveToThread(presentThread.data()); // Start execution presentThread->start(); @@ -325,3 +377,18 @@ void OpenGLDisplayPlugin::swapBuffers() { static auto widget = _container->getPrimaryWidget(); widget->swapBuffers(); } + +void OpenGLDisplayPlugin::withMainThreadContext(std::function f) const { + static auto presentThread = DependencyManager::get(); + presentThread->withMainThreadContext(f); + _container->makeRenderingContextCurrent(); +} + +QImage OpenGLDisplayPlugin::getScreenshot() const { + QImage result; + withMainThreadContext([&] { + static auto widget = _container->getPrimaryWidget(); + result = widget->grabFrameBuffer(); + }); + return result; +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 4426bfd5ef..edbe7db006 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -31,17 +31,20 @@ public: virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; virtual float presentRate() override; - virtual glm::uvec2 getRecommendedRenderSize() const { + virtual glm::uvec2 getRecommendedRenderSize() const override { return getSurfacePixels(); } - virtual glm::uvec2 getRecommendedUiSize() const { + virtual glm::uvec2 getRecommendedUiSize() const override { return getSurfaceSize(); } + virtual QImage getScreenshot() const override; + protected: friend class PresentThread; + virtual glm::uvec2 getSurfaceSize() const = 0; virtual glm::uvec2 getSurfacePixels() const = 0; @@ -53,6 +56,9 @@ protected: virtual void customizeContext(); virtual void uncustomizeContext(); virtual void cleanupForSceneTexture(uint32_t sceneTexture); + void withMainThreadContext(std::function f) const; + + void present(); void updateTextures(); void updateFramerate(); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 928b72970b..83afbc9402 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -14,6 +14,7 @@ #include #include +class QImage; #include #include @@ -96,6 +97,9 @@ public: return baseProjection; } + // Fetch the most recently displayed image as a QImage + virtual QImage getScreenshot() const = 0; + // HMD specific methods // TODO move these into another class? virtual glm::mat4 getEyeToHeadTransform(Eye eye) const { From 7262a10e62cf181e4d36d14d95349545b19c0d4b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 15:39:09 -0800 Subject: [PATCH 153/165] Refactoring present thread / GL base plugin for saner context management --- .../src/display-plugins/DisplayPlugin.cpp | 22 +++--- .../display-plugins/OpenGLDisplayPlugin.cpp | 74 +++++++------------ .../src/display-plugins/OpenGLDisplayPlugin.h | 2 - .../stereo/InterleavedStereoDisplayPlugin.cpp | 6 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 2 - plugins/oculus/src/OculusDisplayPlugin.cpp | 5 -- 6 files changed, 42 insertions(+), 69 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 85e832abdd..6c34612e8c 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -26,17 +26,17 @@ DisplayPluginList getDisplayPlugins() { DisplayPlugin* PLUGIN_POOL[] = { new Basic2DWindowOpenGLDisplayPlugin(), new NullDisplayPlugin(), -//#ifdef DEBUG -//#endif -// -// // Stereo modes -// -// // SBS left/right -// new SideBySideStereoDisplayPlugin(), -// // Interleaved left/right -// new InterleavedStereoDisplayPlugin(), -// -// // HMDs +#ifdef DEBUG +#endif + + // Stereo modes + + // SBS left/right + new SideBySideStereoDisplayPlugin(), + // Interleaved left/right + new InterleavedStereoDisplayPlugin(), + + // HMDs //#ifdef Q_OS_WIN // // SteamVR SDK // new OpenVrDisplayPlugin(), diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 22adeb8447..45e6daef31 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -28,8 +28,6 @@ class PresentThread : public QThread, public Dependency { using Mutex = std::mutex; using Condition = std::condition_variable; using Lock = std::unique_lock; - - friend class OpenGLDisplayPlugin; public: ~PresentThread() { @@ -42,6 +40,14 @@ public: _newPlugin = plugin; } + void setContext(QGLContext * context) { + // Move the OpenGL context to the present thread + // Extra code because of the widget 'wrapper' context + _context = context; + _context->moveToThread(this); + _context->contextHandle()->moveToThread(this); + } + virtual void run() override { Q_ASSERT(_context); while (!_shutdown) { @@ -50,7 +56,7 @@ public: Lock lock(_mutex); // Move the context to the main thread _context->moveToThread(qApp->thread()); - _widgetContext->moveToThread(qApp->thread()); + _context->contextHandle()->moveToThread(qApp->thread()); _pendingMainThreadOperation = false; // Release the main thread to do it's action _condition.notify_one(); @@ -67,6 +73,7 @@ public: // Check before lock if (_newPlugin != nullptr) { Lock lock(_mutex); + _context->makeCurrent(); // Check if we have a new plugin to activate if (_newPlugin != nullptr) { // Deactivate the old plugin @@ -77,8 +84,8 @@ public: _newPlugin->customizeContext(); _activePlugin = _newPlugin; _newPlugin = nullptr; - _context->doneCurrent(); } + _context->doneCurrent(); lock.unlock(); } @@ -89,12 +96,14 @@ public: } // take the latest texture and present it + _context->makeCurrent(); _activePlugin->present(); - + _context->doneCurrent(); } + _context->doneCurrent(); - _widgetContext->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread()); + _context->contextHandle()->moveToThread(qApp->thread()); } void withMainThreadContext(std::function f) { @@ -104,14 +113,16 @@ public: _finishedMainThreadOperation = false; _condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); - _widgetContext->makeCurrent(); + _context->makeCurrent(); f(); - _widgetContext->doneCurrent(); + _context->doneCurrent(); + + // Move the context back to the presentation thread + _context->moveToThread(this); + _context->contextHandle()->moveToThread(this); // restore control of the context to the presentation thread and signal // the end of the operation - _widgetContext->moveToThread(this); - _context->moveToThread(this); _finishedMainThreadOperation = true; lock.unlock(); _condition.notify_one(); @@ -119,6 +130,9 @@ public: private: + void makeCurrent(); + void doneCurrent(); + bool _shutdown { false }; Mutex _mutex; // Used to allow the main thread to perform context operations @@ -128,8 +142,7 @@ private: QThread* _mainThread { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _activePlugin { nullptr }; - QOpenGLContext* _context { nullptr }; - QGLContext* _widgetContext { nullptr }; + QGLContext* _context { nullptr }; }; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { @@ -165,16 +178,8 @@ void OpenGLDisplayPlugin::activate() { DependencyManager::set(); presentThread = DependencyManager::get(); presentThread->setObjectName("Presentation Thread"); - auto widget = _container->getPrimaryWidget(); - - // Move the OpenGL context to the present thread - // Extra code because of the widget 'wrapper' context - presentThread->_widgetContext = widget->context(); - presentThread->_widgetContext->moveToThread(presentThread.data()); - presentThread->_context = presentThread->_widgetContext->contextHandle(); - presentThread->_context->moveToThread(presentThread.data()); - + presentThread->setContext(widget->context()); // Start execution presentThread->start(); } @@ -196,9 +201,6 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - bool makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); - // TODO: write the proper code for linux #if defined(Q_OS_WIN) _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); @@ -213,15 +215,11 @@ void OpenGLDisplayPlugin::customizeContext() { _program = loadDefaultShader(); _plane = loadPlane(_program); - - doneCurrent(); } void OpenGLDisplayPlugin::uncustomizeContext() { - makeCurrent(); _program.reset(); _plane.reset(); - doneCurrent(); } // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the @@ -310,19 +308,11 @@ void OpenGLDisplayPlugin::internalPresent() { } void OpenGLDisplayPlugin::present() { - auto makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); - if (!makeCurrentResult) { - qDebug() << "Failed to make current"; - return; - } - updateTextures(); if (_currentSceneTexture) { internalPresent(); updateFramerate(); } - doneCurrent(); } float OpenGLDisplayPlugin::presentRate() { @@ -360,18 +350,6 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() { return true; #endif } -bool OpenGLDisplayPlugin::makeCurrent() { - static auto widget = _container->getPrimaryWidget(); - widget->makeCurrent(); - auto result = widget->context()->contextHandle() == QOpenGLContext::currentContext(); - Q_ASSERT(result); - return result; -} - -void OpenGLDisplayPlugin::doneCurrent() { - static auto widget = _container->getPrimaryWidget(); - widget->doneCurrent(); -} void OpenGLDisplayPlugin::swapBuffers() { static auto widget = _container->getPrimaryWidget(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index edbe7db006..809a52ef7f 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -63,8 +63,6 @@ protected: void updateTextures(); void updateFramerate(); void drawUnitQuad(); - bool makeCurrent(); - void doneCurrent(); void swapBuffers(); // Plugin specific functionality to composite the scene and overlay and present the result virtual void internalPresent(); diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 4332c53d81..ffaf005533 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -67,5 +67,9 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const { } void InterleavedStereoDisplayPlugin::internalPresent() { - // FIXME + using namespace oglplus; + _program->Bind(); + auto sceneSize = getRecommendedRenderSize(); + Uniform(*_program, "textureSize").SetValue(sceneSize); + WindowOpenGLDisplayPlugin::internalPresent(); } diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 805ad75e95..b6690ea76e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -55,11 +55,9 @@ bool OculusBaseDisplayPlugin::isSupported() const { // DLL based display plugins MUST initialize GLEW inside the DLL code. void OculusBaseDisplayPlugin::customizeContext() { - makeCurrent(); glewExperimental = true; GLenum err = glewInit(); glGetError(); - doneCurrent(); WindowOpenGLDisplayPlugin::customizeContext(); } diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index bcb39f5100..21c318677e 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -154,8 +154,6 @@ void OculusDisplayPlugin::activate() { void OculusDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); - bool makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); #if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo->Init(getRecommendedRenderSize()); @@ -169,14 +167,11 @@ void OculusDisplayPlugin::customizeContext() { enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); - doneCurrent(); } void OculusDisplayPlugin::uncustomizeContext() { #if (OVR_MAJOR_VERSION >= 6) - makeCurrent(); _sceneFbo.reset(); - doneCurrent(); #endif OculusBaseDisplayPlugin::uncustomizeContext(); } From 60aa93c38c6633b3d604f0e800cad33cd75f4048 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 16:42:17 -0800 Subject: [PATCH 154/165] Fixing menu items in display plugins --- interface/src/Application.cpp | 9 +-- interface/src/Application.h | 2 - interface/src/PluginContainerProxy.cpp | 66 ++++++++-------- interface/src/PluginContainerProxy.h | 14 +++- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 79 +++++++++---------- .../Basic2DWindowOpenGLDisplayPlugin.h | 3 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 16 ++-- .../src/display-plugins/OpenGLDisplayPlugin.h | 3 +- .../stereo/InterleavedStereoDisplayPlugin.h | 1 - .../stereo/StereoDisplayPlugin.cpp | 2 +- .../src/input-plugins/SixenseManager.cpp | 2 +- .../input-plugins/ViveControllerManager.cpp | 2 +- libraries/plugins/src/plugins/Forward.h | 5 ++ .../plugins/src/plugins/PluginContainer.h | 8 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 3 +- plugins/oculus/src/OculusDisplayPlugin.cpp | 2 +- 16 files changed, 120 insertions(+), 97 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c58156d2a..bbc36e8623 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4777,19 +4777,18 @@ void Application::updateDisplayMode() { return; } - if (!_currentDisplayPluginActions.isEmpty()) { + + if (!_pluginContainer->currentDisplayActions().isEmpty()) { auto menu = Menu::getInstance(); - foreach(auto itemInfo, _currentDisplayPluginActions) { + foreach(auto itemInfo, _pluginContainer->currentDisplayActions()) { menu->removeMenuItem(itemInfo.first, itemInfo.second); } - _currentDisplayPluginActions.clear(); + _pluginContainer->currentDisplayActions().clear(); } if (newDisplayPlugin) { _offscreenContext->makeCurrent(); - _activatingDisplayPlugin = true; newDisplayPlugin->activate(); - _activatingDisplayPlugin = false; _offscreenContext->makeCurrent(); offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); _offscreenContext->makeCurrent(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 1af252de95..d12d29cde8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -427,8 +427,6 @@ private: InputPluginList _activeInputPlugins; bool _activatingDisplayPlugin { false }; - QVector> _currentDisplayPluginActions; - QVector> _currentInputPluginActions; QMap _lockedFramebufferMap; MainWindow* _window; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 8774eecd77..abb52380d0 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -36,37 +36,31 @@ void PluginContainerProxy::removeMenu(const QString& menuName) { Menu::getInstance()->removeMenu(menuName); } -extern bool _activatingDisplayPlugin; -extern QVector> _currentDisplayPluginActions; -extern QVector> _currentInputPluginActions; -std::map _exclusiveGroups; - -QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - //auto menu = Menu::getInstance(); - //MenuWrapper* parentItem = menu->getMenu(path); - //QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - //if (!groupName.isEmpty()) { - // QActionGroup* group{ nullptr }; - // if (!_exclusiveGroups.count(groupName)) { - // group = _exclusiveGroups[groupName] = new QActionGroup(menu); - // group->setExclusive(true); - // } else { - // group = _exclusiveGroups[groupName]; - // } - // group->addAction(action); - //} - //connect(action, &QAction::triggered, [=] { - // onClicked(action->isChecked()); - //}); - //action->setCheckable(checkable); - //action->setChecked(checked); - //if (_activatingDisplayPlugin) { - // _currentDisplayPluginActions.push_back({ path, name }); - //} else { - // _currentInputPluginActions.push_back({ path, name }); - //} - //return action; - return nullptr; +QAction* PluginContainerProxy::addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { + auto menu = Menu::getInstance(); + MenuWrapper* parentItem = menu->getMenu(path); + QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + if (!groupName.isEmpty()) { + QActionGroup* group{ nullptr }; + if (!_exclusiveGroups.count(groupName)) { + group = _exclusiveGroups[groupName] = new QActionGroup(menu); + group->setExclusive(true); + } else { + group = _exclusiveGroups[groupName]; + } + group->addAction(action); + } + connect(action, &QAction::triggered, [=] { + onClicked(action->isChecked()); + }); + action->setCheckable(checkable); + action->setChecked(checked); + if (type == PluginType::DISPLAY_PLUGIN) { + _currentDisplayPluginActions.push_back({ path, name }); + } else { + _currentInputPluginActions.push_back({ path, name }); + } + return action; } void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { @@ -188,5 +182,13 @@ void PluginContainerProxy::releaseSceneTexture(uint32_t texture) { } void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { - + // FIXME implement present thread compositing +} + +QVector>& PluginContainerProxy::currentDisplayActions() { + return _currentDisplayPluginActions; +} + +QVector>& PluginContainerProxy::currentInputActions() { + return _currentInputPluginActions; } diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 5cc1cc8583..cd15510885 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -2,19 +2,23 @@ #ifndef hifi_PluginContainerProxy_h #define hifi_PluginContainerProxy_h -#include -#include +#include +#include #include #include +class QActionGroup; + class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); virtual ~PluginContainerProxy(); + virtual QVector>& currentDisplayActions() override; + virtual QVector>& currentInputActions() override; virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; + virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override; virtual bool isOptionChecked(const QString& name) override; virtual void setIsOptionChecked(const QString& path, bool checked) override; @@ -32,8 +36,12 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual const DisplayPlugin* getActiveDisplayPlugin() const override; QRect _savedGeometry{ 10, 120, 800, 600 }; + std::map _exclusiveGroups; + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; friend class Application; + }; #endif \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 36216f8912..6c450e0735 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -31,60 +31,59 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { } void Basic2DWindowOpenGLDisplayPlugin::activate() { - //_framerateActions.clear(); - //_container->addMenuItem(MENU_PATH(), FULLSCREEN, - // [this](bool clicked) { - // if (clicked) { - // _container->setFullscreen(getFullscreenTarget()); - // } else { - // _container->unsetFullscreen(); - // } - // }, true, false); - //_container->addMenu(FRAMERATE); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, - // [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_60, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_50, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_40, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_30, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - WindowOpenGLDisplayPlugin::activate(); - //// Vsync detection happens in the parent class activate, so we need to check after that - //if (_vsyncSupported) { - // _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - //} else { - // _vsyncAction = nullptr; - //} + _framerateActions.clear(); + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN, + [this](bool clicked) { + if (clicked) { + _container->setFullscreen(getFullscreenTarget()); + } else { + _container->unsetFullscreen(); + } + }, true, false); + _container->addMenu(FRAMERATE); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_UNLIMITED, + [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_60, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_50, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_40, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_30, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + + // Vsync detection happens in the parent class activate, so we need to check after that + if (_vsyncSupported) { + _vsyncAction = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); + } else { + _vsyncAction = nullptr; + } updateFramerate(); } -void Basic2DWindowOpenGLDisplayPlugin::deactivate() { - WindowOpenGLDisplayPlugin::deactivate(); -} - void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { if (_vsyncAction) { _wantVsync = _vsyncAction->isChecked(); - //bool vsyncEnabed = isVsyncEnabled(); - //if (vsyncEnabed ^ wantVsync) { - // enableVsync(wantVsync); - //} } WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } +void Basic2DWindowOpenGLDisplayPlugin::internalPresent() { + if (_wantVsync != isVsyncEnabled()) { + enableVsync(_wantVsync); + } + WindowOpenGLDisplayPlugin::internalPresent(); +} + int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 80aebf9efc..36a1a73b94 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -19,10 +19,11 @@ public: virtual const QString & getName() const override; virtual void activate() override; - virtual void deactivate() override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void internalPresent() override; + virtual bool isThrottled() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 45e6daef31..12aa37cd56 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -145,6 +145,8 @@ private: QGLContext* _context { nullptr }; }; +bool OpenGLDisplayPlugin::_vsyncSupported = false; + OpenGLDisplayPlugin::OpenGLDisplayPlugin() { _sceneTextureEscrow.setRecycler([this](GLuint texture){ cleanupForSceneTexture(texture); @@ -175,10 +177,18 @@ void OpenGLDisplayPlugin::activate() { // Start the present thread if necessary auto presentThread = DependencyManager::get(); if (!presentThread) { + auto widget = _container->getPrimaryWidget(); + + // TODO: write the proper code for linux +#if defined(Q_OS_WIN) + widget->makeCurrent(); + _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); + widget->doneCurrent(); +#endif + DependencyManager::set(); presentThread = DependencyManager::get(); presentThread->setObjectName("Presentation Thread"); - auto widget = _container->getPrimaryWidget(); presentThread->setContext(widget->context()); // Start execution presentThread->start(); @@ -201,10 +211,6 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - // TODO: write the proper code for linux -#if defined(Q_OS_WIN) - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); -#endif enableVsync(); using namespace oglplus; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 809a52ef7f..747d8b810b 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -70,7 +70,6 @@ protected: mutable QTimer _timer; ProgramPtr _program; ShapeWrapperPtr _plane; - bool _vsyncSupported { false }; Mutex _mutex; SimpleMovingAverage _usecsPerFrame { 10 }; @@ -81,6 +80,8 @@ protected: GLTextureEscrow _overlayTextureEscrow; GLTextureEscrow _sceneTextureEscrow; + + static bool _vsyncSupported; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index b9b3566349..7116363e44 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -19,7 +19,6 @@ public: virtual void customizeContext() override; virtual glm::uvec2 getRecommendedRenderSize() const override; - void internalPresent() override; private: diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index f7e71313df..a691f375eb 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -74,7 +74,7 @@ void StereoDisplayPlugin::activate() { if (screen == qApp->primaryScreen()) { checked = true; } - auto action = _container->addMenuItem(MENU_PATH(), name, + auto action = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), name, [this](bool clicked) { updateScreen(); }, true, checked, "Screens"); _screenActions[i] = action; } diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 18fdc9ddad..5dd0248224 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -68,7 +68,7 @@ void SixenseManager::activate() { #ifdef HAVE_SIXENSE _container->addMenu(MENU_PATH); - _container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH, + _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, TOGGLE_SMOOTH, [this] (bool clicked) { setSixenseFilter(clicked); }, true, true); diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index ec0c35cc96..b315a7a3d9 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -60,7 +60,7 @@ void ViveControllerManager::activate() { InputPlugin::activate(); #ifdef Q_OS_WIN _container->addMenu(MENU_PATH); - _container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS, + _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS, [this] (bool clicked) { this->setRenderControllers(clicked); }, true, true); diff --git a/libraries/plugins/src/plugins/Forward.h b/libraries/plugins/src/plugins/Forward.h index 8d8259ba4f..036b42f7d7 100644 --- a/libraries/plugins/src/plugins/Forward.h +++ b/libraries/plugins/src/plugins/Forward.h @@ -10,6 +10,11 @@ #include #include +enum class PluginType { + DISPLAY_PLUGIN, + INPUT_PLUGIN, +}; + class DisplayPlugin; class InputPlugin; class Plugin; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 25c2bcb11f..337ffd3c57 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -10,6 +10,10 @@ #include #include #include +#include +#include + +#include "Forward.h" class QAction; class QGLWidget; @@ -24,9 +28,11 @@ public: static PluginContainer& getInstance(); PluginContainer(); virtual ~PluginContainer(); + virtual QVector>& currentDisplayActions() = 0; + virtual QVector>& currentInputActions() = 0; virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; + virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0; virtual bool isOptionChecked(const QString& name) = 0; virtual void setIsOptionChecked(const QString& path, bool checked) = 0; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index b6690ea76e..7c057c7152 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -68,6 +68,7 @@ void OculusBaseDisplayPlugin::deinit() { } void OculusBaseDisplayPlugin::activate() { + WindowOpenGLDisplayPlugin::activate(); #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { qFatal("Could not init OVR"); @@ -134,8 +135,6 @@ void OculusBaseDisplayPlugin::activate() { qFatal("Could not attach to sensor device"); } #endif - - WindowOpenGLDisplayPlugin::activate(); } void OculusBaseDisplayPlugin::deactivate() { diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 21c318677e..8846b8a6a6 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -144,7 +144,7 @@ static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; void OculusDisplayPlugin::activate() { - _container->addMenuItem(MENU_PATH(), MONO_PREVIEW, + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW, [this](bool clicked) { _monoPreview = clicked; }, true, true); From c4514743d16440ee17565af885842ad83eb1f2d9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 17:07:04 -0800 Subject: [PATCH 155/165] Fixing tests, moving some plugin container stuff to base class --- interface/src/PluginContainerProxy.cpp | 7 ------- interface/src/PluginContainerProxy.h | 4 ---- libraries/plugins/src/plugins/PluginContainer.h | 15 +++++++++++++-- tests/controllers/src/main.cpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index abb52380d0..aff36fb881 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -185,10 +185,3 @@ void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { // FIXME implement present thread compositing } -QVector>& PluginContainerProxy::currentDisplayActions() { - return _currentDisplayPluginActions; -} - -QVector>& PluginContainerProxy::currentInputActions() { - return _currentInputPluginActions; -} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index cd15510885..5d974f0a0c 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -14,8 +14,6 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); virtual ~PluginContainerProxy(); - virtual QVector>& currentDisplayActions() override; - virtual QVector>& currentInputActions() override; virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; @@ -37,8 +35,6 @@ class PluginContainerProxy : public QObject, PluginContainer { QRect _savedGeometry{ 10, 120, 800, 600 }; std::map _exclusiveGroups; - QVector> _currentDisplayPluginActions; - QVector> _currentInputPluginActions; friend class Application; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 337ffd3c57..6732bc02ba 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -28,8 +28,6 @@ public: static PluginContainer& getInstance(); PluginContainer(); virtual ~PluginContainer(); - virtual QVector>& currentDisplayActions() = 0; - virtual QVector>& currentInputActions() = 0; virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; @@ -48,4 +46,17 @@ public: virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; + + QVector>& currentDisplayActions() { + return _currentDisplayPluginActions; + } + + QVector>& currentInputActions() { + return _currentInputPluginActions; + } + +protected: + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; + }; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index c5c038fde3..8514d33d2e 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -83,7 +83,7 @@ public: virtual ~PluginContainerProxy() {} virtual void addMenu(const QString& menuName) override {} virtual void removeMenu(const QString& menuName) override {} - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; } + virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; } virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {} virtual bool isOptionChecked(const QString& name) override { return false; } virtual void setIsOptionChecked(const QString& path, bool checked) override {} From 90ef7c6bf763d77be56ced44f4325a22ef673a93 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 23:29:56 -0800 Subject: [PATCH 156/165] Disabling 0.5 Oculus plugin (Mac / Linux) for now --- interface/src/PluginContainerProxy.cpp | 1 - plugins/oculusLegacy/CMakeLists.txt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index aff36fb881..aae94162ad 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index bf9d22410d..44cee83a7d 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -6,7 +6,8 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -if (NOT WIN32) +#if (NOT WIN32) +if (FALSE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() From 528a17422d4d32b29915191b71417375272d9e90 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 10:33:10 -0800 Subject: [PATCH 157/165] Last of the OpenGL warnings on OS X --- .../src/QOpenGLContextWrapper.cpp | 40 +++++++++++++++++++ .../render-utils/src/QOpenGLContextWrapper.h | 33 +++++++++++++++ .../src/QOpenGLDebugLoggerWrapper.cpp | 24 +++++++++++ .../src/QOpenGLDebugLoggerWrapper.h | 19 +++++++++ tests/gpu-test/src/main.cpp | 24 ++++------- tests/render-utils/src/main.cpp | 25 ++++-------- tests/shaders/src/main.cpp | 25 +++++------- 7 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 libraries/render-utils/src/QOpenGLContextWrapper.cpp create mode 100644 libraries/render-utils/src/QOpenGLContextWrapper.h create mode 100644 libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp create mode 100644 libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.cpp b/libraries/render-utils/src/QOpenGLContextWrapper.cpp new file mode 100644 index 0000000000..64233ea413 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLContextWrapper.cpp @@ -0,0 +1,40 @@ +// +// QOpenGLContextWrapper.cpp +// +// +// Created by Clement on 12/4/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QOpenGLContextWrapper.h" + +#include + + +QOpenGLContextWrapper::QOpenGLContextWrapper() : + _context(new QOpenGLContext) +{ +} + +void QOpenGLContextWrapper::setFormat(const QSurfaceFormat& format) { + _context->setFormat(format); +} + +bool QOpenGLContextWrapper::create() { + return _context->create(); +} + +void QOpenGLContextWrapper::swapBuffers(QSurface* surface) { + _context->swapBuffers(surface); +} + +bool QOpenGLContextWrapper::makeCurrent(QSurface* surface) { + return _context->makeCurrent(surface); +} + +void QOpenGLContextWrapper::doneCurrent() { + _context->doneCurrent(); +} \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.h b/libraries/render-utils/src/QOpenGLContextWrapper.h new file mode 100644 index 0000000000..6c50d5f438 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLContextWrapper.h @@ -0,0 +1,33 @@ +// +// QOpenGLContextWrapper.h +// +// +// Created by Clement on 12/4/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_QOpenGLContextWrapper_h +#define hifi_QOpenGLContextWrapper_h + +class QOpenGLContext; +class QSurface; +class QSurfaceFormat; + +class QOpenGLContextWrapper { +public: + QOpenGLContextWrapper(); + + void setFormat(const QSurfaceFormat& format); + bool create(); + void swapBuffers(QSurface* surface); + bool makeCurrent(QSurface* surface); + void doneCurrent(); + +private: + QOpenGLContext* _context { nullptr }; +}; + +#endif // hifi_QOpenGLContextWrapper_h \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp new file mode 100644 index 0000000000..bd185034f4 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp @@ -0,0 +1,24 @@ +// +// QOpenGLDebugLoggerWrapper.cpp +// +// +// Created by Clement on 12/4/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QOpenGLDebugLoggerWrapper.h" + +#include +#include + +void setupDebugLogger(QObject* window) { + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); +} \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h new file mode 100644 index 0000000000..e2b1c5d9d4 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h @@ -0,0 +1,19 @@ +// +// QOpenGLDebugLoggerWrapper.h +// +// +// Created by Clement on 12/4/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_QOpenGLDebugLoggerWrapper_h +#define hifi_QOpenGLDebugLoggerWrapper_h + +class QObject; + +void setupDebugLogger(QObject* window); + +#endif // hifi_QOpenGLDebugLoggerWrapper_h \ No newline at end of file diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index 80c2dbf8e9..fbfb49aace 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -33,9 +33,8 @@ #include #include -// Must come after GL headers -#include -#include +#include +#include #include #include @@ -118,7 +117,7 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat(); class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _qGlContext{ nullptr }; + QOpenGLContextWrapper _qGlContext; QSize _size; gpu::ContextPointer _context; @@ -151,19 +150,12 @@ public: setFormat(format); - _qGlContext = new QOpenGLContext; - _qGlContext->setFormat(format); - _qGlContext->create(); + _qGlContext.setFormat(format); + _qGlContext.create(); show(); makeCurrent(); - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message){ - qDebug() << message; - }); - logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - + setupDebugLogger(this); gpu::Context::init(); _context = std::make_shared(); @@ -371,7 +363,7 @@ public: geometryCache->renderWireCube(batch); _context->render(batch); - _qGlContext->swapBuffers(this); + _qGlContext.swapBuffers(this); fps.increment(); if (fps.elapsed() >= 0.5f) { @@ -381,7 +373,7 @@ public: } void makeCurrent() { - _qGlContext->makeCurrent(this); + _qGlContext.makeCurrent(this); } protected: diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 0fa261db8d..43778c5c56 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -14,8 +14,8 @@ #include -#include -#include +#include +#include #include #include @@ -77,7 +77,7 @@ const QString& getQmlDir() { class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper _context; QSize _size; //TextRenderer* _textRenderer[4]; RateCounter fps; @@ -104,9 +104,8 @@ public: setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); + _context.setFormat(format); + _context.create(); show(); makeCurrent(); @@ -114,15 +113,7 @@ public: gpu::Context::init(); - { - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - } + setupDebugLogger(this); qDebug() << (const char*)glGetString(GL_VERSION); //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); @@ -147,7 +138,7 @@ public: void draw(); void makeCurrent() { - _context->makeCurrent(this); + _context.makeCurrent(this); } protected: @@ -185,7 +176,7 @@ void QTestWindow::draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - _context->swapBuffers(this); + _context.swapBuffers(this); glFinish(); fps.increment(); diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index f65cd9b5aa..658bc9c236 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -10,8 +10,6 @@ #include -#include - #include #include #include @@ -22,6 +20,9 @@ #include +#include +#include + #include "../model/Skybox_vert.h" #include "../model/Skybox_frag.h" @@ -120,7 +121,7 @@ // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper _context; protected: void renderText(); @@ -130,22 +131,14 @@ public: setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); + _context.setFormat(format); + _context.create(); show(); makeCurrent(); gpu::Context::init(); - { - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - } + setupDebugLogger(this); makeCurrent(); resize(QSize(800, 600)); } @@ -155,7 +148,7 @@ public: void draw(); void makeCurrent() { - _context->makeCurrent(this); + _context.makeCurrent(this); } }; @@ -248,7 +241,7 @@ void QTestWindow::draw() { testShaderBuild(polyvox_vert, polyvox_frag); }); - _context->swapBuffers(this); + _context.swapBuffers(this); } void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { From 42466728131c63fa6fee072f358466670264cb33 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 10:38:24 -0800 Subject: [PATCH 158/165] enable head-moving of distance grabbing --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index bcb76716d9..05de977bd8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -37,7 +37,7 @@ var BUMPER_ON_VALUE = 0.5; var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = false; // experimental head-controll of distantly held objects +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects var NO_INTERSECT_COLOR = { red: 10, From cb67f05103d66eb2234c50a1d8b2d01f696cece5 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 4 Dec 2015 10:47:27 -0800 Subject: [PATCH 159/165] Remove unimplemented menu items Developer->Avatar->Show Skeleton/Head Collision Shapes. --- interface/src/Menu.cpp | 2 -- interface/src/Menu.h | 2 -- interface/src/avatar/Avatar.cpp | 10 ---------- 3 files changed, 14 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d0c8b502c5..d48511d990 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -433,8 +433,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false, avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtTargets, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b51987479..8041d2533f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -239,10 +239,8 @@ namespace MenuOption { const QString ReloadContent = "Reload Content (Clears all caches)"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; const QString RenderFocusIndicator = "Show Eye Focus"; - const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; const QString RenderLookAtTargets = "Show Look-at Targets"; const QString RenderLookAtVectors = "Show Look-at Vectors"; - const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bf4ddadb62..cf812db383 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -463,16 +463,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } } - /* - // TODO: re-implement these when we have more detailed avatar collision shapes - bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); - if (renderSkeleton) { - } - bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); - if (renderHead && shouldRenderHead(renderArgs)) { - } - */ - bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) { PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes"); From ca84fcd7f414e5f8870df7079933e909f9a9cd77 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:01:18 -0800 Subject: [PATCH 160/165] parent the keepalive timer to the NL thread --- libraries/networking/src/NodeList.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 925c64c77a..5a39f0312c 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -40,7 +40,8 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned _nodeTypesOfInterest(), _domainHandler(this), _numNoReplyDomainCheckIns(0), - _assignmentServerSocket() + _assignmentServerSocket(), + _keepAlivePingTimer(this) { setCustomDeleter([](Dependency* dependency){ static_cast(dependency)->deleteLater(); From ea65ef964fbd1672803ab729d5eaffda9916b02f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 11:13:36 -0800 Subject: [PATCH 161/165] fix an AC race/crash --- libraries/shared/src/SpatiallyNestable.cpp | 51 +++++++++++++--------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a0280943de..0d7d2a7652 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -62,6 +62,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { // we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return nullptr; + } _parent = parentFinder->find(_parentID); parent = _parent.lock(); if (parent) { @@ -98,12 +101,14 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform positionTransform; @@ -119,12 +124,14 @@ glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, in glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform orientationTransform; @@ -139,12 +146,14 @@ glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform positionTransform; positionTransform.setTranslation(position); @@ -155,12 +164,14 @@ glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, in glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform orientationTransform; orientationTransform.setRotation(orientation); From 918342df5f1bd2e04d6e036d747f6d181f5e947d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:18:46 -0800 Subject: [PATCH 162/165] make sure the NodeList is reset on its own thread --- libraries/networking/src/DomainHandler.cpp | 2 +- libraries/networking/src/NodeList.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 681f971ef5..96a6c9c4a5 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -94,7 +94,7 @@ void DomainHandler::softReset() { clearSettings(); // cancel the failure timeout for any pending requests for settings - QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::AutoConnection); + QMetaObject::invokeMethod(&_settingsTimer, "stop"); } void DomainHandler::hardReset() { diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 925c64c77a..38c9d819e2 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -199,6 +199,11 @@ void NodeList::processICEPingPacket(QSharedPointer packet) { } void NodeList::reset() { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "reset"); + return; + } + LimitedNodeList::reset(); _numNoReplyDomainCheckIns = 0; From d5f79b84fca14cf41ead9471349ed0bc23e2a8ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:20:46 -0800 Subject: [PATCH 163/165] make the NodeList reset a blocking queued connection --- libraries/networking/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 38c9d819e2..87899d59a8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -200,7 +200,7 @@ void NodeList::processICEPingPacket(QSharedPointer packet) { void NodeList::reset() { if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "reset"); + QMetaObject::invokeMethod(this, "reset", Qt::BlockingQueuedConnection); return; } From 3bb1dedaf9990a71a55d052c12ad30e270f7a072 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 4 Dec 2015 11:41:23 -0800 Subject: [PATCH 164/165] fixed syntax error --- unpublishedScripts/hiddenEntityReset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 259cdd066c..ecbeec7a81 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1367,7 +1367,7 @@ resetMe: { resetMe: true }, - grabbableKey; { + grabbableKey: { invertSolidWhileHeld: true } From 11917ca501226493a83e26257d82725b0c3dc086 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Dec 2015 12:46:19 -0800 Subject: [PATCH 165/165] Fixing preview / vsync functionality --- interface/src/Application.cpp | 5 +++++ interface/src/PluginContainerProxy.cpp | 2 +- interface/src/PluginContainerProxy.h | 2 +- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 13 +++---------- .../src/display-plugins/OpenGLDisplayPlugin.h | 2 +- .../display-plugins/WindowOpenGLDisplayPlugin.cpp | 2 +- libraries/gl/src/gl/GLWidget.cpp | 15 +++++++++++++++ libraries/gl/src/gl/GLWidget.h | 6 +++++- libraries/plugins/src/plugins/PluginContainer.h | 4 ++-- tests/controllers/src/main.cpp | 2 +- 10 files changed, 35 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bbc36e8623..9e98b51442 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -620,6 +620,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); + _glWidget->makeCurrent(); + _glWidget->initializeGL(); _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); @@ -1194,6 +1196,9 @@ void Application::paintGL() { QSize size = getDeviceSize(); renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); + gpu::FramebufferPointer overlayFramebuffer = _applicationOverlay.getOverlayFramebuffer(); + + } { diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index aae94162ad..048f079653 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -150,7 +150,7 @@ void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); } -QGLWidget* PluginContainerProxy::getPrimaryWidget() { +GLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 5d974f0a0c..3adc696ba9 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -27,7 +27,7 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual bool makeRenderingContextCurrent() override; virtual void releaseSceneTexture(uint32_t texture) override; virtual void releaseOverlayTexture(uint32_t texture) override; - virtual QGLWidget* getPrimaryWidget() override; + virtual GLWidget* getPrimaryWidget() override; virtual QWindow* getPrimaryWindow() override; virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 12aa37cd56..cec84c74d4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -145,8 +146,6 @@ private: QGLContext* _context { nullptr }; }; -bool OpenGLDisplayPlugin::_vsyncSupported = false; - OpenGLDisplayPlugin::OpenGLDisplayPlugin() { _sceneTextureEscrow.setRecycler([this](GLuint texture){ cleanupForSceneTexture(texture); @@ -172,19 +171,14 @@ void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) { void OpenGLDisplayPlugin::activate() { - _timer.start(2); + _timer.start(1); + _vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported(); // Start the present thread if necessary auto presentThread = DependencyManager::get(); if (!presentThread) { auto widget = _container->getPrimaryWidget(); - // TODO: write the proper code for linux -#if defined(Q_OS_WIN) - widget->makeCurrent(); - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); - widget->doneCurrent(); -#endif DependencyManager::set(); presentThread = DependencyManager::get(); @@ -195,7 +189,6 @@ void OpenGLDisplayPlugin::activate() { } presentThread->setNewDisplayPlugin(this); DisplayPlugin::activate(); - emit requestRender(); } void OpenGLDisplayPlugin::stop() { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 747d8b810b..ef78374994 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -81,7 +81,7 @@ protected: GLTextureEscrow _overlayTextureEscrow; GLTextureEscrow _sceneTextureEscrow; - static bool _vsyncSupported; + bool _vsyncSupported { false }; }; diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index b215b19b15..c1922599a5 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -7,7 +7,7 @@ // #include "WindowOpenGLDisplayPlugin.h" -#include +#include #include "plugins/PluginContainer.h" diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index 310675c01f..c67dec1e51 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -7,6 +7,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include "GLWidget.h" @@ -16,11 +17,14 @@ #include #include +#include #include #include + #include "GLHelpers.h" + GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) { #ifdef Q_OS_LINUX // Cause GLWidget::eventFilter to be called. @@ -42,6 +46,12 @@ void GLWidget::initializeGL() { setAcceptDrops(true); // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. setAutoBufferSwap(false); + + // TODO: write the proper code for linux + makeCurrent(); +#if defined(Q_OS_WIN) + _vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");; +#endif } void GLWidget::paintEvent(QPaintEvent* event) { @@ -112,3 +122,8 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) { } return false; } + +bool GLWidget::isVsyncSupported() const { + return _vsyncSupported; +} + diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index df4a73ac50..5b391aa6cd 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -21,15 +21,19 @@ public: int getDeviceWidth() const; int getDeviceHeight() const; QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } + bool isVsyncSupported() const; + virtual void initializeGL() override; protected: - virtual void initializeGL() override; virtual bool event(QEvent* event) override; virtual void paintEvent(QPaintEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; private slots: virtual bool eventFilter(QObject*, QEvent* event) override; + +private: + bool _vsyncSupported { false }; }; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 6732bc02ba..19859fd98b 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -16,7 +16,7 @@ #include "Forward.h" class QAction; -class QGLWidget; +class GLWidget; class QScreen; class QOpenGLContext; class QWindow; @@ -41,7 +41,7 @@ public: virtual bool makeRenderingContextCurrent() = 0; virtual void releaseSceneTexture(uint32_t texture) = 0; virtual void releaseOverlayTexture(uint32_t texture) = 0; - virtual QGLWidget* getPrimaryWidget() = 0; + virtual GLWidget* getPrimaryWidget() = 0; virtual QWindow* getPrimaryWindow() = 0; virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 8514d33d2e..fe49c2b385 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -94,7 +94,7 @@ public: virtual bool makeRenderingContextCurrent() override { return true; } virtual void releaseSceneTexture(uint32_t texture) override {} virtual void releaseOverlayTexture(uint32_t texture) override {} - virtual QGLWidget* getPrimaryWidget() override { return nullptr; } + virtual GLWidget* getPrimaryWidget() override { return nullptr; } virtual QWindow* getPrimaryWindow() override { return nullptr; } virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } virtual bool isForeground() override { return true; }