diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d5eb12c36d..5001e4419d 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -38,7 +38,7 @@ static const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; static const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance) -static const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f; +static const float DEFAULT_NOISE_MUTING_THRESHOLD = 1.0f; static const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; static const QString AUDIO_ENV_GROUP_KEY = "audio_env"; static const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; @@ -69,7 +69,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); packetReceiver.registerListener(PacketType::PerAvatarGainSet, this, "handlePerAvatarGainSetDataPacket"); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 0084e51239..84fccdafe7 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1089,9 +1089,9 @@ { "name": "noise_muting_threshold", "label": "Noise Muting Threshold", - "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)", - "placeholder": "0.003", - "default": "0.003", + "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute). 0.003 is a typical setting to mute loud people.", + "placeholder": "1.0", + "default": "1.0", "advanced": false }, { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6061812d2a..7ab1e7e8bd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -85,19 +85,6 @@ namespace render { } } -static uint64_t timeProcessingJoints = 0; -static int32_t numJointsProcessed = 0; - -float Avatar::getNumJointsProcessedPerSecond() { - float rate = 0.0f; - if (timeProcessingJoints > 0) { - rate = (float)(numJointsProcessed * USECS_PER_SECOND) / (float)timeProcessingJoints; - } - timeProcessingJoints = 0; - numJointsProcessed = 0; - return rate; -} - Avatar::Avatar(RigPointer rig) : AvatarData(), _skeletonOffset(0.0f), @@ -127,6 +114,7 @@ Avatar::Avatar(RigPointer rig) : _nameRectGeometryID = geometryCache->allocateID(); _leftPointerGeometryID = geometryCache->allocateID(); _rightPointerGeometryID = geometryCache->allocateID(); + _lastRenderUpdateTime = usecTimestampNow(); } Avatar::~Avatar() { @@ -187,25 +175,35 @@ AABox Avatar::getBounds() const { } void Avatar::animateScaleChanges(float deltaTime) { - float currentScale = getUniformScale(); - auto desiredScale = getDomainLimitedScale(); - if (currentScale != desiredScale) { + if (_isAnimatingScale) { + float currentScale = getUniformScale(); + float desiredScale = getDomainLimitedScale(); + // use exponential decay toward the domain limit clamped scale const float SCALE_ANIMATION_TIMESCALE = 0.5f; float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * desiredScale; // snap to the end when we get close enough - const float MIN_RELATIVE_SCALE_ERROR = 0.03f; - if (fabsf(desiredScale - currentScale) / desiredScale < MIN_RELATIVE_SCALE_ERROR) { + const float MIN_RELATIVE_ERROR = 0.03f; + float relativeError = fabsf(desiredScale - currentScale) / desiredScale; + if (relativeError < MIN_RELATIVE_ERROR) { animatedScale = desiredScale; + _isAnimatingScale = false; } - setScale(glm::vec3(animatedScale)); // avatar scale is uniform + + // TODO: rebuilding the shape constantly is somehwat expensive. + // We should only rebuild after significant change. rebuildCollisionShape(); } } +void Avatar::setTargetScale(float targetScale) { + AvatarData::setTargetScale(targetScale); + _isAnimatingScale = true; +} + void Avatar::updateAvatarEntities() { PerformanceTimer perfTimer("attachments"); // - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity() @@ -302,63 +300,23 @@ void Avatar::updateAvatarEntities() { } } -void Avatar::setShouldDie() { - // This will cause the avatar to be shrunk away and removed (the actual Avatar gets removed), but then it comes back. - _owningAvatarMixer.clear(); +bool Avatar::shouldDie() const { + const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; + return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } -void Avatar::simulate(float deltaTime) { +void Avatar::simulate(float deltaTime, bool inView) { + PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); - - if (!isDead() && !_motionState) { - DependencyManager::get<AvatarManager>()->addAvatarToSimulation(this); - } - animateScaleChanges(deltaTime); - - bool avatarInView = false; - { // update the shouldAnimate flag to match whether or not we will render the avatar. - PerformanceTimer perfTimer("cull"); - { - // simple frustum check - PerformanceTimer perfTimer("inView"); - ViewFrustum viewFrustum; - qApp->copyDisplayViewFrustum(viewFrustum); - avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) - || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); - } - PerformanceTimer lodPerfTimer("LOD"); - if (avatarInView) { - const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; - const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; - ViewFrustum viewFrustum; - qApp->copyViewFrustum(viewFrustum); - float visibility = calculateRenderAccuracy(viewFrustum.getPosition(), - getBounds(), DependencyManager::get<LODManager>()->getOctreeSizeScale()); - if (!_shouldAnimate) { - if (visibility > MINIMUM_VISIBILITY_FOR_ON) { - _shouldAnimate = true; - qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) { - _shouldAnimate = false; - qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; - } - } - } - - uint64_t start = usecTimestampNow(); - // CRUFT? _shouldSkipRender is never set 'true' - if (_shouldAnimate && avatarInView && !_shouldSkipRender) { - { - PerformanceTimer perfTimer("skeleton"); + { + PROFILE_RANGE(simulation, "updateJoints"); + if (inView && _hasNewJointData) { _skeletonModel->getRig()->copyJointsFromJointData(_jointData); - _skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); + _skeletonModel->simulate(deltaTime, true); + locationChanged(); // joints changed, so if there are any children, update them. - _hasNewJointRotations = false; - _hasNewJointTranslations = false; - } - { - PerformanceTimer perfTimer("head"); + _hasNewJointData = false; + glm::vec3 headPosition = getPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { headPosition = getPosition(); @@ -366,16 +324,12 @@ void Avatar::simulate(float deltaTime) { Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); - head->simulate(deltaTime, false, !_shouldAnimate); + head->simulate(deltaTime, false); + } else { + // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. + _skeletonModel->simulate(deltaTime, false); } - } else { - // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. - getHead()->setPosition(getPosition()); - PerformanceTimer perfTimer("skeleton"); - _skeletonModel->simulate(deltaTime, false); } - timeProcessingJoints += usecTimestampNow() - start; - numJointsProcessed += _jointData.size(); // update animation for display name fade in/out if ( _displayNameTargetAlpha != _displayNameAlpha) { @@ -394,11 +348,13 @@ void Avatar::simulate(float deltaTime) { _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } - measureMotionDerivatives(deltaTime); - - simulateAttachments(deltaTime); - updatePalms(); - updateAvatarEntities(); + { + PROFILE_RANGE(simulation, "misc"); + measureMotionDerivatives(deltaTime); + simulateAttachments(deltaTime); + updatePalms(); + updateAvatarEntities(); + } } bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { @@ -1106,7 +1062,7 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } - if (_moving || _hasNewJointRotations || _hasNewJointTranslations) { + if (_moving || _hasNewJointData) { locationChanged(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d370402865..8f2b0817c1 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -58,8 +58,6 @@ class Avatar : public AvatarData { Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: - static float getNumJointsProcessedPerSecond(); - explicit Avatar(RigPointer rig = nullptr); ~Avatar(); @@ -68,7 +66,7 @@ public: void init(); void updateAvatarEntities(); - void simulate(float deltaTime); + void simulate(float deltaTime, bool inView); virtual void simulateAttachments(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); @@ -141,8 +139,6 @@ public: Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } - Q_INVOKABLE bool getShouldRender() const { return !_shouldSkipRender; } - /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; @@ -179,7 +175,12 @@ public: glm::vec3 getUncachedRightPalmPosition() const; glm::quat getUncachedRightPalmRotation() const; - Q_INVOKABLE void setShouldDie(); + uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } + void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } + + bool shouldDie() const; + void animateScaleChanges(float deltaTime); + void setTargetScale(float targetScale) override; public slots: @@ -230,8 +231,6 @@ protected: // protected methods... bool isLookingAtMe(AvatarSharedPointer avatar) const; - virtual void animateScaleChanges(float deltaTime); - glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } @@ -261,14 +260,14 @@ protected: void ensureInScene(AvatarSharedPointer self); private: + uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; int _rightPointerGeometryID { 0 }; int _nameRectGeometryID { 0 }; bool _initialized; - bool _shouldAnimate { true }; - bool _shouldSkipRender { false }; bool _isLookAtTarget { false }; bool _inScene { false }; + bool _isAnimatingScale { false }; float getBoundingRadius() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6080b3e67b..df3164e6fc 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -137,53 +137,131 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra return avatar->getDataRate(rateName); } +class AvatarPriority { +public: + AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {} + AvatarSharedPointer avatar; + float priority; + // NOTE: we invert the less-than operator to sort high priorities to front + bool operator<(const AvatarPriority& other) const { return priority > other.priority; } +}; + void AvatarManager::updateOtherAvatars(float deltaTime) { // lock the hash for read to check the size QReadLocker lock(&_hashLock); - if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { return; } - lock.unlock(); - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); - PerformanceTimer perfTimer("otherAvatars"); - render::PendingChanges pendingChanges; + uint64_t startTime = usecTimestampNow(); - // simulate avatars - auto hashCopy = getHashCopy(); + auto avatarMap = getHashCopy(); + QList<AvatarSharedPointer> avatarList = avatarMap.values(); + ViewFrustum cameraView; + qApp->copyDisplayViewFrustum(cameraView); + glm::vec3 frustumCenter = cameraView.getPosition(); - uint64_t start = usecTimestampNow(); - AvatarHash::iterator avatarIterator = hashCopy.begin(); - while (avatarIterator != hashCopy.end()) { - auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value()); + const float OUT_OF_VIEW_PENALTY = -10.0; - if (avatar == _myAvatar || !avatar->isInitialized()) { - // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. - // DO NOT update or fade out uninitialized Avatars - ++avatarIterator; - } else if (avatar->shouldDie()) { - removeAvatar(avatarIterator.key()); - ++avatarIterator; - } else { - avatar->ensureInScene(avatar); - avatar->simulate(deltaTime); - ++avatarIterator; + std::priority_queue<AvatarPriority> sortedAvatars; + { + PROFILE_RANGE(simulation, "sort"); + for (int32_t i = 0; i < avatarList.size(); ++i) { + const auto& avatar = std::static_pointer_cast<Avatar>(avatarList.at(i)); + if (avatar == _myAvatar || !avatar->isInitialized()) { + // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. + // DO NOT update or fade out uninitialized Avatars + continue; + } + if (avatar->shouldDie()) { + removeAvatar(avatar->getID()); + continue; + } + if (avatar->isDead()) { + continue; + } - avatar->updateRenderItem(pendingChanges); + // priority = weighted linear combination of: + // (a) apparentSize + // (b) proximity to center of view + // (c) time since last update + // (d) TIME_PENALTY to help recently updated entries sort toward back + glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 offset = avatarPosition - frustumCenter; + float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero + float radius = avatar->getBoundingRadius(); + const glm::vec3& forward = cameraView.getDirection(); + float apparentSize = radius / distance; + float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance; + const float TIME_PENALTY = 0.080f; // seconds + float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY; + // NOTE: we are adding values of different units to get a single measure of "priority". + // Thus we multiply each component by a conversion "weight" that scales its units + // relative to the others. These weights are pure magic tuning and are hard coded in the + // relation below: (hint: unitary weights are not explicityly shown) + float priority = apparentSize + 0.25f * cosineAngle + age; + + // decrement priority of avatars outside keyhole + if (distance > cameraView.getCenterRadius()) { + if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) { + priority += OUT_OF_VIEW_PENALTY; + } + } + sortedAvatars.push(AvatarPriority(avatar, priority)); } } + + render::PendingChanges pendingChanges; + const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec + const uint64_t MAX_UPDATE_BUDGET = 2000; // usec + uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; + uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; + while (!sortedAvatars.empty()) { + const AvatarPriority& sortData = sortedAvatars.top(); + const auto& avatar = std::static_pointer_cast<Avatar>(sortData.avatar); + + // for ALL avatars... + avatar->ensureInScene(avatar); + if (!avatar->getMotionState()) { + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); + if (shape) { + // don't add to the simulation now, instead put it on a list to be added later + AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape); + avatar->setMotionState(motionState); + _motionStatesToAddToPhysics.insert(motionState); + _motionStatesThatMightUpdate.insert(motionState); + } + } + avatar->animateScaleChanges(deltaTime); + + uint64_t now = usecTimestampNow(); + if (now < renderExpiry) { + // we're within budget + const float OUT_OF_VIEW_THRESHOLD = 0.5f * OUT_OF_VIEW_PENALTY; + bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD; + avatar->simulate(deltaTime, inView); + avatar->updateRenderItem(pendingChanges); + avatar->setLastRenderUpdateTime(startTime); + } else if (now < maxExpiry) { + // we've spent most of our time budget, but we still simulate() the avatar as it if were out of view + // --> some avatars may freeze until their priority trickles up + const bool inView = false; + avatar->simulate(deltaTime, inView); + } else { + // we've spent ALL of our time budget --> bail on the rest of the avatar updates + // --> some scale or fade animations may glitch + // --> some avatar velocity measurements may be a little off + break; + } + sortedAvatars.pop(); + } qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); - // simulate avatar fades simulateAvatarFades(deltaTime); - - PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec", - { { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } }); - PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } }); } void AvatarManager::postUpdate(float deltaTime) { @@ -206,6 +284,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); + avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine @@ -215,7 +294,8 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { ++fadingIterator; } } else { - avatar->simulate(deltaTime); + const bool inView = true; // HACK + avatar->simulate(deltaTime, inView); ++fadingIterator; } } @@ -391,21 +471,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -void AvatarManager::addAvatarToSimulation(Avatar* avatar) { - assert(!avatar->getMotionState()); - - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); - if (shape) { - // we don't add to the simulation now, we put it on a list to be added later - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAddToPhysics.insert(motionState); - _motionStatesThatMightUpdate.insert(motionState); - } -} - void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) { for (auto avatarData : _avatarHash) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 193fa35ec5..787d6f2d83 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -69,8 +69,6 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void addAvatarToSimulation(Avatar* avatar); - Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")); Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 928f46facb..d7bf2b79bf 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -70,7 +70,7 @@ void Head::reset() { _baseYaw = _basePitch = _baseRoll = 0.0f; } -void Head::simulate(float deltaTime, bool isMine, bool billboard) { +void Head::simulate(float deltaTime, bool isMine) { // Update audio trailing average for rendering facial animations const float AUDIO_AVERAGING_SECS = 0.05f; const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; @@ -117,7 +117,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } - if (!(_isFaceTrackerConnected || billboard)) { + if (!_isFaceTrackerConnected) { if (!_isEyeTrackerConnected) { // Update eye saccades @@ -220,7 +220,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _leftEyePosition = _rightEyePosition = getPosition(); _eyePosition = getPosition(); - if (!billboard && _owningAvatar) { + if (_owningAvatar) { auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel(); if (skeletonModel) { skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition); @@ -378,10 +378,6 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { return rotationBetween(orientation * IDENTITY_FRONT, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation; } -glm::vec3 Head::getScalePivot() const { - return _position; -} - void Head::setFinalPitch(float finalPitch) { _deltaPitch = glm::clamp(finalPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH) - _basePitch; } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 29cd06865c..3d25c79087 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -31,7 +31,7 @@ public: void init(); void reset(); - void simulate(float deltaTime, bool isMine, bool billboard = false); + void simulate(float deltaTime, bool isMine); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } @@ -70,8 +70,6 @@ public: bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } - /// \return the point about which scaling occurs. - glm::vec3 getScalePivot() const; void setDeltaPitch(float pitch) { _deltaPitch = pitch; } float getDeltaPitch() const { return _deltaPitch; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 54f6682191..4b77323bba 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -220,15 +220,19 @@ void SkeletonModel::updateAttitude() { // Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), // but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - updateAttitude(); - setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); + if (fullUpdate) { + updateAttitude(); + setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); - Model::simulate(deltaTime, fullUpdate); + Model::simulate(deltaTime, fullUpdate); - // let rig compute the model offset - glm::vec3 registrationPoint; - if (_rig->getModelRegistrationPoint(registrationPoint)) { - setOffset(registrationPoint); + // let rig compute the model offset + glm::vec3 registrationPoint; + if (_rig->getModelRegistrationPoint(registrationPoint)) { + setOffset(registrationPoint); + } + } else { + Model::simulate(deltaTime, fullUpdate); } if (!isActive() || !_owningAvatar->isMyAvatar()) { diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 7cfbfb174e..fbeddf41e0 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -253,6 +253,16 @@ int WindowScriptingInterface::createMessageBox(QString title, QString text, int void WindowScriptingInterface::updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton) { auto messageBox = _messageBoxes.value(id); if (messageBox) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "updateMessageBox", + Q_ARG(int, id), + Q_ARG(QString, title), + Q_ARG(QString, text), + Q_ARG(int, buttons), + Q_ARG(int, defaultButton)); + return; + } + messageBox->setProperty("title", title); messageBox->setProperty("text", text); messageBox->setProperty("buttons", buttons); @@ -263,6 +273,12 @@ void WindowScriptingInterface::updateMessageBox(int id, QString title, QString t void WindowScriptingInterface::closeMessageBox(int id) { auto messageBox = _messageBoxes.value(id); if (messageBox) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "closeMessageBox", + Q_ARG(int, id)); + return; + } + disconnect(messageBox); messageBox->setVisible(false); messageBox->deleteLater(); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index a4cb62cc13..828e2e772d 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -157,7 +157,7 @@ void setupPreferences() { } { auto getter = [=]()->float { return myAvatar->getUniformScale(); }; - auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell? + auto setter = [=](float value) { myAvatar->setTargetScale(value); }; auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter); preference->setMin(0.01f); preference->setMax(99.9f); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index fdeeb01739..ac16b16c1d 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1269,6 +1269,7 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const { void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) { PerformanceTimer perfTimer("copyJoints"); + PROFILE_RANGE(simulation_animation_detail, "copyJoints"); if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) { // make a vector of rotations in absolute-geometry-frame const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index eac21a9fe2..b726af3c3b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -63,8 +63,7 @@ AvatarData::AvatarData() : _handState(0), _keyState(NO_KEY_DOWN), _forceFaceTrackerConnected(false), - _hasNewJointRotations(true), - _hasNewJointTranslations(true), + _hasNewJointData(true), _headData(NULL), _displayNameTargetAlpha(1.0f), _displayNameAlpha(1.0f), @@ -134,11 +133,6 @@ void AvatarData::setTargetScale(float targetScale) { } } -void AvatarData::setTargetScaleVerbose(float targetScale) { - setTargetScale(targetScale); - qCDebug(avatars) << "Changed scale to " << _targetScale; -} - glm::vec3 AvatarData::getHandPosition() const { return getOrientation() * _handPosition + getPosition(); } @@ -712,8 +706,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { glm::quat newOrientation; sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, newOrientation); glm::quat currentOrientation = getLocalOrientation(); + if (currentOrientation != newOrientation) { - _hasNewJointRotations = true; + _hasNewJointData = true; setLocalOrientation(newOrientation); } int numBytesRead = sourceBuffer - startSection; @@ -978,7 +973,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { JointData& data = _jointData[i]; if (validTranslations[i]) { sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - _hasNewJointTranslations = true; + _hasNewJointData = true; data.translationSet = true; } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c56660ca06..fc4cc78447 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -85,7 +85,6 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; - // Bitset of state flags - we store the key state, hand state, Faceshift, eye tracking, and existence of // referential data in this bit set. The hand state is an octal, but is split into two sections to maintain // backward compatibility. The bits are ordered as such (0-7 left to right). @@ -405,8 +404,7 @@ public: // Scale float getTargetScale() const; - void setTargetScale(float targetScale); - void setTargetScaleVerbose(float targetScale); + virtual void setTargetScale(float targetScale); float getDomainLimitedScale() const { return glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale); } @@ -513,8 +511,6 @@ public: const glm::vec3& getTargetVelocity() const { return _targetVelocity; } - bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } - void clearRecordingBasis(); TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); @@ -600,8 +596,7 @@ protected: KeyState _keyState; bool _forceFaceTrackerConnected; - bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar - bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar + bool _hasNewJointData; // set in AvatarData, cleared in Avatar HeadData* _headData; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c338d6e641..2242bba5d9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -48,39 +48,18 @@ public: void update(); uvec3 getPageCounts(const uvec3& dimensions) const; uint32_t getPageCount(const uvec3& dimensions) const; + uint32_t getSize() const; GL45Texture& texture; bool sparse { false }; uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION }; GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; + uint32_t allocatedPages { 0 }; uint32_t maxPages { 0 }; uint32_t pageBytes { 0 }; GLint pageDimensionsIndex { 0 }; }; -#if INCREMENTAL_TRANSFER - struct TransferState { - TransferState(GL45Texture& texture); - uvec3 currentPageSize() const; - void updateMip(); - void populatePage(std::vector<uint8_t>& dest); - bool increment(); - - GL45Texture& texture; - GLTexelFormat texelFormat; - uint8_t face { 0 }; - uint16_t mipLevel { 0 }; - uint32_t bytesPerLine { 0 }; - uint32_t bytesPerPixel { 0 }; - uint32_t bytesPerPage { 0 }; - uvec3 mipDimensions; - uvec3 mipOffset; - const uint8_t* srcPointer { nullptr }; - }; - protected: - TransferState _transferState; -#endif - protected: void updateMips() override; void stripToMip(uint16_t newMinMip); @@ -98,8 +77,6 @@ public: void derez(); SparseInfo _sparseInfo; - uint32_t _allocatedPages { 0 }; - uint32_t _lastMipAllocatedPages { 0 }; uint16_t _mipOffset { 0 }; friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 9b16908244..6632bf936e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -116,6 +116,8 @@ void SparseInfo::maybeMakeSparse() { } } +#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f + // This can only be called after we've established our storage size void SparseInfo::update() { if (!sparse) { @@ -124,6 +126,9 @@ void SparseInfo::update() { glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel); pageBytes = texture._gpuObject.getTexelFormat().getSize(); pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z; + // Testing with a simple texture allocating app shows an estimated 20% GPU memory overhead for + // sparse textures as compared to non-sparse, so we acount for that here. + pageBytes = (uint32_t)(pageBytes * SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE); for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) { auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); @@ -146,6 +151,11 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { return pageCounts.x * pageCounts.y * pageCounts.z; } + +uint32_t SparseInfo::getSize() const { + return allocatedPages * pageBytes; +} + void GL45Backend::initTextureManagementStage() { // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; @@ -160,93 +170,6 @@ void GL45Backend::initTextureManagementStage() { } } -#if INCREMENTAL_TRANSFER - -using TransferState = GL45Backend::GL45Texture::TransferState; - -TransferState::TransferState(GL45Texture& texture) : texture(texture) { -} - -void TransferState::updateMip() { - mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); - mipOffset = uvec3(); - if (!texture._gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { - srcPointer = nullptr; - return; - } - - auto mip = texture._gpuObject.accessStoredMipFace(mipLevel, face); - texelFormat = gl::GLTexelFormat::evalGLTexelFormat(texture._gpuObject.getTexelFormat(), mip->getFormat()); - srcPointer = mip->readData(); - bytesPerLine = (uint32_t)mip->getSize() / mipDimensions.y; - bytesPerPixel = bytesPerLine / mipDimensions.x; -} - -bool TransferState::increment() { - const SparseInfo& sparse = texture._sparseInfo; - if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) { - mipOffset.x += sparse.pageDimensions.x; - return true; - } - - if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) { - mipOffset.x = 0; - mipOffset.y += sparse.pageDimensions.y; - return true; - } - - if (mipOffset.z + sparse.pageDimensions.z < mipDimensions.z) { - mipOffset.x = 0; - mipOffset.y = 0; - ++mipOffset.z; - return true; - } - - // Done with this mip?, move on to the next mip - if (mipLevel + 1 < texture.usedMipLevels()) { - mipOffset = uvec3(0); - ++mipLevel; - updateMip(); - return true; - } - - uint8_t maxFace = (uint8_t)((texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - uint8_t nextFace = face + 1; - // Done with this face? Move on to the next - if (nextFace < maxFace) { - ++face; - mipOffset = uvec3(0); - mipLevel = 0; - updateMip(); - return true; - } - - return false; -} - -void TransferState::populatePage(std::vector<uint8_t>& buffer) { - uvec3 pageSize = currentPageSize(); - auto bytesPerPageLine = bytesPerPixel * pageSize.x; - if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { - bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); - assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); - } - auto totalPageSize = bytesPerPageLine * pageSize.y; - if (totalPageSize > buffer.size()) { - buffer.resize(totalPageSize); - } - uint8_t* dst = &buffer[0]; - for (uint32_t y = 0; y < pageSize.y; ++y) { - uint32_t srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x); - uint32_t dstOffset = bytesPerPageLine * y; - memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel); - } -} - -uvec3 TransferState::currentPageSize() const { - return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions); -} -#endif GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; @@ -260,17 +183,11 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId) : GLTexture(backend, texture, externalId), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { } GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this) -#if INCREMENTAL_TRANSFER -, _transferState(*this) -#endif { auto theBackend = _backend.lock(); @@ -316,12 +233,12 @@ GL45Texture::~GL45Texture() { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages <= _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages <= _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } - if (0 != _allocatedPages) { - qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; + if (0 != _sparseInfo.allocatedPages) { + qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _sparseInfo.allocatedPages; } auto size = _size; @@ -365,9 +282,9 @@ void GL45Texture::updateSize() const { } if (_transferrable && _sparseInfo.sparse) { - auto size = _allocatedPages * _sparseInfo.pageBytes; + auto size = _sparseInfo.getSize(); Backend::updateTextureGPUSparseMemoryUsage(_size, size); - setSize(_allocatedPages * _sparseInfo.pageBytes); + setSize(size); } else { setSize(_gpuObject.evalTotalSize(_mipOffset)); } @@ -376,20 +293,16 @@ void GL45Texture::updateSize() const { void GL45Texture::startTransfer() { Parent::startTransfer(); _sparseInfo.update(); -#if INCREMENTAL_TRANSFER - _transferState.updateMip(); -#endif } bool GL45Texture::continueTransfer() { -#if !INCREMENTAL_TRANSFER size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { auto size = _gpuObject.evalMipDimensions(mipLevel); if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); - _allocatedPages += _sparseInfo.getPageCount(size); + _sparseInfo.allocatedPages += _sparseInfo.getPageCount(size); } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); @@ -413,58 +326,6 @@ bool GL45Texture::continueTransfer() { } } return false; -#else - static std::vector<uint8_t> buffer; - if (buffer.empty()) { - buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); - } - const uvec3 pageSize = _transferState.currentPageSize(); - const uvec3& offset = _transferState.mipOffset; - - if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) { - if (_allocatedPages > _sparseInfo.maxPages) { - qCWarning(gpugl45logging) << "Exceeded max page allocation!"; - } - glTexturePageCommitmentEXT(_id, _transferState.mipLevel, - offset.x, offset.y, _transferState.face, - pageSize.x, pageSize.y, pageSize.z, - GL_TRUE); - ++_allocatedPages; - } - - if (_transferState.srcPointer) { - // Transfer the mip data - _transferState.populatePage(buffer); - if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } else if (GL_TEXTURE_CUBE_MAP == _target) { - auto target = CUBE_FACE_LAYOUT[_transferState.face]; - // DSA ARB does not work on AMD, so use EXT - // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); - glTextureSubImage2DEXT(_id, target, _transferState.mipLevel, - offset.x, offset.y, - pageSize.x, pageSize.y, - _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); - } - } - - serverWait(); - auto currentMip = _transferState.mipLevel; - auto result = _transferState.increment(); - if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) { - auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); - auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); - auto newPages = _allocatedPages - _lastMipAllocatedPages; - if (newPages != mipExpectedPages) { - qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; - } - _lastMipAllocatedPages = _allocatedPages; - } - return result; -#endif } void GL45Texture::finishTransfer() { @@ -545,8 +406,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { }); auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages < _allocatedPages); - _allocatedPages -= deallocatedPages; + assert(deallocatedPages < _sparseInfo.allocatedPages); + _sparseInfo.allocatedPages -= deallocatedPages; } _minMip = newMinMip; } else { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b79e69a9b7..1e83a874dc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -272,8 +272,6 @@ void Model::reset() { } bool Model::updateGeometry() { - PROFILE_RANGE(render_detail, __FUNCTION__); - PerformanceTimer perfTimer("Model::updateGeometry"); bool needFullUpdate = false; if (!isLoaded()) { @@ -1128,7 +1126,9 @@ void Model::simulate(float deltaTime, bool fullUpdate) { if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) { snapToRegistrationPoint(); } - simulateInternal(deltaTime); + // update the world space transforms for all joints + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); + updateRig(deltaTime, parentTransform); } } @@ -1138,12 +1138,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateAnimations(deltaTime, parentTransform); } -void Model::simulateInternal(float deltaTime) { - // update the world space transforms for all joints - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); - updateRig(deltaTime, parentTransform); -} - // virtual void Model::updateClusterMatrices() { PerformanceTimer perfTimer("Model::updateClusterMatrices"); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 246d67180e..3f673b0250 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -312,7 +312,6 @@ protected: void scaleToFit(); void snapToRegistrationPoint(); - void simulateInternal(float deltaTime); virtual void updateRig(float deltaTime, glm::mat4 parentTransform); /// Restores the indexed joint to its default position. diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 3f3de89fce..6f56a108bd 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -26,6 +26,8 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr<const SpatiallyNestable> using SpatiallyNestablePointer = std::shared_ptr<SpatiallyNestable>; using SpatiallyNestableConstPointer = std::shared_ptr<const SpatiallyNestable>; +static const uint16_t INVALID_JOINT_INDEX = -1; + enum class NestableType { Entity, Avatar, @@ -184,7 +186,7 @@ protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? + quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to? mutable SpatiallyNestableWeakPointer _parent; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index b4ed462639..a0b7d17e46 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -729,7 +729,7 @@ void ViewFrustum::evalProjectionMatrix(glm::mat4& proj) const { glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar) const { // make sure range near far make sense - assert(rangeNear > 0.0); + assert(rangeNear > 0.0f); assert(rangeFar > rangeNear); // recreate a projection matrix for only a range of depth of this frustum. @@ -738,7 +738,7 @@ glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar glm::mat4 rangeProj = _projection; float A = -(rangeFar + rangeNear) / (rangeFar - rangeNear); - float B = -2 * rangeFar*rangeNear / ((rangeFar - rangeNear)); + float B = -2.0f * rangeFar*rangeNear / ((rangeFar - rangeNear)); rangeProj[2][2] = A; rangeProj[3][2] = B; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index d5f0f4cb06..10970a7749 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -24,7 +24,7 @@ var canWriteAssets = false; var xmlHttpRequest = null; - var isDownloading = false; // Explicitly track download request status. + var isPreparing = false; // Explicitly track download request status. function injectCommonCode(isDirectoryPage) { @@ -139,7 +139,7 @@ function startAutoDownload() { // One file request at a time. - if (isDownloading) { + if (isPreparing) { console.log("WARNIKNG: Clara.io FBX: Prepare only one download at a time"); return; } @@ -178,7 +178,7 @@ var message = this.responseText.slice(responseTextIndex); var statusMessage = ""; - if (isDownloading) { // Ignore messages in flight after finished/cancelled. + if (isPreparing) { // Ignore messages in flight after finished/cancelled. var lines = message.split(/[\n\r]+/); for (var i = 0, length = lines.length; i < length; i++) { @@ -222,33 +222,30 @@ xmlHttpRequest.onload = function () { var statusMessage = ""; - if (!isDownloading) { + if (!isPreparing) { return; } + isPreparing = false; + var HTTP_OK = 200; if (this.status !== HTTP_OK) { statusMessage = "Zip file request terminated with " + this.status + " " + this.statusText; console.log("ERROR: Clara.io FBX: " + statusMessage); EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); - return; - } - - if (zipFileURL.slice(-4) !== ".zip") { + } else if (zipFileURL.slice(-4) !== ".zip") { statusMessage = "Error creating zip file for download."; console.log("ERROR: Clara.io FBX: " + statusMessage + ": " + zipFileURL); EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); - return; + } else { + EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); + console.log("Clara.io FBX: File download initiated for " + zipFileURL); } - EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); - console.log("Clara.io FBX: File download initiated for " + zipFileURL); - xmlHttpRequest = null; - isDownloading = false; } - isDownloading = true; + isPreparing = true; console.log("Clara.io FBX: Request zip file for " + uuid); EventBridge.emitWebEvent(CLARA_IO_STATUS + " Initiating download"); @@ -301,7 +298,7 @@ } function cancelClaraDownload() { - isDownloading = false; + isPreparing = false; if (xmlHttpRequest) { xmlHttpRequest.abort();