From 3f52d237edbf2cc7d810782f8b4c623d6d5e200f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 31 Mar 2016 10:27:17 -0700 Subject: [PATCH 001/128] adding Bullet profiler instances for better stats --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/PhysicsEngine.cpp | 1 + .../physics/src/ThreadSafeDynamicsWorld.cpp | 26 ++++++++++++++++++- .../physics/src/ThreadSafeDynamicsWorld.h | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e3952ba1d6..7b83c2e2ce 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -175,11 +175,13 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { + BT_PROFILE("getWorldTransform"); if (!_entity) { return; } assert(entityTreeIsLocked()); if (_motionType == MOTION_TYPE_KINEMATIC) { + BT_PROFILE("kinematicIntegration"); // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 0040c19c3d..74f6f90900 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -240,6 +240,7 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); if (_myAvatarController) { + BT_PROFILE("avatarController"); // TODO: move this stuff outside and in front of stepSimulation, because // the updateShapeIfNecessary() call needs info from MyAvatar and should // be done on the main thread during the pre-simulation stuff diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index b6f3487f1a..5fe99f137c 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -67,7 +67,10 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep saveKinematicState(fixedTimeStep*clampedSimulationSteps); - applyGravity(); + { + BT_PROFILE("applyGravity"); + applyGravity(); + } for (int i=0;igetActivationState() != ISLAND_SLEEPING) + { + if (body->isKinematicObject()) + { + //to calculate velocities next frame + body->saveKinematicState(timeStep); + } + } + } +} + + diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index e9708149da..68062d8d29 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -41,6 +41,7 @@ public: btScalar fixedTimeStep = btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { }); virtual void synchronizeMotionStates() override; + virtual void saveKinematicState(btScalar timeStep) override; // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide From 442b52313fbee5398df9311b35c234f06ba5ec2b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:02:01 -0700 Subject: [PATCH 002/128] faster kinematic motion calculations --- libraries/entities/src/EntityItem.cpp | 139 +++++++-------------- libraries/shared/src/SpatiallyNestable.cpp | 50 ++++++-- libraries/shared/src/SpatiallyNestable.h | 7 ++ 3 files changed, 93 insertions(+), 103 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 431d638063..69614d0d12 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -876,123 +876,76 @@ void EntityItem::simulate(const quint64& now) { } void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { -#ifdef WANT_DEBUG - qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; -#endif - - const float MIN_TIME_SKIP = 0.0f; - const float MAX_TIME_SKIP = 1.0f; // in seconds - - timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); - - if (hasActions()) { + if (hasActions() || timeElapsed < 0.0f) { return; } - if (hasLocalAngularVelocity()) { - glm::vec3 localAngularVelocity = getLocalAngularVelocity(); + const float MAX_TIME_ELAPSED = 1.0f; // seconds + timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED); + Transform transform; + glm::vec3 linearVelocity; + glm::vec3 angularVelocity; + getLocalEverything(transform, linearVelocity, angularVelocity); + + bool isMoving = false; + if (glm::length2(angularVelocity) > 0.0f) { // angular damping if (_angularDamping > 0.0f) { - localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed); - #ifdef WANT_DEBUG - qCDebug(entities) << " angularDamping :" << _angularDamping; - qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity; - #endif + angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); } - float angularSpeed = glm::length(localAngularVelocity); - - const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { - if (setFlags && angularSpeed > 0.0f) { - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; - } - localAngularVelocity = ENTITY_ITEM_ZERO_VEC3; + const float EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (glm::length2(angularVelocity) < EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED) { + angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps - glm::quat rotation = getRotation(); + glm::quat rotation = transform.getRotation(); float dt = timeElapsed; - while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) { - glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP); + while (dt > 0.0f) { + glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP)); rotation = glm::normalize(dQ * rotation); dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; } - // NOTE: this final partial substep can drift away from a real Bullet simulation however - // it only becomes significant for rapidly rotating objects - // (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec). - glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt); - rotation = glm::normalize(dQ * rotation); - - setRotation(rotation); + transform.setRotation(rotation); + isMoving = true; } - - setLocalAngularVelocity(localAngularVelocity); } - - if (hasLocalVelocity()) { - - // acceleration is in the global frame, so transform it into the local frame. - // TODO: Move this into SpatiallyNestable. - bool success; - Transform transform = getParentTransform(success); - glm::vec3 localAcceleration(glm::vec3::_null); - if (success) { - localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration(); - } else { - localAcceleration = getAcceleration(); - } - + if (glm::length2(linearVelocity) > 0.0f) { // linear damping - glm::vec3 localVelocity = getLocalVelocity(); if (_damping > 0.0f) { - localVelocity *= powf(1.0f - _damping, timeElapsed); - #ifdef WANT_DEBUG - qCDebug(entities) << " damping:" << _damping; - qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity; - qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity); - #endif + linearVelocity *= powf(1.0f - _damping, timeElapsed); } - // integrate position forward - glm::vec3 localPosition = getLocalPosition(); - glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed; - - #ifdef WANT_DEBUG - qCDebug(entities) << " EntityItem::simulate()...."; - qCDebug(entities) << " timeElapsed:" << timeElapsed; - qCDebug(entities) << " old AACube:" << getMaximumAACube(); - qCDebug(entities) << " old position:" << localPosition; - qCDebug(entities) << " old velocity:" << localVelocity; - qCDebug(entities) << " old getAABox:" << getAABox(); - qCDebug(entities) << " newPosition:" << newPosition; - qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition); - #endif - - localPosition = newLocalPosition; - - // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. - localVelocity += localAcceleration * timeElapsed; - - float speed = glm::length(localVelocity); - const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec - if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { - setVelocity(ENTITY_ITEM_ZERO_VEC3); - if (setFlags && speed > 0.0f) { - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + glm::vec3 linearAcceleration = _acceleration; + if (glm::length2(_acceleration) > 0.0f) { + // acceleration is in world-frame but we need it in local-frame + bool success; + Transform parentTransform = getParentTransform(success); + if (success) { + linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; } - } else { - setLocalPosition(localPosition); - setLocalVelocity(localVelocity); } - #ifdef WANT_DEBUG - qCDebug(entities) << " new position:" << position; - qCDebug(entities) << " new velocity:" << velocity; - qCDebug(entities) << " new AACube:" << getMaximumAACube(); - qCDebug(entities) << " old getAABox:" << getAABox(); - #endif + // integrate linearVelocity + linearVelocity += linearAcceleration * timeElapsed; + + const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 + if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { + setVelocity(ENTITY_ITEM_ZERO_VEC3); + } else { + // integrate position forward + // NOTE: we're using the NEW linear velocity, which is why we negate the acceleration term + glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) - 0.5f * linearAcceleration * timeElapsed * timeElapsed; + transform.setTranslation(position); + isMoving = true; + } + } + setLocalEverything(transform, linearVelocity, angularVelocity); + if (!isMoving) { + // flag this entity to be removed from kinematic motion + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 13bf5d9054..550864265f 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -90,11 +90,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons return parent; } - SpatiallyNestablePointer thisPointer = getThisPointer(); - if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(thisPointer); + parent->forgetChild(getThisPointer()); _parentKnowsMe = false; _parent.reset(); } @@ -112,16 +110,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons parent = _parent.lock(); if (parent) { - parent->beParentOfChild(thisPointer); + parent->beParentOfChild(getThisPointer()); _parentKnowsMe = true; } - if (parent || parentID.isNull()) { - success = true; - } else { - success = false; - } - + success = (parent || parentID.isNull()); return parent; } @@ -849,3 +842,40 @@ AACube SpatiallyNestable::getQueryAACube() const { } return result; } + +void SpatiallyNestable::getLocalEverything( + Transform& transform, + glm::vec3& velocity, + glm::vec3& angularVelocity) const { + // transform + _transformLock.withReadLock([&] { + transform = _transform; + }); + // linear velocity + _velocityLock.withReadLock([&] { + velocity = _velocity; + }); + // angular velocity + _angularVelocityLock.withReadLock([&] { + angularVelocity = _angularVelocity; + }); +} + +void SpatiallyNestable::setLocalEverything( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity) { + // transform + _transformLock.withWriteLock([&] { + _transform = localTransform; + }); + // linear velocity + _velocityLock.withWriteLock([&] { + _velocity = localVelocity; + }); + // angular velocity + _angularVelocityLock.withWriteLock([&] { + _angularVelocity = localAngularVelocity; + }); + locationChanged(); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 379f2facd7..6546d46e51 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,6 +149,13 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; + void getLocalEverything(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; + + void setLocalEverything( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity); + mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; From e1602b57faad3e92c2c3862bda45016587882719 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:03:21 -0700 Subject: [PATCH 003/128] faster isNaN checks --- libraries/shared/src/GLMHelpers.cpp | 8 -------- libraries/shared/src/GLMHelpers.h | 4 ++-- libraries/shared/src/SharedUtil.cpp | 17 +---------------- libraries/shared/src/SharedUtil.h | 6 +++--- libraries/shared/src/Transform.cpp | 4 ---- libraries/shared/src/Transform.h | 2 +- 6 files changed, 7 insertions(+), 34 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index d21d88d212..53abb3827d 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -463,14 +463,6 @@ glm::vec2 getFacingDir2D(const glm::mat4& m) { } } -bool isNaN(glm::vec3 value) { - return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); -} - -bool isNaN(glm::quat value) { - return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); -} - glm::mat4 orthoInverse(const glm::mat4& m) { glm::mat4 r = m; r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 469ca1fc81..8b1446d4e5 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -229,8 +229,8 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec2 getFacingDir2D(const glm::quat& rot); glm::vec2 getFacingDir2D(const glm::mat4& m); -bool isNaN(glm::vec3 value); -bool isNaN(glm::quat value); +inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } glm::mat4 orthoInverse(const glm::mat4& m); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 30d4726bcc..d48bddbd88 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -247,12 +247,6 @@ int getNthBit(unsigned char byte, int ordinal) { return ERROR_RESULT; } -bool isBetween(int64_t value, int64_t max, int64_t min) { - return ((value <= max) && (value >= min)); -} - - - void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 @@ -260,12 +254,7 @@ void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { bool isInEnvironment(const char* environment) { char* environmentString = getenv("HIFI_ENVIRONMENT"); - - if (environmentString && strcmp(environmentString, environment) == 0) { - return true; - } else { - return false; - } + return (environmentString && strcmp(environmentString, environment) == 0); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -632,10 +621,6 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } -bool isNaN(float value) { - return value != value; -} - QString formatUsecTime(float usecs, int prec) { static const quint64 SECONDS_PER_MINUTE = 60; static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8fb65a5247..e9201b4a92 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -180,11 +180,11 @@ private: static int DEADBEEF_SIZE; }; -bool isBetween(int64_t value, int64_t max, int64_t min); - +/// \return true when value is between max and min +inline bool isBetween(int64_t value, int64_t max, int64_t min) { return ((value <= max) && (value >= min)); } /// \return bool is the float NaN -bool isNaN(float value); +inline bool isNaN(float value) { return value != value; } QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index a3a3c05731..c51b3dae4b 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -150,7 +150,3 @@ QJsonObject Transform::toJson(const Transform& transform) { } return result; } - -bool Transform::containsNaN() const { - return isNaN(_rotation) || isNaN(_scale) || isNaN(_translation); -} diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 1024173cbd..1e1d10c54b 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -145,7 +145,7 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; - bool containsNaN() const; + bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); } protected: From 25fbf926df007496267efcc3c1b97331a430834a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:04:27 -0700 Subject: [PATCH 004/128] CollisionWorld only updates _active_ Aabbs we manually set/clear active state of static objects that need their Aabbs updated also fixing a bug when starting kinematic motion --- libraries/physics/src/EntityMotionState.cpp | 17 ++++++--------- libraries/physics/src/EntityMotionState.h | 6 +----- libraries/physics/src/ObjectMotionState.cpp | 18 ++++++++++++---- libraries/physics/src/ObjectMotionState.h | 10 +++++---- libraries/physics/src/PhysicsEngine.cpp | 24 ++++++++++++++++----- libraries/physics/src/PhysicsEngine.h | 6 +++--- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 7b83c2e2ce..5f168d2e33 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() { } // virtual -bool EntityMotionState::handleEasyChanges(uint32_t& flags) { +void EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); @@ -137,8 +137,6 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) { if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); } - - return true; } @@ -422,19 +420,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. - if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet. this is to avoid - // overflowing the counter. - incrementAccelerationNearlyGravityCount(); + if (_accelerationNearlyGravityCount < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet, to avoid overflowing the counter + ++_accelerationNearlyGravityCount; } } else { - // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter - resetAccelerationNearlyGravityCount(); + // acceleration wasn't similar to this entity's gravity, reset the counter + _accelerationNearlyGravityCount = 0; } // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. - if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { + if (_accelerationNearlyGravityCount >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); } else { _entity->setAcceleration(glm::vec3(0.0f)); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index ac16ec6d5d..eb42d03b52 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,7 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual bool handleEasyChanges(uint32_t& flags) override; + virtual void handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; /// \return PhysicsMotionType based on params set in EntityItem @@ -51,10 +51,6 @@ public: virtual uint32_t getIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override; - void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } - void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } - uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } - virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectFriction() const override { return _entity->getFriction(); } virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 482c3146f8..6b2022e204 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -39,7 +39,7 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { } // static -uint32_t worldSimulationStep = 0; +uint32_t worldSimulationStep = 1; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; @@ -164,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { +void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -183,6 +183,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { worldTrans.setRotation(newRotation); } _body->setWorldTransform(worldTrans); + if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { + // force activate static body so its Aabb is updated later + _body->activate(true); + } } else if (flags & Simulation::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); btQuaternion newRotation = glmToBullet(getObjectRotation()); @@ -192,6 +196,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { } worldTrans.setRotation(newRotation); _body->setWorldTransform(worldTrans); + if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { + // force activate static body so its Aabb is updated later + _body->activate(true); + } } if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { @@ -232,8 +240,6 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_MASS) { updateBodyMassProperties(); } - - return true; } bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { @@ -292,6 +298,10 @@ void ObjectMotionState::updateBodyVelocities() { _body->setActivationState(ACTIVE_TAG); } +void ObjectMotionState::updateLastKinematicStep() { + _lastKinematicStep = ObjectMotionState::getWorldSimulationStep() - 1; +} + void ObjectMotionState::updateBodyMassProperties() { float mass = getMass(); btVector3 inertia(0.0f, 0.0f, 0.0f); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index bb78eb12d6..44cb88721c 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -50,11 +50,12 @@ const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TY Simulation::DIRTY_COLLISION_GROUP); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | - Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); + Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY | + Simulation::DIRTY_PHYSICS_ACTIVATION); + // These are the set of incoming flags that the PhysicsEngine needs to hear about: -const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | - Simulation::DIRTY_PHYSICS_ACTIVATION); +const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS); // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES; @@ -80,11 +81,12 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual bool handleEasyChanges(uint32_t& flags); + virtual void handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); void updateBodyVelocities(); + void updateLastKinematicStep(); virtual void updateBodyMassProperties(); MotionStateType getType() const { return _type; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 74f6f90900..55861e9b3a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,6 +50,7 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -80,6 +81,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->updateBodyVelocities(); + motionState->updateLastKinematicStep(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -189,12 +191,18 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - if (object->handleEasyChanges(flags)) { - object->clearIncomingDirtyFlags(); - } else { - stillNeedChange.push_back(object); - } + object->handleEasyChanges(flags); + object->clearIncomingDirtyFlags(); } + if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { + _activeStaticBodies.push_back(object->getRigidBody()); + } + } + // active static bodies have changed (in an Easy way) and need their Aabbs updated + // but we've configured Bullet to NOT update them automatically (for improved performance) + // so we must do it outselves + for (int i = 0; i < _activeStaticBodies.size(); ++i) { + _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; } @@ -389,6 +397,12 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); + // Bullet will not deactivate static objects (it doesn't expect them to be active) + // so we must deactivate them ourselves + for (int i = 0; i < _activeStaticBodies.size(); ++i) { + _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); + } + _activeStaticBodies.clear(); _dynamicsWorld->synchronizeMotionStates(); _hasOutgoingChanges = false; return _dynamicsWorld->getChangedMotionStates(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index f644d6f5b2..18e4016fec 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -13,9 +13,9 @@ #define hifi_PhysicsEngine_h #include +#include #include -#include #include #include @@ -41,7 +41,7 @@ public: }; typedef std::map ContactMap; -typedef QVector CollisionEvents; +typedef std::vector CollisionEvents; class PhysicsEngine { public: @@ -110,6 +110,7 @@ private: ContactMap _contactMap; CollisionEvents _collisionEvents; QHash _objectActions; + std::vector _activeStaticBodies; glm::vec3 _originOffset; QUuid _sessionID; @@ -121,7 +122,6 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; - }; typedef std::shared_ptr PhysicsEnginePointer; From de5fe705a33e171016b9855c9383c147620ba312 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 12:06:47 -0700 Subject: [PATCH 005/128] optimize Bullet broadphase using collision groups --- libraries/shared/src/PhysicsCollisionGroups.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 6d320e69cb..794f338dc5 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -51,10 +51,10 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; // STATIC does not collide with itself (as optimization of physics simulation) -const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_KINEMATIC | BULLET_COLLISION_GROUP_STATIC); const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC; // MY_AVATAR does not collide with itself const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); From 20914df3303e79cd61c79a1c91222171e4c15956 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 13:31:14 -0700 Subject: [PATCH 006/128] fix warning about signed/unsigned comparison --- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 55861e9b3a..973be0b4e8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -201,7 +201,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob // active static bodies have changed (in an Easy way) and need their Aabbs updated // but we've configured Bullet to NOT update them automatically (for improved performance) // so we must do it outselves - for (int i = 0; i < _activeStaticBodies.size(); ++i) { + for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; @@ -399,7 +399,7 @@ const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); // Bullet will not deactivate static objects (it doesn't expect them to be active) // so we must deactivate them ourselves - for (int i = 0; i < _activeStaticBodies.size(); ++i) { + for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); } _activeStaticBodies.clear(); From eaa0ba9e32050e606be26d6822b294477dc8649f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 1 Apr 2016 14:08:30 -0700 Subject: [PATCH 007/128] rename marketplace.js to examples.js --- examples/defaultScripts.js | 2 +- examples/{marketplace.js => examples.js} | 54 ++++++++++++------------ 2 files changed, 27 insertions(+), 29 deletions(-) rename examples/{marketplace.js => examples.js} (66%) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index ab3ff956d4..54b02250ef 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -11,7 +11,7 @@ Script.load("away.js"); Script.load("progress.js"); Script.load("edit.js"); -Script.load("marketplace.js"); +Script.load("examples.js"); Script.load("selectAudioDevice.js"); Script.load("notifications.js"); Script.load("users.js"); diff --git a/examples/marketplace.js b/examples/examples.js similarity index 66% rename from examples/marketplace.js rename to examples/examples.js index 146e55c496..bfa85473de 100644 --- a/examples/marketplace.js +++ b/examples/examples.js @@ -1,5 +1,5 @@ // -// marketplace.js +// examples.js // examples // // Created by Eric Levin on 8 Jan 2016 @@ -16,9 +16,9 @@ Script.include([ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; -var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; -var marketplaceWindow = new OverlayWebWindow({ - title: 'Marketplace', +var EXAMPLES_URL = "https://metaverse.highfidelity.com/examples"; +var examplesWindow = new OverlayWebWindow({ + title: 'Examples', source: "about:blank", width: 900, height: 700, @@ -29,43 +29,43 @@ var toolHeight = 50; var toolWidth = 50; -function showMarketplace(marketplaceID) { - var url = MARKETPLACE_URL; +function showExamples(marketplaceID) { + var url = EXAMPLES_URL; if (marketplaceID) { url = url + "/items/" + marketplaceID; } - print("setting marketplace URL to " + url); - marketplaceWindow.setURL(url); - marketplaceWindow.setVisible(true); + print("setting examples URL to " + url); + examplesWindow.setURL(url); + examplesWindow.setVisible(true); } -function hideMarketplace() { - marketplaceWindow.setVisible(false); - marketplaceWindow.setURL("about:blank"); +function hideExamples() { + examplesWindow.setVisible(false); + examplesWindow.setURL("about:blank"); } -function toggleMarketplace() { - if (marketplaceWindow.visible) { - hideMarketplace(); +function toggleExamples() { + if (examplesWindow.visible) { + hideExamples(); } else { - showMarketplace(); + showExamples(); } } var toolBar = (function() { var that = {}, toolBar, - browseMarketplaceButton; + browseExamplesButton; function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.marketplace.toolbar", function(windowDimensions, toolbar) { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) { return { x: windowDimensions.x - 8 - toolbar.width, y: 135 }; }); - browseMarketplaceButton = toolBar.addTool({ - imageURL: toolIconUrl + "market-01.svg", + browseExamplesButton = toolBar.addTool({ + imageURL: toolIconUrl + "examples-01.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, @@ -79,10 +79,10 @@ var toolBar = (function() { showButtonDown: true }); - toolBar.showTool(browseMarketplaceButton, true); + toolBar.showTool(browseExamplesButton, true); } - var browseMarketplaceButtonDown = false; + var browseExamplesButtonDown = false; that.mousePressEvent = function(event) { var clickedOverlay, url, @@ -98,10 +98,8 @@ var toolBar = (function() { y: event.y }); - - - if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) { - toggleMarketplace(); + if (browseExamplesButton === toolBar.clicked(clickedOverlay)) { + toggleExamples(); return true; } @@ -112,7 +110,7 @@ var toolBar = (function() { var handled = false; - if (browseMarketplaceButtonDown) { + if (browseExamplesButtonDown) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y @@ -120,7 +118,7 @@ var toolBar = (function() { } newModelButtonDown = false; - browseMarketplaceButtonDown = false; + browseExamplesButtonDown = false; return handled; } From 0e9b783ca378ed455a4cde15ca88bda6b424c299 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 13:14:04 -0700 Subject: [PATCH 008/128] Release skybox texs when not rendering --- .../src/EntityTreeRenderer.cpp | 19 +++++++++++++++---- libraries/model/src/model/Skybox.h | 2 ++ .../src/procedural/ProceduralSkybox.cpp | 8 ++++++++ .../src/procedural/ProceduralSkybox.h | 2 ++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index edc7f7d754..b87329d5b6 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -297,7 +297,14 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetLocation(); auto sceneTime = sceneStage->getTime(); + // Skybox and procedural skybox data + auto skybox = std::dynamic_pointer_cast(skyStage->getSkybox()); + static QString userData; + if (!zone) { + userData = QString(); + skybox->clear(); + _pendingSkyboxTexture = false; _skyboxTexture.clear(); @@ -373,9 +380,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetBackgroundMode()) { case BACKGROUND_MODE_SKYBOX: { - auto skybox = std::dynamic_pointer_cast(skyStage->getSkybox()); skybox->setColor(zone->getSkyboxProperties().getColorVec3()); - static QString userData; if (userData != zone->getUserData()) { userData = zone->getUserData(); skybox->parse(userData); @@ -414,9 +419,15 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application background through - _pendingSkyboxTexture = false; + // Clear the skybox to release its textures + userData = QString(); + skybox->clear(); + _skyboxTexture.clear(); + _pendingSkyboxTexture = false; + + // Let the application background through + skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); break; } diff --git a/libraries/model/src/model/Skybox.h b/libraries/model/src/model/Skybox.h index e9e7ee8b26..8c9e7bb1d6 100755 --- a/libraries/model/src/model/Skybox.h +++ b/libraries/model/src/model/Skybox.h @@ -35,6 +35,8 @@ public: void setCubemap(const gpu::TexturePointer& cubemap); const gpu::TexturePointer& getCubemap() const { return _cubemap; } + virtual void clear() { setCubemap(nullptr); } + void prepare(gpu::Batch& batch, int textureSlot = SKYBOX_SKYMAP_SLOT, int bufferSlot = SKYBOX_CONSTANTS_SLOT) const; virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const; diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 4ff38eac74..1aa59c90d7 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -25,6 +25,14 @@ ProceduralSkybox::ProceduralSkybox() : model::Skybox() { _procedural._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)); } +void ProceduralSkybox::clear() { + // Parse and prepare a procedural with no shaders to release textures + parse(QString()); + _procedural.ready(); + + Skybox::clear(); +} + void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const { if (_procedural.ready()) { ProceduralSkybox::render(batch, frustum, (*this)); diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.h b/libraries/procedural/src/procedural/ProceduralSkybox.h index e817ce271d..2b8f2327a0 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.h +++ b/libraries/procedural/src/procedural/ProceduralSkybox.h @@ -24,6 +24,8 @@ public: void parse(const QString& userData) { _procedural.parse(userData); } + virtual void clear() override; + virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const; static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox); From eb2e254aa6372e99a4c0d370a850eb35271e388f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 14:20:28 -0700 Subject: [PATCH 009/128] Release px resources when unused --- .../procedural/src/procedural/Procedural.cpp | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index d3aed38198..cedf76b37a 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -96,6 +96,7 @@ bool Procedural::parseVersion(const QJsonValue& version) { bool Procedural::parseUrl(const QUrl& shaderUrl) { if (!shaderUrl.isValid()) { qWarning() << "Invalid shader URL: " << shaderUrl; + _networkShader.reset(); return false; } @@ -110,6 +111,7 @@ bool Procedural::parseUrl(const QUrl& shaderUrl) { _shaderPath = _shaderUrl.toLocalFile(); qDebug() << "Shader path: " << _shaderPath; if (!QFile(_shaderPath).exists()) { + _networkShader.reset(); return false;; } } else { @@ -135,9 +137,14 @@ bool Procedural::parseTextures(const QJsonArray& channels) { auto textureCache = DependencyManager::get(); size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size()); - for (size_t i = 0; i < channelCount; ++i) { - QString url = _parsedChannels.at((int)i).toString(); - _channels[i] = textureCache->getTexture(QUrl(url)); + size_t channel = 0; + for (; channel < channelCount; ++channel) { + QString url = _parsedChannels.at((int)channel).toString(); + _channels[channel] = textureCache->getTexture(QUrl(url)); + } + for (; channel < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++channel) { + // Release those textures no longer in use + _channels[channel] = textureCache->getTexture(QUrl()); } _channelsDirty = true; @@ -149,20 +156,21 @@ bool Procedural::parseTextures(const QJsonArray& channels) { void Procedural::parse(const QJsonObject& proceduralData) { _enabled = false; - if (proceduralData.isEmpty()) { - return; - } - auto version = proceduralData[VERSION_KEY]; auto shaderUrl = proceduralData[URL_KEY].toString(); shaderUrl = ResourceManager::normalizeURL(shaderUrl); auto uniforms = proceduralData[UNIFORMS_KEY].toObject(); auto channels = proceduralData[CHANNELS_KEY].toArray(); - if (parseVersion(version) && - parseUrl(shaderUrl) && - parseUniforms(uniforms) && - parseTextures(channels)) { + bool isValid = true; + + // Run through parsing regardless of validity to clear old cached resources + isValid = parseVersion(version) && isValid; + isValid = parseUrl(shaderUrl) && isValid; + isValid = parseUniforms(uniforms) && isValid; + isValid = parseTextures(channels) && isValid; + + if (!proceduralData.isEmpty() && isValid) { _enabled = true; } } From b5cbd7720e6ddb5e4fe711886ea3e3cd2c41ce57 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 1 Apr 2016 14:56:56 -0700 Subject: [PATCH 010/128] Lock entity tree on export, and clipboard on import. --- interface/src/Application.cpp | 105 ++++++++++++++------------ libraries/entities/src/EntityTree.cpp | 6 +- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ffc9b0333c..9d4a5e37e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2815,60 +2815,68 @@ bool Application::exportEntities(const QString& filename, const QVectorgetTree(); auto exportTree = std::make_shared(); exportTree->createRootElement(); - glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE); - for (auto entityID : entityIDs) { // Gather entities and properties. - auto entityItem = entityTree->findEntityByEntityItemID(entityID); - if (!entityItem) { - qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; - continue; - } - - if (!givenOffset) { - EntityItemID parentID = entityItem->getParentID(); - if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) { - auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. - root.x = glm::min(root.x, position.x); - root.y = glm::min(root.y, position.y); - root.z = glm::min(root.z, position.z); + bool success = true; + entityTree->withReadLock([&] { + for (auto entityID : entityIDs) { // Gather entities and properties. + auto entityItem = entityTree->findEntityByEntityItemID(entityID); + if (!entityItem) { + qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; + continue; } + + if (!givenOffset) { + EntityItemID parentID = entityItem->getParentID(); + if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) { + auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. + root.x = glm::min(root.x, position.x); + root.y = glm::min(root.y, position.y); + root.z = glm::min(root.z, position.z); + } + } + entities[entityID] = entityItem; } - entities[entityID] = entityItem; - } - if (entities.size() == 0) { - return false; - } + if (entities.size() == 0) { + success = false; + return; + } - if (givenOffset) { - root = *givenOffset; - } - for (EntityItemPointer& entityDatum : entities) { - auto properties = entityDatum->getProperties(); - EntityItemID parentID = properties.getParentID(); - if (parentID.isInvalidID()) { - properties.setPosition(properties.getPosition() - root); - } else if (!entities.contains(parentID)) { - entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root); - } // else valid parent -- don't offset - exportTree->addEntity(entityDatum->getEntityItemID(), properties); - } + if (givenOffset) { + root = *givenOffset; + } + for (EntityItemPointer& entityDatum : entities) { + auto properties = entityDatum->getProperties(); + EntityItemID parentID = properties.getParentID(); + if (parentID.isInvalidID()) { + properties.setPosition(properties.getPosition() - root); + } + else if (!entities.contains(parentID)) { + entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root); + } // else valid parent -- don't offset + exportTree->addEntity(entityDatum->getEntityItemID(), properties); + } + }); + if (success) { + exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); - exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); - - // restore the main window's active state - _window->activateWindow(); - return true; + // restore the main window's active state + _window->activateWindow(); + } + return success; } bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) { glm::vec3 offset(x, y, z); QVector entities; QVector ids; - getEntities()->getTree()->findEntities(AACube(offset, scale), entities); - foreach(EntityItemPointer entity, entities) { - ids << entity->getEntityItemID(); - } + auto entityTree = getEntities()->getTree(); + entityTree->withReadLock([&] { + entityTree->findEntities(AACube(offset, scale), entities); + foreach(EntityItemPointer entity, entities) { + ids << entity->getEntityItemID(); + } + }); return exportEntities(filename, ids, &offset); } @@ -2898,12 +2906,15 @@ void Application::saveSettings() { } bool Application::importEntities(const QString& urlOrFilename) { - _entityClipboard->eraseAllOctreeElements(); + bool success = false; + _entityClipboard->withWriteLock([&] { + _entityClipboard->eraseAllOctreeElements(); - bool success = _entityClipboard->readFromURL(urlOrFilename); - if (success) { - _entityClipboard->reaverageOctreeElements(); - } + success = _entityClipboard->readFromURL(urlOrFilename); + if (success) { + _entityClipboard->reaverageOctreeElements(); + } + }); return success; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 5292e12ae8..6d020941b5 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1313,7 +1313,7 @@ void EntityTree::pruneTree() { } QVector EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z) { + float x, float y, float z) { SendEntitiesOperationArgs args; args.packetSender = packetSender; args.ourTree = this; @@ -1323,7 +1323,9 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen // We need to keep a map so that we can map parent identifiers correctly. QHash map; args.map = ↦ - recurseTreeWithOperation(sendEntitiesOperation, &args); + withReadLock([&] { + recurseTreeWithOperation(sendEntitiesOperation, &args); + }); packetSender->releaseQueuedMessages(); return map.values().toVector(); From cec4175e9ddfe4e2c7c4eddc4da4aa1e3771dfd1 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 1 Apr 2016 15:00:51 -0700 Subject: [PATCH 011/128] whitespace --- libraries/entities/src/EntityTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6d020941b5..92c3ce216f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1313,7 +1313,7 @@ void EntityTree::pruneTree() { } QVector EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z) { + float x, float y, float z) { SendEntitiesOperationArgs args; args.packetSender = packetSender; args.ourTree = this; From 6df7ddeb16ca6f0c7658449643c75ce26ffdf5f2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 1 Apr 2016 15:13:28 -0700 Subject: [PATCH 012/128] pass the HighFidelityInterface user agent with WebView --- interface/resources/qml/controls/WebView.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 1361e6e322..1d07c471b4 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -5,6 +5,8 @@ WebEngineView { id: root property var newUrl; + profile.httpUserAgent: "Chrome/48.0 (HighFidelityInterface)" + Component.onCompleted: { console.log("Connecting JS messaging to Hifi Logging") // Ensure the JS from the web-engine makes it to our logging From 6e83ed5cccc08961b7d140d97cdac4d5a9ab7dbf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 1 Apr 2016 15:49:24 -0700 Subject: [PATCH 013/128] use a more generic custom user agent --- interface/resources/qml/controls/WebView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 1d07c471b4..2f94740fe6 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -5,7 +5,7 @@ WebEngineView { id: root property var newUrl; - profile.httpUserAgent: "Chrome/48.0 (HighFidelityInterface)" + profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)" Component.onCompleted: { console.log("Connecting JS messaging to Hifi Logging") From d72c6954174ac2469d4b4324bc9739b4854b84fd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 16:21:32 -0700 Subject: [PATCH 014/128] Sanitize ResourceCache to expose to JS/QML fix sanitize --- interface/src/Application.cpp | 5 ++--- libraries/networking/src/ResourceCache.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bd1a44fc76..f11fd22e2f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -588,9 +588,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // Model background downloads need to happen on the Datagram Processor Thread. The idle loop will // emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background // downloads. - QSharedPointer modelCacheP = DependencyManager::get(); - ResourceCache* modelCache = modelCacheP.data(); - connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets); + auto modelCache = DependencyManager::get(); + connect(this, &Application::checkBackgroundDownloads, modelCache.data(), &ModelCache::checkAsynchronousGets); // put the audio processing on a separate thread QThread* audioThread = new QThread(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f674c96a1e..10f0289052 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -109,7 +109,7 @@ protected: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \param extra extra data to pass to the creator, if appropriate - Q_INVOKABLE QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), + QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false, void* extra = NULL); /// Creates a new resource. @@ -123,7 +123,7 @@ protected: /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue - Q_INVOKABLE static bool attemptRequest(Resource* resource); + static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); static bool attemptHighestPriorityRequest(); From 3b45a57e1d785d63830e2d31eb989271d0a86b21 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:02:44 -0700 Subject: [PATCH 015/128] Remove resource completely when uncached --- libraries/networking/src/ResourceCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b5f5ca7c25..54b70c7da3 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -142,8 +142,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _unusedResourcesSize -= it.value()->getBytes(); + _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); + _unusedResourcesSize -= it.value()->getBytes(); _unusedResources.erase(it); } } From 5bbca785b345e365a9781c6b433cd3f95cf6f689 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 1 Apr 2016 17:43:10 -0700 Subject: [PATCH 016/128] added new audio room examples --- examples/example/audio/largeHall.js | 120 ++++++++++++++++++++++++++++ examples/example/audio/smallRoom.js | 120 ++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 examples/example/audio/largeHall.js create mode 100644 examples/example/audio/smallRoom.js diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js new file mode 100644 index 0000000000..fd400a6fec --- /dev/null +++ b/examples/example/audio/largeHall.js @@ -0,0 +1,120 @@ +(function() { + var _this = this; +​ + Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); +print("EBL PRELOADING NEW VERSION ") + var audioOptions = new AudioEffectOptions({ + bandwidth: 7000, + preDelay: 80, + lateDelay: 0, + reverbTime: 3, + earlyDiffusion: 100, + lateDiffusion: 100, + roomSize: 50, + density: 100, + bassMult: 1.5, + bassFreq: 250, + highGain: -12, + highFreq: 3000, + modRate: 2.3, + modDepth: 50, + earlyGain: -12, + lateGain: -12, + earlyMixLeft: 20, + earlyMixRight: 20, + lateMixLeft: 90, + lateMixRight: 90, + wetDryMix: 90, +}); +​ +​ +​ + var panel = new Panel(10, 160); +​ +var parameters = [ +// { name: "bandwidth", min: 1000, max: 12000, units: " Hz" }, +// { name: "preDelay", min: 0, max: 333, units: " ms" }, +// { name: "lateDelay", min: 0, max: 166, units: " ms" }, +// { name: "reverbTime", min: 0.1, max: 10, units: " seconds" }, +// { name: "earlyDiffusion", min: 0, max: 100, units: " percent" }, +// { name: "lateDiffusion", min: 0, max: 100, units: " percent" }, +// { name: "roomSize", min: 0, max: 100, units: " percent" }, +// { name: "density", min: 0, max: 100, units: " percent" }, +// { name: "bassMult", min: 0.1, max: 4, units: " ratio" }, +// { name: "bassFreq", min: 10, max: 500, units: " Hz" }, +// { name: "highGain", min: -24, max: 0, units: " dB" }, +// { name: "highFreq", min: 1000, max: 12000, units: " Hz" }, +// { name: "modRate", min: 0.1, max: 10, units: " Hz" }, +// { name: "modDepth", min: 0, max: 100, units: " percent" }, +// { name: "earlyGain", min: -96, max: 24, units: " dB" }, +// { name: "lateGain", min: -96, max: 24, units: " dB" }, +// { name: "earlyMixLeft", min: 0, max: 100, units: " percent" }, +// { name: "earlyMixRight", min: 0, max: 100, units: " percent" }, +// { name: "lateMixLeft", min: 0, max: 100, units: " percent" }, +// { name: "lateMixRight", min: 0, max: 100, units: " percent" }, +// { name: "wetDryMix", min: 0, max: 100, units: " percent" }, +] +​ +​ + 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; + } + } +​ + + function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + } +​ + _this.enterEntity = function(entityID) { + print('EBL I am insiude'); + // 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); + }); +​ + AudioDevice.setReverbOptions(audioOptions); + AudioDevice.setReverb(true); + print("Reverb is ON."); +​ +​ + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; + + _this.leaveEntity = function(entityID) { + print('EBL I am outsidee'); + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); +​ +​ + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; +}); \ No newline at end of file diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js new file mode 100644 index 0000000000..72bf3fb5e6 --- /dev/null +++ b/examples/example/audio/smallRoom.js @@ -0,0 +1,120 @@ +(function() { + var _this = this; +​ + Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); +print("EBL PRELOADING NEW VERSION ") + var audioOptions = new AudioEffectOptions({ + bandwidth: 7000, + preDelay: 20, + lateDelay: 0, + reverbTime: 1.5, + earlyDiffusion: 100, + lateDiffusion: 100, + roomSize: 50, + density: 100, + bassMult: 1.5, + bassFreq: 250, + highGain: -12, + highFreq: 3000, + modRate: 2.3, + modDepth: 50, + earlyGain: -24, + lateGain: -24, + earlyMixLeft: 20, + earlyMixRight: 20, + lateMixLeft: 90, + lateMixRight: 90, + wetDryMix: 70, +}); +​ +​ +​ + var panel = new Panel(10, 160); +​ +var parameters = [ +// { name: "bandwidth", min: 1000, max: 12000, units: " Hz" }, +// { name: "preDelay", min: 0, max: 333, units: " ms" }, +// { name: "lateDelay", min: 0, max: 166, units: " ms" }, +// { name: "reverbTime", min: 0.1, max: 10, units: " seconds" }, +// { name: "earlyDiffusion", min: 0, max: 100, units: " percent" }, +// { name: "lateDiffusion", min: 0, max: 100, units: " percent" }, +// { name: "roomSize", min: 0, max: 100, units: " percent" }, +// { name: "density", min: 0, max: 100, units: " percent" }, +// { name: "bassMult", min: 0.1, max: 4, units: " ratio" }, +// { name: "bassFreq", min: 10, max: 500, units: " Hz" }, +// { name: "highGain", min: -24, max: 0, units: " dB" }, +// { name: "highFreq", min: 1000, max: 12000, units: " Hz" }, +// { name: "modRate", min: 0.1, max: 10, units: " Hz" }, +// { name: "modDepth", min: 0, max: 100, units: " percent" }, +// { name: "earlyGain", min: -96, max: 24, units: " dB" }, +// { name: "lateGain", min: -96, max: 24, units: " dB" }, +// { name: "earlyMixLeft", min: 0, max: 100, units: " percent" }, +// { name: "earlyMixRight", min: 0, max: 100, units: " percent" }, +// { name: "lateMixLeft", min: 0, max: 100, units: " percent" }, +// { name: "lateMixRight", min: 0, max: 100, units: " percent" }, +// { name: "wetDryMix", min: 0, max: 100, units: " percent" }, +] +​ +​ + 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; + } + } +​ + + function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + } +​ + _this.enterEntity = function(entityID) { + print('EBL I am insiude'); + // 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); + }); +​ + AudioDevice.setReverbOptions(audioOptions); + AudioDevice.setReverb(true); + print("Reverb is ON."); +​ +​ + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; + + _this.leaveEntity = function(entityID) { + print('EBL I am outsidee'); + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); +​ +​ + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; +}); \ No newline at end of file From f7f7c18d721aa04d838b8b3fdef62769808dd961 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 1 Apr 2016 17:45:15 -0700 Subject: [PATCH 017/128] added new audio room examples --- examples/example/audio/largeHall.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index fd400a6fec..8a37aa5f4a 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -1,3 +1,16 @@ +// +// largeHall.js +// examples +// +// Created by Freidrica on 4/1/16. +// Copyright 2016 High Fidelity, Inc. +// +// This entity script invokes reverb upon entering an entity acting as a trigger zone + +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// (function() { var _this = this; ​ From 0830c55bcfacef6c6f2fa49ad636acae83b4ed8d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 1 Apr 2016 17:48:56 -0700 Subject: [PATCH 018/128] getLocalEverything->getLocalTransformAndVelocities --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 69614d0d12..5c825495b9 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -886,7 +886,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { Transform transform; glm::vec3 linearVelocity; glm::vec3 angularVelocity; - getLocalEverything(transform, linearVelocity, angularVelocity); + getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); bool isMoving = false; if (glm::length2(angularVelocity) > 0.0f) { @@ -942,7 +942,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { isMoving = true; } } - setLocalEverything(transform, linearVelocity, angularVelocity); + setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); if (!isMoving) { // flag this entity to be removed from kinematic motion _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 550864265f..3cbd3c5ac9 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -843,7 +843,7 @@ AACube SpatiallyNestable::getQueryAACube() const { return result; } -void SpatiallyNestable::getLocalEverything( +void SpatiallyNestable::getLocalTransformAndVelocities( Transform& transform, glm::vec3& velocity, glm::vec3& angularVelocity) const { @@ -861,7 +861,7 @@ void SpatiallyNestable::getLocalEverything( }); } -void SpatiallyNestable::setLocalEverything( +void SpatiallyNestable::setLocalTransformAndVelocities( const Transform& localTransform, const glm::vec3& localVelocity, const glm::vec3& localAngularVelocity) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6546d46e51..ef70d0231b 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,9 +149,9 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalEverything(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; + void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - void setLocalEverything( + void setLocalTransformAndVelocities( const Transform& localTransform, const glm::vec3& localVelocity, const glm::vec3& localAngularVelocity); From 048d745af90710f3685798cc91a2c35c9cd8e185 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 1 Apr 2016 17:53:02 -0700 Subject: [PATCH 019/128] update --- examples/example/audio/largeHall.js | 4 ++-- examples/example/audio/smallRoom.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index 8a37aa5f4a..fc69aeb8b8 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -15,7 +15,7 @@ var _this = this; ​ Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); -print("EBL PRELOADING NEW VERSION ") + print("EBL PRELOADING NEW VERSION ") var audioOptions = new AudioEffectOptions({ bandwidth: 7000, preDelay: 80, @@ -123,7 +123,7 @@ var parameters = [ _this.leaveEntity = function(entityID) { print('EBL I am outsidee'); - panel.destroy(); + panel.destroy(); AudioDevice.setReverb(false); print("Reverb is OFF."); ​ diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js index 72bf3fb5e6..3deffa6c6c 100644 --- a/examples/example/audio/smallRoom.js +++ b/examples/example/audio/smallRoom.js @@ -1,3 +1,17 @@ +// +// smallRoom.js +// examples +// +// Created by Freidrica on 4/1/16. +// Copyright 2016 High Fidelity, Inc. +// +// This entity script invokes reverb upon entering an entity acting as a trigger zone + +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + (function() { var _this = this; ​ From b70a4d043bdfa9f6906e76e732198a796eb5c062 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:33:12 -0700 Subject: [PATCH 020/128] Expose resource cache count props --- libraries/networking/src/ResourceCache.cpp | 23 +++++++++++++++--- libraries/networking/src/ResourceCache.h | 27 ++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 54b70c7da3..c10b96ca19 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -114,6 +114,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); + emit dirty(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -127,6 +128,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); + emit dirty(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -134,6 +136,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } + emit dirty(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -142,9 +145,13 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); - _unusedResourcesSize -= it.value()->getBytes(); + auto size = it.value()->getBytes(); + + _totalResourcesSize -= size; + _resources.remove(it.value()->getURL()); + + _unusedResourcesSize -= size; _unusedResources.erase(it); } } @@ -160,6 +167,11 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { + _totalResourcesSize += (newSize - oldSize); + emit dirty(); +} + void ResourceCacheSharedItems::appendActiveRequest(Resource* resource) { Lock lock(_mutex); _loadingRequests.append(resource); @@ -378,6 +390,11 @@ void Resource::finishedLoading(bool success) { emit finished(success); } +void Resource::setBytes(const qint64& bytes) { + QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); + _bytes = bytes; +} + void Resource::reinsert() { _cache->_resources.insert(_url, _self); } @@ -413,7 +430,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - _bytes = _bytesTotal; + setBytes(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 10f0289052..f113254995 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -79,8 +79,18 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT + Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) public: + int getNumTotalResources() const { return _resources.size(); } + qint64 getSizeTotalResources() const { return _totalResourcesSize; } + + int getNumCachedResources() const { return _unusedResources.size(); } + qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -101,9 +111,15 @@ public: void refreshAll(); void refresh(const QUrl& url); +signals: + void dirty(); + public slots: void checkAsynchronousGets(); +protected slots: + void updateTotalSize(const qint64& oldSize, const qint64& newSize); + protected: /// Loads a resource from the specified URL. /// \param fallback a fallback URL to load if the desired one is unavailable @@ -118,8 +134,6 @@ protected: void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); - void reserveUnusedResource(qint64 resourceSize); - void clearUnusedResource(); /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue @@ -130,6 +144,9 @@ protected: private: friend class Resource; + void reserveUnusedResource(qint64 resourceSize); + void clearUnusedResource(); + QHash> _resources; int _lastLRUKey = 0; @@ -140,8 +157,10 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; + qint64 _totalResourcesSize { 0 }; + qint64 _unusedResourcesSize { 0 }; + qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; - qint64 _unusedResourcesSize = 0; QMap> _unusedResources; }; @@ -226,7 +245,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(qint64 bytes) { _bytes = bytes; } + void setBytes(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing. From 5b9198ed3d5df8b6cb69b95b8a6afb6b6dc433e9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:41:57 -0700 Subject: [PATCH 021/128] Expose tex/model cache to js/qml --- interface/src/Application.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f11fd22e2f..802c2569c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1351,7 +1351,6 @@ void Application::initializeUi() { // though I can't find it. Hence, "ApplicationInterface" rootContext->setContextProperty("SnapshotUploader", new SnapshotUploader()); rootContext->setContextProperty("ApplicationInterface", this); - rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); @@ -1381,8 +1380,13 @@ void Application::initializeUi() { rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); + rootContext->setContextProperty("TextureCache", DependencyManager::get().data()); + rootContext->setContextProperty("ModelCache", DependencyManager::get().data()); rootContext->setContextProperty("SoundCache", DependencyManager::get().data()); + rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); @@ -4334,8 +4338,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); From 36e04f4434ec71894cf211d3ded0a039aabb231c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 18:22:51 -0700 Subject: [PATCH 022/128] Mv PlotPerf to shared dir --- examples/utilities/{render => lib}/plotperf/PlotPerf.qml | 0 examples/utilities/{render => lib}/plotperf/qmldir | 0 examples/utilities/render/stats.qml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/utilities/{render => lib}/plotperf/PlotPerf.qml (100%) rename examples/utilities/{render => lib}/plotperf/qmldir (100%) diff --git a/examples/utilities/render/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml similarity index 100% rename from examples/utilities/render/plotperf/PlotPerf.qml rename to examples/utilities/lib/plotperf/PlotPerf.qml diff --git a/examples/utilities/render/plotperf/qmldir b/examples/utilities/lib/plotperf/qmldir similarity index 100% rename from examples/utilities/render/plotperf/qmldir rename to examples/utilities/lib/plotperf/qmldir diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0e51cb8834..0902695f93 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 -import "plotperf" +import "../lib/plotperf" Item { id: statsUI From 41cdb29bd23ab44ee6d2864566ce6a82bc1c4b94 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:51:05 -0700 Subject: [PATCH 023/128] Use a timer in plotperf --- examples/utilities/lib/plotperf/PlotPerf.qml | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/examples/utilities/lib/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml index 179707c0f1..6871ffe6a6 100644 --- a/examples/utilities/lib/plotperf/PlotPerf.qml +++ b/examples/utilities/lib/plotperf/PlotPerf.qml @@ -19,12 +19,8 @@ Item { // The title of the graph property string title - // THe object used as the default source object for the prop plots + // The object used as the default source object for the prop plots property var object - - // THis is my hack to get a property and assign it to a trigger var in order to get - // a signal called whenever the value changed - property var trigger // Plots is an array of plot descriptor // a default plot descriptor expects the following object: @@ -55,45 +51,38 @@ Item { property var tick : 0 function createValues() { - print("trigger is: " + JSON.stringify(trigger)) - if (Array.isArray(plots)) { - for (var i =0; i < plots.length; i++) { - var plot = plots[i]; - print(" a pnew Plot:" + JSON.stringify(plot)); - _values.push( { - object: (plot["object"] !== undefined ? plot["object"] : root.object), - value: plot["prop"], - valueMax: 1, - numSamplesConstantMax: 0, - valueHistory: new Array(), - label: (plot["label"] !== undefined ? plot["label"] : ""), - color: (plot["color"] !== undefined ? plot["color"] : "white"), - scale: (plot["scale"] !== undefined ? plot["scale"] : 1), - unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) - }) - } + for (var i =0; i < plots.length; i++) { + var plot = plots[i]; + _values.push( { + object: (plot["object"] !== undefined ? plot["object"] : root.object), + value: plot["prop"], + valueMax: 1, + numSamplesConstantMax: 0, + valueHistory: new Array(), + label: (plot["label"] !== undefined ? plot["label"] : ""), + color: (plot["color"] !== undefined ? plot["color"] : "white"), + scale: (plot["scale"] !== undefined ? plot["scale"] : 1), + unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) + }) } - print("in creator" + JSON.stringify(_values)); - + pullFreshValues(); } Component.onCompleted: { createValues(); - print(JSON.stringify(_values)); - } function pullFreshValues() { - //print("pullFreshValues"); + // Wait until values are created to begin pulling + if (!_values) { return; } + var VALUE_HISTORY_SIZE = 100; - var UPDATE_CANVAS_RATE = 20; tick++; - var currentValueMax = 0 for (var i = 0; i < _values.length; i++) { - var currentVal = _values[i].object[_values[i].value] * _values[i].scale; + var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale; _values[i].valueHistory.push(currentVal) _values[i].numSamplesConstantMax++; @@ -125,11 +114,13 @@ Item { valueMax = currentValueMax; } - if (tick % UPDATE_CANVAS_RATE == 0) { - mycanvas.requestPaint() - } + mycanvas.requestPaint() + } + + Timer { + interval: 100; running: true; repeat: true + onTriggered: pullFreshValues() } - onTriggerChanged: pullFreshValues() Canvas { id: mycanvas @@ -165,9 +156,9 @@ Item { ctx.fillStyle = val.color; var bestValue = val.valueHistory[val.valueHistory.length -1]; ctx.textAlign = "right"; - ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); + ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1); ctx.textAlign = "left"; - ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); + ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1); } function displayTitle(ctx, text, maxVal) { From b0185dc355590eb578004b4f6c7e47eedf07dfad Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:52:08 -0700 Subject: [PATCH 024/128] Add cacheStats.js --- examples/utilities/cache/cacheStats.js | 21 +++++++ examples/utilities/cache/stats.qml | 77 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 examples/utilities/cache/cacheStats.js create mode 100644 examples/utilities/cache/stats.qml diff --git a/examples/utilities/cache/cacheStats.js b/examples/utilities/cache/cacheStats.js new file mode 100644 index 0000000000..e58a5d0e21 --- /dev/null +++ b/examples/utilities/cache/cacheStats.js @@ -0,0 +1,21 @@ +// +// cacheStats.js +// examples/utilities/cache +// +// Zach Pomerantz, created on 4/1/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Set up the qml ui +var qml = Script.resolvePath('stats.qml'); +var window = new OverlayWindow({ + title: 'Cache Stats', + source: qml, + width: 300, + height: 200 +}); +window.setPosition(500, 50); +window.closed.connect(function() { Script.stop(); }); diff --git a/examples/utilities/cache/stats.qml b/examples/utilities/cache/stats.qml new file mode 100644 index 0000000000..d7888eb1aa --- /dev/null +++ b/examples/utilities/cache/stats.qml @@ -0,0 +1,77 @@ +// +// stats.qml +// examples/utilities/cache +// +// Created by Zach Pomerantz on 4/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../lib/plotperf" + +Item { + id: root + anchors.fill: parent + + property var caches: [["Animation", AnimationCache], ["Model", ModelCache], ["Texture", TextureCache], ["Sound", SoundCache]] + + Grid { + id: grid + rows: root.caches.length; columns: 1; spacing: 8 + anchors.fill: parent + + Repeater { + id: repeater + + model: root.caches + + Row { + PlotPerf { + title: modelData[0] + " Count" + anchors.left: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueNumDigits: "1" + plots: [ + { + prop: "numTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "numCached", + label: "cached", + color: "#1AC567" + } + ] + } + PlotPerf { + title: modelData[0] + " Size" + anchors.right: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueScale: 1048576 + valueUnit: "Mb" + valueNumDigits: "1" + plots: [ + { + prop: "sizeTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "sizeCached", + label: "cached", + color: "#1AC567" + } + ] + } + } + } + } +} From d78338330c70a8328f2c4a9ee604b5ffb78a3beb Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:53:41 -0700 Subject: [PATCH 025/128] Rm unused trigger from renderStats --- examples/utilities/render/stats.qml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0902695f93..4988c23e3b 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -32,7 +32,6 @@ Item { title: "Num Buffers" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUCount"] plots: [ { prop: "bufferCPUCount", @@ -50,7 +49,6 @@ Item { title: "gpu::Buffer Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -71,7 +69,6 @@ Item { title: "Num Textures" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUCount"] plots: [ { prop: "textureCPUCount", @@ -94,7 +91,6 @@ Item { title: "gpu::Texture Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -116,7 +112,6 @@ Item { title: "Triangles" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameTriangleCount"] valueScale: 1000 valueUnit: "K" plots: [ @@ -138,7 +133,6 @@ Item { title: "Drawcalls" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameDrawcallCount"] plots: [ { prop: "frameAPIDrawcallCount", @@ -168,7 +162,6 @@ Item { title: "Items" height: parent.evalEvenHeight() object: parent.drawOpaqueConfig - trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"] plots: [ { object: Render.getConfig("DrawOpaqueDeferred"), From 3c86191a59f7f68cdcb0526b071480151e598cb5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sat, 2 Apr 2016 17:17:06 -0700 Subject: [PATCH 026/128] Add resources prop to caches --- libraries/networking/src/ResourceCache.cpp | 10 ++++++++++ libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c10b96ca19..1f687593bb 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -56,6 +56,16 @@ void ResourceCache::refresh(const QUrl& url) { } } +const QVariantList ResourceCache::getResourceList() const { + QVariantList list; + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } + return list; +} + void ResourceCache::setRequestLimit(int limit) { _requestLimit = limit; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f113254995..3f930a1f11 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -83,6 +83,7 @@ class ResourceCache : public QObject { Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) + Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) public: int getNumTotalResources() const { return _resources.size(); } @@ -91,6 +92,8 @@ public: int getNumCachedResources() const { return _unusedResources.size(); } qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + const QVariantList getResourceList() const; + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } From 865a77ae2016c171287d0f65e5b3823f77beef49 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sat, 2 Apr 2016 21:48:22 -0700 Subject: [PATCH 027/128] Model: fixed two crash issues when changing avatars * When the GeometryReader has the last ref to the GeometryResource ptr It needs to hold on to the reference until invokeMethod is completed. Otherwise, invokeMethod will call a method on a deleted object, leading to memory corruption or crashes. * When the Model URL is changed, the clusterMatrices are invalided and the RenderItemsSets are cleared. However, there still might be renderItems in the scene pending changes list that might refer to those RenderItems and their clusterMatrices. We need to guard against this access to prevent reading from memory that was previously freed. Both of these issues were uncovered using the [avatar-thrasher](https://gist.github.com/hyperlogic/d82a61d141df43d576428501a82c5ee6) test script. --- .../src/model-networking/ModelCache.cpp | 25 +++++++++++++------ libraries/render-utils/src/Model.cpp | 7 ++++-- libraries/render-utils/src/Model.h | 2 ++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 41c2a2e194..9b5acc726e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -118,10 +118,8 @@ void GeometryReader::run() { } QThread::currentThread()->setPriority(QThread::LowPriority); - // Ensure the resource is still being requested - auto resource = _resource.toStrongRef(); - if (!resource) { - qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + if (!_resource.data()) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; resource was deleted"; return; } @@ -146,14 +144,27 @@ void GeometryReader::run() { throw QString("unsupported format"); } - QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", - Q_ARG(void*, fbxGeometry)); + // Ensure the resource has not been deleted, and won't be while invoke method is in flight. + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + } else { + QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", Qt::BlockingQueuedConnection, Q_ARG(void*, fbxGeometry)); + } } else { throw QString("url is invalid"); } } catch (const QString& error) { + qCDebug(modelnetworking) << "Error reading " << _url << ": " << error; - QMetaObject::invokeMethod(resource.data(), "finishedLoading", Q_ARG(bool, false)); + + auto resource = _resource.toStrongRef(); + // Ensure the resoruce has not been deleted, and won't be while invoke method is in flight. + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + } else { + QMetaObject::invokeMethod(resource.data(), "finishedLoading", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); + } } QThread::currentThread()->setPriority(originalPriority); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 858f7d3ee7..eda856342c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -159,11 +159,13 @@ void Model::updateRenderItems() { Transform collisionMeshOffset; collisionMeshOffset.postTranslate(self->_offset); + uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; + render::PendingChanges pendingChanges; foreach (auto itemID, self->_modelMeshRenderItems.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset](ModelMeshPartPayload& data) { + pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset, deleteGeometryCounter](ModelMeshPartPayload& data) { // Ensure the model geometry was not reset between frames - if (data._model->isLoaded()) { + if (data._model && data._model->isLoaded() && deleteGeometryCounter == data._model->_deleteGeometryCounter) { // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); @@ -1146,6 +1148,7 @@ void Model::setBlendedVertices(int blendNumber, const std::weak_ptrdestroyAnimGraph(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4e6e727b44..581184918d 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -394,6 +394,8 @@ protected: friend class ModelMeshPartPayload; RigPointer _rig; + + uint32_t _deleteGeometryCounter { 0 }; }; Q_DECLARE_METATYPE(ModelPointer) From 07cfa13a8249599f483c432eec06ec440eec2795 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 3 Apr 2016 09:23:53 -0700 Subject: [PATCH 028/128] GeometryReader: We should delete the fbxGeometry if we've lost the resource. --- .../model-networking/src/model-networking/ModelCache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 9b5acc726e..c8fe82abb4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -144,10 +144,11 @@ void GeometryReader::run() { throw QString("unsupported format"); } - // Ensure the resource has not been deleted, and won't be while invoke method is in flight. + // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight. auto resource = _resource.toStrongRef(); if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + delete fbxGeometry; } else { QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", Qt::BlockingQueuedConnection, Q_ARG(void*, fbxGeometry)); } @@ -159,7 +160,7 @@ void GeometryReader::run() { qCDebug(modelnetworking) << "Error reading " << _url << ": " << error; auto resource = _resource.toStrongRef(); - // Ensure the resoruce has not been deleted, and won't be while invoke method is in flight. + // Ensure the resoruce has not been deleted, and won't be while invokeMethod is in flight. if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; } else { From fc19b60f8a247decb9f469717f7dd53046ae57e6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sun, 3 Apr 2016 06:05:16 -0700 Subject: [PATCH 029/128] Avoid setting null texs on uncaching models --- libraries/model-networking/src/model-networking/ModelCache.cpp | 2 +- libraries/model-networking/src/model-networking/ModelCache.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 41c2a2e194..68606dbc7d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -232,7 +232,7 @@ std::shared_ptr ModelCache::getGeometry(const QUrl& url, const GeometryExtra geometryExtra = { mapping, textureBaseUrl }; GeometryResource::Pointer resource = getResource(url, QUrl(), true, &geometryExtra).staticCast(); if (resource) { - if (resource->isLoaded() && !resource->hasTextures()) { + if (resource->isLoaded() && resource->shouldSetTextures()) { resource->setTextures(); } return std::make_shared(resource); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 81883d972d..f479dc9ce2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -107,7 +107,8 @@ protected: friend class GeometryMappingResource; // Geometries may not hold onto textures while cached - that is for the texture cache - bool hasTextures() const { return !_materials.empty(); } + // Instead, these methods clear and reset textures from the geometry when caching/loading + bool shouldSetTextures() const { return _geometry && _materials.empty(); } void setTextures(); void resetTextures(); From 79e528633584f111a2c9a9fcdec07e8b798838d0 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sun, 3 Apr 2016 11:53:59 -0700 Subject: [PATCH 030/128] Fix ImageReader threading issues --- .../src/model-networking/TextureCache.cpp | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..ff189b46f7 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -196,7 +196,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture { _textureLoader = textureLoader; } - + NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { switch (_type) { case CUBE_TEXTURE: { @@ -240,14 +240,14 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& texture, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url = QUrl()); virtual void run(); private: static void listSupportedImageFormats(); - QWeakPointer _texture; + QWeakPointer _resource; QUrl _url; QByteArray _content; }; @@ -261,9 +261,9 @@ void NetworkTexture::loadContent(const QByteArray& content) { QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); } -ImageReader::ImageReader(const QWeakPointer& texture, const QByteArray& data, +ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url) : - _texture(texture), + _resource(resource), _url(url), _content(data) { @@ -284,25 +284,25 @@ void ImageReader::run() { } QThread::currentThread()->setPriority(QThread::LowPriority); - auto texture = _texture.toStrongRef(); - if (!texture) { - qCWarning(modelnetworking) << "Could not get strong ref"; + if (!_resource.data()) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + QThread::currentThread()->setPriority(originalPriority); return; } listSupportedImageFormats(); - // try to help the QImage loader by extracting the image file format from the url filename ext - // Some tga are not created properly for example without it + // Help the QImage loader by extracting the image file format from the url filename ext. + // Some tga are not created properly without it. auto filename = _url.fileName().toStdString(); auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); QImage image = QImage::fromData(_content, filenameExtension.c_str()); // Note that QImage.format is the pixel format which is different from the "format" of the image file... - auto imageFormat = image.format(); + auto imageFormat = image.format(); int originalWidth = image.width(); int originalHeight = image.height(); - + if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; @@ -312,15 +312,31 @@ void ImageReader::run() { return; } - gpu::Texture* theTexture = nullptr; - auto ntex = texture.dynamicCast(); - if (ntex) { - theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); + gpu::Texture* texture = nullptr; + { + // Double-check the resource still exists between long operations. + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + QThread::currentThread()->setPriority(originalPriority); + return; + } + + auto url = _url.toString().toStdString(); + texture = resource.dynamicCast()->getTextureLoader()(image, url); + } + + // Ensure the resource has not been deleted, and won't be while invokeMethod is in flight. + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + delete texture; + } else { + QMetaObject::invokeMethod(resource.data(), "setImage", Qt::BlockingQueuedConnection, + Q_ARG(void*, texture), + Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } - QMetaObject::invokeMethod(texture.data(), "setImage", - Q_ARG(void*, theTexture), - Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); QThread::currentThread()->setPriority(originalPriority); } @@ -328,9 +344,9 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth, int originalHeight) { _originalWidth = originalWidth; _originalHeight = originalHeight; - + gpu::Texture* texture = static_cast(voidTexture); - + // Passing ownership _textureSource->resetTexture(texture); auto gpuTexture = _textureSource->getGPUTexture(); From 7ea81f39379105104e8e3505b31025599c42dbe6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 Apr 2016 19:15:01 -0700 Subject: [PATCH 031/128] add and fix comments --- libraries/physics/src/ObjectMotionState.cpp | 5 ++++- libraries/physics/src/PhysicsEngine.cpp | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 6b2022e204..e902758461 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -38,8 +38,11 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } +// We init worldSimulationStep to 1 instead of 0 because we initialize _lastKineticStep to (worldSimulationStep - 1) +// so that the object starts moving on the first frame that it was set kinematic. +static uint32_t worldSimulationStep { 1 }; + // static -uint32_t worldSimulationStep = 1; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 973be0b4e8..be80149c96 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,6 +50,12 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + + // By default Bullet will update the Aabb's of all objects every frame, even statics. + // This can waste CPU cycles so we configure Bullet to only update ACTIVE objects here. + // However, this means when a static object is moved we must manually update its Aabb + // in order for its broadphase collision queries to work correctly. Look at how we use + // _activeStaticBodies to track and update the Aabb's of moved static objects. _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -200,7 +206,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob } // active static bodies have changed (in an Easy way) and need their Aabbs updated // but we've configured Bullet to NOT update them automatically (for improved performance) - // so we must do it outselves + // so we must do it ourselves for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } From 74058ac049336dbdf7a332b6458be7ee68b7e8f5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 3 Apr 2016 19:15:16 -0700 Subject: [PATCH 032/128] more correct moving test for ballistic kinematics --- libraries/entities/src/EntityItem.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5c825495b9..5b9791ca7b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -919,7 +919,8 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } glm::vec3 linearAcceleration = _acceleration; - if (glm::length2(_acceleration) > 0.0f) { + bool nonZeroAcceleration = (glm::length2(_acceleration) > 0.0f); + if (nonZeroAcceleration) { // acceleration is in world-frame but we need it in local-frame bool success; Transform parentTransform = getParentTransform(success); @@ -928,17 +929,20 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } } + // integrate position forward + glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) + 0.5f * linearAcceleration * timeElapsed * timeElapsed; + transform.setTranslation(position); + // integrate linearVelocity linearVelocity += linearAcceleration * timeElapsed; const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { setVelocity(ENTITY_ITEM_ZERO_VEC3); + if (nonZeroAcceleration) { + isMoving = true; + } } else { - // integrate position forward - // NOTE: we're using the NEW linear velocity, which is why we negate the acceleration term - glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) - 0.5f * linearAcceleration * timeElapsed * timeElapsed; - transform.setTranslation(position); isMoving = true; } } From 4f373937f9dc94d54cf4da57fa612de801f9539d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 2 Apr 2016 20:37:11 -0700 Subject: [PATCH 033/128] Additional performance markers --- libraries/fbx/src/FBXReader_Node.cpp | 22 +++++++++++-------- libraries/fbx/src/OBJReader.cpp | 17 ++++++++------ .../src/model-networking/TextureCache.cpp | 4 ++++ libraries/shared/src/shared/NsightHelpers.h | 2 +- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index a6fba5a4d5..68e9d6abac 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -9,17 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "FBXReader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + template int streamSize() { return sizeof(T); } @@ -299,6 +302,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { } FBXNode FBXReader::parseFBX(QIODevice* device) { + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, device); // verify the prolog const QByteArray BINARY_PROLOG = "Kaydara FBX Binary "; if (device->peek(BINARY_PROLOG.size()) != BINARY_PROLOG) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c28d680fb0..84c6c7aaa4 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -12,17 +12,20 @@ // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ // http://paulbourke.net/dataformats/obj/ +#include "OBJReader.h" -#include -#include -#include -#include -#include #include // .obj files are not locale-specific. The C/ASCII charset applies. +#include +#include +#include +#include +#include + +#include #include + #include "FBXReader.h" -#include "OBJReader.h" #include "ModelFormatLogging.h" QHash COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f}, @@ -404,7 +407,7 @@ done: FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) { - + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr); QBuffer buffer { &model }; buffer.open(QIODevice::ReadOnly); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..6870fa9b72 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -21,6 +21,8 @@ #include #include #include + +#include #include #include @@ -278,6 +280,7 @@ void ImageReader::listSupportedImageFormats() { } void ImageReader::run() { + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr); auto originalPriority = QThread::currentThread()->priority(); if (originalPriority == QThread::InheritPriority) { originalPriority = QThread::NormalPriority; @@ -315,6 +318,7 @@ void ImageReader::run() { gpu::Texture* theTexture = nullptr; auto ntex = texture.dynamicCast(); if (ntex) { + PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr); theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); } diff --git a/libraries/shared/src/shared/NsightHelpers.h b/libraries/shared/src/shared/NsightHelpers.h index 9853171b34..c637c78162 100644 --- a/libraries/shared/src/shared/NsightHelpers.h +++ b/libraries/shared/src/shared/NsightHelpers.h @@ -20,7 +20,7 @@ public: }; #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); -#define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, payload); +#define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, (uint64_t)payload); #else #define PROFILE_RANGE(name) #define PROFILE_RANGE_EX(name, argbColor, payload) From 667c27866ed152019f2a5e0762aacc592d4fa747 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 3 Apr 2016 20:15:42 -0700 Subject: [PATCH 034/128] Pushing texel format translation into header --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 364 +------------------- libraries/gpu/src/gpu/GLTexelFormat.h | 372 +++++++++++++++++++++ 2 files changed, 373 insertions(+), 363 deletions(-) create mode 100644 libraries/gpu/src/gpu/GLTexelFormat.h diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 3fc7906285..242b9100e1 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -10,6 +10,7 @@ // #include "GPULogging.h" #include "GLBackendShared.h" +#include "GLTexelFormat.h" using namespace gpu; @@ -36,369 +37,6 @@ void GLBackend::GLTexture::setSize(GLuint size) { _size = size; } -class GLTexelFormat { -public: - GLenum internalFormat; - GLenum format; - GLenum type; - - static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { - if (dstFormat != srcFormat) { - GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - - switch(dstFormat.getDimension()) { - case gpu::SCALAR: { - texel.format = GL_RED; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RED; - break; - case gpu::DEPTH: - texel.internalFormat = GL_DEPTH_COMPONENT; - break; - case gpu::DEPTH_STENCIL: - texel.type = GL_UNSIGNED_INT_24_8; - texel.format = GL_DEPTH_STENCIL; - texel.internalFormat = GL_DEPTH24_STENCIL8; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - case gpu::VEC2: { - texel.format = GL_RG; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RG; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC3: { - texel.format = GL_RGB; - - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RGB; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC4: { - texel.format = GL_RGBA; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(srcFormat.getSemantic()) { - case gpu::BGRA: - case gpu::SBGRA: - texel.format = GL_BGRA; - break; - case gpu::RGB: - case gpu::RGBA: - case gpu::SRGB: - case gpu::SRGBA: - default: - break; - }; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - texel.internalFormat = GL_RGB; - break; - case gpu::RGBA: - texel.internalFormat = GL_RGBA; - break; - case gpu::SRGB: - texel.internalFormat = GL_SRGB; - break; - case gpu::SRGBA: - texel.internalFormat = GL_SRGB_ALPHA; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - return texel; - } else { - GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - - switch(dstFormat.getDimension()) { - case gpu::SCALAR: { - texel.format = GL_RED; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - case gpu::SRGB: - case gpu::SRGBA: - texel.internalFormat = GL_RED; - switch (dstFormat.getType()) { - case gpu::UINT32: { - texel.internalFormat = GL_R32UI; - break; - } - case gpu::INT32: { - texel.internalFormat = GL_R32I; - break; - } - case gpu::NUINT32: { - texel.internalFormat = GL_RED; - break; - } - case gpu::NINT32: { - texel.internalFormat = GL_RED_SNORM; - break; - } - case gpu::FLOAT: { - texel.internalFormat = GL_R32F; - break; - } - case gpu::UINT16: { - texel.internalFormat = GL_R16UI; - break; - } - case gpu::INT16: { - texel.internalFormat = GL_R16I; - break; - } - case gpu::NUINT16: { - texel.internalFormat = GL_R16; - break; - } - case gpu::NINT16: { - texel.internalFormat = GL_R16_SNORM; - break; - } - case gpu::HALF: { - texel.internalFormat = GL_R16F; - break; - } - case gpu::UINT8: { - texel.internalFormat = GL_R8UI; - break; - } - case gpu::INT8: { - texel.internalFormat = GL_R8I; - break; - } - case gpu::NUINT8: { - if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { - texel.internalFormat = GL_SLUMINANCE; - } else { - texel.internalFormat = GL_R8; - } - break; - } - case gpu::NINT8: { - texel.internalFormat = GL_R8_SNORM; - break; - } - case gpu::NUM_TYPES: { // quiet compiler - Q_UNREACHABLE(); - } - - } - break; - - case gpu::R11G11B10: - texel.format = GL_RGB; - // the type should be float - texel.internalFormat = GL_R11F_G11F_B10F; - break; - - case gpu::DEPTH: - texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it - texel.internalFormat = GL_DEPTH_COMPONENT; - switch (dstFormat.getType()) { - case gpu::UINT32: - case gpu::INT32: - case gpu::NUINT32: - case gpu::NINT32: { - texel.internalFormat = GL_DEPTH_COMPONENT32; - break; - } - case gpu::FLOAT: { - texel.internalFormat = GL_DEPTH_COMPONENT32F; - break; - } - case gpu::UINT16: - case gpu::INT16: - case gpu::NUINT16: - case gpu::NINT16: - case gpu::HALF: { - texel.internalFormat = GL_DEPTH_COMPONENT16; - break; - } - case gpu::UINT8: - case gpu::INT8: - case gpu::NUINT8: - case gpu::NINT8: { - texel.internalFormat = GL_DEPTH_COMPONENT24; - break; - } - case gpu::NUM_TYPES: { // quiet compiler - Q_UNREACHABLE(); - } - } - break; - case gpu::DEPTH_STENCIL: - texel.type = GL_UNSIGNED_INT_24_8; - texel.format = GL_DEPTH_STENCIL; - texel.internalFormat = GL_DEPTH24_STENCIL8; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC2: { - texel.format = GL_RG; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RG; - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - - break; - } - - case gpu::VEC3: { - texel.format = GL_RGB; - - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RGB; - break; - case gpu::SRGB: - case gpu::SRGBA: - texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - case gpu::VEC4: { - texel.format = GL_RGBA; - texel.type = _elementTypeToGLType[dstFormat.getType()]; - - switch(dstFormat.getSemantic()) { - case gpu::RGB: - texel.internalFormat = GL_RGB; - break; - case gpu::RGBA: - texel.internalFormat = GL_RGBA; - switch (dstFormat.getType()) { - case gpu::UINT32: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA32UI; - break; - case gpu::INT32: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA32I; - break; - case gpu::FLOAT: - texel.internalFormat = GL_RGBA32F; - break; - case gpu::UINT16: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA16UI; - break; - case gpu::INT16: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA16I; - break; - case gpu::NUINT16: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16; - break; - case gpu::NINT16: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16_SNORM; - break; - case gpu::HALF: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA16F; - break; - case gpu::UINT8: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA8UI; - break; - case gpu::INT8: - texel.format = GL_RGBA_INTEGER; - texel.internalFormat = GL_RGBA8I; - break; - case gpu::NUINT8: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA8; - break; - case gpu::NINT8: - texel.format = GL_RGBA; - texel.internalFormat = GL_RGBA8_SNORM; - break; - case gpu::NUINT32: - case gpu::NINT32: - case gpu::NUM_TYPES: // quiet compiler - Q_UNREACHABLE(); - } - break; - case gpu::SRGB: - texel.internalFormat = GL_SRGB; - break; - case gpu::SRGBA: - texel.internalFormat = GL_SRGB_ALPHA; // standard 2.2 gamma correction color - break; - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - break; - } - - default: - qCDebug(gpulogging) << "Unknown combination of texel format"; - } - return texel; - } - } -}; - - GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { GLTexture* object = Backend::getGPUObject(texture); diff --git a/libraries/gpu/src/gpu/GLTexelFormat.h b/libraries/gpu/src/gpu/GLTexelFormat.h new file mode 100644 index 0000000000..274b5eeba3 --- /dev/null +++ b/libraries/gpu/src/gpu/GLTexelFormat.h @@ -0,0 +1,372 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLBackendShared.h" + +class GLTexelFormat { +public: + GLenum internalFormat; + GLenum format; + GLenum type; + + static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) { + using namespace gpu; + if (dstFormat != srcFormat) { + GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_R8; + break; + case gpu::DEPTH: + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (srcFormat.getSemantic()) { + case gpu::BGRA: + case gpu::SBGRA: + texel.format = GL_BGRA; + break; + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + default: + break; + }; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + break; + case gpu::SRGB: + texel.internalFormat = GL_SRGB8; + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + return texel; + } else { + GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + texel.internalFormat = GL_R8; + switch (dstFormat.getType()) { + case gpu::UINT32: { + texel.internalFormat = GL_R32UI; + break; + } + case gpu::INT32: { + texel.internalFormat = GL_R32I; + break; + } + case gpu::NUINT32: { + texel.internalFormat = GL_R8; + break; + } + case gpu::NINT32: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_R32F; + break; + } + case gpu::UINT16: { + texel.internalFormat = GL_R16UI; + break; + } + case gpu::INT16: { + texel.internalFormat = GL_R16I; + break; + } + case gpu::NUINT16: { + texel.internalFormat = GL_R16; + break; + } + case gpu::NINT16: { + texel.internalFormat = GL_R16_SNORM; + break; + } + case gpu::HALF: { + texel.internalFormat = GL_R16F; + break; + } + case gpu::UINT8: { + texel.internalFormat = GL_R8UI; + break; + } + case gpu::INT8: { + texel.internalFormat = GL_R8I; + break; + } + case gpu::NUINT8: { + if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { + texel.internalFormat = GL_SLUMINANCE8; + } else { + texel.internalFormat = GL_R8; + } + break; + } + case gpu::NINT8: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + + } + break; + + case gpu::R11G11B10: + texel.format = GL_RGB; + // the type should be float + texel.internalFormat = GL_R11F_G11F_B10F; + break; + + case gpu::DEPTH: + texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it + texel.internalFormat = GL_DEPTH_COMPONENT32; + switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: { + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_DEPTH_COMPONENT32F; + break; + } + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: { + texel.internalFormat = GL_DEPTH_COMPONENT16; + break; + } + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: { + texel.internalFormat = GL_DEPTH_COMPONENT24; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + } + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + case gpu::SRGB: + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + switch (dstFormat.getType()) { + case gpu::UINT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32UI; + break; + case gpu::INT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32I; + break; + case gpu::FLOAT: + texel.internalFormat = GL_RGBA32F; + break; + case gpu::UINT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16UI; + break; + case gpu::INT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16I; + break; + case gpu::NUINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16; + break; + case gpu::NINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16_SNORM; + break; + case gpu::HALF: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16F; + break; + case gpu::UINT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8UI; + break; + case gpu::INT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8I; + break; + case gpu::NUINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8; + break; + case gpu::NINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } + break; + case gpu::SRGB: + texel.internalFormat = GL_SRGB8; + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpulogging) << "Unknown combination of texel format"; + } + return texel; + } + } +}; From b2058376ba38c4df8418197a5013386a6555dad2 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:03:05 +0200 Subject: [PATCH 035/128] used "ReSharper C++" to fix some style and spelling in Application.(h|cpp) --- interface/src/Application.cpp | 182 +++++++++++++++------------------- interface/src/Application.h | 85 ++++++++-------- 2 files changed, 123 insertions(+), 144 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61d0f4f995..0130df4a73 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -18,23 +18,12 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include -#include #include -#include -#include #include #include @@ -44,28 +33,18 @@ #include #include -#include #include -#include -#include -#include #include #include -#include - -#include #include -#include - #include #include #include #include #include -#include #include #include #include @@ -110,12 +89,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -137,7 +113,6 @@ #include "InterfaceActionFactory.h" #include "InterfaceLogging.h" #include "LODManager.h" -#include "Menu.h" #include "ModelPackager.h" #include "PluginContainerProxy.h" #include "scripting/AccountScriptingInterface.h" @@ -171,7 +146,7 @@ -// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU +// ON Windows PC, Nvidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) extern "C" { @@ -254,14 +229,14 @@ public: }); } - void updateHeartbeat() { + static void updateHeartbeat() { auto now = usecTimestampNow(); auto elapsed = now - _heartbeat; _movingAverage.addSample(elapsed); _heartbeat = now; } - void deadlockDetectionCrash() { + static void deadlockDetectionCrash() { uint32_t* crashTrigger = nullptr; *crashTrigger = 0xDEAD10CC; } @@ -390,11 +365,11 @@ public: LambdaEvent(std::function && fun) : QEvent(static_cast(Lambda)), _fun(fun) { } - void call() { _fun(); } + void call() const { _fun(); } }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); + QString logMessage = LogHandler::getInstance().printMessage(static_cast(type), context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_WIN @@ -528,7 +503,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0) { - // FIXME this may be excessivly conservative. On the other hand + // FIXME this may be excessively conservative. On the other hand // maybe I'm used to having an 8-core machine // Perhaps find the ideal thread count and subtract 2 or 3 // (main thread, present thread, random OS load) @@ -940,13 +915,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _applicationStateDevice = std::make_shared(); _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->isHMDMode(); + return static_cast(qApp->isHMDMode()); })); _applicationStateDevice->addInputVariant(QString("SnapTurn"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getSnapTurn(); + return static_cast(qApp->getMyAvatar()->getSnapTurn()); })); _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); + return static_cast(qApp->getMyAvatar()->getCharacterController()->onGround()); })); _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { auto offscreenUi = DependencyManager::get(); @@ -1014,12 +989,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); applicationUpdater->checkForUpdate(); - // Now that menu is initalized we can sync myAvatar with it's state. + // Now that menu is initialized we can sync myAvatar with it's state. getMyAvatar()->updateMotionBehaviorFromMenu(); // FIXME spacemouse code still needs cleanup #if 0 - // the 3Dconnexion device wants to be initiliazed after a window is displayed. + // the 3Dconnexion device wants to be initialized after a window is displayed. SpacemouseManager::getInstance().init(); #endif @@ -1124,7 +1099,7 @@ void Application::showCursor(const QCursor& cursor) { _cursorNeedsChanging = true; } -void Application::updateHeartbeat() { +void Application::updateHeartbeat() const { static_cast(_deadlockWatchdogThread)->updateHeartbeat(); } @@ -1218,12 +1193,12 @@ void Application::cleanupBeforeQuit() { Application::~Application() { EntityTreePointer tree = getEntities()->getTree(); - tree->setSimulation(NULL); + tree->setSimulation(nullptr); _octreeProcessor.terminate(); _entityEditSender.terminate(); - _physicsEngine->setCharacterController(NULL); + _physicsEngine->setCharacterController(nullptr); ModelEntityItem::cleanupLoadedAnimations(); @@ -1264,7 +1239,7 @@ Application::~Application() { _window->deleteLater(); - qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages + qInstallMessageHandler(nullptr); // NOTE: Do this as late as possible so we continue to get our log messages } void Application::initializeGL() { @@ -1467,7 +1442,7 @@ void Application::paintGL() { uint64_t diff = now - lastPaintBegin; float instantaneousFps = 0.0f; if (diff != 0) { - instantaneousFps = (float)USECS_PER_SECOND / (float)diff; + instantaneousFps = static_cast(USECS_PER_SECOND) / static_cast(diff); _framesPerSecond.updateAverage(_lastInstantaneousFps); } @@ -1479,7 +1454,7 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, static_cast(_frameCount)); PerformanceTimer perfTimer("paintGL"); if (nullptr == _displayPlugin) { @@ -1744,7 +1719,7 @@ void Application::runTests() { runUnitTests(); } -void Application::audioMuteToggled() { +void Application::audioMuteToggled() const { QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio); Q_CHECK_PTR(muteAction); muteAction->setChecked(DependencyManager::get()->isMuted()); @@ -1825,12 +1800,12 @@ bool Application::event(QEvent* event) { return false; } - if ((int)event->type() == (int)Lambda) { - ((LambdaEvent*)event)->call(); + if (static_cast(event->type()) == static_cast(Lambda)) { + static_cast(event)->call(); return true; } - if ((int)event->type() == (int)Paint) { + if (static_cast(event->type()) == static_cast(Paint)) { paintGL(); return true; } @@ -1860,25 +1835,25 @@ bool Application::event(QEvent* event) { switch (event->type()) { case QEvent::MouseMove: - mouseMoveEvent((QMouseEvent*)event); + mouseMoveEvent(static_cast(event)); return true; case QEvent::MouseButtonPress: - mousePressEvent((QMouseEvent*)event); + mousePressEvent(static_cast(event)); return true; case QEvent::MouseButtonDblClick: - mouseDoublePressEvent((QMouseEvent*)event); + mouseDoublePressEvent(static_cast(event)); return true; case QEvent::MouseButtonRelease: - mouseReleaseEvent((QMouseEvent*)event); + mouseReleaseEvent(static_cast(event)); return true; case QEvent::KeyPress: - keyPressEvent((QKeyEvent*)event); + keyPressEvent(static_cast(event)); return true; case QEvent::KeyRelease: - keyReleaseEvent((QKeyEvent*)event); + keyReleaseEvent(static_cast(event)); return true; case QEvent::FocusOut: - focusOutEvent((QFocusEvent*)event); + focusOutEvent(static_cast(event)); return true; case QEvent::TouchBegin: touchBeginEvent(static_cast(event)); @@ -2306,13 +2281,13 @@ void Application::focusOutEvent(QFocusEvent* event) { // synthesize events for keys currently pressed, since we may not get their release events foreach (int key, _keysPressed) { - QKeyEvent event(QEvent::KeyRelease, key, Qt::NoModifier); - keyReleaseEvent(&event); + QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier); + keyReleaseEvent(&keyEvent); } _keysPressed.clear(); } -void Application::maybeToggleMenuVisible(QMouseEvent* event) { +void Application::maybeToggleMenuVisible(QMouseEvent* event) const { #ifndef Q_OS_MAC // If in full screen, and our main windows menu bar is hidden, and we're close to the top of the QMainWindow // then show the menubar. @@ -2428,7 +2403,7 @@ void Application::mousePressEvent(QMouseEvent* event) { } } -void Application::mouseDoublePressEvent(QMouseEvent* event) { +void Application::mouseDoublePressEvent(QMouseEvent* event) const { // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -2528,7 +2503,7 @@ void Application::touchEndEvent(QTouchEvent* event) { // put any application specific touch behavior below here.. } -void Application::wheelEvent(QWheelEvent* event) { +void Application::wheelEvent(QWheelEvent* event) const { _altPressed = false; _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts @@ -2599,7 +2574,7 @@ void Application::idle(uint64_t now) { bool isThrottled = displayPlugin->isThrottled(); // Only run simulation code if more than the targetFramePeriod have passed since last time we ran // This attempts to lock the simulation at 60 updates per second, regardless of framerate - float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC; + float timeSinceLastUpdateUs = static_cast(_lastTimeUpdated.nsecsElapsed()) / NSECS_PER_USEC; float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { @@ -2639,7 +2614,7 @@ void Application::idle(uint64_t now) { static uint64_t lastIdleStart{ now }; uint64_t idleStartToStartDuration = now - lastIdleStart; if (idleStartToStartDuration != 0) { - _simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration); + _simsPerSecond.updateAverage(static_cast(USECS_PER_SECOND) / static_cast(idleStartToStartDuration)); } lastIdleStart = now; } @@ -2707,9 +2682,11 @@ float Application::getAverageSimsPerSecond() { } return _simsPerSecondReport; } + void Application::setAvatarSimrateSample(float sample) { _avatarSimsPerSecond.updateAverage(sample); } + float Application::getAvatarSimrate() { uint64_t now = usecTimestampNow(); @@ -2724,7 +2701,7 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { controller::InputDevice::setLowVelocityFilter(lowVelocityFilter); } -ivec2 Application::getMouse() { +ivec2 Application::getMouse() const { auto reticlePosition = getApplicationCompositor().getReticlePosition(); // in the HMD, the reticlePosition is the mouse position @@ -2741,11 +2718,11 @@ FaceTracker* Application::getActiveFaceTracker() { auto dde = DependencyManager::get(); return (dde->isActive() ? static_cast(dde.data()) : - (faceshift->isActive() ? static_cast(faceshift.data()) : NULL)); + (faceshift->isActive() ? static_cast(faceshift.data()) : nullptr)); } FaceTracker* Application::getSelectedFaceTracker() { - FaceTracker* faceTracker = NULL; + FaceTracker* faceTracker = nullptr; #ifdef HAVE_FACESHIFT if (Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)) { faceTracker = DependencyManager::get().data(); @@ -2759,7 +2736,7 @@ FaceTracker* Application::getSelectedFaceTracker() { return faceTracker; } -void Application::setActiveFaceTracker() { +void Application::setActiveFaceTracker() const { #if defined(HAVE_FACESHIFT) || defined(HAVE_DDE) bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking); #endif @@ -2896,7 +2873,7 @@ void Application::loadSettings() { _settingsLoaded = true; } -void Application::saveSettings() { +void Application::saveSettings() const { sessionRunTime.set(_sessionRunTimer.elapsed() / MSECS_PER_SEC); DependencyManager::get()->saveSettings(); DependencyManager::get()->saveSettings(); @@ -2986,7 +2963,7 @@ void Application::init() { connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); } -void Application::updateLOD() { +void Application::updateLOD() const { PerformanceTimer perfTimer("LOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode if (!isThrottleRendering()) { @@ -3188,13 +3165,13 @@ void Application::reloadResourceCaches() { getMyAvatar()->resetFullAvatarURL(); } -void Application::rotationModeChanged() { +void Application::rotationModeChanged() const { if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { getMyAvatar()->setHeadPitch(0); } } -void Application::updateDialogs(float deltaTime) { +void Application::updateDialogs(float deltaTime) const { PerformanceTimer perfTimer("updateDialogs"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); @@ -3220,7 +3197,7 @@ void Application::updateDialogs(float deltaTime) { void Application::update(float deltaTime) { - PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1); + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, static_cast(_frameCount) + 1); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); @@ -3230,7 +3207,7 @@ void Application::update(float deltaTime) { if (!_physicsEnabled && _processOctreeStatsCounter > 0) { // process octree stats packets are sent in between full sends of a scene. - // We keep physics disabled until we've recieved a full scene and everything near the avatar in that + // We keep physics disabled until we've received a full scene and everything near the avatar in that // scene is ready to compute its collision shape. if (nearbyEntitiesAreReadyForPhysics()) { @@ -3380,14 +3357,14 @@ void Application::update(float deltaTime) { }); } { - PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("StepSimulation", 0xffff8000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("stepSimulation"); getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); } { - PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("harvestChanges"); if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { @@ -3425,20 +3402,20 @@ void Application::update(float deltaTime) { qApp->setAvatarSimrateSample(1.0f / deltaTime); { - PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); avatarManager->updateOtherAvatars(deltaTime); } qApp->updateMyAvatarLookAtPosition(); { - PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); avatarManager->updateMyAvatar(deltaTime); } } { - PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("Overlays", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } @@ -3458,7 +3435,7 @@ void Application::update(float deltaTime) { // Update my voxel servers with my current voxel query... { - PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); + PROFILE_RANGE_EX("QueryOctree", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); PerformanceTimer perfTimer("queryOctree"); quint64 sinceLastQuery = now - _lastQueriedTime; const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; @@ -3497,7 +3474,7 @@ void Application::update(float deltaTime) { } { - PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); + PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, static_cast(0)); std::unique_lock guard(_preRenderLambdasLock); for (auto& iter : _preRenderLambdas) { @@ -3535,7 +3512,7 @@ int Application::sendNackPackets() { QSet missingSequenceNumbers; _octreeServerSceneStats.withReadLock([&] { - // retreive octree scene stats of this node + // retrieve octree scene stats of this node if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { return; } @@ -3551,7 +3528,7 @@ int Application::sendNackPackets() { } if (nackPacketList->getNumPackets()) { - packetsSent += (int)nackPacketList->getNumPackets(); + packetsSent += static_cast(nackPacketList->getNumPackets()); // send the packet list nodeList->sendPacketList(std::move(nackPacketList), *node); @@ -3735,7 +3712,7 @@ bool Application::isHMDMode() const { } float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); } -QRect Application::getDesirableApplicationGeometry() { +QRect Application::getDesirableApplicationGeometry() const { QRect applicationGeometry = getWindow()->geometry(); // If our parent window is on the HMD, then don't use its geometry, instead use @@ -3748,7 +3725,7 @@ QRect Application::getDesirableApplicationGeometry() { // if our app's screen is the hmd screen, we don't want to place the // running scripts widget on it. So we need to pick a better screen. - // we will use the screen for the HMDTools since it's a guarenteed + // we will use the screen for the HMDTools since it's a guaranteed // better screen. if (appScreen == hmdScreen) { QScreen* betterScreen = hmdTools->windowHandle()->screen(); @@ -3777,7 +3754,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.calculate(); } -glm::vec3 Application::getSunDirection() { +glm::vec3 Application::getSunDirection() const { // Sun direction is in fact just the location of the sun relative to the origin auto skyStage = DependencyManager::get()->getSkyStage(); return skyStage->getSunLight()->getDirection(); @@ -3979,7 +3956,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS); + renderDebugFlags = static_cast(renderDebugFlags | + static_cast(RenderArgs::RENDER_DEBUG_HULLS)); } renderArgs->_debugFlags = renderDebugFlags; //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); @@ -4033,7 +4011,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi auto originalViewport = renderArgs->_viewport; // Grab current viewport to reset it at the end - float aspect = (float)region.width() / region.height(); + float aspect = static_cast(region.width()) / region.height(); float fov = MIRROR_FIELD_OF_VIEW; auto myAvatar = getMyAvatar(); @@ -4044,7 +4022,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * myAvatar->getScale()); } else { // HEAD zoom level - // FIXME note that the positioing of the camera relative to the avatar can suffer limited + // FIXME note that the positioning of the camera relative to the avatar can suffer limited // precision as the user's position moves further away from the origin. Thus at // /1e7,1e7,1e7 (well outside the buildable volume) the mirror camera veers and sways // wildly as you rotate your avatar because the floating point values are becoming @@ -4069,7 +4047,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // set the bounds of rear mirror view // the region is in device independent coordinates; must convert to device - float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); + float ratio = static_cast(QApplication::desktop()->windowHandle()->devicePixelRatio()) * getRenderResolutionScale(); int width = region.width() * ratio; int height = region.height() * ratio; gpu::Vec4i viewport = gpu::Vec4i(0, 0, width, height); @@ -4090,7 +4068,7 @@ void Application::resetSensors(bool andReload) { QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection); } -void Application::updateWindowTitle(){ +void Application::updateWindowTitle() const { QString buildVersion = " (build " + applicationVersion() + ")"; auto nodeList = DependencyManager::get(); @@ -4148,14 +4126,14 @@ void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; } -void Application::nodeAdded(SharedNodePointer node) { +void Application::nodeAdded(SharedNodePointer node) const { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet right away getMyAvatar()->sendIdentityPacket(); } } -void Application::nodeActivated(SharedNodePointer node) { +void Application::nodeActivated(SharedNodePointer node) const { if (node->getType() == NodeType::AssetServer) { // asset server just connected - check if we have the asset browser showing @@ -4289,7 +4267,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer statsMessageLength = octreeStats.unpackFromPacket(message); // see if this is the first we've heard of this node... - NodeToJurisdictionMap* jurisdiction = NULL; + NodeToJurisdictionMap* jurisdiction = nullptr; QString serverType; if (sendingNode->getType() == NodeType::EntityServer) { jurisdiction = &_entityServerJurisdictions; @@ -4445,7 +4423,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { return defaultUpload; } -void Application::setSessionUUID(const QUuid& sessionUUID) { +void Application::setSessionUUID(const QUuid& sessionUUID) const { // HACK: until we swap the library dependency order between physics and entities // we cache the sessionID in two distinct places for physics. Physics::setSessionUUID(sessionUUID); // TODO: remove this one @@ -4586,7 +4564,7 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) } } -void Application::toggleRunningScriptsWidget() { +void Application::toggleRunningScriptsWidget() const { static const QUrl url("hifi/dialogs/RunningScripts.qml"); DependencyManager::get()->show(url, "RunningScripts"); //if (_runningScriptsWidget->isVisible()) { @@ -4623,7 +4601,7 @@ void Application::packageModel() { ModelPackager::package(); } -void Application::openUrl(const QUrl& url) { +void Application::openUrl(const QUrl& url) const { if (!url.isEmpty()) { if (url.scheme() == HIFI_URL_SCHEME) { DependencyManager::get()->handleLookupString(url.toString()); @@ -4653,7 +4631,7 @@ void Application::setPreviousScriptLocation(const QString& location) { _previousScriptLocation.set(location); } -void Application::loadScriptURLDialog() { +void Application::loadScriptURLDialog() const { auto newScript = OffscreenUi::getText(nullptr, "Open and Run Script", "Script URL"); if (!newScript.isEmpty()) { DependencyManager::get()->loadScript(newScript); @@ -4718,7 +4696,7 @@ void Application::notifyPacketVersionMismatch() { } } -void Application::checkSkeleton() { +void Application::checkSkeleton() const { if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) { qCDebug(interfaceapp) << "MyAvatar model has no skeleton"; @@ -4799,7 +4777,7 @@ void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) { } } -int Application::getMaxOctreePacketsPerSecond() { +int Application::getMaxOctreePacketsPerSecond() const { return _maxOctreePPS; } @@ -4823,7 +4801,7 @@ DisplayPlugin* Application::getActiveDisplayPlugin() { } const DisplayPlugin* Application::getActiveDisplayPlugin() const { - return ((Application*)this)->getActiveDisplayPlugin(); + return const_cast(this)->getActiveDisplayPlugin(); } static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { @@ -4903,7 +4881,7 @@ void Application::updateDisplayMode() { } } - // concactonate the groupings into a single list in the order: standard, advanced, developer + // concatenate the groupings into a single list in the order: standard, advanced, developer standard.insert(std::end(standard), std::begin(advanced), std::end(advanced)); standard.insert(std::end(standard), std::begin(developer), std::end(developer)); @@ -4915,7 +4893,7 @@ void Application::updateDisplayMode() { first = false; } - // after all plugins have been added to the menu, add a seperator to the menu + // after all plugins have been added to the menu, add a separator to the menu auto menu = Menu::getInstance(); auto parent = menu->getMenu(MenuOption::OutputMenu); parent->addSeparator(); @@ -4986,7 +4964,7 @@ void Application::updateDisplayMode() { emit activeDisplayPluginChanged(); - // reset the avatar, to set head and hand palms back to a resonable default pose. + // reset the avatar, to set head and hand palms back to a reasonable default pose. getMyAvatar()->reset(false); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); @@ -5115,7 +5093,7 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) { updateDisplayMode(); } -void Application::handleLocalServerConnection() { +void Application::handleLocalServerConnection() const { auto server = qobject_cast(sender()); qDebug() << "Got connection on local server from additional instance - waiting for parameters"; @@ -5128,7 +5106,7 @@ void Application::handleLocalServerConnection() { qApp->getWindow()->activateWindow(); } -void Application::readArgumentsFromLocalSocket() { +void Application::readArgumentsFromLocalSocket() const { auto socket = qobject_cast(sender()); auto message = socket->readAll(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f67fbb545..4f6064df20 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -135,14 +135,14 @@ public: const ViewFrustum* getDisplayViewFrustum() const; ViewFrustum* getShadowViewFrustum() override { return &_shadowViewFrustum; } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } - EntityTreeRenderer* getEntities() { return DependencyManager::get().data(); } + EntityTreeRenderer* getEntities() const { return DependencyManager::get().data(); } QUndoStack* getUndoStack() { return &_undoStack; } - MainWindow* getWindow() { return _window; } - EntityTreePointer getEntityClipboard() { return _entityClipboard; } + MainWindow* getWindow() const { return _window; } + EntityTreePointer getEntityClipboard() const { return _entityClipboard; } EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; } EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; } - ivec2 getMouse(); + ivec2 getMouse() const; FaceTracker* getActiveFaceTracker(); FaceTracker* getSelectedFaceTracker(); @@ -155,7 +155,7 @@ public: bool isForeground() const { return _isForeground; } - uint32_t getFrameCount() { return _frameCount; } + uint32_t getFrameCount() const { return _frameCount; } float getFps() const { return _fps; } float getTargetFrameRate(); // frames/second float getLastInstanteousFps() const { return _lastInstantaneousFps; } @@ -179,7 +179,7 @@ public: DisplayPlugin* getActiveDisplayPlugin(); const DisplayPlugin* getActiveDisplayPlugin() const; - FileLogger* getLogger() { return _logger; } + FileLogger* getLogger() const { return _logger; } glm::vec2 getViewportDimensions() const; @@ -189,7 +189,7 @@ public: bool isAboutToQuit() const { return _aboutToQuit; } - // the isHMDmode is true whenever we use the interface from an HMD and not a standard flat display + // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display // rendering of several elements depend on that // TODO: carry that information on the Camera as a setting bool isHMDMode() const; @@ -197,14 +197,14 @@ public: glm::mat4 getEyeOffset(int eye) const; glm::mat4 getEyeProjection(int eye) const; - QRect getDesirableApplicationGeometry(); + QRect getDesirableApplicationGeometry() const; Bookmarks* getBookmarks() const { return _bookmarks; } virtual bool canAcceptURL(const QString& url) const override; virtual bool acceptURL(const QString& url, bool defaultUpload = false) override; void setMaxOctreePacketsPerSecond(int maxOctreePPS); - int getMaxOctreePacketsPerSecond(); + int getMaxOctreePacketsPerSecond() const; render::ScenePointer getMain3DScene() override { return _main3DScene; } render::ScenePointer getMain3DScene() const { return _main3DScene; } @@ -239,22 +239,22 @@ public slots: bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool importEntities(const QString& url); - void setLowVelocityFilter(bool lowVelocityFilter); + static void setLowVelocityFilter(bool lowVelocityFilter); Q_INVOKABLE void loadDialog(); - Q_INVOKABLE void loadScriptURLDialog(); + Q_INVOKABLE void loadScriptURLDialog() const; void toggleLogDialog(); - void toggleRunningScriptsWidget(); + void toggleRunningScriptsWidget() const; void toggleAssetServerWidget(QString filePath = ""); - void handleLocalServerConnection(); - void readArgumentsFromLocalSocket(); + void handleLocalServerConnection() const; + void readArgumentsFromLocalSocket() const; - void packageModel(); + static void packageModel(); - void openUrl(const QUrl& url); + void openUrl(const QUrl& url) const; void resetSensors(bool andReload = false); - void setActiveFaceTracker(); + void setActiveFaceTracker() const; #ifdef HAVE_IVIEWHMD void setActiveEyeTracker(); @@ -264,7 +264,7 @@ public slots: #endif void aboutApp(); - void showHelp(); + static void showHelp(); void cycleCamera(); void cameraMenuChanged(); @@ -273,14 +273,14 @@ public slots: void reloadResourceCaches(); - void updateHeartbeat(); + void updateHeartbeat() const; - void crashApplication(); - void deadlockApplication(); + static void crashApplication(); + static void deadlockApplication(); - void rotationModeChanged(); + void rotationModeChanged() const; - void runTests(); + static void runTests(); private slots: void showDesktop(); @@ -290,7 +290,7 @@ private slots: void resettingDomain(); - void audioMuteToggled(); + void audioMuteToggled() const; void faceTrackerMuteToggled(); void activeChanged(Qt::ApplicationState state); @@ -298,7 +298,7 @@ private slots: void notifyPacketVersionMismatch(); void loadSettings(); - void saveSettings(); + void saveSettings() const; bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); @@ -308,18 +308,18 @@ private slots: void displayAvatarAttachmentWarning(const QString& message) const; bool displayAvatarAttachmentConfirmationDialog(const QString& name) const; - void setSessionUUID(const QUuid& sessionUUID); + void setSessionUUID(const QUuid& sessionUUID) const; void domainChanged(const QString& domainHostname); - void updateWindowTitle(); - void nodeAdded(SharedNodePointer node); - void nodeActivated(SharedNodePointer node); + void updateWindowTitle() const; + void nodeAdded(SharedNodePointer node) const; + void nodeActivated(SharedNodePointer node) const; void nodeKilled(SharedNodePointer node); - void packetSent(quint64 length); + static void packetSent(quint64 length); void updateDisplayMode(); void updateInputModes(); private: - void initDisplay(); + static void initDisplay(); void init(); void cleanupBeforeQuit(); @@ -327,14 +327,14 @@ private: void update(float deltaTime); // Various helper functions called during update() - void updateLOD(); + void updateLOD() const; void updateThreads(float deltaTime); - void updateDialogs(float deltaTime); + void updateDialogs(float deltaTime) const; void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); - void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); + static void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); - glm::vec3 getSunDirection(); + glm::vec3 getSunDirection() const; void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region); @@ -344,7 +344,7 @@ private: MyAvatar* getMyAvatar() const; - void checkSkeleton(); + void checkSkeleton() const; void initializeAcceptedFiles(); @@ -366,18 +366,18 @@ private: void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - void mouseDoublePressEvent(QMouseEvent* event); + void mouseDoublePressEvent(QMouseEvent* event) const; void mouseReleaseEvent(QMouseEvent* event); void touchBeginEvent(QTouchEvent* event); void touchEndEvent(QTouchEvent* event); void touchUpdateEvent(QTouchEvent* event); - void wheelEvent(QWheelEvent* event); + void wheelEvent(QWheelEvent* event) const; void dropEvent(QDropEvent* event); - void dragEnterEvent(QDragEnterEvent* event); + static void dragEnterEvent(QDragEnterEvent* event); - void maybeToggleMenuVisible(QMouseEvent* event); + void maybeToggleMenuVisible(QMouseEvent* event) const; MainWindow* _window; QElapsedTimer& _sessionRunTimer; @@ -423,7 +423,7 @@ private: int _avatarSimsPerSecondReport {0}; quint64 _lastAvatarSimsPerSecondUpdate {0}; Camera _myCamera; // My view onto the world - Camera _mirrorCamera; // Cammera for mirror view + Camera _mirrorCamera; // Camera for mirror view QRect _mirrorViewRect; Setting::Handle _previousScriptLocation; @@ -475,7 +475,8 @@ private: quint64 _lastFaceTrackerUpdate; - render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; + render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * static_cast(TREE_SCALE)), + static_cast(TREE_SCALE)) }; render::EnginePointer _renderEngine{ new render::Engine() }; gpu::ContextPointer _gpuContext; // initialized during window creation From 142f37da1c55c08fe7c6268aa0b261647f16ca22 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:33:47 +0200 Subject: [PATCH 036/128] fix accidentally violated style rule 3.1.2.1 --- CONTRIBUTING.md | 2 +- interface/src/Application.cpp | 40 +++++++++++++++++------------------ interface/src/Application.h | 3 +-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f1153b4f4..86ea351609 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Contributing git checkout -b new_branch_name ``` 4. Code - * Follow the [coding standard](http://docs.highfidelity.io/v1.0/docs/coding-standard) + * Follow the [coding standard](https://readme.highfidelity.com/v1.0/docs/coding-standard) 5. Commit * Use [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 6. Update your branch diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0130df4a73..17a918c0e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -369,7 +369,7 @@ public: }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage(static_cast(type), context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_WIN @@ -915,13 +915,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _applicationStateDevice = std::make_shared(); _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->isHMDMode()); + return (float)qApp->isHMDMode(); })); _applicationStateDevice->addInputVariant(QString("SnapTurn"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->getMyAvatar()->getSnapTurn()); + return (float)qApp->getMyAvatar()->getSnapTurn(); })); _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return static_cast(qApp->getMyAvatar()->getCharacterController()->onGround()); + return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); })); _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { auto offscreenUi = DependencyManager::get(); @@ -1442,7 +1442,7 @@ void Application::paintGL() { uint64_t diff = now - lastPaintBegin; float instantaneousFps = 0.0f; if (diff != 0) { - instantaneousFps = static_cast(USECS_PER_SECOND) / static_cast(diff); + instantaneousFps = (float)USECS_PER_SECOND / (float)diff; _framesPerSecond.updateAverage(_lastInstantaneousFps); } @@ -1454,7 +1454,7 @@ void Application::paintGL() { _lastFramesPerSecondUpdate = now; } - PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, static_cast(_frameCount)); + PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); PerformanceTimer perfTimer("paintGL"); if (nullptr == _displayPlugin) { @@ -1800,12 +1800,12 @@ bool Application::event(QEvent* event) { return false; } - if (static_cast(event->type()) == static_cast(Lambda)) { + if ((int)event->type() == (int)Lambda) { static_cast(event)->call(); return true; } - if (static_cast(event->type()) == static_cast(Paint)) { + if ((int)event->type() == (int)Paint) { paintGL(); return true; } @@ -2574,7 +2574,7 @@ void Application::idle(uint64_t now) { bool isThrottled = displayPlugin->isThrottled(); // Only run simulation code if more than the targetFramePeriod have passed since last time we ran // This attempts to lock the simulation at 60 updates per second, regardless of framerate - float timeSinceLastUpdateUs = static_cast(_lastTimeUpdated.nsecsElapsed()) / NSECS_PER_USEC; + float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC; float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { @@ -3197,7 +3197,7 @@ void Application::updateDialogs(float deltaTime) const { void Application::update(float deltaTime) { - PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, static_cast(_frameCount) + 1); + PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); @@ -3357,14 +3357,14 @@ void Application::update(float deltaTime) { }); } { - PROFILE_RANGE_EX("StepSimulation", 0xffff8000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("stepSimulation"); getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); } { - PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("harvestChanges"); if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { @@ -3402,20 +3402,20 @@ void Application::update(float deltaTime) { qApp->setAvatarSimrateSample(1.0f / deltaTime); { - PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); avatarManager->updateOtherAvatars(deltaTime); } qApp->updateMyAvatarLookAtPosition(); { - PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); avatarManager->updateMyAvatar(deltaTime); } } { - PROFILE_RANGE_EX("Overlays", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } @@ -3435,7 +3435,7 @@ void Application::update(float deltaTime) { // Update my voxel servers with my current voxel query... { - PROFILE_RANGE_EX("QueryOctree", 0xffff0000, static_cast(getActiveDisplayPlugin()->presentCount())); + PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("queryOctree"); quint64 sinceLastQuery = now - _lastQueriedTime; const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; @@ -3474,7 +3474,7 @@ void Application::update(float deltaTime) { } { - PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, static_cast(0)); + PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); std::unique_lock guard(_preRenderLambdasLock); for (auto& iter : _preRenderLambdas) { @@ -3528,7 +3528,7 @@ int Application::sendNackPackets() { } if (nackPacketList->getNumPackets()) { - packetsSent += static_cast(nackPacketList->getNumPackets()); + packetsSent += (int)nackPacketList->getNumPackets(); // send the packet list nodeList->sendPacketList(std::move(nackPacketList), *node); @@ -4011,7 +4011,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi auto originalViewport = renderArgs->_viewport; // Grab current viewport to reset it at the end - float aspect = static_cast(region.width()) / region.height(); + float aspect = (float)region.width() / region.height(); float fov = MIRROR_FIELD_OF_VIEW; auto myAvatar = getMyAvatar(); @@ -4047,7 +4047,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // set the bounds of rear mirror view // the region is in device independent coordinates; must convert to device - float ratio = static_cast(QApplication::desktop()->windowHandle()->devicePixelRatio()) * getRenderResolutionScale(); + float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); int width = region.width() * ratio; int height = region.height() * ratio; gpu::Vec4i viewport = gpu::Vec4i(0, 0, width, height); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f6064df20..e3196febd5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -475,8 +475,7 @@ private: quint64 _lastFaceTrackerUpdate; - render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * static_cast(TREE_SCALE)), - static_cast(TREE_SCALE)) }; + render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; render::EnginePointer _renderEngine{ new render::Engine() }; gpu::ContextPointer _gpuContext; // initialized during window creation From 2be4097bc528ddfde0287b3a9a21ef651ec72b54 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 4 Apr 2016 17:36:43 +0200 Subject: [PATCH 037/128] another 3.1.2.1 rollback --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 17a918c0e8..0172b3ce3a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2614,7 +2614,7 @@ void Application::idle(uint64_t now) { static uint64_t lastIdleStart{ now }; uint64_t idleStartToStartDuration = now - lastIdleStart; if (idleStartToStartDuration != 0) { - _simsPerSecond.updateAverage(static_cast(USECS_PER_SECOND) / static_cast(idleStartToStartDuration)); + _simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration); } lastIdleStart = now; } From 1da8fe5838df37c9ea2260d5823d19d98c738f45 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 09:46:10 -0700 Subject: [PATCH 038/128] only a single log line per client version mismatch --- ice-server/src/IceServer.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a512d5a049..59c36eae30 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -62,7 +62,14 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { if (headerVersion == versionForPacketType(headerType)) { return true; } else { - qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); + static QSet mismatchedClients; + + // only output a version mismatch once per ice-server run + if (!mismatchedClients.contains(packet.getSenderSockAddr())) { + mismatchedClients.insert(packet.getSenderSockAddr()); + + qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); + } return false; } From 145b734b98cb557b9e8a5e12868db572bf1bfbbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 09:49:04 -0700 Subject: [PATCH 039/128] completely remove version mismatch debug --- ice-server/src/IceServer.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 59c36eae30..c1e92f276f 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -62,15 +62,6 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { if (headerVersion == versionForPacketType(headerType)) { return true; } else { - static QSet mismatchedClients; - - // only output a version mismatch once per ice-server run - if (!mismatchedClients.contains(packet.getSenderSockAddr())) { - mismatchedClients.insert(packet.getSenderSockAddr()); - - qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr(); - } - return false; } } From d98abbc7df5d05b72a29a5015c81445df4f89499 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 3 Apr 2016 01:04:05 -0700 Subject: [PATCH 040/128] First pass at threaded texture transfers --- interface/src/Application.cpp | 3 + libraries/gl/src/gl/GLHelpers.cpp | 4 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 5 + libraries/gl/src/gl/OffscreenGLCanvas.h | 1 + libraries/gl/src/gl/OglplusHelpers.cpp | 40 +- libraries/gl/src/gl/OglplusHelpers.h | 3 +- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 3 + libraries/gl/src/gl/QOpenGLContextWrapper.h | 3 +- libraries/gpu/src/gpu/GLBackend.cpp | 1 + libraries/gpu/src/gpu/GLBackend.h | 65 ++- libraries/gpu/src/gpu/GLBackendOutput.cpp | 4 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 2 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 441 +++++++++--------- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 109 +++++ .../gpu/src/gpu/GLBackendTextureTransfer.h | 61 +++ libraries/gpu/src/gpu/GLTexelFormat.h | 3 + libraries/shared/src/GenericThread.cpp | 19 +- libraries/shared/src/GenericThread.h | 7 +- 18 files changed, 540 insertions(+), 234 deletions(-) create mode 100644 libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp create mode 100644 libraries/gpu/src/gpu/GLBackendTextureTransfer.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0172b3ce3a..80173b7d9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1255,6 +1255,9 @@ void Application::initializeGL() { // Where the gpuContext is initialized and where the TRUE Backend is created and assigned gpu::Context::init(); _gpuContext = std::make_shared(); + // The gpu context can make child contexts for transfers, so + // we need to restore primary rendering context + _offscreenContext->makeCurrent(); initDisplay(); qCDebug(interfaceapp, "Initialized Display."); diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 6ad7f816b8..c9de3ccd90 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -12,7 +12,7 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { // 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); + format.setVersion(4, 5); #ifdef DEBUG format.setOption(QSurfaceFormat::DebugContext); #endif @@ -27,7 +27,7 @@ const QGLFormat& getDefaultGLFormat() { static QGLFormat glFormat; static std::once_flag once; std::call_once(once, [] { - glFormat.setVersion(4, 1); + glFormat.setVersion(4, 5); glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 glFormat.setSampleBuffers(false); glFormat.setDepth(false); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 8e5579f90b..90ff369cd6 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -83,3 +83,8 @@ void OffscreenGLCanvas::doneCurrent() { QObject* OffscreenGLCanvas::getContextObject() { return _context; } + +void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) { + moveToThread(thread); + _context->moveToThread(thread); +} \ No newline at end of file diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index 9858c7cefa..387804bf56 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -26,6 +26,7 @@ public: bool create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); + void moveToThreadWithContext(QThread* thread); QOpenGLContext* getContext() { return _context; } diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp index 1dd7068448..11c4f2fe3d 100644 --- a/libraries/gl/src/gl/OglplusHelpers.cpp +++ b/libraries/gl/src/gl/OglplusHelpers.cpp @@ -6,8 +6,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OglplusHelpers.h" -#include + #include +#include +#include using namespace oglplus; using namespace oglplus::shapes; @@ -20,11 +22,13 @@ uniform mat4 mvp = mat4(1); in vec3 Position; in vec2 TexCoord; +out vec3 vPosition; out vec2 vTexCoord; void main() { gl_Position = mvp * vec4(Position, 1); - vTexCoord = TexCoord ; + vTexCoord = TexCoord; + vPosition = Position; } )VS"; @@ -35,7 +39,9 @@ static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core uniform sampler2D sampler; uniform float alpha = 1.0; +in vec3 vPosition; in vec2 vTexCoord; + out vec4 FragColor; void main() { @@ -47,12 +53,38 @@ void main() { )FS"; +static const char * SIMPLE_TEXTURED_CUBEMAP_FS = R"FS(#version 410 core +#pragma line __LINE__ + +uniform samplerCube sampler; +uniform float alpha = 1.0; + +in vec3 vPosition; +in vec3 vTexCoord; + +out vec4 FragColor; + +void main() { + + FragColor = texture(sampler, vPosition); + FragColor.a *= alpha; +} + +)FS"; + + ProgramPtr loadDefaultShader() { ProgramPtr result; compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS); return result; } +ProgramPtr loadCubemapShader() { + ProgramPtr result; + compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_CUBEMAP_FS); + return result; +} + void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { using namespace oglplus; try { @@ -93,6 +125,10 @@ ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) { ); } +ShapeWrapperPtr loadSkybox(ProgramPtr program) { + return ShapeWrapperPtr(new shapes::ShapeWrapper({ { "Position" } }, shapes::SkyBox(), *program)); +} + // Return a point's cartesian coordinates on a sphere from pitch and yaw static glm::vec3 getPoint(float yaw, float pitch) { return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h index 4734b8b213..b599e8270d 100644 --- a/libraries/gl/src/gl/OglplusHelpers.h +++ b/libraries/gl/src/gl/OglplusHelpers.h @@ -37,7 +37,6 @@ #include #include #include -#include #ifdef _WIN32 #pragma warning(pop) @@ -55,7 +54,9 @@ using ProgramPtr = std::shared_ptr; using Mat4Uniform = oglplus::Uniform; ProgramPtr loadDefaultShader(); +ProgramPtr loadCubemapShader(); void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); +ShapeWrapperPtr loadSkybox(ProgramPtr program); ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 6397d30e13..185fdaf7f4 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -13,6 +13,9 @@ #include +QOpenGLContext* QOpenGLContextWrapper::currentContext() { + return QOpenGLContext::currentContext(); +} QOpenGLContextWrapper::QOpenGLContextWrapper() : _context(new QOpenGLContext) diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index b736253213..09f1d67280 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -19,7 +19,6 @@ class QSurfaceFormat; class QOpenGLContextWrapper { public: QOpenGLContextWrapper(); - void setFormat(const QSurfaceFormat& format); bool create(); void swapBuffers(QSurface* surface); @@ -27,6 +26,8 @@ public: void doneCurrent(); void setShareContext(QOpenGLContext* otherContext); + static QOpenGLContext* currentContext(); + QOpenGLContext* getContext() { return _context; } diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index b5b6437ed8..f51448f8fd 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -125,6 +125,7 @@ GLBackend::GLBackend() { glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment); initInput(); initTransform(); + initTextureTransferHelper(); } GLBackend::~GLBackend() { diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f5abacd279..4f22a68631 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -24,6 +24,8 @@ namespace gpu { +class GLTextureTransferHelper; + class GLBackend : public Backend { // Context Backend static interface required @@ -35,7 +37,6 @@ class GLBackend : public Backend { explicit GLBackend(bool syncCache); GLBackend(); public: - virtual ~GLBackend(); virtual void render(Batch& batch); @@ -75,25 +76,63 @@ public: class GLTexture : public GPUObject { public: - Stamp _storageStamp; - Stamp _contentStamp; - GLuint _texture; - GLenum _target; + const Stamp _storageStamp; + Stamp _contentStamp { 0 }; + const GLuint _texture; + const GLenum _target; - GLTexture(); + GLTexture(const gpu::Texture& gpuTexture); ~GLTexture(); - void setSize(GLuint size); GLuint size() const { return _size; } + enum SyncState { + // The texture is currently undergoing no processing, although it's content + // may be out of date, or it's storage may be invalid relative to the + // owning GPU texture + Idle, + // The texture has been queued for transfer to the GPU + Pending, + // The texture has been transferred to the GPU, but is awaiting + // any post transfer operations that may need to occur on the + // primary rendering thread + Transferred, + }; + + void setSyncState(SyncState syncState) { _syncState = syncState; } + SyncState getSyncState() const { return _syncState; } + + // Is the storage out of date relative to the gpu texture? + bool invalid() const; + + // Is the content out of date relative to the gpu texture? + bool outdated() const; + + // Is the texture in a state where it can be rendered with no work? + bool ready() const; + + // Move the image bits from the CPU to the GPU + void transfer() const; + + // Execute any post-move operations that must occur only on the main thread + void postTransfer(); + + static const size_t CUBE_NUM_FACES = 6; + static const GLenum CUBE_FACE_LAYOUT[6]; + private: - GLuint _size; + void transferMip(GLenum target, const Texture::PixelsPointer& mip) const; + + const GLuint _size; + // The owning texture + const Texture& _gpuTexture; + std::atomic _syncState { SyncState::Idle }; }; - static GLTexture* syncGPUObject(const Texture& texture); + static GLTexture* syncGPUObject(const TexturePointer& texture); static GLuint getTextureID(const TexturePointer& texture, bool sync = true); // very specific for now - static void syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object); + static void syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object); class GLShader : public GPUObject { public: @@ -241,6 +280,11 @@ protected: void renderPassTransfer(Batch& batch); void renderPassDraw(Batch& batch); + void initTextureTransferHelper(); + static void transferGPUObject(const TexturePointer& texture); + + static std::shared_ptr _textureTransferHelper; + // Draw Stage void do_draw(Batch& batch, size_t paramOffset); void do_drawIndexed(Batch& batch, size_t paramOffset); @@ -484,6 +528,7 @@ protected: typedef void (GLBackend::*CommandCall)(Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; + }; }; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 37a10e670b..4f714fb53d 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe for (auto& b : framebuffer.getRenderBuffers()) { surface = b._texture; if (surface) { - gltexture = GLBackend::syncGPUObject(*surface); + gltexture = GLBackend::syncGPUObject(surface); } else { gltexture = nullptr; } @@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe if (framebuffer.getDepthStamp() != object->_depthStamp) { auto surface = framebuffer.getDepthStencilBuffer(); if (framebuffer.hasDepthStencil() && surface) { - gltexture = GLBackend::syncGPUObject(*surface); + gltexture = GLBackend::syncGPUObject(surface); } if (gltexture) { diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 046f1ff0e5..10845d1129 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -255,7 +255,7 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { _stats._RSNumTextureBounded++; // Always make sure the GLObject is in sync - GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); + GLTexture* object = GLBackend::syncGPUObject(resourceTexture); if (object) { GLuint to = object->_texture; GLuint target = object->_target; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 242b9100e1..92123a68be 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -9,19 +9,81 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GPULogging.h" + +#include + #include "GLBackendShared.h" #include "GLTexelFormat.h" +#include "GLBackendTextureTransfer.h" using namespace gpu; -GLBackend::GLTexture::GLTexture() : - _storageStamp(0), - _contentStamp(0), - _texture(0), - _target(GL_TEXTURE_2D), - _size(0) +GLenum gpuToGLTextureType(const Texture& texture) { + // If we get here, we need to allocate and or update the content of the texture + // or it's already being transferred + switch (texture.getType()) { + case Texture::TEX_2D: + return GL_TEXTURE_2D; + break; + + case Texture::TEX_CUBE: + return GL_TEXTURE_CUBE_MAP; + break; + + default: + qFatal("Unsupported texture type"); + } + Q_UNREACHABLE(); + return GL_TEXTURE_2D; +} + +GLuint allocateSingleTexture() { + GLuint result; + glGenTextures(1, &result); + return result; +} + +const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +// Create the texture and allocate storage +GLBackend::GLTexture::GLTexture(const Texture& texture) : + _storageStamp(texture.getStamp()), _texture(allocateSingleTexture()), + _target(gpuToGLTextureType(texture)), _size((GLuint)texture.getSize()), _gpuTexture(texture) { Backend::incrementTextureGPUCount(); + Backend::updateTextureGPUMemoryUsage(0, _size); + Backend::setGPUObject(texture, this); + + GLsizei width = texture.getWidth(); + GLsizei height = texture.getHeight(); + GLsizei levels = 1; + if (texture.maxMip() > 0) { + if (texture.isAutogenerateMips()) { + while ((width | height) >> levels) { + ++levels; + } + } + levels = std::max(1, std::min(texture.maxMip() + 1, levels)); + } + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); + withPreservedTexture(_target, [&] { + glBindTexture(_target, _texture); + (void)CHECK_GL_ERROR(); + // GO through the process of allocating the correct storage + if (GLEW_VERSION_4_2) { + glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height); + } else { + glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0); + } + (void)CHECK_GL_ERROR(); + syncSampler(texture.getSampler(), texture.getType(), this); + (void)CHECK_GL_ERROR(); + }); } GLBackend::GLTexture::~GLTexture() { @@ -32,199 +94,164 @@ GLBackend::GLTexture::~GLTexture() { Backend::decrementTextureGPUCount(); } -void GLBackend::GLTexture::setSize(GLuint size) { - Backend::updateTextureGPUMemoryUsage(_size, size); - _size = size; +bool GLBackend::GLTexture::invalid() const { + return _storageStamp < _gpuTexture.getStamp(); } -GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { - GLTexture* object = Backend::getGPUObject(texture); +bool GLBackend::GLTexture::outdated() const { + return _contentStamp < _gpuTexture.getDataStamp(); +} - // If GPU object already created and in sync - bool needUpdate = false; - if (object && (object->_storageStamp == texture.getStamp())) { - // If gpu object info is in sync with sysmem version - if (object->_contentStamp >= texture.getDataStamp()) { - // Then all good, GPU object is ready to be used - return object; - } else { - // Need to update the content of the GPU object from the source sysmem of the texture - needUpdate = true; - } - } else if (!texture.isDefined()) { +bool GLBackend::GLTexture::ready() const { + // If we have an invalid texture, we're never ready + if (invalid()) { + return false; + } + + // If we're out of date, but the transfer is in progress, report ready + // as a special case + auto syncState = _syncState.load(); + + if (outdated()) { + return Pending == syncState; + } + + return Idle == syncState; +} + +//#define USE_PBO + +// Move content bits from the CPU to the GPU for a given mip / face +void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const { + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat()); +#ifdef USE_PBO + GLuint pixelBufferID; + glGenBuffers(1, &pixelBufferID); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID); + //if (GLEW_VERSION_4_4) { + // glBufferStorage(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW); + //} else { + glBufferData(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW); + //} + void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + memcpy(mappedBuffer, mip->readData(), mip->getSize()); + //// use while PBO is still bound, assumes GL_TEXTURE_2D and offset 0 + glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, 0); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glDeleteBuffers(1, &pixelBufferID); +#else + //glTexImage2D(target, 0, internalFormat, texture.getWidth(), texture.getHeight(), 0, texelFormat.format, texelFormat.type, bytes); + glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); + (void)CHECK_GL_ERROR(); +#endif +} + +// Move content bits from the CPU to the GPU +void GLBackend::GLTexture::transfer() const { + PROFILE_RANGE(__FUNCTION__); + qDebug() << "Transferring texture: " << _texture; + // Need to update the content of the GPU object from the source sysmem of the texture + if (_contentStamp >= _gpuTexture.getDataStamp()) { + return; + } + + glBindTexture(_target, _texture); + // GO through the process of allocating the correct storage and/or update the content + switch (_gpuTexture.getType()) { + case Texture::TEX_2D: + if (_gpuTexture.isStoredMipFaceAvailable(0)) { + transferMip(GL_TEXTURE_2D, _gpuTexture.accessStoredMipFace(0)); + } + break; + + case Texture::TEX_CUBE: + // transfer pixels from each faces + for (int f = 0; f < CUBE_NUM_FACES; f++) { + if (_gpuTexture.isStoredMipFaceAvailable(0, f)) { + transferMip(CUBE_FACE_LAYOUT[f], _gpuTexture.accessStoredMipFace(0, f)); + } + } + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported"; + break; + } + + if (_gpuTexture.isAutogenerateMips()) { + glGenerateMipmap(_target); + (void)CHECK_GL_ERROR(); + } +} + +// Do any post-transfer operations that might be required on the main context / rendering thread +void GLBackend::GLTexture::postTransfer() { + setSyncState(GLTexture::Idle); + switch (_gpuTexture.getType()) { + case Texture::TEX_2D: + // At this point the mip piels have been loaded, we can notify + _gpuTexture.notifyMipFaceGPULoaded(0, 0); + break; + + case Texture::TEX_CUBE: + for (uint8_t f = 0; f < CUBE_NUM_FACES; ++f) { + // At this point the mip piels have been loaded, we can notify + _gpuTexture.notifyMipFaceGPULoaded(0, f); + } + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported"; + break; + } +} + +GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) { + const Texture& texture = *texturePointer; + if (!texture.isDefined()) { // NO texture definition yet so let's avoid thinking return nullptr; } + // If the object hasn't been created, or the object definition is out of date, drop and re-create + GLTexture* object = Backend::getGPUObject(texture); + if (object && object->ready()) { + return object; + } + + // Object isn't ready, check what we need to do... + + // Create the texture if need be (force re-creation if the storage stamp changes + // for easier use of immutable storage) + if (!object || object->invalid()) { + // This automatically destroys the old texture + object = new GLTexture(texture); + } + // need to have a gpu object? - if (!object) { - object = new GLTexture(); - glGenTextures(1, &object->_texture); - (void) CHECK_GL_ERROR(); - Backend::setGPUObject(texture, object); + if (texture.getNumSlices() != 1) { + return object; } - // GO through the process of allocating the correct storage and/or update the content - switch (texture.getType()) { - case Texture::TEX_2D: { - if (texture.getNumSlices() == 1) { - GLint boundTex = -1; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); - glBindTexture(GL_TEXTURE_2D, object->_texture); - - if (needUpdate) { - if (texture.isStoredMipFaceAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - const GLvoid* bytes = mip->readData(); - Element srcFormat = mip->getFormat(); - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glBindTexture(GL_TEXTURE_2D, object->_texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - object->_target = GL_TEXTURE_2D; - - syncSampler(texture.getSampler(), texture.getType(), object); - - - // At this point the mip piels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, 0); - - object->_contentStamp = texture.getDataStamp(); - } - } else { - const GLvoid* bytes = 0; - Element srcFormat = texture.getTexelFormat(); - if (texture.isStoredMipFaceAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - - bytes = mip->readData(); - srcFormat = mip->getFormat(); - - object->_contentStamp = texture.getDataStamp(); - } - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexImage2D(GL_TEXTURE_2D, 0, - texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, bytes); - - if (bytes && texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - object->_target = GL_TEXTURE_2D; - - syncSampler(texture.getSampler(), texture.getType(), object); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, 0); - - object->_storageStamp = texture.getStamp(); - object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); - } - - glBindTexture(GL_TEXTURE_2D, boundTex); - } - break; + // Object might be outdated, if so, start the transfer + // (outdated objects that are already in transfer will have reported 'true' for ready() + if (object->outdated()) { + _textureTransferHelper->transferTexture(texturePointer); } - case Texture::TEX_CUBE: { - if (texture.getNumSlices() == 1) { - GLint boundTex = -1; - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - const int NUM_FACES = 6; - const GLenum FACE_LAYOUT[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - if (needUpdate) { - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - // transfer pixels from each faces - for (int f = 0; f < NUM_FACES; f++) { - if (texture.isStoredMipFaceAvailable(0, f)) { - Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->getFormat(); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, f); - } - } - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - object->_target = GL_TEXTURE_CUBE_MAP; - - syncSampler(texture.getSampler(), texture.getType(), object); - - object->_contentStamp = texture.getDataStamp(); - - } else { - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - - // transfer pixels from each faces - for (int f = 0; f < NUM_FACES; f++) { - if (texture.isStoredMipFaceAvailable(0, f)) { - Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->getFormat(); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); - - // At this point the mip pixels have been loaded, we can notify - texture.notifyMipFaceGPULoaded(0, f); - } - } - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - object->_target = GL_TEXTURE_CUBE_MAP; - - syncSampler(texture.getSampler(), texture.getType(), object); - - object->_storageStamp = texture.getStamp(); - object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); - } - - glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex); - } - break; + if (GLTexture::Transferred == object->getSyncState()) { + object->postTransfer(); } - default: - qCDebug(gpulogging) << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported"; - } - (void) CHECK_GL_ERROR(); return object; } +std::shared_ptr GLBackend::_textureTransferHelper; +void GLBackend::initTextureTransferHelper() { + _textureTransferHelper = std::make_shared(); +} GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { if (!texture) { @@ -232,7 +259,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { } GLTexture* object { nullptr }; if (sync) { - object = GLBackend::syncGPUObject(*texture); + object = GLBackend::syncGPUObject(texture); } else { object = Backend::getGPUObject(*texture); } @@ -243,38 +270,37 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) { } } -void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTexture* object) { +void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GLTexture* object) { if (!object) return; - if (!object->_texture) return; class GLFilterMode { public: GLint minFilter; GLint magFilter; }; - static const GLFilterMode filterModes[] = { - {GL_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_POINT, - {GL_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR, - {GL_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT, - {GL_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR, - - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_MAG_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_MAG_POINT_MIP_LINEAR, - {GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, - {GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_POINT_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST}, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, - {GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, //FILTER_MIN_MAG_LINEAR_MIP_POINT, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, //FILTER_MIN_MAG_MIP_LINEAR, - {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} //FILTER_ANISOTROPIC, + static const GLFilterMode filterModes[] = { + { GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT, + { GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR, + { GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT, + { GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR, + + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR, + { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC, }; auto fm = filterModes[sampler.getFilter()]; glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); - static const GLenum comparisonFuncs[] = { + static const GLenum comparisonFuncs[] = { GL_NEVER, GL_LESS, GL_EQUAL, @@ -291,7 +317,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - static const GLenum wrapModes[] = { + static const GLenum wrapModes[] = { GL_REPEAT, // WRAP_REPEAT, GL_MIRRORED_REPEAT, // WRAP_MIRROR, GL_CLAMP_TO_EDGE, // WRAP_CLAMP, @@ -302,23 +328,20 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameteri(object->_target, GL_TEXTURE_WRAP_T, wrapModes[sampler.getWrapModeV()]); glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]); - glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*) &sampler.getBorderColor()); + glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset()); - glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float) sampler.getMinMip()); + glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - } - - void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); if (!resourceTexture) { return; } - GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); + GLTexture* object = GLBackend::syncGPUObject(resourceTexture); if (!object) { return; } @@ -333,7 +356,7 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { if (freeSlot < 0) { // If had to use slot 0 then restore state - GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]); + GLTexture* boundObject = GLBackend::syncGPUObject(_resource._textures[0]); if (boundObject) { glBindTexture(boundObject->_target, boundObject->_texture); } diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp new file mode 100644 index 0000000000..aa5839b5b2 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -0,0 +1,109 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLBackendTextureTransfer.h" + +#include "GLBackendShared.h" +#include "GLTexelFormat.h" + +#ifdef THREADED_TEXTURE_TRANSFER +#include +#include +#include +#endif + +using namespace gpu; + +static ProgramPtr _program; +static ProgramPtr _cubeProgram; +static ShapeWrapperPtr _plane; +static ShapeWrapperPtr _skybox; +static BasicFramebufferWrapperPtr _framebuffer; + +GLTextureTransferHelper::GLTextureTransferHelper() { +#ifdef THREADED_TEXTURE_TRANSFER + _canvas = std::make_shared(); + _canvas->create(QOpenGLContextWrapper::currentContext()); + if (!_canvas->makeCurrent()) { + qFatal("Unable to create texture transfer context"); + } + _canvas->doneCurrent(); + initialize(true, QThread::LowPriority); + _canvas->moveToThreadWithContext(_thread); +#endif +} + +void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { + GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); +#ifdef THREADED_TEXTURE_TRANSFER + TextureTransferPackage package { texturePointer, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) }; + glFlush(); + object->setSyncState(GLBackend::GLTexture::Pending); + queueItem(package); +#else + object->transfer(); + object->postTransfer(); +#endif +} + +void GLTextureTransferHelper::setup() { +#ifdef THREADED_TEXTURE_TRANSFER + _canvas->makeCurrent(); + _program = loadDefaultShader(); + _plane = loadPlane(_program); + _cubeProgram = loadCubemapShader(); + _skybox = loadSkybox(_cubeProgram); + _framebuffer = std::make_shared(); + _framebuffer->Init({ 100, 100 }); + _framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw); +#endif +} + +bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { + for (auto package : messages) { + glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(package.fence); + TexturePointer texturePointer = package.texture.lock(); + // Texture no longer exists, move on to the next + if (!texturePointer) { + continue; + } + + GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); + object->transfer(); + + // Now force a draw using the texture + try { + switch (texturePointer->getType()) { + case Texture::TEX_2D: + _program->Use(); + _plane->Use(); + _plane->Draw(); + break; + + case Texture::TEX_CUBE: + _cubeProgram->Use(); + _skybox->Use(); + _skybox->Draw(); + break; + + default: + qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << texturePointer->getType() << " not supported"; + break; + } + } catch (const std::runtime_error& error) { + qWarning() << "Failed to render texture on background thread: " << error.what(); + } + + glBindTexture(object->_target, 0); + glFinish(); + object->_contentStamp = texturePointer->getDataStamp(); + object->setSyncState(GLBackend::GLTexture::Transferred); + } + return true; +} diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.h b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h new file mode 100644 index 0000000000..3a147defdf --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h @@ -0,0 +1,61 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include "GLBackendShared.h" + +#define THREADED_TEXTURE_TRANSFER + +class OffscreenGLCanvas; + +namespace gpu { + +struct TextureTransferPackage { + std::weak_ptr texture; + GLsync fence; +}; + +class GLTextureTransferHelper : public GenericQueueThread { +public: + GLTextureTransferHelper(); + void transferTexture(const gpu::TexturePointer& texturePointer); + void postTransfer(const gpu::TexturePointer& texturePointer); + +protected: + void setup() override; + bool processQueueItems(const Queue& messages) override; + void transferTextureSynchronous(const gpu::Texture& texture); + +private: + std::shared_ptr _canvas; +}; + +template +void withPreservedTexture(GLenum target, F f) { + GLint boundTex = -1; + switch (target) { + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + break; + + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); + break; + + default: + qFatal("Unsupported texture type"); + } + (void)CHECK_GL_ERROR(); + + f(); + + glBindTexture(target, boundTex); + (void)CHECK_GL_ERROR(); +} + +} diff --git a/libraries/gpu/src/gpu/GLTexelFormat.h b/libraries/gpu/src/gpu/GLTexelFormat.h index 274b5eeba3..189189f68b 100644 --- a/libraries/gpu/src/gpu/GLTexelFormat.h +++ b/libraries/gpu/src/gpu/GLTexelFormat.h @@ -14,6 +14,9 @@ public: GLenum format; GLenum type; + static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) { + return evalGLTexelFormat(dstFormat, dstFormat); + } static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) { using namespace gpu; if (dstFormat != srcFormat) { diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index c1c31ab50a..00a80a2864 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -46,6 +46,8 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _thread->start(); _thread->setPriority(priority); + } else { + setup(); } } @@ -60,10 +62,16 @@ void GenericThread::terminate() { _thread->deleteLater(); _thread = NULL; } + } else { + shutdown(); } } void GenericThread::threadRoutine() { + if (_isThreaded) { + setup(); + } + while (!_stopThread) { // override this function to do whatever your class actually does, return false to exit thread early @@ -78,8 +86,13 @@ void GenericThread::threadRoutine() { } } - // If we were on a thread, then quit our thread - if (_isThreaded && _thread) { - _thread->quit(); + if (_isThreaded) { + shutdown(); + + // If we were on a thread, then quit our thread + if (_thread) { + _thread->quit(); + } } + } diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index 8362d3ba57..47f6d9dacd 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -33,9 +33,6 @@ public: /// Call to stop the thread void terminate(); - /// Override this function to do whatever your class actually does, return false to exit thread early. - virtual bool process() = 0; - virtual void terminating() { }; // lets your subclass know we're terminating, and it should respond appropriately bool isThreaded() const { return _isThreaded; } @@ -48,6 +45,10 @@ signals: void finished(); protected: + /// Override this function to do whatever your class actually does, return false to exit thread early. + virtual bool process() = 0; + virtual void setup() {}; + virtual void shutdown() {}; /// Locks all the resources of the thread. void lock() { _mutex.lock(); } From d1898eeac6f27fb9fb214e3795eb9b6412fe8f6d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 10:31:36 -0700 Subject: [PATCH 041/128] ModelCache: reset thread priority back to normal Based on PR feedback on https://github.com/highfidelity/hifi/pull/7550 --- .../model-networking/src/model-networking/ModelCache.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4985859c40..852e3d9e81 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -10,6 +10,7 @@ // #include "ModelCache.h" +#include #include #include "FBXReader.h" #include "OBJReader.h" @@ -117,6 +118,9 @@ void GeometryReader::run() { originalPriority = QThread::NormalPriority; } QThread::currentThread()->setPriority(QThread::LowPriority); + Finally setPriorityBackToNormal([originalPriority]() { + QThread::currentThread()->setPriority(originalPriority); + }); if (!_resource.data()) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; resource was deleted"; @@ -167,8 +171,6 @@ void GeometryReader::run() { QMetaObject::invokeMethod(resource.data(), "finishedLoading", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); } } - - QThread::currentThread()->setPriority(originalPriority); } class GeometryDefinitionResource : public GeometryResource { From e70319d83dce7a0ed7b93018b7f54cdd56908630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 4 Apr 2016 10:53:16 -0700 Subject: [PATCH 042/128] don't re-connect multiple times to QNetworkAccessManager signal --- ice-server/src/IceServer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index c1e92f276f..b66ccaa057 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -53,6 +53,10 @@ IceServer::IceServer(int argc, char* argv[]) : QTimer* inactivePeerTimer = new QTimer(this); connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers); inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS); + + // handle public keys when they arrive from the QNetworkAccessManager + auto& networkAccessManager = NetworkAccessManager::getInstance(); + connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); } bool IceServer::packetVersionMatch(const udt::Packet& packet) { @@ -200,7 +204,6 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla void IceServer::requestDomainPublicKey(const QUuid& domainID) { // send a request to the metaverse API for the public key for this domain auto& networkAccessManager = NetworkAccessManager::getInstance(); - connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); From d23d0f64326efc4ebb6cb41afa69ebafd4e54ffa Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 10:57:04 -0700 Subject: [PATCH 043/128] Restore thread priority after tex parsing --- .../src/model-networking/TextureCache.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index ff189b46f7..bbe907694a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -11,20 +11,22 @@ #include "TextureCache.h" +#include +#include +#include +#include +#include + #include #include #include -#include -#include -#include -#include -#include -#include - #include +#include +#include + #include "ModelNetworkingLogging.h" TextureCache::TextureCache() { @@ -283,10 +285,12 @@ void ImageReader::run() { originalPriority = QThread::NormalPriority; } QThread::currentThread()->setPriority(QThread::LowPriority); + Finally restorePriority([originalPriority]{ + QThread::currentThread()->setPriority(originalPriority); + }); if (!_resource.data()) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - QThread::currentThread()->setPriority(originalPriority); return; } @@ -318,7 +322,6 @@ void ImageReader::run() { auto resource = _resource.toStrongRef(); if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; - QThread::currentThread()->setPriority(originalPriority); return; } @@ -336,8 +339,6 @@ void ImageReader::run() { Q_ARG(void*, texture), Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } - - QThread::currentThread()->setPriority(originalPriority); } void NetworkTexture::setImage(void* voidTexture, int originalWidth, From 0bd747fa06a8186cb6729d9178d190409fec32f2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 11:00:27 -0700 Subject: [PATCH 044/128] remove code that sends entity 'touch' events --- examples/controllers/handControllerGrab.js | 67 ---------------------- 1 file changed, 67 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index a3bed0a256..1945ff09ff 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -7,7 +7,6 @@ // Copyright 2015 High Fidelity, Inc. // // Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// Also supports touch and equipping objects. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -305,7 +304,6 @@ function MyController(hand) { switch (this.state) { case STATE_OFF: this.off(); - this.touchTest(); break; case STATE_SEARCHING: case STATE_HOLD_SEARCHING: @@ -1675,71 +1673,6 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("continueFarTrigger"); }; - _this.allTouchedIDs = {}; - - this.touchTest = function() { - var maxDistance = 0.05; - var leftHandPosition = MyAvatar.getLeftPalmPosition(); - var rightHandPosition = MyAvatar.getRightPalmPosition(); - var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); - var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); - var ids = []; - - if (leftEntities.length !== 0) { - leftEntities.forEach(function(entity) { - ids.push(entity); - }); - - } - - if (rightEntities.length !== 0) { - rightEntities.forEach(function(entity) { - ids.push(entity); - }); - } - - ids.forEach(function(id) { - var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); - if (!props || - !props.boundingBox || - props.name === 'pointer') { - return; - } - var entityMinPoint = props.boundingBox.brn; - var entityMaxPoint = props.boundingBox.tfl; - var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); - var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); - - if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { - // we haven't been touched before, but either right or left is touching us now - _this.allTouchedIDs[id] = true; - _this.startTouch(id); - } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { - // we have been touched before and are still being touched - // continue touch - _this.continueTouch(id); - } else if (_this.allTouchedIDs[id]) { - delete _this.allTouchedIDs[id]; - _this.stopTouch(id); - } - }); - }; - - this.startTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "startTouch", args); - }; - - this.continueTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "continueTouch", args); - }; - - this.stopTouch = function(entityID) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(entityID, "stopTouch", args); - }; - this.release = function() { this.turnLightsOff(); this.turnOffVisualizations(); From a53cb2e532e568caed6f6e1b40d8cccecf2a4fa1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Apr 2016 11:10:50 -0700 Subject: [PATCH 045/128] use _gravity rather than _acceleration also tweaks and comments about supporting low gravity --- libraries/entities/src/EntityItem.cpp | 74 +++++++++++++++++++-------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5b9791ca7b..578d57273f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -895,9 +895,9 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); } - const float EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (glm::length2(angularVelocity) < EPSILON_ANGULAR_VELOCITY_LENGTH_SQUARED) { - angularVelocity = ENTITY_ITEM_ZERO_VEC3; + const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) { + angularVelocity = Vectors::ZERO; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps @@ -912,43 +912,75 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { isMoving = true; } } - if (glm::length2(linearVelocity) > 0.0f) { + glm::vec3 position = transform.getTranslation(); + + const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED = 1.0e-6f; // 1mm/sec ^2 + bool hasLinearVelocity = (glm::length2(linearVelocity) > MIN_KINEMATIC_LINEAR_SPEED_SQUARED ); + if (hasLinearVelocity) { // linear damping if (_damping > 0.0f) { linearVelocity *= powf(1.0f - _damping, timeElapsed); } - glm::vec3 linearAcceleration = _acceleration; - bool nonZeroAcceleration = (glm::length2(_acceleration) > 0.0f); - if (nonZeroAcceleration) { - // acceleration is in world-frame but we need it in local-frame - bool success; - Transform parentTransform = getParentTransform(success); - if (success) { - linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; - } + // integrate position forward sans acceleration + position += linearVelocity * timeElapsed; + } + + const float MIN_KINEMATIC_GRAVITY_MOTION_SQUARED = 1.0e-6f; // 0.001 mm/sec^2 + bool hasGravity = (glm::length2(_gravity) > MIN_KINEMATIC_GRAVITY_MOTION_SQUARED); + if (hasGravity) { + // acceleration is in world-frame but we need it in local-frame + glm::vec3 linearAcceleration = _gravity; + bool success; + Transform parentTransform = getParentTransform(success); + if (success) { + linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; } - // integrate position forward - glm::vec3 position = transform.getTranslation() + (linearVelocity * timeElapsed) + 0.5f * linearAcceleration * timeElapsed * timeElapsed; - transform.setTranslation(position); + // integrate position's acceleration term + position += 0.5f * linearAcceleration * timeElapsed * timeElapsed; // integrate linearVelocity linearVelocity += linearAcceleration * timeElapsed; + } - const float EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED = 1.0e-6f; // 1mm/sec ^2 - if (glm::length2(linearVelocity) < EPSILON_LINEAR_VELOCITY_LENGTH_SQUARED) { - setVelocity(ENTITY_ITEM_ZERO_VEC3); - if (nonZeroAcceleration) { + if (hasLinearVelocity || hasGravity) { + // We MUST eventually stop kinematic motion for slow entities otherwise they will take + // a looooong time to settle down, so we remeasure linear speed and zero the velocity + // if it is too small. + if (glm::length2(linearVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) { + linearVelocity = Vectors::ZERO; + if (!hasLinearVelocity) { + // Despite some gravity the final linear velocity is still too small to defeat the + // "effective resistance of free-space" which means we must reset position back to + // where it started since otherwise the entity may creep vveerrryy sslloowwllyy at + // a constant speed. + position = transform.getTranslation(); + + // Ultimately what this means is that there is some minimum gravity we can + // fully support for kinematic motion. It's exact value is a function of this + // entity's linearDamping and the hardcoded MIN_KINEMATIC_FOO parameters above, + // but the theoretical minimum gravity for zero damping at 90Hz is: + // + // minGravity = minSpeed / dt = 0.001 m/sec * 90 /sec = 0.09 m/sec^2 + // + // In practice the true minimum is half that value, since if the frame rate is ever + // less than the expected then sometimes dt will be twice as long. + // + // Since we don't set isMoving true here this entity is destined to transition to + // STATIC unless it has some angular motion keeping it alive. + } else { isMoving = true; } } else { isMoving = true; } } + transform.setTranslation(position); setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); + if (!isMoving) { - // flag this entity to be removed from kinematic motion + // flag this entity to transition from KINEMATIC to STATIC _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } From a08ab8e127d066aacf73ca12cac9679f1a8b19f1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 4 Apr 2016 11:48:45 -0700 Subject: [PATCH 046/128] restore setFlag in simulateKinematicMotion() --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 578d57273f..9fa58c9187 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -979,7 +979,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { transform.setTranslation(position); setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - if (!isMoving) { + if (setFlags && !isMoving) { // flag this entity to transition from KINEMATIC to STATIC _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } From aa0245b9c24822410a8e32cac698a6828d9ff1e7 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 12:20:45 -0700 Subject: [PATCH 047/128] Debug when limit of checkins reached --- libraries/networking/src/NodeList.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 02bb17e870..63189abb3e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -336,6 +336,7 @@ void NodeList::sendDomainServerCheckIn() { if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS // so emit our signal that says that + qDebug() << "Limit of silent domain checkins reached"; emit limitOfSilentDomainCheckInsReached(); } From a9197385b5437f160e656867e8b6fea66d40e9e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 12:24:26 -0700 Subject: [PATCH 048/128] Make debug builds work again. Only run mt.exe on the manifest in non development builds. --- interface/CMakeLists.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b7aeb7696e..2e50502840 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -107,12 +107,15 @@ elseif(WIN32) # add an executable that also has the icon itself and the configured rc file as resources add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT}) - add_custom_command( - TARGET ${TARGET_NAME} - POST_BUILD - COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$"\;\#1 -outputresource:"$"\;\#1 - COMMENT "Adding OS version support manifest to exe" - ) + if ( NOT DEV_BUILD ) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$"\;\#1 -outputresource:"$"\;\#1 + COMMENT "Adding OS version support manifest to exe" + ) + endif() + else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() From d7b13d226f5b469098c7556ebef75199165d0d7d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 4 Apr 2016 12:36:18 -0700 Subject: [PATCH 049/128] Application: fix for jittery hands when moving. The issue was that the hands are sampled in sensor coordinates. But when the avatar is moved via physics, the sensor to world matrix must be updated to move the hands in the world by the correct amount. These new hand positions are then computed before IK is performed. --- interface/src/Application.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0172b3ce3a..9e97fba466 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1470,10 +1470,6 @@ void Application::paintGL() { // update the avatar with a fresh HMD pose getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); - // update sensorToWorldMatrix for camera and hand controllers - getMyAvatar()->updateSensorToWorldMatrix(); - - auto lodManager = DependencyManager::get(); @@ -3406,6 +3402,9 @@ void Application::update(float deltaTime) { avatarManager->updateOtherAvatars(deltaTime); } + // update sensorToWorldMatrix for camera and hand controllers + getMyAvatar()->updateSensorToWorldMatrix(); + qApp->updateMyAvatarLookAtPosition(); { From ace4546dec1a5fcbb064baefbd52d266febba836 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 12:49:03 -0700 Subject: [PATCH 050/128] make handGrabController search ray follow controller rather than IK driven hand --- examples/controllers/handControllerGrab.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index a3bed0a256..d8795341bb 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -495,7 +495,8 @@ function MyController(hand) { } }; - this.searchIndicatorOn = function(handPosition, distantPickRay) { + this.searchIndicatorOn = function(distantPickRay) { + var handPosition = distantPickRay.origin; var SEARCH_SPHERE_SIZE = 0.011; var SEARCH_SPHERE_FOLLOW_RATE = 0.50; @@ -857,7 +858,9 @@ function MyController(hand) { var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; - var currentControllerPosition = Controller.getPoseValue(controllerHandInput).position; + var currentControllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, + Controller.getPoseValue(controllerHandInput).translation), + MyAvatar.position); var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? @@ -865,19 +868,13 @@ function MyController(hand) { var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); var distantPickRay = { - origin: PICK_WITH_HAND_RAY ? handPosition : Camera.position, + origin: PICK_WITH_HAND_RAY ? currentControllerPosition : Camera.position, direction: PICK_WITH_HAND_RAY ? Quat.getUp(controllerRotation) : Vec3.mix(Quat.getUp(controllerRotation), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), length: PICK_MAX_DISTANCE }; - var searchVisualizationPickRay = { - origin: currentControllerPosition, - direction: Quat.getUp(this.getHandRotation()), - length: PICK_MAX_DISTANCE - }; - // Pick at some maximum rate, not always var pickRays = []; var now = Date.now(); @@ -1086,7 +1083,7 @@ function MyController(hand) { this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } - this.searchIndicatorOn(handPosition, distantPickRay); + this.searchIndicatorOn(distantPickRay); Reticle.setVisible(false); }; @@ -1668,7 +1665,7 @@ function MyController(hand) { if (intersection.intersects) { this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); } - this.searchIndicatorOn(handPosition, pickRay); + this.searchIndicatorOn(pickRay); } } From b3b5c5d1eacee6d761034477d16b5c256f5d711b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 4 Apr 2016 13:14:52 -0700 Subject: [PATCH 051/128] small change to trigger a build --- interface/src/Application.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61d0f4f995..fdd31ed579 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,9 +169,7 @@ #include "Util.h" #include "InterfaceParentFinder.h" - - -// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU +// ON Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) extern "C" { From f34e951c3f06de3c04b27c2553a5cab82e4b8880 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:13 -0700 Subject: [PATCH 052/128] Make resource cache props thread-safe --- libraries/networking/src/ResourceCache.cpp | 32 ++++++++++++++++------ libraries/networking/src/ResourceCache.h | 31 +++++++++++++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1f687593bb..2e2b89046b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() { void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResource(); + resetResourceCounters(); // Refresh all remaining resources in use foreach (auto resource, _resources) { @@ -53,16 +54,24 @@ void ResourceCache::refresh(const QUrl& url) { resource->refresh(); } else { _resources.remove(url); + resetResourceCounters(); } } -const QVariantList ResourceCache::getResourceList() const { +QVariantList ResourceCache::getResourceList() { QVariantList list; - auto resources = _resources.uniqueKeys(); - list.reserve(resources.size()); - for (auto& resource : resources) { - list << resource; + if (QThread::currentThread() != thread()) { + // NOTE: invokeMethod does not allow a const QObject* + QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariantList, list)); + } else { + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } } + return list; } @@ -124,7 +133,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); - emit dirty(); + resetResourceCounters(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -138,7 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); - emit dirty(); + + resetResourceCounters(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -146,7 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } - emit dirty(); + resetResourceCounters(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -177,6 +187,12 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::resetResourceCounters() { + _numTotalResources = _resources.size(); + _numUnusedResources = _unusedResources.size(); + emit dirty(); +} + void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { _totalResourcesSize += (newSize - oldSize); emit dirty(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 3f930a1f11..933eb1a6d9 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -12,7 +12,9 @@ #ifndef hifi_ResourceCache_h #define hifi_ResourceCache_h +#include #include + #include #include #include @@ -29,6 +31,8 @@ #include "ResourceManager.h" +Q_DECLARE_METATYPE(size_t) + class QNetworkReply; class QTimer; @@ -79,20 +83,19 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT - Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) - Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) - Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) + Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) public: - int getNumTotalResources() const { return _resources.size(); } - qint64 getSizeTotalResources() const { return _totalResourcesSize; } + size_t getNumTotalResources() const { return _numTotalResources; } + size_t getSizeTotalResources() const { return _totalResourcesSize; } - int getNumCachedResources() const { return _unusedResources.size(); } - qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + size_t getNumCachedResources() const { return _numUnusedResources; } + size_t getSizeCachedResources() const { return _unusedResourcesSize; } - const QVariantList getResourceList() const; + Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -149,6 +152,7 @@ private: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); + void resetResourceCounters(); QHash> _resources; int _lastLRUKey = 0; @@ -160,8 +164,11 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; - qint64 _totalResourcesSize { 0 }; - qint64 _unusedResourcesSize { 0 }; + std::atomic _numTotalResources { 0 }; + std::atomic _numUnusedResources { 0 }; + + std::atomic _totalResourcesSize { 0 }; + std::atomic _unusedResourcesSize { 0 }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; QMap> _unusedResources; From 107cfcf10b5acf675a9fb5102b25c737f29663d2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:30 -0700 Subject: [PATCH 053/128] Change Resource setBytes->setSize --- .../model-networking/src/model-networking/TextureCache.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 4 ++-- libraries/networking/src/ResourceCache.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..2ffd7e18a0 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -338,7 +338,7 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth, if (gpuTexture) { _width = gpuTexture->getWidth(); _height = gpuTexture->getHeight(); - setBytes(gpuTexture->getStoredSize()); + setSize(gpuTexture->getStoredSize()); } else { // FIXME: If !gpuTexture, we failed to load! _width = _height = 0; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 2e2b89046b..c661c2f32a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -416,7 +416,7 @@ void Resource::finishedLoading(bool success) { emit finished(success); } -void Resource::setBytes(const qint64& bytes) { +void Resource::setSize(const qint64& bytes) { QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); _bytes = bytes; } @@ -456,7 +456,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - setBytes(_bytesTotal); + setSize(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 933eb1a6d9..84eba1cdc0 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -255,7 +255,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(const qint64& bytes); + void setSize(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing. From b8587e0711591ac852739ce300217a7a37cd405d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 16:06:53 -0700 Subject: [PATCH 054/128] update collision shapes of entities which are children of avatars --- libraries/entities/src/EntityItem.cpp | 6 +++++- libraries/physics/src/EntityMotionState.cpp | 7 ++++++- libraries/shared/src/SpatiallyNestable.cpp | 15 +++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9fa58c9187..6306277431 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1963,7 +1963,11 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG } void EntityItem::locationChanged() { - requiresRecalcBoxes(); + _dirtyFlags |= Simulation::DIRTY_TRANSFORM; + EntityTreePointer tree = getTree(); + if (tree) { + tree->entityChanged(getThisPointer()); + } SpatiallyNestable::locationChanged(); // tell all the children, also } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5f168d2e33..f232827fc2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -159,7 +159,12 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { } return MOTION_TYPE_DYNAMIC; } - return (_entity->isMovingRelativeToParent() || _entity->hasActions()) ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC; + if (_entity->isMovingRelativeToParent() || + _entity->hasActions() || + _entity->hasAncestorOfType(NestableType::Avatar)) { + return MOTION_TYPE_KINEMATIC; + } + return MOTION_TYPE_STATIC; } bool EntityMotionState::isMoving() const { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 3cbd3c5ac9..dfe1f2c0e4 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -879,3 +879,18 @@ void SpatiallyNestable::setLocalTransformAndVelocities( }); locationChanged(); } + + +bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) { + if (_nestableType == nestableType) { + return true; + } + + bool success; + SpatiallyNestablePointer parent = getParentPointer(success); + if (!success || !parent) { + return false; + } + + return parent->hasAncestorOfType(nestableType); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ef70d0231b..8b225d5ae8 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -142,6 +142,8 @@ public: bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; } virtual SpatialParentTree* getParentTree() const { return nullptr; } + bool hasAncestorOfType(NestableType nestableType); + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; From 69bb0ebd741f56f388e560728359d759b8d9d5ff Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 16:11:54 -0700 Subject: [PATCH 055/128] Revert "faster kinematic motion for entities" --- libraries/entities/src/EntityItem.cpp | 161 ++++++++++-------- libraries/physics/src/EntityMotionState.cpp | 19 ++- libraries/physics/src/EntityMotionState.h | 6 +- libraries/physics/src/ObjectMotionState.cpp | 21 +-- libraries/physics/src/ObjectMotionState.h | 10 +- libraries/physics/src/PhysicsEngine.cpp | 31 +--- libraries/physics/src/PhysicsEngine.h | 6 +- .../physics/src/ThreadSafeDynamicsWorld.cpp | 26 +-- .../physics/src/ThreadSafeDynamicsWorld.h | 1 - libraries/shared/src/GLMHelpers.cpp | 8 + libraries/shared/src/GLMHelpers.h | 4 +- libraries/shared/src/PhysicsCollisionGroups.h | 4 +- libraries/shared/src/SharedUtil.cpp | 17 +- libraries/shared/src/SharedUtil.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 50 ++---- libraries/shared/src/SpatiallyNestable.h | 7 - libraries/shared/src/Transform.cpp | 4 + libraries/shared/src/Transform.h | 2 +- 18 files changed, 164 insertions(+), 219 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9fa58c9187..431d638063 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -876,112 +876,123 @@ void EntityItem::simulate(const quint64& now) { } void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { - if (hasActions() || timeElapsed < 0.0f) { +#ifdef WANT_DEBUG + qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; +#endif + + const float MIN_TIME_SKIP = 0.0f; + const float MAX_TIME_SKIP = 1.0f; // in seconds + + timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); + + if (hasActions()) { return; } - const float MAX_TIME_ELAPSED = 1.0f; // seconds - timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED); + if (hasLocalAngularVelocity()) { + glm::vec3 localAngularVelocity = getLocalAngularVelocity(); - Transform transform; - glm::vec3 linearVelocity; - glm::vec3 angularVelocity; - getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - - bool isMoving = false; - if (glm::length2(angularVelocity) > 0.0f) { // angular damping if (_angularDamping > 0.0f) { - angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); + localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed); + #ifdef WANT_DEBUG + qCDebug(entities) << " angularDamping :" << _angularDamping; + qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity; + #endif } - const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED = 0.0017453f * 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec - if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) { - angularVelocity = Vectors::ZERO; + float angularSpeed = glm::length(localAngularVelocity); + + const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec + if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { + if (setFlags && angularSpeed > 0.0f) { + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } + localAngularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { // for improved agreement with the way Bullet integrates rotations we use an approximation // and break the integration into bullet-sized substeps - glm::quat rotation = transform.getRotation(); + glm::quat rotation = getRotation(); float dt = timeElapsed; - while (dt > 0.0f) { - glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP)); + while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) { + glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP); rotation = glm::normalize(dQ * rotation); dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; } - transform.setRotation(rotation); - isMoving = true; - } - } - glm::vec3 position = transform.getTranslation(); + // NOTE: this final partial substep can drift away from a real Bullet simulation however + // it only becomes significant for rapidly rotating objects + // (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec). + glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt); + rotation = glm::normalize(dQ * rotation); - const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED = 1.0e-6f; // 1mm/sec ^2 - bool hasLinearVelocity = (glm::length2(linearVelocity) > MIN_KINEMATIC_LINEAR_SPEED_SQUARED ); - if (hasLinearVelocity) { - // linear damping - if (_damping > 0.0f) { - linearVelocity *= powf(1.0f - _damping, timeElapsed); + setRotation(rotation); } - // integrate position forward sans acceleration - position += linearVelocity * timeElapsed; + setLocalAngularVelocity(localAngularVelocity); } - const float MIN_KINEMATIC_GRAVITY_MOTION_SQUARED = 1.0e-6f; // 0.001 mm/sec^2 - bool hasGravity = (glm::length2(_gravity) > MIN_KINEMATIC_GRAVITY_MOTION_SQUARED); - if (hasGravity) { - // acceleration is in world-frame but we need it in local-frame - glm::vec3 linearAcceleration = _gravity; + if (hasLocalVelocity()) { + + // acceleration is in the global frame, so transform it into the local frame. + // TODO: Move this into SpatiallyNestable. bool success; - Transform parentTransform = getParentTransform(success); + Transform transform = getParentTransform(success); + glm::vec3 localAcceleration(glm::vec3::_null); if (success) { - linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration; + localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration(); + } else { + localAcceleration = getAcceleration(); } - // integrate position's acceleration term - position += 0.5f * linearAcceleration * timeElapsed * timeElapsed; + // linear damping + glm::vec3 localVelocity = getLocalVelocity(); + if (_damping > 0.0f) { + localVelocity *= powf(1.0f - _damping, timeElapsed); + #ifdef WANT_DEBUG + qCDebug(entities) << " damping:" << _damping; + qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity; + qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity); + #endif + } - // integrate linearVelocity - linearVelocity += linearAcceleration * timeElapsed; - } + // integrate position forward + glm::vec3 localPosition = getLocalPosition(); + glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed; - if (hasLinearVelocity || hasGravity) { - // We MUST eventually stop kinematic motion for slow entities otherwise they will take - // a looooong time to settle down, so we remeasure linear speed and zero the velocity - // if it is too small. - if (glm::length2(linearVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) { - linearVelocity = Vectors::ZERO; - if (!hasLinearVelocity) { - // Despite some gravity the final linear velocity is still too small to defeat the - // "effective resistance of free-space" which means we must reset position back to - // where it started since otherwise the entity may creep vveerrryy sslloowwllyy at - // a constant speed. - position = transform.getTranslation(); + #ifdef WANT_DEBUG + qCDebug(entities) << " EntityItem::simulate()...."; + qCDebug(entities) << " timeElapsed:" << timeElapsed; + qCDebug(entities) << " old AACube:" << getMaximumAACube(); + qCDebug(entities) << " old position:" << localPosition; + qCDebug(entities) << " old velocity:" << localVelocity; + qCDebug(entities) << " old getAABox:" << getAABox(); + qCDebug(entities) << " newPosition:" << newPosition; + qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition); + #endif - // Ultimately what this means is that there is some minimum gravity we can - // fully support for kinematic motion. It's exact value is a function of this - // entity's linearDamping and the hardcoded MIN_KINEMATIC_FOO parameters above, - // but the theoretical minimum gravity for zero damping at 90Hz is: - // - // minGravity = minSpeed / dt = 0.001 m/sec * 90 /sec = 0.09 m/sec^2 - // - // In practice the true minimum is half that value, since if the frame rate is ever - // less than the expected then sometimes dt will be twice as long. - // - // Since we don't set isMoving true here this entity is destined to transition to - // STATIC unless it has some angular motion keeping it alive. - } else { - isMoving = true; + localPosition = newLocalPosition; + + // apply effective acceleration, which will be the same as gravity if the Entity isn't at rest. + localVelocity += localAcceleration * timeElapsed; + + float speed = glm::length(localVelocity); + const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec + if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { + setVelocity(ENTITY_ITEM_ZERO_VEC3); + if (setFlags && speed > 0.0f) { + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } else { - isMoving = true; + setLocalPosition(localPosition); + setLocalVelocity(localVelocity); } - } - transform.setTranslation(position); - setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity); - if (setFlags && !isMoving) { - // flag this entity to transition from KINEMATIC to STATIC - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + #ifdef WANT_DEBUG + qCDebug(entities) << " new position:" << position; + qCDebug(entities) << " new velocity:" << velocity; + qCDebug(entities) << " new AACube:" << getMaximumAACube(); + qCDebug(entities) << " old getAABox:" << getAABox(); + #endif } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5f168d2e33..e3952ba1d6 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() { } // virtual -void EntityMotionState::handleEasyChanges(uint32_t& flags) { +bool EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); @@ -137,6 +137,8 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); } + + return true; } @@ -173,13 +175,11 @@ bool EntityMotionState::isMoving() const { // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { - BT_PROFILE("getWorldTransform"); if (!_entity) { return; } assert(entityTreeIsLocked()); if (_motionType == MOTION_TYPE_KINEMATIC) { - BT_PROFILE("kinematicIntegration"); // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. uint32_t thisStep = ObjectMotionState::getWorldSimulationStep(); @@ -420,18 +420,19 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. - if (_accelerationNearlyGravityCount < STEPS_TO_DECIDE_BALLISTIC) { - // only increment this if we haven't reached the threshold yet, to avoid overflowing the counter - ++_accelerationNearlyGravityCount; + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); } } else { - // acceleration wasn't similar to this entity's gravity, reset the counter - _accelerationNearlyGravityCount = 0; + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); } // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // the entity server's estimates include gravity. - if (_accelerationNearlyGravityCount >= STEPS_TO_DECIDE_BALLISTIC) { + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); } else { _entity->setAcceleration(glm::vec3(0.0f)); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index eb42d03b52..ac16ec6d5d 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,7 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual void handleEasyChanges(uint32_t& flags) override; + virtual bool handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; /// \return PhysicsMotionType based on params set in EntityItem @@ -51,6 +51,10 @@ public: virtual uint32_t getIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override; + void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } + void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } + uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectFriction() const override { return _entity->getFriction(); } virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index e902758461..482c3146f8 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -38,11 +38,8 @@ const glm::vec3& ObjectMotionState::getWorldOffset() { return _worldOffset; } -// We init worldSimulationStep to 1 instead of 0 because we initialize _lastKineticStep to (worldSimulationStep - 1) -// so that the object starts moving on the first frame that it was set kinematic. -static uint32_t worldSimulationStep { 1 }; - // static +uint32_t worldSimulationStep = 0; void ObjectMotionState::setWorldSimulationStep(uint32_t step) { assert(step > worldSimulationStep); worldSimulationStep = step; @@ -167,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -void ObjectMotionState::handleEasyChanges(uint32_t& flags) { +bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -186,10 +183,6 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { worldTrans.setRotation(newRotation); } _body->setWorldTransform(worldTrans); - if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { - // force activate static body so its Aabb is updated later - _body->activate(true); - } } else if (flags & Simulation::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); btQuaternion newRotation = glmToBullet(getObjectRotation()); @@ -199,10 +192,6 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { } worldTrans.setRotation(newRotation); _body->setWorldTransform(worldTrans); - if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) { - // force activate static body so its Aabb is updated later - _body->activate(true); - } } if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { @@ -243,6 +232,8 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_MASS) { updateBodyMassProperties(); } + + return true; } bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { @@ -301,10 +292,6 @@ void ObjectMotionState::updateBodyVelocities() { _body->setActivationState(ACTIVE_TAG); } -void ObjectMotionState::updateLastKinematicStep() { - _lastKinematicStep = ObjectMotionState::getWorldSimulationStep() - 1; -} - void ObjectMotionState::updateBodyMassProperties() { float mass = getMass(); btVector3 inertia(0.0f, 0.0f, 0.0f); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 44cb88721c..bb78eb12d6 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -50,12 +50,11 @@ const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TY Simulation::DIRTY_COLLISION_GROUP); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | - Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY | - Simulation::DIRTY_PHYSICS_ACTIVATION); - + Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); // These are the set of incoming flags that the PhysicsEngine needs to hear about: -const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS); +const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | + Simulation::DIRTY_PHYSICS_ACTIVATION); // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES; @@ -81,12 +80,11 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual void handleEasyChanges(uint32_t& flags); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); void updateBodyVelocities(); - void updateLastKinematicStep(); virtual void updateBodyMassProperties(); MotionStateType getType() const { return _type; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index be80149c96..0040c19c3d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -50,13 +50,6 @@ void PhysicsEngine::init() { // default gravity of the world is zero, so each object must specify its own gravity // TODO: set up gravity zones _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - - // By default Bullet will update the Aabb's of all objects every frame, even statics. - // This can waste CPU cycles so we configure Bullet to only update ACTIVE objects here. - // However, this means when a static object is moved we must manually update its Aabb - // in order for its broadphase collision queries to work correctly. Look at how we use - // _activeStaticBodies to track and update the Aabb's of moved static objects. - _dynamicsWorld->setForceUpdateAllAabbs(false); } } @@ -87,7 +80,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->updateBodyVelocities(); - motionState->updateLastKinematicStep(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -197,18 +189,12 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - object->handleEasyChanges(flags); - object->clearIncomingDirtyFlags(); + if (object->handleEasyChanges(flags)) { + object->clearIncomingDirtyFlags(); + } else { + stillNeedChange.push_back(object); + } } - if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { - _activeStaticBodies.push_back(object->getRigidBody()); - } - } - // active static bodies have changed (in an Easy way) and need their Aabbs updated - // but we've configured Bullet to NOT update them automatically (for improved performance) - // so we must do it ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); } return stillNeedChange; } @@ -254,7 +240,6 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); if (_myAvatarController) { - BT_PROFILE("avatarController"); // TODO: move this stuff outside and in front of stepSimulation, because // the updateShapeIfNecessary() call needs info from MyAvatar and should // be done on the main thread during the pre-simulation stuff @@ -403,12 +388,6 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { BT_PROFILE("copyOutgoingChanges"); - // Bullet will not deactivate static objects (it doesn't expect them to be active) - // so we must deactivate them ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); - } - _activeStaticBodies.clear(); _dynamicsWorld->synchronizeMotionStates(); _hasOutgoingChanges = false; return _dynamicsWorld->getChangedMotionStates(); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 18e4016fec..f644d6f5b2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -13,9 +13,9 @@ #define hifi_PhysicsEngine_h #include -#include #include +#include #include #include @@ -41,7 +41,7 @@ public: }; typedef std::map ContactMap; -typedef std::vector CollisionEvents; +typedef QVector CollisionEvents; class PhysicsEngine { public: @@ -110,7 +110,6 @@ private: ContactMap _contactMap; CollisionEvents _collisionEvents; QHash _objectActions; - std::vector _activeStaticBodies; glm::vec3 _originOffset; QUuid _sessionID; @@ -122,6 +121,7 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; + }; typedef std::shared_ptr PhysicsEnginePointer; diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 5fe99f137c..b6f3487f1a 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -67,10 +67,7 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep saveKinematicState(fixedTimeStep*clampedSimulationSteps); - { - BT_PROFILE("applyGravity"); - applyGravity(); - } + applyGravity(); for (int i=0;igetActivationState() != ISLAND_SLEEPING) - { - if (body->isKinematicObject()) - { - //to calculate velocities next frame - body->saveKinematicState(timeStep); - } - } - } -} - - diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 68062d8d29..e9708149da 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -41,7 +41,6 @@ public: btScalar fixedTimeStep = btScalar(1.)/btScalar(60.), SubStepCallback onSubStep = []() { }); virtual void synchronizeMotionStates() override; - virtual void saveKinematicState(btScalar timeStep) override; // btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated // but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 53abb3827d..d21d88d212 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -463,6 +463,14 @@ glm::vec2 getFacingDir2D(const glm::mat4& m) { } } +bool isNaN(glm::vec3 value) { + return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} + +bool isNaN(glm::quat value) { + return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} + glm::mat4 orthoInverse(const glm::mat4& m) { glm::mat4 r = m; r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 8b1446d4e5..469ca1fc81 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -229,8 +229,8 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec2 getFacingDir2D(const glm::quat& rot); glm::vec2 getFacingDir2D(const glm::mat4& m); -inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } -inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +bool isNaN(glm::vec3 value); +bool isNaN(glm::quat value); glm::mat4 orthoInverse(const glm::mat4& m); diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 794f338dc5..6d320e69cb 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -51,10 +51,10 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; // STATIC does not collide with itself (as optimization of physics simulation) -const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_KINEMATIC | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC; +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; // MY_AVATAR does not collide with itself const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index d48bddbd88..30d4726bcc 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -247,6 +247,12 @@ int getNthBit(unsigned char byte, int ordinal) { return ERROR_RESULT; } +bool isBetween(int64_t value, int64_t max, int64_t min) { + return ((value <= max) && (value >= min)); +} + + + void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 @@ -254,7 +260,12 @@ void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { bool isInEnvironment(const char* environment) { char* environmentString = getenv("HIFI_ENVIRONMENT"); - return (environmentString && strcmp(environmentString, environment) == 0); + + if (environmentString && strcmp(environmentString, environment) == 0) { + return true; + } else { + return false; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -621,6 +632,10 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } +bool isNaN(float value) { + return value != value; +} + QString formatUsecTime(float usecs, int prec) { static const quint64 SECONDS_PER_MINUTE = 60; static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index e9201b4a92..8fb65a5247 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -180,11 +180,11 @@ private: static int DEADBEEF_SIZE; }; -/// \return true when value is between max and min -inline bool isBetween(int64_t value, int64_t max, int64_t min) { return ((value <= max) && (value >= min)); } +bool isBetween(int64_t value, int64_t max, int64_t min); + /// \return bool is the float NaN -inline bool isNaN(float value) { return value != value; } +bool isNaN(float value); QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 3cbd3c5ac9..13bf5d9054 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -90,9 +90,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons return parent; } + SpatiallyNestablePointer thisPointer = getThisPointer(); + if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(getThisPointer()); + parent->forgetChild(thisPointer); _parentKnowsMe = false; _parent.reset(); } @@ -110,11 +112,16 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons parent = _parent.lock(); if (parent) { - parent->beParentOfChild(getThisPointer()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } - success = (parent || parentID.isNull()); + if (parent || parentID.isNull()) { + success = true; + } else { + success = false; + } + return parent; } @@ -842,40 +849,3 @@ AACube SpatiallyNestable::getQueryAACube() const { } return result; } - -void SpatiallyNestable::getLocalTransformAndVelocities( - Transform& transform, - glm::vec3& velocity, - glm::vec3& angularVelocity) const { - // transform - _transformLock.withReadLock([&] { - transform = _transform; - }); - // linear velocity - _velocityLock.withReadLock([&] { - velocity = _velocity; - }); - // angular velocity - _angularVelocityLock.withReadLock([&] { - angularVelocity = _angularVelocity; - }); -} - -void SpatiallyNestable::setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity) { - // transform - _transformLock.withWriteLock([&] { - _transform = localTransform; - }); - // linear velocity - _velocityLock.withWriteLock([&] { - _velocity = localVelocity; - }); - // angular velocity - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = localAngularVelocity; - }); - locationChanged(); -} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ef70d0231b..379f2facd7 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -149,13 +149,6 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - - void setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity); - mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index c51b3dae4b..a3a3c05731 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -150,3 +150,7 @@ QJsonObject Transform::toJson(const Transform& transform) { } return result; } + +bool Transform::containsNaN() const { + return isNaN(_rotation) || isNaN(_scale) || isNaN(_translation); +} diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 1e1d10c54b..1024173cbd 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -145,7 +145,7 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; - bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); } + bool containsNaN() const; protected: From 7b7ec5a174a0b1120278869beb9f044b5f8791ff Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 4 Apr 2016 16:41:21 -0700 Subject: [PATCH 056/128] Prohibit entity script file includes from outside the original entity script's directory (unless its in our resources). --- libraries/script-engine/src/ScriptEngine.cpp | 70 ++++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 7 +- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 31047dd423..15690baa0f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -578,7 +578,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& _registeredHandlers[entityID] = RegisteredEventHandlers(); } CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName]; - CallbackData handlerData = {handler, currentEntityIdentifier}; + CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL}; handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). } @@ -795,7 +795,7 @@ void ScriptEngine::timerFired() { // call the associated JS function, if it exists if (timerData.function.isValid()) { - callWithEnvironment(timerData.definingEntityIdentifier, timerData.function, timerData.function, QScriptValueList()); + callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList()); } } @@ -810,7 +810,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int // make sure the timer stops when the script does connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); - CallbackData timerData = {function, currentEntityIdentifier}; + CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL}; _timerFunctionMap.insert(newTimer, timerData); newTimer->start(intervalMS); @@ -885,19 +885,46 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac return; // bail early } QList urls; + bool knowsSensitivity = false; + Qt::CaseSensitivity sensitivity; + auto getSensitivity = [&]() { + if (!knowsSensitivity) { + QString path = currentSandboxURL.path(); + QFileInfo upperFI(path.toUpper()); + QFileInfo lowerFI(path.toLower()); + sensitivity = (upperFI == lowerFI) ? Qt::CaseInsensitive : Qt::CaseSensitive; + knowsSensitivity = true; + } + return sensitivity; + }; + for (QString file : includeFiles) { QUrl thisURL { resolvePath(file) }; if (!_includedURLs.contains(thisURL)) { - urls.append(thisURL); - _includedURLs << thisURL; - } - else { + if (!currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") && + ( + (currentSandboxURL.scheme() != "file") || + ( + !thisURL.toString(QUrl::RemoveFilename).startsWith(defaultScriptsLocation().toString(), getSensitivity()) && + !thisURL.toString(QUrl::RemoveFilename).startsWith(currentSandboxURL.toString(QUrl::RemoveFilename), getSensitivity()) + ) + ) + ) { + qCWarning(scriptengine) << "Script.include() ignoring file path" << thisURL << "outside of original entity script" << currentSandboxURL; + } else { + // We could also check here for CORS, but we don't yet. + // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here. + urls.append(thisURL); + _includedURLs << thisURL; + } + } else { qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL; } } BatchLoader* loader = new BatchLoader(urls); EntityItemID capturedEntityIdentifier = currentEntityIdentifier; + QUrl capturedSandboxURL = currentSandboxURL; auto evaluateScripts = [=](const QMap& data) { auto parentURL = _parentURL; @@ -912,13 +939,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac auto operation = [&]() { evaluate(contents, url.toString()); }; - doWithEnvironment(capturedEntityIdentifier, operation); + doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); } } _parentURL = parentURL; if (callback.isFunction()) { - callWithEnvironment(capturedEntityIdentifier, QScriptValue(callback), QScriptValue(), QScriptValueList()); + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, QScriptValue(callback), QScriptValue(), QScriptValueList()); } loader->deleteLater(); @@ -996,10 +1023,11 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin CallbackList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { for (int i = 0; i < handlersForEvent.count(); ++i) { - // handlersForEvent[i] can tonain many handlers that may have each been added by different interface or entity scripts, + // handlersForEvent[i] can contain many handlers that may have each been added by different interface or entity scripts, // and the entity scripts may be for entities other than the one this is a handler for. // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added. - callWithEnvironment(handlersForEvent[i].definingEntityIdentifier, handlersForEvent[i].function, QScriptValue(), eventHandlerArgs); + CallbackData& handler = handlersForEvent[i]; + callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, QScriptValue(), eventHandlerArgs); } } } @@ -1106,13 +1134,14 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } QScriptValue entityScriptConstructor, entityScriptObject; + QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL; auto initialization = [&]{ entityScriptConstructor = evaluate(contents, fileName); entityScriptObject = entityScriptConstructor.construct(); }; - doWithEnvironment(entityID, initialization); + doWithEnvironment(entityID, sandboxURL, initialization); - EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; + EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified, sandboxURL }; _entityScripts[entityID] = newDetails; if (isURL) { setParentURL(""); @@ -1201,9 +1230,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { // Even if entityID is supplied as currentEntityIdentifier, this still documents the source // of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different // global values for different entity scripts). -void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function operation) { +void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation) { EntityItemID oldIdentifier = currentEntityIdentifier; + QUrl oldSandboxURL = currentSandboxURL; currentEntityIdentifier = entityID; + currentSandboxURL = sandboxURL; #if DEBUG_CURRENT_ENTITY QScriptValue oldData = this->globalObject().property("debugEntityID"); @@ -1215,12 +1246,13 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function #endif currentEntityIdentifier = oldIdentifier; + currentSandboxURL = oldSandboxURL; } -void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { +void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { auto operation = [&]() { function.call(thisObject, args); }; - doWithEnvironment(entityID, operation); + doWithEnvironment(entityID, sandboxURL, operation); } void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) { @@ -1249,7 +1281,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QScriptValueList args; args << entityID.toScriptValue(this); args << qScriptValueFromSequence(this, params); - callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); } } @@ -1281,7 +1313,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QScriptValueList args; args << entityID.toScriptValue(this); args << event.toScriptValue(this); - callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); } } } @@ -1315,7 +1347,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS args << entityID.toScriptValue(this); args << otherID.toScriptValue(this); args << collisionToScriptValue(this, collision); - callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8dfc9c9abe..a6a623e751 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -47,6 +47,7 @@ class CallbackData { public: QScriptValue function; EntityItemID definingEntityIdentifier; + QUrl definingSandboxURL; }; typedef QList CallbackList; @@ -57,6 +58,7 @@ public: QString scriptText; QScriptValue scriptObject; int64_t lastModified; + QUrl definingSandboxURL; }; class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider { @@ -214,8 +216,9 @@ protected: Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); EntityItemID currentEntityIdentifier {}; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. - void doWithEnvironment(const EntityItemID& entityID, std::function operation); - void callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args); + QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty. + void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); + void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); friend class ScriptEngines; static std::atomic _stoppingAllScripts; From c168e2cc5894be2d612b50f15d9bfebcb8e8de40 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 4 Apr 2016 13:37:18 -0700 Subject: [PATCH 057/128] PR feedback --- libraries/gpu/src/gpu/GLBackend.h | 6 ++-- libraries/gpu/src/gpu/GLBackendTexture.cpp | 23 +++++++-------- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 29 +++++++++++++++---- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 4f22a68631..f9fd299827 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -103,13 +103,13 @@ public: SyncState getSyncState() const { return _syncState; } // Is the storage out of date relative to the gpu texture? - bool invalid() const; + bool isInvalid() const; // Is the content out of date relative to the gpu texture? - bool outdated() const; + bool isOutdated() const; // Is the texture in a state where it can be rendered with no work? - bool ready() const; + bool isReady() const; // Move the image bits from the CPU to the GPU void transfer() const; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 92123a68be..f38cc89a8c 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -19,8 +19,6 @@ using namespace gpu; GLenum gpuToGLTextureType(const Texture& texture) { - // If we get here, we need to allocate and or update the content of the texture - // or it's already being transferred switch (texture.getType()) { case Texture::TEX_2D: return GL_TEXTURE_2D; @@ -94,17 +92,17 @@ GLBackend::GLTexture::~GLTexture() { Backend::decrementTextureGPUCount(); } -bool GLBackend::GLTexture::invalid() const { +bool GLBackend::GLTexture::isInvalid() const { return _storageStamp < _gpuTexture.getStamp(); } -bool GLBackend::GLTexture::outdated() const { +bool GLBackend::GLTexture::isOutdated() const { return _contentStamp < _gpuTexture.getDataStamp(); } -bool GLBackend::GLTexture::ready() const { +bool GLBackend::GLTexture::isReady() const { // If we have an invalid texture, we're never ready - if (invalid()) { + if (isInvalid()) { return false; } @@ -112,7 +110,7 @@ bool GLBackend::GLTexture::ready() const { // as a special case auto syncState = _syncState.load(); - if (outdated()) { + if (isOutdated()) { return Pending == syncState; } @@ -167,7 +165,7 @@ void GLBackend::GLTexture::transfer() const { case Texture::TEX_CUBE: // transfer pixels from each faces - for (int f = 0; f < CUBE_NUM_FACES; f++) { + for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { if (_gpuTexture.isStoredMipFaceAvailable(0, f)) { transferMip(CUBE_FACE_LAYOUT[f], _gpuTexture.accessStoredMipFace(0, f)); } @@ -188,15 +186,14 @@ void GLBackend::GLTexture::transfer() const { // Do any post-transfer operations that might be required on the main context / rendering thread void GLBackend::GLTexture::postTransfer() { setSyncState(GLTexture::Idle); + // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory switch (_gpuTexture.getType()) { case Texture::TEX_2D: - // At this point the mip piels have been loaded, we can notify _gpuTexture.notifyMipFaceGPULoaded(0, 0); break; case Texture::TEX_CUBE: for (uint8_t f = 0; f < CUBE_NUM_FACES; ++f) { - // At this point the mip piels have been loaded, we can notify _gpuTexture.notifyMipFaceGPULoaded(0, f); } break; @@ -216,7 +213,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // If the object hasn't been created, or the object definition is out of date, drop and re-create GLTexture* object = Backend::getGPUObject(texture); - if (object && object->ready()) { + if (object && object->isReady()) { return object; } @@ -224,7 +221,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Create the texture if need be (force re-creation if the storage stamp changes // for easier use of immutable storage) - if (!object || object->invalid()) { + if (!object || object->isInvalid()) { // This automatically destroys the old texture object = new GLTexture(texture); } @@ -236,7 +233,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Object might be outdated, if so, start the transfer // (outdated objects that are already in transfer will have reported 'true' for ready() - if (object->outdated()) { + if (object->isOutdated()) { _textureTransferHelper->transferTexture(texturePointer); } diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp index aa5839b5b2..2610d9bc4a 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -12,12 +12,15 @@ #include "GLTexelFormat.h" #ifdef THREADED_TEXTURE_TRANSFER -#include -#include -#include -#endif -using namespace gpu; +#include +#include + +//#define FORCE_DRAW_AFTER_TRANSFER + +#ifdef FORCE_DRAW_AFTER_TRANSFER + +#include static ProgramPtr _program; static ProgramPtr _cubeProgram; @@ -25,6 +28,12 @@ static ShapeWrapperPtr _plane; static ShapeWrapperPtr _skybox; static BasicFramebufferWrapperPtr _framebuffer; +#endif + +#endif + +using namespace gpu; + GLTextureTransferHelper::GLTextureTransferHelper() { #ifdef THREADED_TEXTURE_TRANSFER _canvas = std::make_shared(); @@ -54,6 +63,8 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture void GLTextureTransferHelper::setup() { #ifdef THREADED_TEXTURE_TRANSFER _canvas->makeCurrent(); + +#ifdef FORCE_DRAW_AFTER_TRANSFER _program = loadDefaultShader(); _plane = loadPlane(_program); _cubeProgram = loadCubemapShader(); @@ -62,6 +73,8 @@ void GLTextureTransferHelper::setup() { _framebuffer->Init({ 100, 100 }); _framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw); #endif + +#endif } bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { @@ -77,6 +90,7 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); object->transfer(); +#ifdef FORCE_DRAW_AFTER_TRANSFER // Now force a draw using the texture try { switch (texturePointer->getType()) { @@ -99,9 +113,12 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { } catch (const std::runtime_error& error) { qWarning() << "Failed to render texture on background thread: " << error.what(); } +#endif glBindTexture(object->_target, 0); - glFinish(); + auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); + glDeleteSync(writeSync); object->_contentStamp = texturePointer->getDataStamp(); object->setSyncState(GLBackend::GLTexture::Transferred); } From cecb3a6ff12eeb3cf12e174b91cd391dbe009629 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 17:07:08 -0700 Subject: [PATCH 058/128] unmangle merge --- libraries/shared/src/SpatiallyNestable.cpp | 38 ---------------------- 1 file changed, 38 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 22d423a49e..3275420f5d 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -849,44 +849,6 @@ AACube SpatiallyNestable::getQueryAACube() const { } return result; } -<<<<<<< HEAD - -void SpatiallyNestable::getLocalTransformAndVelocities( - Transform& transform, - glm::vec3& velocity, - glm::vec3& angularVelocity) const { - // transform - _transformLock.withReadLock([&] { - transform = _transform; - }); - // linear velocity - _velocityLock.withReadLock([&] { - velocity = _velocity; - }); - // angular velocity - _angularVelocityLock.withReadLock([&] { - angularVelocity = _angularVelocity; - }); -} - -void SpatiallyNestable::setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity) { - // transform - _transformLock.withWriteLock([&] { - _transform = localTransform; - }); - // linear velocity - _velocityLock.withWriteLock([&] { - _velocity = localVelocity; - }); - // angular velocity - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = localAngularVelocity; - }); - locationChanged(); -} bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) { if (_nestableType == nestableType) { From af05b97c1e9418a727053c155875d8085ab8c78e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 17:31:59 -0700 Subject: [PATCH 059/128] put back accidently deleted line. cleanups --- libraries/entities/src/EntityItem.cpp | 2 ++ libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index acdcc4a8a2..17b4e6a87d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1974,6 +1974,7 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG } void EntityItem::locationChanged() { + requiresRecalcBoxes(); _dirtyFlags |= Simulation::DIRTY_TRANSFORM; EntityTreePointer tree = getTree(); if (tree) { @@ -1988,6 +1989,7 @@ void EntityItem::dimensionsChanged() { } void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const { + // TODO -- combine this with convertLocationToScriptSemantics bool success; auto globalPosition = getPosition(success); if (success) { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6f6094c99b..700160514c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -162,7 +162,7 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { return MOTION_TYPE_DYNAMIC; } if (_entity->isMovingRelativeToParent() || - _entity->hasActions() || + _entity->hasActions() || _entity->hasAncestorOfType(NestableType::Avatar)) { return MOTION_TYPE_KINEMATIC; } From 294bdcb18eaaa24f7df5b5d3db077b28e033a274 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 4 Apr 2016 17:41:01 -0700 Subject: [PATCH 060/128] has-ancestor should test self --- libraries/shared/src/SpatiallyNestable.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 3275420f5d..96a5a1d8ae 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -851,15 +851,15 @@ AACube SpatiallyNestable::getQueryAACube() const { } bool SpatiallyNestable::hasAncestorOfType(NestableType nestableType) { - if (_nestableType == nestableType) { - return true; - } - bool success; SpatiallyNestablePointer parent = getParentPointer(success); if (!success || !parent) { return false; } + if (parent->_nestableType == nestableType) { + return true; + } + return parent->hasAncestorOfType(nestableType); } From ac30aed9482d9a4117b8d4c5a94b57a6ed8aa55f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 17:52:41 -0700 Subject: [PATCH 061/128] Hold onto octree child after creation --- libraries/octree/src/Octree.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index ffbc2e6709..051e4f8791 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -384,9 +384,10 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig // check the exists mask to see if we have a child to traverse into if (oneAtBit(childInBufferMask, childIndex)) { - if (!destinationElement->getChildAtIndex(childIndex)) { + auto childAt = destinationElement->getChildAtIndex(childIndex); + if (!childAt) { // add a child at that index, if it doesn't exist - destinationElement->addChildAtIndex(childIndex); + childAt = destinationElement->addChildAtIndex(childIndex); bool nodeIsDirty = destinationElement->isDirty(); if (nodeIsDirty) { _isDirty = true; @@ -394,8 +395,7 @@ int Octree::readElementData(OctreeElementPointer destinationElement, const unsig } // tell the child to read the subsequent data - int lowerLevelBytes = readElementData(destinationElement->getChildAtIndex(childIndex), - nodeData + bytesRead, bytesLeftToRead, args); + int lowerLevelBytes = readElementData(childAt, nodeData + bytesRead, bytesLeftToRead, args); bytesRead += lowerLevelBytes; bytesLeftToRead -= lowerLevelBytes; From ffc2c75534345f0bc099004e847e96b3b8b23e9b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 09:59:12 -0700 Subject: [PATCH 062/128] Don't release the Oculus plugin when disabling the plugin --- plugins/oculus/src/OculusHelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index c9e702ecd0..9d3f95a979 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -90,12 +90,14 @@ ovrSession acquireOculusSession() { void releaseOculusSession() { Q_ASSERT(refCount > 0 && session); +#if 0 if (!--refCount) { qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session"; ovr_Destroy(session); ovr_Shutdown(); session = nullptr; } +#endif } From 6a7a572b53206ad3aa4b118dbc6e1da36e87274b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 11:06:24 -0700 Subject: [PATCH 063/128] Model: Toggling Physics > Draw Collision Hulls works again Collision renderItems were never getting removed when shouldShowCollisionHull became false. --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index a9dcb3883c..b510f58b12 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -434,6 +434,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { _showCollisionHull = shouldShowCollisionHull; render::PendingChanges pendingChanges; + _model->removeFromScene(scene, pendingChanges); + render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); From c9c414d5a8aeffc29ae7efc3e86cdd02d0c03acb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 5 Apr 2016 13:44:17 +1200 Subject: [PATCH 064/128] Fix entities editor display of large negative coordinates and angles --- examples/html/edit-style.css | 6 +++--- interface/resources/qml/ToolWindow.qml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index 02a3ba3cab..27a2cbe5e1 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -231,11 +231,11 @@ input[type="text"] { input[type="number"] { position: relative; height: 28px; - width: 120px; + width: 124px; } input[type=number] { - padding-right: 6px; + padding-right: 3px; } input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; @@ -657,7 +657,7 @@ div.refresh input[type="button"] { padding-left: 25px; } .pyr .tuple input { - padding-left: 45px; + padding-left: 40px; } .tuple div > label:first-child { diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index b6d70cb245..ddd314d9ff 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -30,7 +30,7 @@ Window { title: "Edit" property alias tabView: tabView implicitWidth: 520; implicitHeight: 695 - minSize: Qt.vector2d(400, 500) + minSize: Qt.vector2d(412, 500) HifiConstants { id: hifi } From 71e6f9bdd67f2f97f9c6e49452fd420a8c9a1c76 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 13:03:14 -0700 Subject: [PATCH 065/128] Display a blank frame before switching away from oculus --- plugins/oculus/src/OculusDisplayPlugin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index a53643ba21..78a38d2b6a 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -52,6 +52,16 @@ void OculusDisplayPlugin::customizeContext() { } void OculusDisplayPlugin::uncustomizeContext() { + using namespace oglplus; + + // Present a final black frame to the HMD + _compositeFramebuffer->Bound(FramebufferTarget::Draw, [] { + Context::ClearColor(0, 0, 0, 1); + Context::Clear().ColorBuffer(); + }); + + hmdPresent(); + #if (OVR_MAJOR_VERSION >= 6) _sceneFbo.reset(); #endif From fd4a374e088decbaca7780b692519d449032eef0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 13:04:17 -0700 Subject: [PATCH 066/128] Add comment --- plugins/oculus/src/OculusHelpers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 9d3f95a979..71342f6e1b 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -90,6 +90,8 @@ ovrSession acquireOculusSession() { void releaseOculusSession() { Q_ASSERT(refCount > 0 && session); + // HACK the Oculus runtime doesn't seem to play well with repeated shutdown / restart. + // So for now we'll just hold on to the session #if 0 if (!--refCount) { qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session"; From d8282ae79993d36946919a879e955b7a4e0ec7c5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 13:56:39 -0700 Subject: [PATCH 067/128] log value of QTWEBENGINE_REMOTE_DEBUGGING before exit --- interface/src/Application.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..86925429ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -38,6 +38,8 @@ #include +#include + #include #include @@ -1120,6 +1122,11 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + QProcessEnvironment env; + bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); + qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; + // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE DependencyManager::get()->setEnabled(false); From 4c632cb4c4cad30eb799ccbe1729feae3a3058a7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 14:00:43 -0700 Subject: [PATCH 068/128] Application: focusOut keyboard device when clicking on web entity. --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..80e34f3ae9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1008,6 +1008,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : RenderableWebEntityItem* webEntity = dynamic_cast(entity.get()); if (webEntity) { webEntity->setProxyWindow(_window->windowHandle()); + if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { + _keyboardMouseDevice->pluginFocusOutEvent(); + } _keyboardFocusedItem = entityItemID; _lastAcceptedKeyPress = usecTimestampNow(); if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) { From fd2ee8ce4e2ef9558ea1b0ec9207b87f223102b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 11:18:57 -0700 Subject: [PATCH 069/128] add migration of plaintext password to base64 --- .../resources/describe-settings.json | 4 +-- .../src/DomainServerSettingsManager.cpp | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 44a1796a8d..53d062d4bd 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,5 +1,5 @@ { - "version": 1.1, + "version": 1.2, "settings": [ { "name": "metaverse", @@ -249,7 +249,7 @@ "label": "X end", "can_set": true, "placeholder": "16384.0" - }, + }, { "name": "y_min", "label": "Y start", diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 49ae03ccd4..112f7304f0 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -129,7 +129,9 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // reload the master and user config so that the merged config is right _configMap.loadMasterAndUserConfig(argumentList); } - } else if (oldVersion < 1.1) { + } + + if (oldVersion < 1.1) { static const QString ENTITY_SERVER_SETTINGS_KEY = "entity_server_settings"; static const QString ENTITY_FILE_NAME_KEY = "persistFilename"; static const QString ENTITY_FILE_PATH_KEYPATH = ENTITY_SERVER_SETTINGS_KEY + ".persistFilePath"; @@ -165,6 +167,28 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList } } + + if (oldVersion < 1.2) { + // This was prior to the base64 encoding of password for HTTP Basic Authentication. + // If we have a password in the previous settings file, make it base 64 + static const QString BASIC_AUTH_PASSWORD_KEY_PATH { "security.http_password" }; + + QVariant* passwordVariant = valueForKeyPath(_configMap.getUserConfig(), BASIC_AUTH_PASSWORD_KEY_PATH); + + if (passwordVariant && passwordVariant->canConvert(QMetaType::QString)) { + QString plaintextPassword = passwordVariant->toString(); + + qDebug() << "Migrating plaintext password to base64 password in domain-server settings."; + + *passwordVariant = plaintextPassword.toUtf8().toBase64(); + + // write the new settings to file + persistToFile(); + + // reload the master and user config so the merged config is correct + _configMap.loadMasterAndUserConfig(argumentList); + } + } } // write the current description version to our settings From 5054243655f4e68362a54bb15b29c99dcce2036f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 11:21:32 -0700 Subject: [PATCH 070/128] compare HTTP auth password to base 64 settings value --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d80196e9fa..14c26d4dfb 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1680,7 +1680,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH); QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : ""; - if (settingsUsername == headerUsername && headerPassword == settingsPassword) { + if (settingsUsername == headerUsername && headerPassword.toUtf8().toBase64() == settingsPassword) { return true; } } From 13a3b47d1b883ec8301fef3736c42a7fadc5bc70 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 11:26:57 -0700 Subject: [PATCH 071/128] convert password to base64 before settings post --- domain-server/resources/web/settings/js/settings.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index fae07ace45..586487c10c 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -867,6 +867,14 @@ function saveSettings() { // grab a JSON representation of the form via form2js var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true); + // check if we've set the basic http password - if so convert it to base64 + if (formJSON["security"]) { + var password = formJSON["security"]["http_password"]; + if (password.length > 0) { + formJSON["security"]["http_password"] = btoa(password); + } + } + console.log(formJSON); // re-enable all inputs From 7cd115f4219cd93e15010f3ed50ef91f4319fee7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 14:10:50 -0700 Subject: [PATCH 072/128] store and transmit passwords as SHA256 hash --- .../resources/web/settings/index.shtml | 1 + .../resources/web/settings/js/settings.js | 2 +- .../resources/web/settings/js/sha256.js | 247 ++++++++++++++++++ domain-server/src/DomainServer.cpp | 3 +- .../src/DomainServerSettingsManager.cpp | 2 +- 5 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 domain-server/resources/web/settings/js/sha256.js diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 35eab080b9..3f969ef913 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -103,4 +103,5 @@ + diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 586487c10c..dfdfeded04 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -871,7 +871,7 @@ function saveSettings() { if (formJSON["security"]) { var password = formJSON["security"]["http_password"]; if (password.length > 0) { - formJSON["security"]["http_password"] = btoa(password); + formJSON["security"]["http_password"] = sha256_digest(password); } } diff --git a/domain-server/resources/web/settings/js/sha256.js b/domain-server/resources/web/settings/js/sha256.js new file mode 100644 index 0000000000..6f2160018f --- /dev/null +++ b/domain-server/resources/web/settings/js/sha256.js @@ -0,0 +1,247 @@ +/* +* A JavaScript implementation of the SHA256 hash function. +* +* FILE: sha256.js +* VERSION: 0.8 +* AUTHOR: Christoph Bichlmeier +* +* NOTE: This version is not tested thoroughly! +* +* Copyright (c) 2003, Christoph Bichlmeier +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* ====================================================================== +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* SHA256 logical functions */ +function rotateRight(n,x) { + return ((x >>> n) | (x << (32 - n))); +} +function choice(x,y,z) { + return ((x & y) ^ (~x & z)); +} +function majority(x,y,z) { + return ((x & y) ^ (x & z) ^ (y & z)); +} +function sha256_Sigma0(x) { + return (rotateRight(2, x) ^ rotateRight(13, x) ^ rotateRight(22, x)); +} +function sha256_Sigma1(x) { + return (rotateRight(6, x) ^ rotateRight(11, x) ^ rotateRight(25, x)); +} +function sha256_sigma0(x) { + return (rotateRight(7, x) ^ rotateRight(18, x) ^ (x >>> 3)); +} +function sha256_sigma1(x) { + return (rotateRight(17, x) ^ rotateRight(19, x) ^ (x >>> 10)); +} +function sha256_expand(W, j) { + return (W[j&0x0f] += sha256_sigma1(W[(j+14)&0x0f]) + W[(j+9)&0x0f] + +sha256_sigma0(W[(j+1)&0x0f])); +} + +/* Hash constant words K: */ +var K256 = new Array( + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +); + +/* global arrays */ +var ihash, count, buffer; +var sha256_hex_digits = "0123456789abcdef"; + +/* Add 32-bit integers with 16-bit operations (bug in some JS-interpreters: +overflow) */ +function safe_add(x, y) +{ + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); +} + +/* Initialise the SHA256 computation */ +function sha256_init() { + ihash = new Array(8); + count = new Array(2); + buffer = new Array(64); + count[0] = count[1] = 0; + ihash[0] = 0x6a09e667; + ihash[1] = 0xbb67ae85; + ihash[2] = 0x3c6ef372; + ihash[3] = 0xa54ff53a; + ihash[4] = 0x510e527f; + ihash[5] = 0x9b05688c; + ihash[6] = 0x1f83d9ab; + ihash[7] = 0x5be0cd19; +} + +/* Transform a 512-bit message block */ +function sha256_transform() { + var a, b, c, d, e, f, g, h, T1, T2; + var W = new Array(16); + + /* Initialize registers with the previous intermediate value */ + a = ihash[0]; + b = ihash[1]; + c = ihash[2]; + d = ihash[3]; + e = ihash[4]; + f = ihash[5]; + g = ihash[6]; + h = ihash[7]; + + /* make 32-bit words */ + for(var i=0; i<16; i++) + W[i] = ((buffer[(i<<2)+3]) | (buffer[(i<<2)+2] << 8) | (buffer[(i<<2)+1] +<< 16) | (buffer[i<<2] << 24)); + + for(var j=0; j<64; j++) { + T1 = h + sha256_Sigma1(e) + choice(e, f, g) + K256[j]; + if(j < 16) T1 += W[j]; + else T1 += sha256_expand(W, j); + T2 = sha256_Sigma0(a) + majority(a, b, c); + h = g; + g = f; + f = e; + e = safe_add(d, T1); + d = c; + c = b; + b = a; + a = safe_add(T1, T2); + } + + /* Compute the current intermediate hash value */ + ihash[0] += a; + ihash[1] += b; + ihash[2] += c; + ihash[3] += d; + ihash[4] += e; + ihash[5] += f; + ihash[6] += g; + ihash[7] += h; +} + +/* Read the next chunk of data and update the SHA256 computation */ +function sha256_update(data, inputLen) { + var i, index, curpos = 0; + /* Compute number of bytes mod 64 */ + index = ((count[0] >> 3) & 0x3f); + var remainder = (inputLen & 0x3f); + + /* Update number of bits */ + if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; + count[1] += (inputLen >> 29); + + /* Transform as many times as possible */ + for(i=0; i+63> 3) & 0x3f); + buffer[index++] = 0x80; + if(index <= 56) { + for(var i=index; i<56; i++) + buffer[i] = 0; + } else { + for(var i=index; i<64; i++) + buffer[i] = 0; + sha256_transform(); + for(var i=0; i<56; i++) + buffer[i] = 0; + } + buffer[56] = (count[1] >>> 24) & 0xff; + buffer[57] = (count[1] >>> 16) & 0xff; + buffer[58] = (count[1] >>> 8) & 0xff; + buffer[59] = count[1] & 0xff; + buffer[60] = (count[0] >>> 24) & 0xff; + buffer[61] = (count[0] >>> 16) & 0xff; + buffer[62] = (count[0] >>> 8) & 0xff; + buffer[63] = count[0] & 0xff; + sha256_transform(); +} + +/* Split the internal hash values into an array of bytes */ +function sha256_encode_bytes() { + var j=0; + var output = new Array(32); + for(var i=0; i<8; i++) { + output[j++] = ((ihash[i] >>> 24) & 0xff); + output[j++] = ((ihash[i] >>> 16) & 0xff); + output[j++] = ((ihash[i] >>> 8) & 0xff); + output[j++] = (ihash[i] & 0xff); + } + return output; +} + +/* Get the internal hash as a hex string */ +function sha256_encode_hex() { + var output = new String(); + for(var i=0; i<8; i++) { + for(var j=28; j>=0; j-=4) + output += sha256_hex_digits.charAt((ihash[i] >>> j) & 0x0f); + } + return output; +} + +/* Main function: returns a hex string representing the SHA256 value of the +given data */ +function sha256_digest(data) { + sha256_init(); + sha256_update(data, data.length); + sha256_final(); + return sha256_encode_hex(); +} + +/* test if the JS-interpreter is working properly */ +function sha256_self_test() { + return sha256_digest("message digest") == +"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"; +} diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 14c26d4dfb..4ff3564e72 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1679,8 +1679,9 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString(); const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH); QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : ""; + QString hexHeaderPassword = QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex(); - if (settingsUsername == headerUsername && headerPassword.toUtf8().toBase64() == settingsPassword) { + if (settingsUsername == headerUsername && hexHeaderPassword == settingsPassword) { return true; } } diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 112f7304f0..7420183ede 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -180,7 +180,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList qDebug() << "Migrating plaintext password to base64 password in domain-server settings."; - *passwordVariant = plaintextPassword.toUtf8().toBase64(); + *passwordVariant = QCryptographicHash::hash(plaintextPassword.toUtf8(), QCryptographicHash::Sha256).toHex(); // write the new settings to file persistToFile(); From f42e968dda7096a93b95707a93d27ab8688c3b0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 14:12:46 -0700 Subject: [PATCH 073/128] commit to repush to see if github is working yet --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 86925429ab..b50fe1292b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1122,7 +1122,7 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { - // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not. QProcessEnvironment env; bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; From a0edbac486c090106b0e38dfd56a60095895f17a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 14:12:50 -0700 Subject: [PATCH 074/128] change comment for domain-server migration to SHA256 --- domain-server/src/DomainServerSettingsManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 7420183ede..0ca0cf8232 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -178,7 +178,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList if (passwordVariant && passwordVariant->canConvert(QMetaType::QString)) { QString plaintextPassword = passwordVariant->toString(); - qDebug() << "Migrating plaintext password to base64 password in domain-server settings."; + qDebug() << "Migrating plaintext password to SHA256 hash in domain-server settings."; *passwordVariant = QCryptographicHash::hash(plaintextPassword.toUtf8(), QCryptographicHash::Sha256).toHex(); From bda8761e00bfede783f80c5171e700db5ff5d68e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 5 Apr 2016 14:30:41 -0700 Subject: [PATCH 075/128] fix how env variable is accessed --- interface/src/Application.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50fe1292b..b4bc5fa665 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1122,10 +1122,9 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { - // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not. - QProcessEnvironment env; - bool webengineRemoteDebuggingSet = env.keys().contains("QTWEBENGINE_REMOTE_DEBUGGING"); - qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebuggingSet; + // add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not + QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false"); + qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging; // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE From d536026ff4d2f24671e6c9ec70810bb5e784b404 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Apr 2016 14:44:20 -0700 Subject: [PATCH 076/128] suppress a couple more noisy messages in AudioRingBuffer --- libraries/audio/src/AudioRingBuffer.cpp | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index ae69efee92..96f1bbb9dd 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -23,13 +23,15 @@ #include "AudioRingBuffer.h" +static const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." }; + AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : -_frameCapacity(numFramesCapacity), -_sampleCapacity(numFrameSamples * numFramesCapacity), -_bufferLength(numFrameSamples * (numFramesCapacity + 1)), -_numFrameSamples(numFrameSamples), -_randomAccessMode(randomAccessMode), -_overflowCount(0) + _frameCapacity(numFramesCapacity), + _sampleCapacity(numFrameSamples * numFramesCapacity), + _bufferLength(numFrameSamples * (numFramesCapacity + 1)), + _numFrameSamples(numFrameSamples), + _randomAccessMode(randomAccessMode), + _overflowCount(0) { if (numFrameSamples) { _buffer = new int16_t[_bufferLength]; @@ -41,6 +43,8 @@ _overflowCount(0) _nextOutput = NULL; _endOfLastWrite = NULL; } + + static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG); }; AudioRingBuffer::~AudioRingBuffer() { @@ -131,8 +135,6 @@ int AudioRingBuffer::writeData(const char* data, int maxSize) { _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete); _overflowCount++; - const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." }; - static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG); qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG); } @@ -179,7 +181,12 @@ int AudioRingBuffer::addSilentSamples(int silentSamples) { if (silentSamples > samplesRoomFor) { // there's not enough room for this write. write as many silent samples as we have room for silentSamples = samplesRoomFor; - qCDebug(audio) << "Dropping some silent samples to prevent ring buffer overflow"; + + static const QString DROPPED_SILENT_DEBUG { + "AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow." + }; + static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG); + qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG); } // memset zeroes into the buffer, accomodate a wrap around the end @@ -243,7 +250,7 @@ int AudioRingBuffer::writeSamples(ConstIterator source, int maxSamples) { int samplesToDelete = samplesToCopy - samplesRoomFor; _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete); _overflowCount++; - qCDebug(audio) << "Overflowed ring buffer! Overwriting old data"; + qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG); } int16_t* bufferLast = _buffer + _bufferLength - 1; @@ -264,7 +271,7 @@ int AudioRingBuffer::writeSamplesWithFade(ConstIterator source, int maxSamples, int samplesToDelete = samplesToCopy - samplesRoomFor; _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete); _overflowCount++; - qCDebug(audio) << "Overflowed ring buffer! Overwriting old data"; + qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG); } int16_t* bufferLast = _buffer + _bufferLength - 1; From 062760ff3bd3a0bd7fde954016b859c895951219 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:04:11 -0700 Subject: [PATCH 077/128] Log failed routes --- libraries/controllers/src/controllers/UserInputMapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index fe64566b29..33739c7b9d 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -1033,7 +1033,7 @@ Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) { Route::Pointer route = parseRoute(channelIt); if (!route) { - qWarning() << "Couldn't parse route"; + qWarning() << "Couldn't parse route:" << mapping->name << channelIt; continue; } From 6bcfeccdd844ecf0a179370b53621a27dfc648bc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:13:26 -0700 Subject: [PATCH 078/128] Log failed MenuUserData::forObject --- libraries/ui/src/VrMenu.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 5acf81c319..e6f0e92067 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -43,6 +43,11 @@ public: auto result = static_cast(object->userData(USER_DATA_ID)); if (!result) { qWarning() << "Unable to find MenuUserData for object " << object; + if (auto action = dynamic_cast(object)) { + qWarning() << action->text(); + } else if (auto menu = dynamic_cast(object)) { + qWarning() << menu->title(); + } return nullptr; } return result; From 91126037e0e81007657b2bb369a2214d561b962b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:18:08 -0700 Subject: [PATCH 079/128] Fix showDesktop SIGNAL --- libraries/ui/src/OffscreenUi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 745a28eb0b..269cf86e2d 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -447,7 +447,7 @@ void OffscreenUi::createDesktop(const QUrl& url) { new KeyboardFocusHack(); - connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop())); + connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop())); } QQuickItem* OffscreenUi::getDesktop() { From cba866b3758fcfdfb400963ab0e82a4d1412769a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:44:56 -0700 Subject: [PATCH 080/128] Do not warn if no bookmarks file --- interface/src/Bookmarks.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index 2620451538..0e7941a5a4 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -63,6 +63,11 @@ bool Bookmarks::contains(const QString& name) const { void Bookmarks::readFromFile() { QFile loadFile(_bookmarksFilename); + if (!loadFile.exists()) { + // User has not yet saved bookmarks + return; + } + if (!loadFile.open(QIODevice::ReadOnly)) { qWarning("Couldn't open bookmarks file for reading"); return; From 37efeb7f2952e8001bad3b7b4e04562e345ce56b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 14:04:26 -0700 Subject: [PATCH 081/128] Avoid warning for expected unset PresentThread --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 6 ++++-- libraries/shared/src/DependencyManager.h | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e5d98d18f7..3d997b0109 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -245,8 +245,10 @@ bool OpenGLDisplayPlugin::activate() { #if THREADED_PRESENT // Start the present thread if necessary - auto presentThread = DependencyManager::get(); - if (!presentThread) { + QSharedPointer presentThread; + if (DependencyManager::isSet()) { + presentThread = DependencyManager::get(); + } else { auto widget = _container->getPrimaryWidget(); DependencyManager::set(); presentThread = DependencyManager::get(); diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index c0568bc752..719763f706 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -49,6 +49,9 @@ public: template static QSharedPointer get(); + template + static bool isSet(); + template static QSharedPointer set(Args&&... args); @@ -89,6 +92,14 @@ QSharedPointer DependencyManager::get() { return instance.toStrongRef(); } +template +bool DependencyManager::isSet() { + static size_t hashCode = manager().getHashCode(); + + QSharedPointer& instance = manager().safeGet(hashCode); + return !instance.isNull(); +} + template QSharedPointer DependencyManager::set(Args&&... args) { static size_t hashCode = manager().getHashCode(); From 29c287227c60689932b8a45e5dba9425aeb52142 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 5 Apr 2016 15:30:53 -0700 Subject: [PATCH 082/128] Fix AssignmentClient unpacking an assignment when it already has one --- assignment-client/src/AssignmentClient.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 85a2c95b4d..0455377d89 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -235,6 +235,11 @@ void AssignmentClient::sendAssignmentRequest() { void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack."; + if (_currentAssignment) { + qCWarning(assigmnentclient) << "Received a PacketType::CreateAssignment while still running an active assignment. Ignoring."; + return; + } + // construct the deployed assignment from the packet data _currentAssignment = AssignmentFactory::unpackAssignment(*message); From 07ff687bfec0c8ff742ea6619f5b35dad2c3c306 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Apr 2016 18:12:02 -0700 Subject: [PATCH 083/128] Application: change keyboard input focus when using ui overlay. call focusOutEvent on keyboard input plugin when an offscreen ui has activeFocus. --- interface/src/Application.cpp | 9 +++++++++ interface/src/Application.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311583acb7..66039cf41c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2564,6 +2564,15 @@ void Application::idle(uint64_t now) { _overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays)); } + // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus. + auto offscreenUi = DependencyManager::get(); + if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) { + _keyboardMouseDevice->pluginFocusOutEvent(); + _keyboardDeviceHasFocus = false; + } else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) { + _keyboardDeviceHasFocus = true; + } + auto displayPlugin = getActiveDisplayPlugin(); // depending on whether we're throttling or not. // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in diff --git a/interface/src/Application.h b/interface/src/Application.h index e3196febd5..f2b6edeea4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -518,6 +518,8 @@ private: std::mutex _preRenderLambdasLock; std::atomic _processOctreeStatsCounter { 0 }; + + bool _keyboardDeviceHasFocus { true }; }; #endif // hifi_Application_h From 9cac249122bd0d0889c6b9122a51b7b33cdb33b2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 6 Apr 2016 10:36:38 -0700 Subject: [PATCH 084/128] f1 --- examples/example/audio/largeHall.js | 24 ----- examples/example/audio/smallRoom.js | 152 +++++++--------------------- 2 files changed, 35 insertions(+), 141 deletions(-) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index fc69aeb8b8..02f0592388 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -44,30 +44,6 @@ ​ var panel = new Panel(10, 160); ​ -var parameters = [ -// { name: "bandwidth", min: 1000, max: 12000, units: " Hz" }, -// { name: "preDelay", min: 0, max: 333, units: " ms" }, -// { name: "lateDelay", min: 0, max: 166, units: " ms" }, -// { name: "reverbTime", min: 0.1, max: 10, units: " seconds" }, -// { name: "earlyDiffusion", min: 0, max: 100, units: " percent" }, -// { name: "lateDiffusion", min: 0, max: 100, units: " percent" }, -// { name: "roomSize", min: 0, max: 100, units: " percent" }, -// { name: "density", min: 0, max: 100, units: " percent" }, -// { name: "bassMult", min: 0.1, max: 4, units: " ratio" }, -// { name: "bassFreq", min: 10, max: 500, units: " Hz" }, -// { name: "highGain", min: -24, max: 0, units: " dB" }, -// { name: "highFreq", min: 1000, max: 12000, units: " Hz" }, -// { name: "modRate", min: 0.1, max: 10, units: " Hz" }, -// { name: "modDepth", min: 0, max: 100, units: " percent" }, -// { name: "earlyGain", min: -96, max: 24, units: " dB" }, -// { name: "lateGain", min: -96, max: 24, units: " dB" }, -// { name: "earlyMixLeft", min: 0, max: 100, units: " percent" }, -// { name: "earlyMixRight", min: 0, max: 100, units: " percent" }, -// { name: "lateMixLeft", min: 0, max: 100, units: " percent" }, -// { name: "lateMixRight", min: 0, max: 100, units: " percent" }, -// { name: "wetDryMix", min: 0, max: 100, units: " percent" }, -] -​ ​ function setter(name) { return function(value) { diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js index 3deffa6c6c..4e728278a0 100644 --- a/examples/example/audio/smallRoom.js +++ b/examples/example/audio/smallRoom.js @@ -13,122 +13,40 @@ // (function() { - var _this = this; -​ - Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); -print("EBL PRELOADING NEW VERSION ") - var audioOptions = new AudioEffectOptions({ - bandwidth: 7000, - preDelay: 20, - lateDelay: 0, - reverbTime: 1.5, - earlyDiffusion: 100, - lateDiffusion: 100, - roomSize: 50, - density: 100, - bassMult: 1.5, - bassFreq: 250, - highGain: -12, - highFreq: 3000, - modRate: 2.3, - modDepth: 50, - earlyGain: -24, - lateGain: -24, - earlyMixLeft: 20, - earlyMixRight: 20, - lateMixLeft: 90, - lateMixRight: 90, - wetDryMix: 70, -}); -​ -​ -​ - var panel = new Panel(10, 160); -​ -var parameters = [ -// { name: "bandwidth", min: 1000, max: 12000, units: " Hz" }, -// { name: "preDelay", min: 0, max: 333, units: " ms" }, -// { name: "lateDelay", min: 0, max: 166, units: " ms" }, -// { name: "reverbTime", min: 0.1, max: 10, units: " seconds" }, -// { name: "earlyDiffusion", min: 0, max: 100, units: " percent" }, -// { name: "lateDiffusion", min: 0, max: 100, units: " percent" }, -// { name: "roomSize", min: 0, max: 100, units: " percent" }, -// { name: "density", min: 0, max: 100, units: " percent" }, -// { name: "bassMult", min: 0.1, max: 4, units: " ratio" }, -// { name: "bassFreq", min: 10, max: 500, units: " Hz" }, -// { name: "highGain", min: -24, max: 0, units: " dB" }, -// { name: "highFreq", min: 1000, max: 12000, units: " Hz" }, -// { name: "modRate", min: 0.1, max: 10, units: " Hz" }, -// { name: "modDepth", min: 0, max: 100, units: " percent" }, -// { name: "earlyGain", min: -96, max: 24, units: " dB" }, -// { name: "lateGain", min: -96, max: 24, units: " dB" }, -// { name: "earlyMixLeft", min: 0, max: 100, units: " percent" }, -// { name: "earlyMixRight", min: 0, max: 100, units: " percent" }, -// { name: "lateMixLeft", min: 0, max: 100, units: " percent" }, -// { name: "lateMixRight", min: 0, max: 100, units: " percent" }, -// { name: "wetDryMix", min: 0, max: 100, units: " percent" }, -] -​ -​ - function setter(name) { - return function(value) { - audioOptions[name] = value; - AudioDevice.setReverbOptions(audioOptions); + var _this = this; + Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); + var audioOptions = new AudioEffectOptions({ + bandwidth: 7000, + preDelay: 20, + lateDelay: 0, + reverbTime: 1.5, + earlyDiffusion: 100, + lateDiffusion: 100, + roomSize: 50, + density: 100, + bassMult: 1.5, + bassFreq: 250, + highGain: -12, + highFreq: 3000, + modRate: 2.3, + modDepth: 50, + earlyGain: -24, + lateGain: -24, + earlyMixLeft: 20, + earlyMixRight: 20, + lateMixLeft: 90, + lateMixRight: 90, + wetDryMix: 70 + }); + + var panel = new Panel(10, 160); + + 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; - } - } -​ - - function scriptEnding() { - panel.destroy(); - AudioDevice.setReverb(false); - print("Reverb is OFF."); - } -​ - _this.enterEntity = function(entityID) { - print('EBL I am insiude'); - // 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); - }); -​ - AudioDevice.setReverbOptions(audioOptions); - AudioDevice.setReverb(true); - print("Reverb is ON."); -​ -​ - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); - }; - - _this.leaveEntity = function(entityID) { - print('EBL I am outsidee'); - panel.destroy(); - AudioDevice.setReverb(false); - print("Reverb is OFF."); -​ -​ - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); - }; + + }); \ No newline at end of file From ce290a19930c3bda02fc663d7cd6719811d605e2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 6 Apr 2016 10:38:59 -0700 Subject: [PATCH 085/128] got rid of illegal character --- examples/example/audio/smallRoom.js | 59 +++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js index 4e728278a0..b63adc8bb9 100644 --- a/examples/example/audio/smallRoom.js +++ b/examples/example/audio/smallRoom.js @@ -15,6 +15,7 @@ (function() { var _this = this; Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); + print("EBL PRELOADING NEW VERSION ") var audioOptions = new AudioEffectOptions({ bandwidth: 7000, preDelay: 20, @@ -36,17 +37,61 @@ earlyMixRight: 20, lateMixLeft: 90, lateMixRight: 90, - wetDryMix: 70 + wetDryMix: 70, }); - var panel = new Panel(10, 160); - function setter(name) { - return function(value) { - audioOptions[name] = value; - AudioDevice.setReverbOptions(audioOptions); + 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; + } + } + + function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + } + _this.enterEntity = function(entityID) { + print('EBL I am insiude'); + // 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); + }); + AudioDevice.setReverbOptions(audioOptions); + AudioDevice.setReverb(true); + print("Reverb is ON."); + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; + + _this.leaveEntity = function(entityID) { + print('EBL I am outsidee'); + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; }); \ No newline at end of file From 21f6d7bee350542308b73f006251961660d855fc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 6 Apr 2016 10:50:58 -0700 Subject: [PATCH 086/128] fixed largeroom illegal characters --- examples/example/audio/largeHall.js | 169 +++++++++++++--------------- 1 file changed, 78 insertions(+), 91 deletions(-) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index 02f0592388..73abc6da6d 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -12,98 +12,85 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function() { - var _this = this; -​ - Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); - print("EBL PRELOADING NEW VERSION ") - var audioOptions = new AudioEffectOptions({ - bandwidth: 7000, - preDelay: 80, - lateDelay: 0, - reverbTime: 3, - earlyDiffusion: 100, - lateDiffusion: 100, - roomSize: 50, - density: 100, - bassMult: 1.5, - bassFreq: 250, - highGain: -12, - highFreq: 3000, - modRate: 2.3, - modDepth: 50, - earlyGain: -12, - lateGain: -12, - earlyMixLeft: 20, - earlyMixRight: 20, - lateMixLeft: 90, - lateMixRight: 90, - wetDryMix: 90, -}); -​ -​ -​ - var panel = new Panel(10, 160); -​ -​ - function setter(name) { - return function(value) { - audioOptions[name] = value; - AudioDevice.setReverbOptions(audioOptions); + var _this = this; + Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); + print("EBL PRELOADING NEW VERSION ") + var audioOptions = new AudioEffectOptions({ + bandwidth: 7000, + preDelay: 80, + lateDelay: 0, + reverbTime: 3, + earlyDiffusion: 100, + lateDiffusion: 100, + roomSize: 50, + density: 100, + bassMult: 1.5, + bassFreq: 250, + highGain: -12, + highFreq: 3000, + modRate: 2.3, + modDepth: 50, + earlyGain: -12, + lateGain: -12, + earlyMixLeft: 20, + earlyMixRight: 20, + lateMixLeft: 90, + lateMixRight: 90, + wetDryMix: 90, + }); + var panel = new Panel(10, 160); + + function setter(name) { + return function(value) { + audioOptions[name] = value; + AudioDevice.setReverbOptions(audioOptions); + } } - } -​ - function getter(name) { - return function() { - return audioOptions[name]; + + function getter(name) { + return function() { + return audioOptions[name]; + } } - } -​ - function displayer(units) { - return function(value) { - return (value).toFixed(1) + units; + + function displayer(units) { + return function(value) { + return (value).toFixed(1) + units; + } } - } -​ - - function scriptEnding() { - panel.destroy(); - AudioDevice.setReverb(false); - print("Reverb is OFF."); - } -​ - _this.enterEntity = function(entityID) { - print('EBL I am insiude'); - // 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); - }); -​ - AudioDevice.setReverbOptions(audioOptions); - AudioDevice.setReverb(true); - print("Reverb is ON."); -​ -​ - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); - }; - - _this.leaveEntity = function(entityID) { - print('EBL I am outsidee'); - panel.destroy(); - AudioDevice.setReverb(false); - print("Reverb is OFF."); -​ -​ - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); - }; + + function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + } + _this.enterEntity = function(entityID) { + print('EBL I am insiude'); + // 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); + }); + AudioDevice.setReverbOptions(audioOptions); + AudioDevice.setReverb(true); + print("Reverb is ON."); + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; + + _this.leaveEntity = function(entityID) { + print('EBL I am outsidee'); + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); + // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); + }; }); \ No newline at end of file From 2be2f940eabceeb5d3e0eb9ef5353a864786e90e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 6 Apr 2016 10:59:18 -0700 Subject: [PATCH 087/128] remove panel --- examples/example/audio/largeHall.js | 19 +------------------ examples/example/audio/smallRoom.js | 19 ------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index 73abc6da6d..a1a2db84b7 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -13,7 +13,6 @@ // (function() { var _this = this; - Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); print("EBL PRELOADING NEW VERSION ") var audioOptions = new AudioEffectOptions({ bandwidth: 7000, @@ -38,7 +37,6 @@ lateMixRight: 90, wetDryMix: 90, }); - var panel = new Panel(10, 160); function setter(name) { return function(value) { @@ -60,30 +58,15 @@ } function scriptEnding() { - panel.destroy(); AudioDevice.setReverb(false); print("Reverb is OFF."); } _this.enterEntity = function(entityID) { print('EBL I am insiude'); - // 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); - }); + AudioDevice.setReverbOptions(audioOptions); AudioDevice.setReverb(true); print("Reverb is ON."); - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); }; _this.leaveEntity = function(entityID) { diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js index b63adc8bb9..59811c4f52 100644 --- a/examples/example/audio/smallRoom.js +++ b/examples/example/audio/smallRoom.js @@ -14,7 +14,6 @@ (function() { var _this = this; - Script.include("http://public.highfidelity.io/scripts/utilities/tools/cookies.js"); print("EBL PRELOADING NEW VERSION ") var audioOptions = new AudioEffectOptions({ bandwidth: 7000, @@ -39,7 +38,6 @@ lateMixRight: 90, wetDryMix: 70, }); - var panel = new Panel(10, 160); function setter(name) { return function(value) { @@ -61,37 +59,20 @@ } function scriptEnding() { - panel.destroy(); AudioDevice.setReverb(false); print("Reverb is OFF."); } _this.enterEntity = function(entityID) { print('EBL I am insiude'); // 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); - }); AudioDevice.setReverbOptions(audioOptions); AudioDevice.setReverb(true); print("Reverb is ON."); - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); }; _this.leaveEntity = function(entityID) { print('EBL I am outsidee'); - panel.destroy(); AudioDevice.setReverb(false); print("Reverb is OFF."); - // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); }; }); \ No newline at end of file From 8c15116190895ecfc6e47e5f08f989ee73dd2714 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Apr 2016 11:00:43 -0700 Subject: [PATCH 088/128] fix auto-hide logic in depthReticle --- examples/depthReticle.js | 13 ++++++++++++- .../src/display-plugins/CompositorHelper.cpp | 6 ++---- .../src/display-plugins/CompositorHelper.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 13 ++++++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 90e5db0f1a..10d604f707 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -98,10 +98,21 @@ function seekToLookAt() { } function autoHideReticle() { + var now = Date.now(); + + // sometimes we don't actually get mouse move messages (for example, if the focus has been set + // to an overlay or web page 'overlay') in but the mouse can still be moving, and we don't want + // to autohide in these cases, so we will take this opportunity to also check if the reticle + // position has changed. + if (lastMouseX != Reticle.position.x || lastMouseY != Reticle.position.y) { + lastMouseMoveOrClick = now; + lastMouseX = Reticle.position.x; + lastMouseY = Reticle.position.y; + } + // if we haven't moved in a long period of time, and we're not pointing at some // system overlay (like a window), then hide the reticle if (Reticle.visible && !Reticle.pointingAtSystemOverlay) { - var now = Date.now(); var timeSinceLastMouseMove = now - lastMouseMoveOrClick; if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { Reticle.visible = false; diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index 3e09e96704..b39fd8861d 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -467,8 +467,6 @@ void CompositorHelper::toggle() { } } - - glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const glm::vec3& headPosition) const { glm::mat4 result; if (isHMD()) { @@ -487,7 +485,7 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const pointerTransform[3] = vec4(cursorRay + headPosition, 1); // Scale up the cursor because of distance reticleScale *= reticleDepth; - } + } glm::mat4 overlayXfm; _modelTransform.getMatrix(overlayXfm); pointerTransform = overlayXfm * pointerTransform; @@ -503,7 +501,7 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const mousePosition.y *= -1.0f; vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; - return glm::scale(glm::translate(glm::mat4(), vec3(mousePosition, 0.0f)), vec3(mouseSize, 1.0f)); + result = glm::scale(glm::translate(glm::mat4(), vec3(mousePosition, 0.0f)), vec3(mouseSize, 1.0f)); } return result; } diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index 47433bf419..062e5c1319 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -176,7 +176,7 @@ private: bool _reticleOverQml { false }; - bool _allowMouseCapture { true }; + std::atomic _allowMouseCapture { true }; bool _fakeMouseEvent { false }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index bca27211a8..5e30910575 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -475,13 +475,20 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn return result; } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, + const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { + QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); - return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entitiesToInclude, entitiesToDiscard); + return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard); } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { +// FIXME - we should remove this API and encourage all users to use findRayIntersection() instead. We've changed +// findRayIntersection() to be blocking because it never makes sense for a script to get back a non-answer +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, + const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { + + qDebug() << "Entities.findRayIntersectionBlocking() is obsolete, use Entities.findRayIntersection() instead."; const QVector& entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); const QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard); From 1e710712ccd70cfe8895be8605262f97d46b743b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 6 Apr 2016 11:12:05 -0700 Subject: [PATCH 089/128] Check entities scripting thread before signaling it --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- libraries/script-engine/src/ScriptEngine.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b87329d5b6..eab28f500a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -71,8 +71,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf } EntityTreeRenderer::~EntityTreeRenderer() { - // NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a - // signal tied to call it's deleteLater on doneRunning + // NOTE: We don't need to delete _entitiesScriptEngine because + // it is registered with ScriptEngines, which will call deleteLater for us. } void EntityTreeRenderer::clear() { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 31047dd423..e03d577300 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -154,7 +154,9 @@ ScriptEngine::~ScriptEngine() { void ScriptEngine::disconnectNonEssentialSignals() { disconnect(); - connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit); + if (_isRunning && _isThreaded) { // ensure the thread is running + connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit); + } } void ScriptEngine::runInThread() { From e194fc39f460f9807df463ebb87ddb35eaef33b4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Apr 2016 11:29:03 -0700 Subject: [PATCH 090/128] Move the texture transfer context back to the main thread for shutdown --- libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp | 6 ++++++ libraries/gpu/src/gpu/GLBackendTextureTransfer.h | 1 + 2 files changed, 7 insertions(+) diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp index 2610d9bc4a..907bc6a538 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -77,6 +77,12 @@ void GLTextureTransferHelper::setup() { #endif } +void GLTextureTransferHelper::shutdown() { + _canvas->doneCurrent(); + _canvas->moveToThreadWithContext(qApp->thread()); +} + + bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { for (auto package : messages) { glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED); diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.h b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h index 3a147defdf..1e850586d4 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.h +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.h @@ -28,6 +28,7 @@ public: protected: void setup() override; + void shutdown() override; bool processQueueItems(const Queue& messages) override; void transferTextureSynchronous(const gpu::Texture& texture); From 0e08b15db7088c04c545cb048aa87eda9673f773 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 6 Apr 2016 11:30:29 -0700 Subject: [PATCH 091/128] spacing fix attempt --- examples/example/audio/largeHall.js | 1 - examples/example/audio/smallRoom.js | 36 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/examples/example/audio/largeHall.js b/examples/example/audio/largeHall.js index a1a2db84b7..3c710a8eaa 100644 --- a/examples/example/audio/largeHall.js +++ b/examples/example/audio/largeHall.js @@ -71,7 +71,6 @@ _this.leaveEntity = function(entityID) { print('EBL I am outsidee'); - panel.destroy(); AudioDevice.setReverb(false); print("Reverb is OFF."); // Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameWelcome'); diff --git a/examples/example/audio/smallRoom.js b/examples/example/audio/smallRoom.js index 59811c4f52..e692c8810d 100644 --- a/examples/example/audio/smallRoom.js +++ b/examples/example/audio/smallRoom.js @@ -39,29 +39,29 @@ wetDryMix: 70, }); - function setter(name) { - return function(value) { - audioOptions[name] = value; - AudioDevice.setReverbOptions(audioOptions); - } + function setter(name) { + return function(value) { + audioOptions[name] = value; + AudioDevice.setReverbOptions(audioOptions); } + } - function getter(name) { - return function() { - return audioOptions[name]; - } + function getter(name) { + return function() { + return audioOptions[name]; } + } - function displayer(units) { - return function(value) { - return (value).toFixed(1) + units; - } + function displayer(units) { + return function(value) { + return (value).toFixed(1) + units; } + } - function scriptEnding() { - AudioDevice.setReverb(false); - print("Reverb is OFF."); - } + function scriptEnding() { + AudioDevice.setReverb(false); + print("Reverb is OFF."); + } _this.enterEntity = function(entityID) { print('EBL I am insiude'); // create a slider for each parameter @@ -71,7 +71,7 @@ }; _this.leaveEntity = function(entityID) { - print('EBL I am outsidee'); + print('EBL I am outside'); AudioDevice.setReverb(false); print("Reverb is OFF."); }; From 5284af6b51dafe989e944efdb7100c28a2dd0b68 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 6 Apr 2016 12:15:19 -0700 Subject: [PATCH 092/128] Update text3d shader post pbr. --- .../render-utils/src/sdf_text3D_overlay.slf | 52 +++++++++++++++++++ libraries/render-utils/src/text/Font.cpp | 11 ++-- 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 libraries/render-utils/src/sdf_text3D_overlay.slf diff --git a/libraries/render-utils/src/sdf_text3D_overlay.slf b/libraries/render-utils/src/sdf_text3D_overlay.slf new file mode 100644 index 0000000000..d357b05e14 --- /dev/null +++ b/libraries/render-utils/src/sdf_text3D_overlay.slf @@ -0,0 +1,52 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// sdf_text.frag +// fragment shader +// +// Created by Bradley Austin Davis on 2015-02-04 +// Based on fragment shader code from +// https://github.com/paulhoux/Cinder-Samples/blob/master/TextRendering/include/text/Text.cpp +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +uniform sampler2D Font; +uniform bool Outline; +uniform vec4 Color; + +// the interpolated normal +in vec3 _normal; +in vec2 _texCoord0; + +layout(location = 0) out vec4 _fragColor0; + +const float gamma = 2.2; +const float smoothing = 32.0; +const float interiorCutoff = 0.8; +const float outlineExpansion = 0.2; + +void main() { + // retrieve signed distance + float sdf = texture(Font, _texCoord0).g; + if (Outline) { + if (sdf > interiorCutoff) { + sdf = 1.0 - sdf; + } else { + sdf += outlineExpansion; + } + } + // perform adaptive anti-aliasing of the edges + // The larger we're rendering, the less anti-aliasing we need + float s = smoothing * length(fwidth(_texCoord0)); + float w = clamp( s, 0.0, 0.5); + float a = smoothstep(0.5 - w, 0.5 + w, sdf); + + // gamma correction for linear attenuation + a = pow(a, 1.0 / gamma); + + // discard if unvisible + if (a < 0.01) { + discard; + } + _fragColor0 = vec4(Color.rgb, a); +} \ No newline at end of file diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 762a7fb723..3c460fdd99 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -9,6 +9,7 @@ #include "sdf_text3D_vert.h" #include "sdf_text3D_frag.h" +#include "sdf_text3D_overlay_frag.h" #include "../RenderUtilsLogging.h" #include "FontFamilies.h" @@ -220,10 +221,13 @@ void Font::setupGPU() { { auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert)); auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag)); + auto pixelShaderOverlay = gpu::Shader::createPixel(std::string(sdf_text3D_overlay_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); + gpu::ShaderPointer programOverlay = gpu::Shader::createProgram(vertexShader, pixelShaderOverlay); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); + gpu::Shader::makeProgram(*programOverlay, slotBindings); _fontLoc = program->getTextures().findLocation("Font"); _outlineLoc = program->getUniforms().findLocation("Outline"); @@ -237,9 +241,10 @@ void Font::setupGPU() { gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _pipeline = gpu::Pipeline::create(program, state); - auto layeredState = std::make_shared(state->getValues()); - layeredState->setDepthTest(false); - _layeredPipeline = gpu::Pipeline::create(program, layeredState); + auto layeredState = std::make_shared(); + layeredState->setCullMode(gpu::State::CULL_BACK); + layeredState->setDepthTest(true, true, gpu::LESS_EQUAL); + _layeredPipeline = gpu::Pipeline::create(programOverlay, layeredState); } // Sanity checks From 21c2db7cdce8ffe32658b515790999d5ba56db99 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 Apr 2016 12:40:59 -0700 Subject: [PATCH 093/128] attempt to make the failed-to-load-entity-script error-message be more helpful --- libraries/script-engine/src/ScriptEngine.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 31047dd423..bcd509ff53 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1089,9 +1089,18 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } if (!testConstructor.isFunction()) { - qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" - " NOT CONSTRUCTOR\n" - " SCRIPT:" << scriptOrURL; + QString testConstructorType = QString(testConstructor.toVariant().typeName()); + if (testConstructorType == "") { + testConstructorType = "empty"; + } + QString testConstructorValue = testConstructor.toString(); + if (testConstructorValue.size() > 80) { + testConstructorValue = testConstructorValue.mid(0, 80) + "..."; + } + qCDebug(scriptengine) << "Error -- ScriptEngine::loadEntityScript() entity:" << entityID + << "failed to load entity script -- expected a function, got " + testConstructorType + << "," << testConstructorValue + << "," << scriptOrURL; if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); From 6d1b7f1d376ff79cb21718c63fb2e98e98144559 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Apr 2016 11:32:17 -0700 Subject: [PATCH 094/128] Wrap sound script object to hold a strong ref --- assignment-client/src/Agent.cpp | 2 +- assignment-client/src/Agent.h | 6 +-- libraries/audio/src/AudioInjector.cpp | 4 +- libraries/audio/src/AudioInjector.h | 2 +- libraries/audio/src/Sound.cpp | 20 ++++------ libraries/audio/src/Sound.h | 37 +++++++++++++------ .../src/AudioScriptingInterface.cpp | 6 +-- .../src/AudioScriptingInterface.h | 2 +- 8 files changed, 44 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2734cdf01f..740f456595 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -397,7 +397,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { if (_numAvatarSoundSentBytes == soundByteArray.size()) { // we're done with this sound object - so set our pointer back to NULL // and our sent bytes back to zero - _avatarSound = NULL; + _avatarSound.clear(); _numAvatarSoundSentBytes = 0; } } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index fbaec7efe6..d86b99db33 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -56,7 +56,7 @@ public: public slots: void run(); - void playAvatarSound(Sound* avatarSound) { setAvatarSound(avatarSound); } + void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); } private slots: void requestScript(); @@ -77,7 +77,7 @@ private: MixedAudioStream _receivedAudioStream; float _lastReceivedAudioLoudness; - void setAvatarSound(Sound* avatarSound) { _avatarSound = avatarSound; } + void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; } void sendAvatarIdentityPacket(); void sendAvatarBillboardPacket(); @@ -85,7 +85,7 @@ private: QString _scriptContents; QTimer* _scriptRequestTimeout { nullptr }; bool _isListeningToAudioStream = false; - Sound* _avatarSound = nullptr; + SharedSoundPointer _avatarSound; int _numAvatarSoundSentBytes = 0; bool _isAvatar = false; QTimer* _avatarIdentityTimer = nullptr; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index ad6b436d02..a6515f5f65 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -32,8 +32,8 @@ AudioInjector::AudioInjector(QObject* parent) : } -AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : - _audioData(sound->getByteArray()), +AudioInjector::AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions) : + _audioData(sound.getByteArray()), _options(injectorOptions) { diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 79e2e645dd..2dad2856b9 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -45,7 +45,7 @@ public: }; AudioInjector(QObject* parent); - AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); + AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions); AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions); bool isFinished() const { return _state == State::Finished; } diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 9816b1b61d..806e33819e 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -27,22 +27,18 @@ #include "AudioLogging.h" #include "Sound.h" -static int soundMetaTypeId = qRegisterMetaType(); - -QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) { - return engine->newQObject(in.data()); +QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { + return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership); } -void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out) { - out = SharedSoundPointer(qobject_cast(object.toQObject())); +void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out) { + if (auto soundInterface = qobject_cast(object.toQObject())) { + out = soundInterface->getSound(); + } } -QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in) { - return engine->newQObject(in); -} - -void soundPointerFromScriptValue(const QScriptValue &object, Sound* &out) { - out = qobject_cast(object.toQObject()); +SoundScriptingInterface::SoundScriptingInterface(SharedSoundPointer sound) : _sound(sound) { + QObject::connect(sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready); } Sound::Sound(const QUrl& url, bool isStereo) : diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 91456f2fff..23ef92aa6a 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -20,18 +20,16 @@ class Sound : public Resource { Q_OBJECT - - Q_PROPERTY(bool downloaded READ isReady) - Q_PROPERTY(float duration READ getDuration) + public: Sound(const QUrl& url, bool isStereo = false); bool isStereo() const { return _isStereo; } bool isReady() const { return _isReady; } - float getDuration() { return _duration; } + float getDuration() const { return _duration; } - const QByteArray& getByteArray() { return _byteArray; } + const QByteArray& getByteArray() const { return _byteArray; } signals: void ready(); @@ -50,13 +48,28 @@ private: typedef QSharedPointer SharedSoundPointer; +class SoundScriptingInterface : public QObject { + Q_OBJECT + + Q_PROPERTY(bool downloaded READ isReady) + Q_PROPERTY(float duration READ getDuration) + +public: + SoundScriptingInterface(SharedSoundPointer sound); + SharedSoundPointer getSound() { return _sound; } + + bool isReady() const { return _sound->isReady(); } + float getDuration() { return _sound->getDuration(); } + +signals: + void ready(); + +private: + SharedSoundPointer _sound; +}; + Q_DECLARE_METATYPE(SharedSoundPointer) -QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in); -void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out); - -Q_DECLARE_METATYPE(Sound*) -QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in); -void soundPointerFromScriptValue(const QScriptValue& object, Sound* &out); - +QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in); +void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out); #endif // hifi_Sound_h diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index 7e7ca77b88..f7cc04b209 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -17,7 +17,6 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); - qScriptRegisterMetaType(engine, soundPointerToScriptValue, soundPointerFromScriptValue); } AudioScriptingInterface& AudioScriptingInterface::getInstance() { @@ -31,13 +30,14 @@ AudioScriptingInterface::AudioScriptingInterface() : } -ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { +ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions) { if (QThread::currentThread() != thread()) { ScriptAudioInjector* injector = NULL; QMetaObject::invokeMethod(this, "playSound", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ScriptAudioInjector*, injector), - Q_ARG(Sound*, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions)); + Q_ARG(SharedSoundPointer, sound), + Q_ARG(const AudioInjectorOptions&, injectorOptions)); return injector; } diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 0b0b6587a2..07a6b171f4 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -27,7 +27,7 @@ public: protected: // this method is protected to stop C++ callers from calling, but invokable from script - Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); + Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); Q_INVOKABLE void setStereoInput(bool stereo); From 079e4080c1d43042447dc79fd87dbdb5b2f2c75f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Apr 2016 08:04:52 +1200 Subject: [PATCH 095/128] Fix entities editor fonts on OSX --- examples/html/edit-style.css | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index 27a2cbe5e1..7975d825fa 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -10,43 +10,50 @@ @font-face { font-family: Raleway-Regular; - src: url(../../resources/fonts/Raleway-Regular.ttf), /* Production */ + src: url(../../resources/fonts/Raleway-Regular.ttf), /* Windows production */ + url(../../fonts/Raleway-Regular.ttf), /* OSX production */ url(../../interface/resources/fonts/Raleway-Regular.ttf); /* Development */ } @font-face { font-family: Raleway-Light; src: url(../../resources/fonts/Raleway-Light.ttf), + url(../../fonts/Raleway-Light.ttf), url(../../interface/resources/fonts/Raleway-Light.ttf); } @font-face { font-family: Raleway-Bold; src: url(../../resources/fonts/Raleway-Bold.ttf), + url(../../fonts/Raleway-Bold.ttf), url(../../interface/resources/fonts/Raleway-Bold.ttf); } @font-face { font-family: Raleway-SemiBold; src: url(../../resources/fonts/Raleway-SemiBold.ttf), + url(../../fonts/Raleway-SemiBold.ttf), url(../../interface/resources/fonts/Raleway-SemiBold.ttf); } @font-face { font-family: FiraSans-SemiBold; src: url(../../resources/fonts/FiraSans-SemiBold.ttf), + url(../../fonts/FiraSans-SemiBold.ttf), url(../../interface/resources/fonts/FiraSans-SemiBold.ttf); } @font-face { font-family: AnonymousPro-Regular; - src: url(../../resources/fonts/AnonymousPro-Regular.ttf), + src: url(../../resources/fonts/AnonymousPro-Regular.ttf), + url(../../fonts/AnonymousPro-Regular.ttf), url(../../interface/resources/fonts/AnonymousPro-Regular.ttf); } @font-face { font-family: HiFi-Glyphs; - src: url(../../resources/fonts/hifi-glyphs.ttf), + src: url(../../resources/fonts/hifi-glyphs.ttf), + url(../../fonts/hifi-glyphs.ttf), url(../../interface/resources/fonts/hifi-glyphs.ttf); } From dfa7416acb8df38fffe8fcc2109f3ad78decdc22 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Apr 2016 08:10:24 +1200 Subject: [PATCH 096/128] Fix horizontal scrollbar appearing in entity properties tab on OSX --- examples/html/edit-style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index 7975d825fa..1414e0a490 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -76,8 +76,10 @@ body { -moz-user-select: none; -ms-user-select: none; user-select: none; -} + overflow-x: hidden; + overflow-y: auto; +} table { font-family: FiraSans-SemiBold; From b6a511ac80fd9be5e25cc5987c08061809116188 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Apr 2016 08:15:25 +1200 Subject: [PATCH 097/128] Fix spin box buttons not appearing on OSX --- examples/html/edit-style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index 1414e0a490..ed9898ed86 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -252,6 +252,7 @@ input[type=number]::-webkit-inner-spin-button { display: block; position: relative; width: 10px; + height: 100%; overflow: hidden; font-family: hifi-glyphs; font-size: 50px; From 9119b8271883e64900ba2b0daed810e9ec8d5e1a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Apr 2016 08:19:16 +1200 Subject: [PATCH 098/128] Fix right margin of entities list --- examples/html/edit-style.css | 3 +++ examples/html/entityList.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index ed9898ed86..ce304e71e4 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -789,6 +789,7 @@ textarea:enabled[scrolling="true"]::-webkit-resizer { width: 100%; overflow-x: hidden; overflow-y: auto; + box-sizing: border-box; padding-top: 28px; /* Space for header and footer outside of scroll region. */ margin-top: 28px; border-left: 2px solid #575757; @@ -807,6 +808,7 @@ textarea:enabled[scrolling="true"]::-webkit-resizer { } #entity-table thead { + box-sizing: border-box; border: 2px solid #575757; border-top-left-radius: 7px; border-top-right-radius: 7px; @@ -814,6 +816,7 @@ textarea:enabled[scrolling="true"]::-webkit-resizer { } #entity-table tfoot { + box-sizing: border-box; border: 2px solid #575757; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 532b18bb97..ec507afbc8 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -254,7 +254,7 @@ function resize() { // Take up available window space - elEntityTableScroll.style.height = window.innerHeight - 232; + elEntityTableScroll.style.height = window.innerHeight - 200; // Update the widths of the header cells to match the body var tds = document.querySelectorAll("#entity-table-body tr:first-child td"); From 1f708ccb57d335eb7a811b4eac5bdebfd9b4a512 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Apr 2016 13:35:08 -0700 Subject: [PATCH 099/128] default to first person view --- interface/src/Menu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 12cec7b383..d69796b453 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -219,12 +219,12 @@ Menu::Menu() { // View > First Person cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt:: Key_P - false, qApp, SLOT(cameraMenuChanged()))); + true, qApp, SLOT(cameraMenuChanged()))); // View > Third Person cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::ThirdPerson, 0, - true, qApp, SLOT(cameraMenuChanged()))); + false, qApp, SLOT(cameraMenuChanged()))); // View > Mirror cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu, From 672b4df7c13b0e0a9d42b38bd8fa9c2510989f57 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 Apr 2016 13:36:44 -0700 Subject: [PATCH 100/128] get rid of magic number --- libraries/script-engine/src/ScriptEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index bcd509ff53..67e32a2ad8 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1094,8 +1094,9 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co testConstructorType = "empty"; } QString testConstructorValue = testConstructor.toString(); - if (testConstructorValue.size() > 80) { - testConstructorValue = testConstructorValue.mid(0, 80) + "..."; + const int maxTestConstructorValueSize = 80; + if (testConstructorValue.size() > maxTestConstructorValueSize) { + testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "..."; } qCDebug(scriptengine) << "Error -- ScriptEngine::loadEntityScript() entity:" << entityID << "failed to load entity script -- expected a function, got " + testConstructorType From 4300f2e4153acebe940d754d5ac06dc71b8899eb Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2016 12:37:35 -0700 Subject: [PATCH 101/128] Delete resource the Qt way --- libraries/networking/src/ResourceCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b5f5ca7c25..190fd2ce31 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -341,7 +341,7 @@ void Resource::allReferencesCleared() { _cache->addUnusedResource(self); } else { - delete this; + deleteLater(); } } From 47aed9c8bd8996de2ebd514c290194778454e65c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Apr 2016 14:56:20 -0700 Subject: [PATCH 102/128] fix redraw issue when logging in to or out of a domain --- interface/src/Application.cpp | 30 ++++++++++++++++++++++++------ interface/src/Application.h | 6 ++++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index adcd43952c..90a74a962a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3462,11 +3462,9 @@ void Application::update(float deltaTime) { const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); - // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it if (queryIsDue || viewIsDifferentEnough) { _lastQueriedTime = now; - if (DependencyManager::get()->shouldRenderEntities()) { queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); } @@ -3561,7 +3559,7 @@ int Application::sendNackPackets() { return packetsSent; } -void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { +void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend) { if (!_settingsLoaded) { return; // bail early if settings are not loaded @@ -3648,7 +3646,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node auto queryPacket = NLPacket::create(packetType); - nodeList->eachNode([&](const SharedNodePointer& node){ + nodeList->eachNode([&](const SharedNodePointer& node) { // only send to the NodeTypes that are serverType if (node->getActiveSocket() && node->getType() == serverType) { @@ -3717,6 +3715,16 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setMaxQueryPacketsPerSecond(0); } + // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner + // that will cause our next query to be guarenteed to be different and the server will resend to us + if (forceResend) { + _octreeQuery.setCameraPosition(glm::vec3(-0.1, -0.1, -0.1)); + const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); + _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); + _octreeQuery.setCameraNearClip(0.1f); + _octreeQuery.setCameraFarClip(0.1f); + } + // encode the query data int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); queryPacket->setPayloadSize(packetSize); @@ -4133,6 +4141,7 @@ void Application::clearDomainOctreeDetails() { auto skyStage = DependencyManager::get()->getSkyStage(); skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); + _recentlyClearedDomain = true; } void Application::domainChanged(const QString& domainHostname) { @@ -4154,7 +4163,7 @@ void Application::nodeAdded(SharedNodePointer node) const { } } -void Application::nodeActivated(SharedNodePointer node) const { +void Application::nodeActivated(SharedNodePointer node) { if (node->getType() == NodeType::AssetServer) { // asset server just connected - check if we have the asset browser showing @@ -4173,10 +4182,19 @@ void Application::nodeActivated(SharedNodePointer node) const { } } } + + // If we get a new EntityServer activated, do a "forceRedraw" query. This will send a degenerate + // query so that if the server doesn't + if (_recentlyClearedDomain && node->getType() == NodeType::EntityServer) { + _recentlyClearedDomain = false; + if (DependencyManager::get()->shouldRenderEntities()) { + queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions, true); + } + } + } void Application::nodeKilled(SharedNodePointer node) { - // These are here because connecting NodeList::nodeKilled to OctreePacketProcessor::nodeKilled doesn't work: // OctreePacketProcessor::nodeKilled is not being called when NodeList::nodeKilled is emitted. // This may have to do with GenericThread::threadRoutine() blocking the QThread event loop diff --git a/interface/src/Application.h b/interface/src/Application.h index f2b6edeea4..116d2b2137 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -312,7 +312,7 @@ private slots: void domainChanged(const QString& domainHostname); void updateWindowTitle() const; void nodeAdded(SharedNodePointer node) const; - void nodeActivated(SharedNodePointer node) const; + void nodeActivated(SharedNodePointer node); void nodeKilled(SharedNodePointer node); static void packetSent(quint64 length); void updateDisplayMode(); @@ -331,7 +331,7 @@ private: void updateThreads(float deltaTime); void updateDialogs(float deltaTime) const; - void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); + void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions, bool forceResend = false); static void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); glm::vec3 getSunDirection() const; @@ -520,6 +520,8 @@ private: std::atomic _processOctreeStatsCounter { 0 }; bool _keyboardDeviceHasFocus { true }; + + bool _recentlyClearedDomain { false }; }; #endif // hifi_Application_h From f35c59ce5f26b3258cb0369bc8f03b103321ddd3 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 6 Apr 2016 15:21:43 -0700 Subject: [PATCH 103/128] Guard against meaningless query and fragment parts. --- libraries/script-engine/src/ScriptEngine.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 15690baa0f..663ad51dbf 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -898,6 +898,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac return sensitivity; }; + // Guard against meaningless query and fragment parts. + // Do NOT use PreferLocalFile as its behavior is unpredictable (e.g., on defaultScriptsLocation()) + const auto strippingFlags = QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment; for (QString file : includeFiles) { QUrl thisURL { resolvePath(file) }; if (!_includedURLs.contains(thisURL)) { @@ -905,13 +908,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac ( (currentSandboxURL.scheme() != "file") || ( - !thisURL.toString(QUrl::RemoveFilename).startsWith(defaultScriptsLocation().toString(), getSensitivity()) && - !thisURL.toString(QUrl::RemoveFilename).startsWith(currentSandboxURL.toString(QUrl::RemoveFilename), getSensitivity()) + !thisURL.toString(strippingFlags).startsWith(defaultScriptsLocation().toString(), getSensitivity()) && + !thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity()) ) ) ) { qCWarning(scriptengine) << "Script.include() ignoring file path" << thisURL << "outside of original entity script" << currentSandboxURL; - } else { + } else { // We could also check here for CORS, but we don't yet. // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here. urls.append(thisURL); From 06e827cb5ea4ef5215252bb7c8c0cc86f1f4a5c5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 6 Apr 2016 14:40:55 -0700 Subject: [PATCH 104/128] Guard against no script engine thread affinity --- libraries/script-engine/src/ScriptEngine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e03d577300..4904c0d1de 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -154,8 +154,10 @@ ScriptEngine::~ScriptEngine() { void ScriptEngine::disconnectNonEssentialSignals() { disconnect(); - if (_isRunning && _isThreaded) { // ensure the thread is running - connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit); + QThread* receiver; + // Ensure the thread should be running, and does exist + if (_isRunning && _isThreaded && (receiver = thread())) { + connect(this, &ScriptEngine::doneRunning, receiver, &QThread::quit); } } From 5375fdd0f05acd0dee050c2b00d9d708a51e41a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 6 Apr 2016 16:42:14 -0700 Subject: [PATCH 105/128] don't do simple kinematic simulation on things that have parents --- libraries/entities/src/EntityItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 17b4e6a87d..4cd8a34248 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -888,6 +888,9 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { if (hasActions()) { return; } + if (!_parentID.isNull()) { + return; + } if (hasLocalAngularVelocity()) { glm::vec3 localAngularVelocity = getLocalAngularVelocity(); From 5f4d6ca1d31efe47697c82b4082831817b305d1d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 6 Apr 2016 19:07:26 -0700 Subject: [PATCH 106/128] CR feedback --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 90a74a962a..280f2c5d1f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4184,7 +4184,8 @@ void Application::nodeActivated(SharedNodePointer node) { } // If we get a new EntityServer activated, do a "forceRedraw" query. This will send a degenerate - // query so that if the server doesn't + // query so that the server will think our next non-degenerate query is "different enough" to send + // us a full scene if (_recentlyClearedDomain && node->getType() == NodeType::EntityServer) { _recentlyClearedDomain = false; if (DependencyManager::get()->shouldRenderEntities()) { From fd7a6ed0424a5fb4e89e5dc7bdb590f38b2a59b6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Apr 2016 17:20:40 +1200 Subject: [PATCH 107/128] Fix checkbox being clickable outside of checkbox and label extents --- examples/html/edit-style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index 02a3ba3cab..841ba34702 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -452,6 +452,10 @@ input[type=checkbox]:checked + label:hover { min-height: 29px; } +.property.checkbox { + width: auto; +} + .property label { display: table-cell; vertical-align: middle; From 7f164a79595e3eb899ede057e045b7c2b52a514b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 08:42:40 -0700 Subject: [PATCH 108/128] CR feedback --- libraries/entities/src/EntityScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 5e30910575..540cc68689 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -488,7 +488,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(cons RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) { - qDebug() << "Entities.findRayIntersectionBlocking() is obsolete, use Entities.findRayIntersection() instead."; + qWarning() << "Entities.findRayIntersectionBlocking() is obsolete, use Entities.findRayIntersection() instead."; const QVector& entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); const QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard); From 2c3aeddbe4fd8bc6992b64e0a4ce1c51f2d3bba8 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 10:25:08 -0700 Subject: [PATCH 109/128] reduce log spam for the deadlock watchdog --- interface/src/Application.cpp | 42 ++++++++++++++++++++++++----------- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 280f2c5d1f..2512dc8b26 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -250,37 +250,49 @@ public: auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto sinceLastReport = (now > _lastReport) ? now - _lastReport : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); + auto menu = Menu::getInstance(); + bool suppressStatusMessages = menu ? menu->isOptionChecked(MenuOption::SupressDeadlockWatchdogStatus) : false; if (elapsedMovingAverage > _maxElapsedAverage) { - qDebug() << "DEADLOCK WATCHDOG NEW maxElapsedAverage:" + qDebug() << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage - << "NEW maxElapsedAverage:" << elapsedMovingAverage + << "NEW maxElapsedAverage:" << elapsedMovingAverage << "** NEW MAX ELAPSED AVERAGE **" << "samples:" << _movingAverage.getSamples(); _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { - qDebug() << "DEADLOCK WATCHDOG NEW maxElapsed:" + qDebug() << "DEADLOCK WATCHDOG WARNING:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage << "PREVIOUS maxElapsed:" << _maxElapsed - << "NEW maxElapsed:" << lastHeartbeatAge + << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); _maxElapsed = lastHeartbeatAge; } - if ((sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) || (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT)) { - qDebug() << "DEADLOCK WATCHDOG STATUS -- lastHeartbeatAge:" << lastHeartbeatAge - << "elapsedMovingAverage:" << elapsedMovingAverage - << "maxElapsed:" << _maxElapsed - << "maxElapsedAverage:" << _maxElapsedAverage - << "samples:" << _movingAverage.getSamples(); + if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { + qDebug() << "DEADLOCK WATCHDOG WARNING:" + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE**" + << "maxElapsed:" << _maxElapsed + << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); + _lastReport = now; + } + + if (!suppressStatusMessages && sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) { + qDebug() << "DEADLOCK WATCHDOG STATUS:" + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage + << "maxElapsed:" << _maxElapsed + << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); _lastReport = now; } -#ifdef NDEBUG if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { qDebug() << "DEADLOCK DETECTED -- " << "lastHeartbeatAge:" << lastHeartbeatAge @@ -290,9 +302,13 @@ public: << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); - deadlockDetectionCrash(); + + // Don't actually crash in debug builds, in case this apparent deadlock is simply from + // the developer actively debugging code + #ifdef NDEBUG + deadlockDetectionCrash(); + #endif } -#endif } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d69796b453..4ea69af2b8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -530,6 +530,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::LogExtraTimings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SupressDeadlockWatchdogStatus, 0, false); // Developer > Audio >>> MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3488f03b0e..48bda01076 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -162,6 +162,7 @@ namespace MenuOption { const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; + const QString SupressDeadlockWatchdogStatus = "Supress Deadlock Watchdog Status"; const QString ThirdPerson = "Third Person"; const QString ThreePointCalibration = "3 Point Calibration"; const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp From 85019b2b5e5fda1672b486fa279b38a5b8e0e1f4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Apr 2016 15:11:42 -0700 Subject: [PATCH 110/128] Fixing logging errors on initial load of controller routes --- .../controllers/standard_navigation.json | 3 -- interface/src/Application.cpp | 42 +++++++++++-------- .../src/controllers/StateController.cpp | 29 +++++++------ .../src/controllers/StateController.h | 24 ++++++----- .../src/controllers/UserInputMapper.cpp | 18 ++++++-- .../src/controllers/UserInputMapper.h | 8 +++- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/interface/resources/controllers/standard_navigation.json b/interface/resources/controllers/standard_navigation.json index 62c0883142..c9dc90cbe6 100644 --- a/interface/resources/controllers/standard_navigation.json +++ b/interface/resources/controllers/standard_navigation.json @@ -2,9 +2,6 @@ "name": "Standard to Action", "when": "Application.NavigationFocused", "channels": [ - { "disabled_from": { "makeAxis" : [ "Standard.DD", "Standard.DU" ] }, "to": "Actions.UiNavVertical" }, - { "disabled_from": { "makeAxis" : [ "Standard.DL", "Standard.DR" ] }, "to": "Actions.UiNavLateral" }, - { "disabled_from": { "makeAxis" : [ "Standard.LB", "Standard.RB" ] }, "to": "Actions.UiNavGroup" }, { "from": "Standard.DU", "to": "Actions.UiNavVertical" }, { "from": "Standard.DD", "to": "Actions.UiNavVertical", "filters": "invert" }, { "from": "Standard.DL", "to": "Actions.UiNavLateral", "filters": "invert" }, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 280f2c5d1f..61b6258c4f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -380,6 +380,11 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt } } +static const QString STATE_IN_HMD = "InHMD"; +static const QString STATE_SNAP_TURN = "SnapTurn"; +static const QString STATE_GROUNDED = "Grounded"; +static const QString STATE_NAV_FOCUSED = "NavigationFocused"; + bool setupEssentials(int& argc, char** argv) { unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); @@ -449,6 +454,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_SNAP_TURN, STATE_GROUNDED, STATE_NAV_FOCUSED } }); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -898,6 +904,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { auto reticlePosition = getApplicationCompositor().getReticlePosition(); offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); + } else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) { + if (!offscreenUi->navigationFocused()) { + auto reticlePosition = getApplicationCompositor().getReticlePosition(); + offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); + } } else if (action == controller::toInt(controller::Action::RETICLE_X)) { auto oldPos = getApplicationCompositor().getReticlePosition(); getApplicationCompositor().setReticlePosition({ oldPos.x + state, oldPos.y }); @@ -910,28 +921,23 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } }); - // A new controllerInput device used to reflect current values from the application state - _applicationStateDevice = std::make_shared(); + _applicationStateDevice = userInputMapper->getStateDevice(); - _applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->isHMDMode(); - })); - _applicationStateDevice->addInputVariant(QString("SnapTurn"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getSnapTurn(); - })); - _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); - })); - _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { - auto offscreenUi = DependencyManager::get(); - return offscreenUi->navigationFocused() ? 1.0 : 0.0; - })); - - userInputMapper->registerDevice(_applicationStateDevice); + _applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float { + return qApp->isHMDMode() ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float { + return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_GROUNDED, []() -> float { + return qApp->getMyAvatar()->getCharacterController()->onGround() ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_NAV_FOCUSED, []() -> float { + return DependencyManager::get()->navigationFocused() ? 1 : 0; + }); // Setup the keyboardMouseDevice and the user input mapper with the default bindings userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice()); - userInputMapper->loadDefaultMapping(userInputMapper->getStandardDeviceID()); // force the model the look at the correct directory (weird order of operations issue) scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation()); diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp index 1d39449e4d..47d15fda5b 100644 --- a/libraries/controllers/src/controllers/StateController.cpp +++ b/libraries/controllers/src/controllers/StateController.cpp @@ -19,32 +19,37 @@ namespace controller { +static QStringList stateVariables; + +void StateController::setStateVariables(const QStringList& newStateVariables) { + stateVariables = newStateVariables; +} + StateController::StateController() : InputDevice("Application") { + _deviceID = UserInputMapper::STANDARD_DEVICE; + for (const auto& variable : stateVariables) { + _namedReadLambdas[variable] = [] { return 0; }; + } } -StateController::~StateController() { -} - -void StateController::update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) {} - -void StateController::focusOutEvent() {} - -void StateController::addInputVariant(QString name, ReadLambda lambda) { - _namedReadLambdas.push_back(NamedReadLambda(name, lambda)); +void StateController::setInputVariant(const QString& name, ReadLambda lambda) { + // All state variables must be predeclared; + Q_ASSERT(_namedReadLambdas.contains(name)); + _namedReadLambdas[name] = lambda; } Input::NamedVector StateController::getAvailableInputs() const { Input::NamedVector availableInputs; int i = 0; - for (auto& pair : _namedReadLambdas) { - availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), pair.first)); + for (const auto& name : stateVariables) { + availableInputs.push_back(Input::NamedPair(Input(_deviceID, i, ChannelType::BUTTON), name)); i++; } return availableInputs; } EndpointPointer StateController::createEndpoint(const Input& input) const { - return std::make_shared(_namedReadLambdas[input.getChannel()].second); + return std::make_shared(_namedReadLambdas[stateVariables[input.getChannel()]]); } } \ No newline at end of file diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h index ed36e4f838..57414c3ae8 100644 --- a/libraries/controllers/src/controllers/StateController.h +++ b/libraries/controllers/src/controllers/StateController.h @@ -24,26 +24,28 @@ class StateController : public QObject, public InputDevice { Q_PROPERTY(QString name READ getName) public: + using Pointer = std::shared_ptr; + using ReadLambda = std::function; + using NamedReadLambda = QPair; + + static void setStateVariables(const QStringList& stateVariables); + + StateController(); + const QString& getName() const { return _name; } // Device functions virtual Input::NamedVector getAvailableInputs() const override; - virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; - virtual void focusOutEvent() override; - StateController(); - virtual ~StateController(); + void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override {} + void focusOutEvent() override {} - using ReadLambda = std::function; - using NamedReadLambda = QPair; - - void addInputVariant(QString name, ReadLambda lambda); - - virtual EndpointPointer createEndpoint(const Input& input) const override; + void setInputVariant(const QString& name, ReadLambda lambda); + EndpointPointer createEndpoint(const Input& input) const override; protected: - QVector _namedReadLambdas; + QHash _namedReadLambdas; }; } diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 33739c7b9d..369f7f447a 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -44,13 +44,15 @@ namespace controller { - const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF; const uint16_t UserInputMapper::STANDARD_DEVICE = 0; + const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0x00FF; + const uint16_t UserInputMapper::STATE_DEVICE = Input::INVALID_DEVICE - 0x0100; } // Default contruct allocate the poutput size with the current hardcoded action channels controller::UserInputMapper::UserInputMapper() { registerDevice(std::make_shared()); + registerDevice(_stateDevice = std::make_shared()); registerDevice(std::make_shared()); } @@ -235,6 +237,10 @@ void fixBisectedAxis(float& full, float& negative, float& positive) { void UserInputMapper::update(float deltaTime) { Locker locker(_lock); + + static uint64_t updateCount = 0; + ++updateCount; + // Reset the axis state for next loop for (auto& channel : _actionStates) { channel = 0.0f; @@ -694,7 +700,7 @@ Pose UserInputMapper::getPose(const Input& input) const { return getPose(endpoint); } -Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) { +Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile, bool enable) { Locker locker(_lock); if (jsonFile.isEmpty()) { return Mapping::Pointer(); @@ -707,7 +713,11 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile) { } file.close(); } - return parseMapping(json); + auto result = parseMapping(json); + if (enable) { + enableMapping(result->name); + } + return result; } MappingPointer UserInputMapper::loadMappings(const QStringList& jsonFiles) { @@ -1033,7 +1043,7 @@ Mapping::Pointer UserInputMapper::parseMapping(const QJsonValue& json) { Route::Pointer route = parseRoute(channelIt); if (!route) { - qWarning() << "Couldn't parse route:" << mapping->name << channelIt; + qWarning() << "Couldn't parse route:" << mapping->name << QString(QJsonDocument(channelIt.toObject()).toJson()); continue; } diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 1021032b40..95cc629c73 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -30,6 +30,7 @@ #include "DeviceProxy.h" #include "StandardControls.h" #include "Actions.h" +#include "StateController.h" namespace controller { @@ -55,8 +56,9 @@ namespace controller { using uint16 = uint16_t; using uint32 = uint32_t; - static const uint16_t ACTIONS_DEVICE; static const uint16_t STANDARD_DEVICE; + static const uint16_t ACTIONS_DEVICE; + static const uint16_t STATE_DEVICE; UserInputMapper(); virtual ~UserInputMapper(); @@ -100,10 +102,11 @@ namespace controller { const DevicesMap& getDevices() { return _registeredDevices; } uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } InputDevice::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } + StateController::Pointer getStateDevice() { return _stateDevice; } MappingPointer newMapping(const QString& mappingName); MappingPointer parseMapping(const QString& json); - MappingPointer loadMapping(const QString& jsonFile); + MappingPointer loadMapping(const QString& jsonFile, bool enable = false); MappingPointer loadMappings(const QStringList& jsonFiles); void loadDefaultMapping(uint16 deviceID); @@ -120,6 +123,7 @@ namespace controller { // GetFreeDeviceID should be called before registering a device to use an ID not used by a different device. uint16 getFreeDeviceID() { return _nextFreeDeviceID++; } DevicesMap _registeredDevices; + StateController::Pointer _stateDevice; uint16 _nextFreeDeviceID = STANDARD_DEVICE + 1; std::vector _actionStates = std::vector(toInt(Action::NUM_ACTIONS), 0.0f); From d8310cc6b1772ab443e57d0576555b4a0c15c90d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Apr 2016 15:20:44 -0700 Subject: [PATCH 111/128] Reduce controller log spam --- libraries/controllers/src/controllers/ScriptingInterface.cpp | 2 ++ libraries/controllers/src/controllers/StateController.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 275aeedb6b..c2e64ca19e 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -33,8 +33,10 @@ static QVariantMap createDeviceMap(const controller::InputDevice::Pointer device for (const auto& inputMapping : userInputMapper->getAvailableInputs(device->getDeviceID())) { const auto& input = inputMapping.first; const auto inputName = QString(inputMapping.second).remove(SANITIZE_NAME_EXPRESSION); +#ifdef DEBUG qCDebug(controllers) << "\tInput " << input.getChannel() << (int)input.getType() << QString::number(input.getID(), 16) << ": " << inputName; +#endif deviceMap.insert(inputName, input.getID()); } return deviceMap; diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp index 47d15fda5b..e930c76af2 100644 --- a/libraries/controllers/src/controllers/StateController.cpp +++ b/libraries/controllers/src/controllers/StateController.cpp @@ -28,7 +28,7 @@ void StateController::setStateVariables(const QStringList& newStateVariables) { StateController::StateController() : InputDevice("Application") { _deviceID = UserInputMapper::STANDARD_DEVICE; for (const auto& variable : stateVariables) { - _namedReadLambdas[variable] = [] { return 0; }; + _namedReadLambdas[variable] = []()->float{ return 0; }; } } From bd1eb5842a17b4b03121f697f411bb8861ec27f2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 12:45:24 -0700 Subject: [PATCH 112/128] fix crash related to menu vs watchdog create order --- interface/src/Application.cpp | 11 +++++++++-- interface/src/Application.h | 1 + interface/src/Menu.cpp | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2512dc8b26..baca2766ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -241,6 +241,8 @@ public: *crashTrigger = 0xDEAD10CC; } + static void setSuppressStatus(bool suppress) { _suppressStatus = suppress; } + void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); @@ -251,7 +253,6 @@ public: auto sinceLastReport = (now > _lastReport) ? now - _lastReport : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); auto menu = Menu::getInstance(); - bool suppressStatusMessages = menu ? menu->isOptionChecked(MenuOption::SupressDeadlockWatchdogStatus) : false; if (elapsedMovingAverage > _maxElapsedAverage) { qDebug() << "DEADLOCK WATCHDOG WARNING:" @@ -283,7 +284,7 @@ public: _lastReport = now; } - if (!suppressStatusMessages && sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) { + if (!_suppressStatus && sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) { qDebug() << "DEADLOCK WATCHDOG STATUS:" << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage @@ -312,6 +313,7 @@ public: } } + static std::atomic _suppressStatus; static std::atomic _heartbeat; static std::atomic _lastReport; static std::atomic _maxElapsed; @@ -321,12 +323,17 @@ public: bool _quit { false }; }; +std::atomic DeadlockWatchdogThread::_suppressStatus; std::atomic DeadlockWatchdogThread::_heartbeat; std::atomic DeadlockWatchdogThread::_lastReport; std::atomic DeadlockWatchdogThread::_maxElapsed; std::atomic DeadlockWatchdogThread::_maxElapsedAverage; ThreadSafeMovingAverage DeadlockWatchdogThread::_movingAverage; +void Application::toggleSuppressDeadlockWatchdogStatus(bool checked) { + DeadlockWatchdogThread::setSuppressStatus(checked); +} + #ifdef Q_OS_WIN class MyNativeEventFilter : public QAbstractNativeEventFilter { public: diff --git a/interface/src/Application.h b/interface/src/Application.h index 116d2b2137..0bc8163f7c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -255,6 +255,7 @@ public slots: void resetSensors(bool andReload = false); void setActiveFaceTracker() const; + void toggleSuppressDeadlockWatchdogStatus(bool checked); #ifdef HAVE_IVIEWHMD void setActiveEyeTracker(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4ea69af2b8..f6386ba72d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -530,7 +530,9 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::LogExtraTimings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SupressDeadlockWatchdogStatus, 0, false); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SupressDeadlockWatchdogStatus, 0, false, + qApp, SLOT(toggleSuppressDeadlockWatchdogStatus(bool))); + // Developer > Audio >>> MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); From 81bb5ff07d4d54274e38ae8d3e9272e846eff10f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 13:13:19 -0700 Subject: [PATCH 113/128] when using the fullscreen mirror hot key, return to the view mode you were in when leaving full screen mirror --- interface/src/Application.cpp | 24 +++++++++++++++++++++++- interface/src/Application.h | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 280f2c5d1f..9f43afc476 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2152,10 +2152,32 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::MiniMirror); } else { + // whenever switching to/from full screen mirror from the keyboard, remember + // the state you were in before full screen mirror, and return to that. + auto previousMode = _myCamera.getMode(); + if (previousMode != CAMERA_MODE_MIRROR) { + switch (previousMode) { + case CAMERA_MODE_FIRST_PERSON: + _returnFromFullScreenMirrorTo = MenuOption::FirstPerson; + break; + case CAMERA_MODE_THIRD_PERSON: + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + break; + + // FIXME - it's not clear that these modes make sense to return to... + case CAMERA_MODE_INDEPENDENT: + _returnFromFullScreenMirrorTo = MenuOption::IndependentMode; + break; + case CAMERA_MODE_ENTITY: + _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; + break; + } + } + bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); if (isMirrorChecked) { - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); + Menu::getInstance()->setIsOptionChecked(_returnFromFullScreenMirrorTo, true); } cameraMenuChanged(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 116d2b2137..5998cb00b2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -522,6 +522,8 @@ private: bool _keyboardDeviceHasFocus { true }; bool _recentlyClearedDomain { false }; + + QString _returnFromFullScreenMirrorTo; }; #endif // hifi_Application_h From 45733478da8f14d5bfbd5b41e92fe3a90adf9770 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 Apr 2016 13:15:39 -0700 Subject: [PATCH 114/128] make auto-unequip code smarter -- equipping a long thing by the end is now possible --- examples/controllers/handControllerGrab.js | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 2e9129f3ac..4b20651899 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ -Script.include("../libraries/utils.js"); +Script.include("/~/libraries/utils.js"); // @@ -79,6 +79,7 @@ var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing t var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed var SHOW_GRAB_SPHERE = false; // draw a green sphere to show the grab search position and size +var CHECK_TOO_FAR_UNEQUIP_TIME = 1.0; // seconds // // equip @@ -290,11 +291,13 @@ function MyController(hand) { this.intersectionDistance = 0.0; this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; - this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; + this.lastPickTime = 0; + this.lastUnequipCheckTime = 0; + var _this = this; this.update = function() { @@ -1523,18 +1526,30 @@ function MyController(hand) { return; } - if (props.parentID == MyAvatar.sessionUUID && - Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { - // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. - print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." + - props.parentID + " " + vec3toStr(props.position)); - this.setState(STATE_RELEASE); - if (this.state == STATE_CONTINUE_NEAR_GRABBING) { - this.callEntityMethodOnGrabbed("releaseGrab"); - } else { // (this.state == STATE_CONTINUE_EQUIP || this.state == STATE_CONTINUE_HOLD) - this.callEntityMethodOnGrabbed("releaseEquip"); + + var now = Date.now(); + if (now - this.lastUnequipCheckTime > MSECS_PER_SEC * CHECK_TOO_FAR_UNEQUIP_TIME) { + this.lastUnequipCheckTime = now; + + if (props.parentID == MyAvatar.sessionUUID && + Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { + var handPosition = this.getHandPosition(); + // the center of the equipped object being far from the hand isn't enough to autoequip -- we also + // need to fail the findEntities test. + nearPickedCandidateEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + if (nearPickedCandidateEntities.indexOf(this.grabbedEntity) == -1) { + // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. + print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." + + props.parentID + " " + vec3toStr(props.position)); + this.setState(STATE_RELEASE); + if (this.state == STATE_CONTINUE_NEAR_GRABBING) { + this.callEntityMethodOnGrabbed("releaseGrab"); + } else { // (this.state == STATE_CONTINUE_EQUIP || this.state == STATE_CONTINUE_HOLD) + this.callEntityMethodOnGrabbed("releaseEquip"); + } + return; + } } - return; } // Keep track of the fingertip velocity to impart when we release the object. From 4c78c0b3301871d58053f5a0f4670d542fd1b70f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 7 Apr 2016 13:17:49 -0700 Subject: [PATCH 115/128] Fix broken xbox controllers --- .../src/controllers/StateController.cpp | 6 ++++-- .../src/controllers/UserInputMapper.cpp | 9 +++++++-- .../src/controllers/impl/Endpoint.cpp | 5 ++++- .../controllers/src/controllers/impl/Endpoint.h | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp index e930c76af2..9b0301eb14 100644 --- a/libraries/controllers/src/controllers/StateController.cpp +++ b/libraries/controllers/src/controllers/StateController.cpp @@ -26,7 +26,7 @@ void StateController::setStateVariables(const QStringList& newStateVariables) { } StateController::StateController() : InputDevice("Application") { - _deviceID = UserInputMapper::STANDARD_DEVICE; + _deviceID = UserInputMapper::STATE_DEVICE; for (const auto& variable : stateVariables) { _namedReadLambdas[variable] = []()->float{ return 0; }; } @@ -49,7 +49,9 @@ Input::NamedVector StateController::getAvailableInputs() const { } EndpointPointer StateController::createEndpoint(const Input& input) const { - return std::make_shared(_namedReadLambdas[stateVariables[input.getChannel()]]); + auto name = stateVariables[input.getChannel()]; + ReadLambda& readLambda = const_cast&>(_namedReadLambdas)[name]; + return std::make_shared(readLambda); } } \ No newline at end of file diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 369f7f447a..2b7d837aa5 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -140,7 +140,6 @@ void UserInputMapper::loadDefaultMapping(uint16 deviceID) { return; } - auto mapping = loadMappings(proxyEntry->second->getDefaultMappingConfigs()); if (mapping) { auto prevMapping = _mappingsByDevice[deviceID]; @@ -705,6 +704,12 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile, bool enab if (jsonFile.isEmpty()) { return Mapping::Pointer(); } + // Each mapping only needs to be loaded once + static QSet loaded; + if (loaded.contains(jsonFile)) { + return Mapping::Pointer(); + } + loaded.insert(jsonFile); QString json; { QFile file(jsonFile); @@ -971,7 +976,7 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) { result->json = QString(QJsonDocument(obj).toJson()); result->source = parseSource(obj[JSON_CHANNEL_FROM]); result->debug = obj[JSON_CHANNEL_DEBUG].toBool(); - result->debug = obj[JSON_CHANNEL_PEEK].toBool(); + result->peek = obj[JSON_CHANNEL_PEEK].toBool(); if (!result->source) { qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM]; return Route::Pointer(); diff --git a/libraries/controllers/src/controllers/impl/Endpoint.cpp b/libraries/controllers/src/controllers/impl/Endpoint.cpp index e771b1916f..289f83b228 100644 --- a/libraries/controllers/src/controllers/impl/Endpoint.cpp +++ b/libraries/controllers/src/controllers/impl/Endpoint.cpp @@ -12,5 +12,8 @@ // warning LNK4221: This object file does not define any previously undefined public symbols, // so it will not be used by any link operation that consumes this library // -//#include "Endpoint.h" +#include "Endpoint.h" +namespace controller { + Endpoint::WriteLambda DEFAULT_WRITE_LAMBDA = [](float) {}; +} diff --git a/libraries/controllers/src/controllers/impl/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h index 475dc035bb..a938dd30b6 100644 --- a/libraries/controllers/src/controllers/impl/Endpoint.h +++ b/libraries/controllers/src/controllers/impl/Endpoint.h @@ -67,6 +67,23 @@ namespace controller { WriteLambda _writeLambda; }; + extern Endpoint::WriteLambda DEFAULT_WRITE_LAMBDA; + + class LambdaRefEndpoint : public Endpoint { + public: + using Endpoint::apply; + LambdaRefEndpoint(const ReadLambda& readLambda, const WriteLambda& writeLambda = DEFAULT_WRITE_LAMBDA) + : Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { + } + + virtual float peek() const override { return _readLambda(); } + virtual void apply(float value, const Pointer& source) override { _writeLambda(value); } + + private: + const ReadLambda& _readLambda; + const WriteLambda& _writeLambda; + }; + class VirtualEndpoint : public Endpoint { public: From a58a627fdff230a3061d220a097511f48bd6d103 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 5 Apr 2016 15:53:58 -0700 Subject: [PATCH 116/128] Support oculus remote input --- .../resources/controllers/oculus_remote.json | 14 ++++ .../resources/controllers/oculus_touch.json | 23 ++++++ .../oculus/src/OculusControllerManager.cpp | 72 +++++++++++++++---- plugins/oculus/src/OculusControllerManager.h | 4 +- 4 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 interface/resources/controllers/oculus_remote.json create mode 100644 interface/resources/controllers/oculus_touch.json diff --git a/interface/resources/controllers/oculus_remote.json b/interface/resources/controllers/oculus_remote.json new file mode 100644 index 0000000000..0e5b7b667b --- /dev/null +++ b/interface/resources/controllers/oculus_remote.json @@ -0,0 +1,14 @@ +{ + "name": "Oculus Remote to Standard", + "channels": [ + { "from": "OculusRemote.Back", "to": "Standard.Back" }, + { "from": "OculusRemote.Start", "to": "Standard.Start" }, + + { "from": "OculusRemote.DU", "to": "Standard.DU" }, + { "from": "OculusRemote.DD", "to": "Standard.DD" }, + { "from": "OculusRemote.DL", "to": "Standard.DL" }, + { "from": "OculusRemote.DR", "to": "Standard.DR" } + ] +} + + diff --git a/interface/resources/controllers/oculus_touch.json b/interface/resources/controllers/oculus_touch.json new file mode 100644 index 0000000000..cc8c2f8bdc --- /dev/null +++ b/interface/resources/controllers/oculus_touch.json @@ -0,0 +1,23 @@ +{ + "name": "Oculus Touch to Standard", + "channels": [ + { "from": "OculusTouch.LY", "filters": "invert", "to": "Standard.LY" }, + { "from": "OculusTouch.LX", "to": "Standard.LX" }, + { "from": "OculusTouch.LT", "to": "Standard.LT" }, + + { "from": "OculusTouch.RY", "filters": "invert", "to": "Standard.RY" }, + { "from": "OculusTouch.RX", "to": "Standard.RX" }, + + { "from": "OculusTouch.RT", "to": "Standard.RT" }, + { "from": "OculusTouch.RB", "to": "Standard.RB" }, + { "from": "OculusTouch.RS", "to": "Standard.RS" }, + + { "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" }, + { "from": "OculusTouch.RightApplicationMenu", "to": "Standard.Start" }, + + { "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" }, + { "from": "OculusTouch.RightHand", "to": "Standard.RightHand" } + ] +} + + diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index f11ec18b10..b728023e4f 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -44,12 +44,14 @@ bool OculusControllerManager::activate() { // register with UserInputMapper auto userInputMapper = DependencyManager::get(); - if (_remote) { - userInputMapper->registerDevice(_remote); - } - if (_touch) { - userInputMapper->registerDevice(_touch); - } + _remote = std::make_shared(*this); + userInputMapper->registerDevice(_remote); + +#if 0 + _touch = std::make_shared(); + userInputMapper->registerDevice(_touch); +#endif + return true; } @@ -74,16 +76,21 @@ void OculusControllerManager::deactivate() { void OculusControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { PerformanceTimer perfTimer("OculusControllerManager::TouchDevice::update"); - if (!OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { - qCWarning(oculus) << "Unable to read oculus input state"; - return; - } if (_touch) { - _touch->update(deltaTime, inputCalibrationData, jointsCaptured); + if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { + _touch->update(deltaTime, inputCalibrationData, jointsCaptured); + } else { + qCWarning(oculus) << "Unable to read Oculus touch input state"; + } } + if (_remote) { - _remote->update(deltaTime, inputCalibrationData, jointsCaptured); + if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) { + _remote->update(deltaTime, inputCalibrationData, jointsCaptured); + } else { + qCWarning(oculus) << "Unable to read Oculus remote input state"; + } } } @@ -99,6 +106,12 @@ void OculusControllerManager::pluginFocusOutEvent() { using namespace controller; static const std::vector> BUTTON_MAP { { + { ovrButton_Up, DU }, + { ovrButton_Down, DD }, + { ovrButton_Left, DL }, + { ovrButton_Right, DR }, + { ovrButton_Enter, START }, + { ovrButton_Back, BACK }, { ovrButton_X, X }, { ovrButton_Y, Y }, { ovrButton_A, A }, @@ -124,6 +137,39 @@ static const std::vector> TOUCH_MAP { { ovrTouch_RIndexPointing, RIGHT_INDEX_POINT }, } }; + +controller::Input::NamedVector OculusControllerManager::RemoteDevice::getAvailableInputs() const { + using namespace controller; + QVector availableInputs { + makePair(DU, "Up"), + makePair(DD, "Down"), + makePair(DL, "Left"), + makePair(DR, "Right"), + makePair(START, "Start"), + makePair(BACK, "Back"), + }; + return availableInputs; +} + +QString OculusControllerManager::RemoteDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/oculus_remote.json"; + return MAPPING_JSON; +} + +void OculusControllerManager::RemoteDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { + _buttonPressedMap.clear(); + const auto& inputState = _parent._inputState; + for (const auto& pair : BUTTON_MAP) { + if (inputState.Buttons & pair.first) { + _buttonPressedMap.insert(pair.second); + } + } +} + +void OculusControllerManager::RemoteDevice::focusOutEvent() { + _buttonPressedMap.clear(); +} + void OculusControllerManager::TouchDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { _poseStateMap.clear(); _buttonPressedMap.clear(); @@ -211,7 +257,7 @@ controller::Input::NamedVector OculusControllerManager::TouchDevice::getAvailabl } QString OculusControllerManager::TouchDevice::getDefaultMappingConfig() const { - static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touch.json"; + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/oculus_touch.json"; return MAPPING_JSON; } diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index fc10dcc73d..60969097f8 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -45,7 +45,7 @@ private: class RemoteDevice : public OculusInputDevice { public: using Pointer = std::shared_ptr; - RemoteDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Remote") {} + RemoteDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "OculusRemote") {} controller::Input::NamedVector getAvailableInputs() const override; QString getDefaultMappingConfig() const override; @@ -58,7 +58,7 @@ private: class TouchDevice : public OculusInputDevice { public: using Pointer = std::shared_ptr; - TouchDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Touch") {} + TouchDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "OculusTouch") {} controller::Input::NamedVector getAvailableInputs() const override; QString getDefaultMappingConfig() const override; From 2f28c64edbff38aa356a0ee27a1dc511d8dab594 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 6 Apr 2016 15:10:48 -0700 Subject: [PATCH 117/128] Fixing menu navigation in oculus remote --- .../resources/controllers/oculus_remote.json | 5 ++-- .../oculus/src/OculusControllerManager.cpp | 24 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/interface/resources/controllers/oculus_remote.json b/interface/resources/controllers/oculus_remote.json index 0e5b7b667b..580d7b1184 100644 --- a/interface/resources/controllers/oculus_remote.json +++ b/interface/resources/controllers/oculus_remote.json @@ -1,9 +1,8 @@ { "name": "Oculus Remote to Standard", "channels": [ - { "from": "OculusRemote.Back", "to": "Standard.Back" }, - { "from": "OculusRemote.Start", "to": "Standard.Start" }, - + { "from": "OculusRemote.Start", "to": "Actions.UiNavSelect" }, + { "from": "OculusRemote.Back", "to": "Actions.UiNavBack" }, { "from": "OculusRemote.DU", "to": "Standard.DU" }, { "from": "OculusRemote.DD", "to": "Standard.DD" }, { "from": "OculusRemote.DL", "to": "Standard.DL" }, diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index b728023e4f..50ef6b09a1 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -44,13 +44,16 @@ bool OculusControllerManager::activate() { // register with UserInputMapper auto userInputMapper = DependencyManager::get(); - _remote = std::make_shared(*this); - userInputMapper->registerDevice(_remote); -#if 0 - _touch = std::make_shared(); - userInputMapper->registerDevice(_touch); -#endif + if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) { + _remote = std::make_shared(*this); + userInputMapper->registerDevice(_remote); + } + + if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { + _touch = std::make_shared(*this); + userInputMapper->registerDevice(_touch); + } return true; } @@ -76,7 +79,6 @@ void OculusControllerManager::deactivate() { void OculusControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { PerformanceTimer perfTimer("OculusControllerManager::TouchDevice::update"); - if (_touch) { if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { _touch->update(deltaTime, inputCalibrationData, jointsCaptured); @@ -141,10 +143,10 @@ static const std::vector> TOUCH_MAP { controller::Input::NamedVector OculusControllerManager::RemoteDevice::getAvailableInputs() const { using namespace controller; QVector availableInputs { - makePair(DU, "Up"), - makePair(DD, "Down"), - makePair(DL, "Left"), - makePair(DR, "Right"), + makePair(DU, "DU"), + makePair(DD, "DD"), + makePair(DL, "DL"), + makePair(DR, "DR"), makePair(START, "Start"), makePair(BACK, "Back"), }; From 09004680d08e5a48733ce65dc4c16cfe77d1664d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 13:32:26 -0700 Subject: [PATCH 118/128] handle a couple edge cases --- interface/src/Application.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9f43afc476..2e27560e58 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2171,12 +2171,23 @@ void Application::keyPressEvent(QKeyEvent* event) { case CAMERA_MODE_ENTITY: _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; break; + + default: + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + break; } } bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); if (isMirrorChecked) { + + // if we got here without coming in from a non-Full Screen mirror case, then our + // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old + // behavior of returning to ThirdPerson + if (_returnFromFullScreenMirrorTo.isEmpty()) { + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + } Menu::getInstance()->setIsOptionChecked(_returnFromFullScreenMirrorTo, true); } cameraMenuChanged(); From d1a2a30c024e922484ac09766ef82ee7109e7b82 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 7 Apr 2016 13:41:05 -0700 Subject: [PATCH 119/128] fix build buster --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index baca2766ab..c5b1a79bb9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -252,7 +252,6 @@ public: auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto sinceLastReport = (now > _lastReport) ? now - _lastReport : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); - auto menu = Menu::getInstance(); if (elapsedMovingAverage > _maxElapsedAverage) { qDebug() << "DEADLOCK WATCHDOG WARNING:" From 8f530ceaf9c7a23ba90ee81ce10e5f1e8507fcaa Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 7 Apr 2016 13:42:40 -0700 Subject: [PATCH 120/128] Reading animation properties without an entityTree lock is considered harmful In RenderableModelEntityItem::update() make a copy of the _animationProperties, which is under the entityTree lock. In RenderableModelEntityItem::render() read from the copy of _animationProperties when not under the entityTree lock. --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 9 ++++++--- .../entities-renderer/src/RenderableModelEntityItem.h | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b510f58b12..19e5ab4683 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -271,10 +271,10 @@ bool RenderableModelEntityItem::getAnimationFrame() { return false; } - if (!hasAnimation() || !_jointMappingCompleted) { + if (!hasRenderAnimation() || !_jointMappingCompleted) { return false; } - AnimationPointer myAnimation = getAnimation(_animationProperties.getURL()); // FIXME: this could be optimized + AnimationPointer myAnimation = getAnimation(getRenderAnimationURL()); // FIXME: this could be optimized if (myAnimation && myAnimation->isLoaded()) { const QVector& frames = myAnimation->getFramesReference(); // NOTE: getFrames() is too heavy @@ -384,7 +384,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } if (_model) { - if (hasAnimation()) { + if (hasRenderAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); @@ -528,6 +528,9 @@ void RenderableModelEntityItem::update(const quint64& now) { } } + // make a copy of the animation properites + _renderAnimationProperties = _animationProperties; + ModelEntityItem::update(now); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 6d40a80950..90aca41f34 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -82,6 +82,11 @@ public: virtual int getJointIndex(const QString& name) const override; virtual QStringList getJointNames() const override; + // These operate on a copy of the renderAnimationProperties, so they can be accessed + // without having the entityTree lock. + bool hasRenderAnimation() const { return !_renderAnimationProperties.getURL().isEmpty(); } + const QString& getRenderAnimationURL() const { return _renderAnimationProperties.getURL(); } + private: QVariantMap parseTexturesToMap(QString textures); void remapTextures(); @@ -97,6 +102,8 @@ private: QVector> _points; bool _dimensionsInitialized = true; + AnimationPropertyGroup _renderAnimationProperties; + render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID }; bool _showCollisionHull = false; From 72d8990fed562e445c6c9f8807bacea682dfbc37 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 7 Apr 2016 14:13:02 -0700 Subject: [PATCH 121/128] Fix menu launch from Oculus remote --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 280f2c5d1f..b6e3b49595 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -895,6 +895,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : DependencyManager::get()->toggleMute(); } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) { cycleCamera(); + } else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) { + if (!offscreenUi->navigationFocused()) { + auto reticlePosition = getApplicationCompositor().getReticlePosition(); + offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); + } } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { auto reticlePosition = getApplicationCompositor().getReticlePosition(); offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); From e37e46d34a9da1f34774d12511bf22c71ddc249c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Apr 2016 10:30:00 +1200 Subject: [PATCH 122/128] Disable arrow keys being able to move between HTML form fields Moving between form fields with arrow keys makes it to easy to make unintended changes to adjacent fields. --- interface/resources/qml/hifi/Desktop.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 409c468878..59278a17b4 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -21,7 +21,7 @@ Desktop { Component.onCompleted: { WebEngine.settings.javascriptCanOpenWindows = true; WebEngine.settings.javascriptCanAccessClipboard = false; - WebEngine.settings.spatialNavigationEnabled = true; + WebEngine.settings.spatialNavigationEnabled = false; WebEngine.settings.localContentCanAccessRemoteUrls = true; } From 86d314f31a3d90c0bf19cdd3938519bc2e3e4130 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Apr 2016 10:47:45 +1200 Subject: [PATCH 123/128] Clarify code comment --- examples/html/edit-style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/edit-style.css b/examples/html/edit-style.css index ce304e71e4..e71c854dbb 100644 --- a/examples/html/edit-style.css +++ b/examples/html/edit-style.css @@ -12,7 +12,7 @@ font-family: Raleway-Regular; src: url(../../resources/fonts/Raleway-Regular.ttf), /* Windows production */ url(../../fonts/Raleway-Regular.ttf), /* OSX production */ - url(../../interface/resources/fonts/Raleway-Regular.ttf); /* Development */ + url(../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */ } @font-face { From 4e3ab7394135741c6889e3e89ca973d44ade0cbe Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Apr 2016 17:27:51 -0700 Subject: [PATCH 124/128] layout std140 in particle shader --- .../src/RenderableParticleEffectEntityItem.cpp | 1 + libraries/entities-renderer/src/textured_particle.slv | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 4d8eebf05b..a199c6b10e 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -39,6 +39,7 @@ public: InterpolationData radius; InterpolationData color; // rgba float lifespan; + glm::vec3 spare; }; struct ParticlePrimitive { diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index d3747d21eb..79f75187c5 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -30,10 +30,10 @@ struct Colors { struct ParticleUniforms { Radii radius; Colors color; - float lifespan; + vec4 lifespan; // x is lifespan, 3 spare floats }; -uniform particleBuffer { +layout(std140) uniform particleBuffer { ParticleUniforms particle; }; @@ -112,7 +112,7 @@ void main(void) { int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; // Particle properties - float age = inColor.x / particle.lifespan; + float age = inColor.x / particle.lifespan.x; float seed = inColor.y; // Pass the texcoord and the z texcoord is representing the texture icon From 723af9bcbd38b2475ec95e9a09fe3411eb3ca07a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 Apr 2016 20:34:34 -0700 Subject: [PATCH 125/128] host voxel icons on s3 rather than hungry.com --- examples/voxels.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/voxels.js b/examples/voxels.js index 4ca5d46ff7..19a31487fe 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -7,7 +7,8 @@ Script.include([ ]); var isActive = false; -var toolIconUrl = "http://headache.hungry.com/~seth/hifi/"; +var toolIconUrl = "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/icons/" + var toolHeight = 50; var toolWidth = 50; From fba6a74cf6b2b24f351c5231fa1e3de16358cf04 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 8 Apr 2016 00:50:15 -0700 Subject: [PATCH 126/128] remove refresh for now --- examples/html/entityProperties.html | 60 ++++++----------------------- 1 file changed, 11 insertions(+), 49 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index bd8abb9a91..56ebe4580c 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -468,36 +468,9 @@ var elPreviewCameraButton = document.getElementById("preview-camera-button"); - var urlUpdaters = document.getElementsByClassName("update-url-version"); var PARAM_REGEXP = /(?:\?)(\S+)/; // Check if this has any parameters. var TIMESTAMP_REGEXP = /(&?HFTime=\d+)/; - var refreshEvent = function (event) { - var urlElement = event.target.parentElement.getElementsByTagName("INPUT")[0]; - var content = urlElement.value; - var date = new Date(); - var timeStamp = date.getTime(); - - if(content.length > 0){ - if(PARAM_REGEXP.test(content)){ - // Has params, so lets remove existing definition and append again. - content = content.replace(TIMESTAMP_REGEXP,"") + "&"; - }else{ - content += "?"; - } - content = content.replace("?&","?"); - urlElement.value = content + "HFTime=" + timeStamp; - } - - var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", true, true ); - urlElement.dispatchEvent(evt); - }; - - for(var index = 0; index < urlUpdaters.length; index++){ - var urlUpdater = urlUpdaters[index]; - urlUpdater.addEventListener("click", refreshEvent, true); - } if (window.EventBridge !== undefined) { var properties; @@ -1397,20 +1370,17 @@ -
+
-
-
+
-
-
+
-
@@ -1545,16 +1515,15 @@
-
+
-
-
+
-
M
-
+
-
-
+
-
-
+
-
@@ -1693,10 +1658,9 @@
-
+
-
@@ -1745,20 +1709,18 @@
-
+
-
M
-
+
-
From b407e20e4b69c4bb2c2567792e43f5cc9a2428c9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 8 Apr 2016 00:52:09 -0700 Subject: [PATCH 127/128] remove regexp --- examples/html/entityProperties.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 56ebe4580c..d3fcbc8e8a 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -467,10 +467,6 @@ var elZTextureURL = document.getElementById("property-z-texture-url"); var elPreviewCameraButton = document.getElementById("preview-camera-button"); - - var PARAM_REGEXP = /(?:\?)(\S+)/; // Check if this has any parameters. - var TIMESTAMP_REGEXP = /(&?HFTime=\d+)/; - if (window.EventBridge !== undefined) { var properties; From 43f735dd211e75a24673422b906638d5eab53670 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 9 Apr 2016 22:18:43 -0700 Subject: [PATCH 128/128] avoid loop where bullet moves an entity and then an entity tells bullet that it has moved. --- .../entities-renderer/src/RenderableEntityItem.h | 2 +- .../src/RenderableModelEntityItem.cpp | 4 ++-- .../src/RenderableModelEntityItem.h | 2 +- .../src/RenderableParticleEffectEntityItem.h | 2 +- .../entities-renderer/src/RenderableZoneEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 8 +++++--- libraries/entities/src/EntityItem.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 12 ++++++++++-- libraries/shared/src/SpatiallyNestable.cpp | 12 ++++++------ libraries/shared/src/SpatiallyNestable.h | 6 +++--- 10 files changed, 31 insertions(+), 21 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 30d3f9d83c..92bb98ad32 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -92,7 +92,7 @@ private: public: \ virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \ virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \ - virtual void locationChanged() override { EntityItem::locationChanged(); _renderHelper.notifyChanged(); } \ + virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); _renderHelper.notifyChanged(); } \ virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); _renderHelper.notifyChanged(); } \ private: \ SimpleRenderableEntityItem _renderHelper; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 19e5ab4683..879ff01056 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -798,8 +798,8 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector& tra } -void RenderableModelEntityItem::locationChanged() { - EntityItem::locationChanged(); +void RenderableModelEntityItem::locationChanged(bool tellPhysics) { + EntityItem::locationChanged(tellPhysics); if (_model && _model->isActive()) { _model->setRotation(getRotation()); _model->setTranslation(getPosition()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 90aca41f34..bf55c829e9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -75,7 +75,7 @@ public: virtual void setJointTranslationsSet(const QVector& translationsSet) override; virtual void loader() override; - virtual void locationChanged() override; + virtual void locationChanged(bool tellPhysics = true) override; virtual void resizeJointArrays(int newSize = -1) override; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 1f066a81fd..a36c3640d6 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -29,7 +29,7 @@ public: virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; protected: - virtual void locationChanged() override { EntityItem::locationChanged(); notifyBoundChanged(); } + virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } void notifyBoundChanged(); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 4ba862fff8..241a066341 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -42,7 +42,7 @@ public: virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); private: - virtual void locationChanged() override { EntityItem::locationChanged(); notifyBoundChanged(); } + virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } void notifyBoundChanged(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4cd8a34248..417e6008e8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1976,14 +1976,16 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG return result; } -void EntityItem::locationChanged() { +void EntityItem::locationChanged(bool tellPhysics) { requiresRecalcBoxes(); - _dirtyFlags |= Simulation::DIRTY_TRANSFORM; + if (tellPhysics) { + _dirtyFlags |= Simulation::DIRTY_TRANSFORM; + } EntityTreePointer tree = getTree(); if (tree) { tree->entityChanged(getThisPointer()); } - SpatiallyNestable::locationChanged(); // tell all the children, also + SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also } void EntityItem::dimensionsChanged() { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 622f78b2d3..08550c9ce5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -432,7 +432,7 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - virtual void locationChanged() override; + virtual void locationChanged(bool tellPhysics = true) override; virtual void dimensionsChanged() override; EntityTypes::EntityType _type; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 700160514c..a9dcb4a16c 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -207,8 +207,16 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(entityTreeIsLocked()); measureBodyAcceleration(); - _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); - _entity->setRotation(bulletToGLM(worldTrans.getRotation())); + bool positionSuccess; + _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); + if (!positionSuccess) { + qDebug() << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID(); + } + bool orientationSuccess; + _entity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); + if (!orientationSuccess) { + qDebug() << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); + } _entity->setVelocity(getBodyLinearVelocity()); _entity->setAngularVelocity(getBodyAngularVelocity()); _entity->setLastSimulated(usecTimestampNow()); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 96a5a1d8ae..6b3e3806a7 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -314,7 +314,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { return getTransform(jointIndex, success).getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { +void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success, bool tellPhysics) { // guard against introducing NaN into the transform if (isNaN(position)) { success = false; @@ -328,7 +328,7 @@ void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); if (success) { - locationChanged(); + locationChanged(tellPhysics); } else { qDebug() << "setPosition failed for" << getID(); } @@ -363,7 +363,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const return getTransform(jointIndex, success).getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) { +void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success, bool tellPhysics) { // guard against introducing NaN into the transform if (isNaN(orientation)) { success = false; @@ -378,7 +378,7 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& succe Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); if (success) { - locationChanged(); + locationChanged(tellPhysics); } } @@ -751,9 +751,9 @@ void SpatiallyNestable::forEachDescendant(std::functionlocationChanged(); + object->locationChanged(tellPhysics); }); } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 58a141b1fa..c120c1010c 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -59,13 +59,13 @@ public: virtual glm::vec3 getPosition(bool& success) const; virtual glm::vec3 getPosition() const; - virtual void setPosition(const glm::vec3& position, bool& success); + virtual void setPosition(const glm::vec3& position, bool& success, bool tellPhysics = true); virtual void setPosition(const glm::vec3& position); virtual glm::quat getOrientation(bool& success) const; virtual glm::quat getOrientation() const; virtual glm::quat getOrientation(int jointIndex, bool& success) const; - virtual void setOrientation(const glm::quat& orientation, bool& success); + virtual void setOrientation(const glm::quat& orientation, bool& success, bool tellPhysics = true); virtual void setOrientation(const glm::quat& orientation); virtual glm::vec3 getVelocity(bool& success) const; @@ -159,7 +159,7 @@ protected: mutable ReadWriteLockable _childrenLock; mutable QHash _children; - virtual void locationChanged(); // called when a this object's location has changed + virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed virtual void dimensionsChanged() { } // called when a this object's dimensions have changed // _queryAACube is used to decide where something lives in the octree