From f0871c6878ff614b5b2f3d775ea161e0edb8ae91 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 21 Jul 2017 21:06:15 -0700 Subject: [PATCH 01/38] avoid unnecessary and expensive gets --- interface/src/avatar/MyAvatar.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b32ef4024e..7910df90ec 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1643,10 +1643,13 @@ void MyAvatar::prepareForPhysicsSimulation() { } void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { - glm::vec3 position = getPosition(); - glm::quat orientation = getOrientation(); + glm::vec3 position; + glm::quat orientation; if (_characterController.isEnabledAndReady()) { _characterController.getPositionAndOrientation(position, orientation); + } else { + position = getPosition(); + orientation = getOrientation(); } nextAttitude(position, orientation); _bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix); From 29be9aee65a14e314905dead6dc8229f6667b1f2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 21 Jul 2017 21:34:44 -0700 Subject: [PATCH 02/38] move nextAttitude() from AvatarData to MyAvatar --- interface/src/avatar/MyAvatar.cpp | 17 +++++++++++++++++ interface/src/avatar/MyAvatar.h | 1 + .../src/avatars-renderer/Avatar.h | 2 +- libraries/avatars/src/AvatarData.cpp | 17 ----------------- libraries/avatars/src/AvatarData.h | 3 --- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7910df90ec..2e3b9a584e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1642,6 +1642,23 @@ void MyAvatar::prepareForPhysicsSimulation() { _prePhysicsRoomPose = AnimPose(_sensorToWorldMatrix); } +// There are a number of possible strategies for this set of tools through endRender, below. +void MyAvatar::nextAttitude(glm::vec3 position, glm::quat orientation) { + bool success; + Transform trans = getTransform(success); + if (!success) { + qCWarning(interfaceapp) << "Warning -- MyAvatar::nextAttitude failed"; + return; + } + trans.setTranslation(position); + trans.setRotation(orientation); + SpatiallyNestable::setTransform(trans, success); + if (!success) { + qCWarning(interfaceapp) << "Warning -- MyAvatar::nextAttitude failed"; + } + updateAttitude(); +} + void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { glm::vec3 position; glm::quat orientation; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 648a5b5f29..86321137d4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -432,6 +432,7 @@ public: void updateMotors(); void prepareForPhysicsSimulation(); + void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void harvestResultsFromPhysicsSimulation(float deltaTime); const QString& getCollisionSoundURL() { return _collisionSoundURL; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 89db519abc..db9d36be7a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -184,7 +184,7 @@ public: void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; void slamPosition(const glm::vec3& position); - virtual void updateAttitude() override { _skeletonModel->updateAttitude(); } + virtual void updateAttitude() { _skeletonModel->updateAttitude(); } // Call this when updating Avatar position with a delta. This will allow us to // _accurately_ measure position changes and compute the resulting velocity diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6fdb4d1ef6..85228af941 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -110,23 +110,6 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { return _defaultFullAvatarModelUrl; } -// There are a number of possible strategies for this set of tools through endRender, below. -void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { - bool success; - Transform trans = getTransform(success); - if (!success) { - qCWarning(avatars) << "Warning -- AvatarData::nextAttitude failed"; - return; - } - trans.setTranslation(position); - trans.setRotation(orientation); - SpatiallyNestable::setTransform(trans, success); - if (!success) { - qCWarning(avatars) << "Warning -- AvatarData::nextAttitude failed"; - } - updateAttitude(); -} - void AvatarData::setTargetScale(float targetScale) { auto newValue = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); if (_targetScale != newValue) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 16768ec62a..1cf7d7dd91 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -445,9 +445,6 @@ public: using SpatiallyNestable::setOrientation; virtual void setOrientation(const glm::quat& orientation) override; - void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. - virtual void updateAttitude() {} // Tell skeleton mesh about changes - glm::quat getHeadOrientation() const { lazyInitHeadData(); return _headData->getOrientation(); From f598b1f1f581761010f45ca0f7907a71943c484f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Jul 2017 15:56:05 -0700 Subject: [PATCH 03/38] fix spelling typo in comment --- interface/src/avatar/MyHead.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index 9f2d080cd6..7fc6b9fa26 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -29,7 +29,7 @@ MyHead::MyHead(MyAvatar* owningAvatar) : Head(owningAvatar) { glm::quat MyHead::getHeadOrientation() const { // NOTE: Head::getHeadOrientation() is not used for orienting the camera "view" while in Oculus mode, so // you may wonder why this code is here. This method will be called while in Oculus mode to determine how - // to change the driving direction while in Oculus mode. It is used to support driving toward where you're + // to change the driving direction while in Oculus mode. It is used to support driving toward where your // head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not // always the same. @@ -39,7 +39,7 @@ glm::quat MyHead::getHeadOrientation() const { return headPose.rotation * Quaternions::Y_180; } - return myAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f))); + return myAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f))); } void MyHead::simulate(float deltaTime) { From 49942832474dd2638100d4114ac7d0ab68466f9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Jul 2017 15:57:18 -0700 Subject: [PATCH 04/38] remove unnecessary state check --- libraries/physics/src/CharacterController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index bd4d1201c7..9a7abc4e98 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -445,7 +445,7 @@ void CharacterController::handleChangedCollisionGroup() { void CharacterController::updateUpAxis(const glm::quat& rotation) { _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); - if (_state != State::Hover && _rigidBody) { + if (_rigidBody) { _rigidBody->setGravity(_gravity * _currentUp); } } From 8c55476c65feb3762141403cc6225bd9f8b85699 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Jul 2017 15:58:39 -0700 Subject: [PATCH 05/38] fix motor direction when walking upside down also maintain worldUp and remove unnecessary cruft --- interface/src/Application.cpp | 4 +- interface/src/avatar/MyAvatar.cpp | 6 +-- interface/src/avatar/MyAvatar.h | 1 - .../src/avatars-renderer/Avatar.cpp | 38 ++++++------------- .../src/avatars-renderer/Avatar.h | 13 ++----- .../src/avatars-renderer/SkeletonModel.cpp | 6 +-- .../src/avatars-renderer/SkeletonModel.h | 2 +- libraries/avatars/src/AvatarData.cpp | 14 +++---- libraries/avatars/src/AvatarData.h | 12 +++--- libraries/shared/src/shared/Camera.h | 2 +- 10 files changed, 38 insertions(+), 60 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dbb94cfdae..166b4fee72 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2314,7 +2314,7 @@ void Application::paintGL() { } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { if (isHMDMode()) { - auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); + auto mirrorBodyOrientation = myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // Mirror HMD yaw and roll @@ -2336,7 +2336,7 @@ void Application::paintGL() { + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); } else { - _myCamera.setOrientation(myAvatar->getWorldAlignedOrientation() + _myCamera.setOrientation(myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2e3b9a584e..b644defde2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1291,7 +1291,7 @@ eyeContactTarget MyAvatar::getEyeContactTarget() { } glm::vec3 MyAvatar::getDefaultEyePosition() const { - return getPosition() + getWorldAlignedOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); + return getPosition() + getOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); } const float SCRIPT_PRIORITY = 1.0f + 1.0f; @@ -1588,7 +1588,7 @@ void MyAvatar::updateMotors() { // non-hovering = walking: follow camera twist about vertical but not lift // so we decompose camera's rotation and store the twist part in motorRotation glm::quat liftRotation; - swingTwistDecomposition(getMyHead()->getHeadOrientation(), _worldUpDirection, liftRotation, motorRotation); + motorRotation = getOrientation(); } const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f; @@ -1656,7 +1656,7 @@ void MyAvatar::nextAttitude(glm::vec3 position, glm::quat orientation) { if (!success) { qCWarning(interfaceapp) << "Warning -- MyAvatar::nextAttitude failed"; } - updateAttitude(); + updateAttitude(orientation); } void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 86321137d4..2f8f838cf9 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -552,7 +552,6 @@ public: Q_INVOKABLE bool isUp(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up. Q_INVOKABLE bool isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; }; - public slots: void increaseSize(); void decreaseSize(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 4016592d0a..06814c2707 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -151,11 +151,6 @@ glm::vec3 Avatar::getNeckPosition() const { return _skeletonModel->getNeckPosition(neckPosition) ? neckPosition : getPosition(); } - -glm::quat Avatar::getWorldAlignedOrientation () const { - return computeRotationFromBodyToWorldUp() * getOrientation(); -} - AABox Avatar::getBounds() const { if (!_skeletonModel->isRenderable() || _skeletonModel->needsFixupInScene()) { // approximately 2m tall, scaled to user request. @@ -436,6 +431,11 @@ void Avatar::slamPosition(const glm::vec3& newPosition) { _lastVelocity = glm::vec3(0.0f); } +void Avatar::updateAttitude(const glm::quat& orientation) { + _skeletonModel->updateAttitude(orientation); + _worldUpDirection = orientation * Vectors::UNIT_Y; +} + void Avatar::applyPositionDelta(const glm::vec3& delta) { setPosition(getPosition() + delta); _positionDeltaAccumulator += delta; @@ -628,22 +628,6 @@ void Avatar::render(RenderArgs* renderArgs) { } } -glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { - glm::quat orientation = getOrientation(); - glm::vec3 currentUp = orientation * IDENTITY_UP; - float angle = acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f)); - if (angle < EPSILON) { - return glm::quat(); - } - glm::vec3 axis; - if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis - axis = orientation * IDENTITY_RIGHT; - } else { - axis = glm::normalize(glm::cross(currentUp, _worldUpDirection)); - } - return glm::angleAxis(angle * proportion, axis); -} - void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { _attachmentsToDelete.clear(); @@ -1401,14 +1385,14 @@ glm::quat Avatar::getUncachedRightPalmRotation() const { return rightPalmRotation; } -void Avatar::setPosition(const glm::vec3& position) { - AvatarData::setPosition(position); - updateAttitude(); +void Avatar::setPositionViaScript(const glm::vec3& position) { + setPosition(position); + updateAttitude(getOrientation()); } -void Avatar::setOrientation(const glm::quat& orientation) { - AvatarData::setOrientation(orientation); - updateAttitude(); +void Avatar::setOrientationViaScript(const glm::quat& orientation) { + setOrientation(orientation); + updateAttitude(orientation); } void Avatar::updatePalms() { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index db9d36be7a..2c75012209 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -112,8 +112,6 @@ public: const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } - glm::quat getWorldAlignedOrientation() const; - AABox getBounds() const; /// Returns the distance to use as a LOD parameter. @@ -184,7 +182,7 @@ public: void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; void slamPosition(const glm::vec3& position); - virtual void updateAttitude() { _skeletonModel->updateAttitude(); } + virtual void updateAttitude(const glm::quat& orientation) override; // Call this when updating Avatar position with a delta. This will allow us to // _accurately_ measure position changes and compute the resulting velocity @@ -197,10 +195,8 @@ public: void getCapsule(glm::vec3& start, glm::vec3& end, float& radius); float computeMass(); - using SpatiallyNestable::setPosition; - virtual void setPosition(const glm::vec3& position) override; - using SpatiallyNestable::setOrientation; - virtual void setOrientation(const glm::quat& orientation) override; + void setPositionViaScript(const glm::vec3& position) override; + void setOrientationViaScript(const glm::quat& orientation) override; // these call through to the SpatiallyNestable versions, but they are here to expose these to javascript. Q_INVOKABLE virtual const QUuid getParentID() const override { return SpatiallyNestable::getParentID(); } @@ -240,7 +236,7 @@ public: bool hasNewJointData() const { return _hasNewJointData; } float getBoundingRadius() const; - + void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene); void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene); bool isInScene() const { return render::Item::isValidID(_renderItemID); } @@ -303,7 +299,6 @@ protected: glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } - glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index 9651951b46..c0d5fc07d7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -118,16 +118,16 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig.updateFromEyeParameters(eyeParams); } -void SkeletonModel::updateAttitude() { +void SkeletonModel::updateAttitude(const glm::quat& orientation) { setTranslation(_owningAvatar->getSkeletonPosition()); - setRotation(_owningAvatar->getOrientation() * Quaternions::Y_180); + setRotation(orientation * Quaternions::Y_180); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale()); } // Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), // but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - updateAttitude(); + updateAttitude(_owningAvatar->getOrientation()); if (fullUpdate) { setBlendshapeCoefficients(_owningAvatar->getHead()->getSummedBlendshapeCoefficients()); diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h index e48884c581..919e82825c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h @@ -35,7 +35,7 @@ public: void simulate(float deltaTime, bool fullUpdate = true) override; void updateRig(float deltaTime, glm::mat4 parentTransform) override; - void updateAttitude(); + void updateAttitude(const glm::quat& orientation); /// Returns the index of the left hand joint, or -1 if not found. int getLeftHandJointIndex() const { return isActive() ? getFBXGeometry().leftHandJointIndex : -1; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 85228af941..9570056353 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -91,9 +91,6 @@ AvatarData::AvatarData() : _targetVelocity(0.0f), _density(DEFAULT_AVATAR_DENSITY) { - setBodyPitch(0.0f); - setBodyYaw(-90.0f); - setBodyRoll(0.0f); } AvatarData::~AvatarData() { @@ -2083,6 +2080,7 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { currentBasis = std::make_shared(Transform::fromJson(json[JSON_AVATAR_BASIS])); } + glm::quat orientation; if (json.contains(JSON_AVATAR_RELATIVE)) { // During playback you can either have the recording basis set to the avatar current state // meaning that all playback is relative to this avatars starting position, or @@ -2094,12 +2092,14 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { auto relativeTransform = Transform::fromJson(json[JSON_AVATAR_RELATIVE]); auto worldTransform = currentBasis->worldTransform(relativeTransform); setPosition(worldTransform.getTranslation()); - setOrientation(worldTransform.getRotation()); + orientation = worldTransform.getRotation(); } else { // We still set the position in the case that there is no movement. setPosition(currentBasis->getTranslation()); - setOrientation(currentBasis->getRotation()); + orientation = currentBasis->getRotation(); } + setOrientation(orientation); + updateAttitude(orientation); // Do after avatar orientation because head look-at needs avatar orientation. if (json.contains(JSON_AVATAR_HEAD)) { @@ -2217,11 +2217,11 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } -void AvatarData::setPosition(const glm::vec3& position) { +void AvatarData::setPositionViaScript(const glm::vec3& position) { SpatiallyNestable::setPosition(position); } -void AvatarData::setOrientation(const glm::quat& orientation) { +void AvatarData::setOrientationViaScript(const glm::quat& orientation) { SpatiallyNestable::setOrientation(orientation); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1cf7d7dd91..0e936c49e0 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -351,14 +351,14 @@ public: class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPositionViaScript) Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale) Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll) - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) + Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientationViaScript) Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation) Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch) Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw) @@ -440,10 +440,10 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - using SpatiallyNestable::setPosition; - virtual void setPosition(const glm::vec3& position) override; - using SpatiallyNestable::setOrientation; - virtual void setOrientation(const glm::quat& orientation) override; + virtual void setPositionViaScript(const glm::vec3& position); + virtual void setOrientationViaScript(const glm::quat& orientation); + + virtual void updateAttitude(const glm::quat& orientation) {} glm::quat getHeadOrientation() const { lazyInitHeadData(); diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h index 5f2162ff6e..c7b943f0dd 100644 --- a/libraries/shared/src/shared/Camera.h +++ b/libraries/shared/src/shared/Camera.h @@ -127,7 +127,7 @@ private: glm::mat4 _projection; // derived - glm::vec3 _position; + glm::vec3 _position { 0.0f, 0.0f, 0.0f }; glm::quat _orientation; bool _isKeepLookingAt{ false }; glm::vec3 _lookingAt; From 5bc38bd7f07869f3392a8babbda49b75a63cc773 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 7 Jul 2017 11:15:42 -0400 Subject: [PATCH 06/38] [WL21389] Collision Shapes need to be updated (details below). Revised approach involves creating a helper function within ShapeFactory to aid in devising the ShapeType to be used by an ShapeEntityItem for collision. The ShapeFactory is currently doing this for creating the actual Bullet Library collision shapes. ShapeEntityItem overrides its virtually inherited computeShapeInfo which in turn calls the new ShapeFactory helper function. ShapeEntityItem has a new memvar _collisionShapeType to cache its actual ShapeType used by the physics system. This memvar is returned via the getShapeType accessor which is expected to return an object's ShapeType. Note(s): This is similar to the original approach save translation between entity::Shape and ShapeType isn't tied to the EntityItemProperties shapeTypeNames or shapeType. This approach more directly solves the issue of getting the actual ShapeType used by the time it's needed to determine the bullet collision object type created when initializing the physic information. Translation of the ShapeEntityItem's entity::Shape to its ShapeType is handled by ShapeFactory which handles creating the bullet collision objects when setting up physics on the ShapeEntityItems. Known Issue(s): This doesn't compile. It appears that the Entity Library needs to know about the Physics Library. The naive attempt at providing that link failed to resolve all compilation issues. Current Error: C1083: Cannot open include file: btBulletDynamicsCommon.h: No such file or directory (C:\projects\cusack\libraries\entities\src\ShapeEntityItem.cpp) C:\projects\cusack\libraries\physics\src\ShapeFactory.h 15 1 entities modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities/CMakeLists.txt modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.h modified: libraries/physics/src/ShapeFactory.cpp modified: libraries/physics/src/ShapeFactory.h modified: libraries/physics/src/ShapeInfo.cpp modified: scripts/developer/tests/basicEntityTest/entitySpawner.js new file: scripts/developer/tests/basicEntityTest/shapeSpawner.js --- .../src/RenderableShapeEntityItem.cpp | 10 +- libraries/entities/CMakeLists.txt | 3 +- libraries/entities/src/ShapeEntityItem.cpp | 54 ++++- libraries/entities/src/ShapeEntityItem.h | 4 +- libraries/physics/src/ShapeFactory.cpp | 203 ++++++++++++++++-- libraries/physics/src/ShapeFactory.h | 3 + libraries/shared/src/ShapeInfo.cpp | 5 +- .../tests/basicEntityTest/entitySpawner.js | 4 +- .../tests/basicEntityTest/shapeSpawner.js | 33 +++ 9 files changed, 286 insertions(+), 33 deletions(-) create mode 100644 scripts/developer/tests/basicEntityTest/shapeSpawner.js diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 62ab3377a8..b197e0b9e6 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -48,18 +48,22 @@ RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const } EntityItemPointer RenderableShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return baseFactory(entityID, properties); + auto result = baseFactory(entityID, properties); + + qCDebug(entities) << "Creating RenderableShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; + + return result; } EntityItemPointer RenderableShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Cube); + result->setShape(entity::Shape::Cube); return result; } EntityItemPointer RenderableShapeEntityItem::sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Sphere); + result->setShape(entity::Shape::Sphere); return result; } diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 19341ec3e2..90de43b5f8 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) -link_hifi_libraries(shared networking octree avatars) +link_hifi_libraries(shared networking octree avatars physics) + diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 018d8c568a..d9c48f8593 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "EntitiesLogging.h" #include "EntityItemProperties.h" @@ -58,7 +59,11 @@ ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entity } EntityItemPointer ShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return baseFactory(entityID, properties); + auto result = baseFactory(entityID, properties); + + qCDebug(entities) << "Creating ShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; + + return result; } EntityItemPointer ShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -101,6 +106,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { } } +//TODO_CUSACK: Move back to header prior to PN +void ShapeEntityItem::setShape( const QString &shape ) { + setShape(entity::shapeFromString(shape)); +} + bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class @@ -160,10 +170,46 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); } +void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { + + if ( _collisionShapeType == ShapeType::SHAPE_TYPE_NONE ) { + if (_shape == entity::Shape::NUM_SHAPES) + { + EntityItem::computeShapeInfo(info); + + //--EARLY EXIT--( allow default handling to process ) + return; + } + + _collisionShapeType = ShapeFactory::computeShapeType(getShape(), getDimensions()); + } + + return EntityItem::computeShapeInfo(info); +} + // This value specifes how the shape should be treated by physics calculations. // For now, all polys will act as spheres ShapeType ShapeEntityItem::getShapeType() const { - return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; + //TODO_CUSACK: This needs to be retrieved from properties if possible + // or stored within a new member and set during parsing of + // the properties like setShape via set/get/readEntityProperties. + // Perhaps if the _actual_ collisionShapeType is needed (the version that's in use + // based on analysis of the shape's halfExtents when BulletLibrary collision shape was + // created as opposed to the desired ShapeType is it possible to retrieve that information)? + //if (_shape == entity::Shape::Cylinder) { + // return SHAPE_TYPE_CYLINDER_Y; + //} + + //// Original functionality: Everything not a cube, is treated like an ellipsoid/sphere + //return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; + + if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) + { + //--EARLY EXIT--( Maintain previous behavior of treating invalid as Ellipsoid/Sphere ) + return SHAPE_TYPE_ELLIPSOID; + } + + return _collisionShapeType; } void ShapeEntityItem::setColor(const rgbColor& value) { @@ -223,10 +269,12 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const void ShapeEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " shape:" << stringFromShape(_shape); + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 96f69deb0c..f021fcf957 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -70,7 +70,7 @@ public: entity::Shape getShape() const { return _shape; } void setShape(const entity::Shape& shape); - void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } + void setShape(const QString& shape); float getAlpha() const { return _alpha; }; void setAlpha(float alpha) { _alpha = alpha; } @@ -84,6 +84,7 @@ public: QColor getQColor() const; void setColor(const QColor& value); + void computeShapeInfo(ShapeInfo& info); ShapeType getShapeType() const override; bool shouldBePhysical() const override { return !isDead(); } @@ -100,6 +101,7 @@ protected: float _alpha { 1 }; rgbColor _color; entity::Shape _shape { entity::Shape::Sphere }; + ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_NONE }; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index d209667966..a9bc8b2e05 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -17,7 +17,7 @@ #include "BulletUtil.h" // These are the same normalized directions used by the btShapeHull class. -// 12 points for the face centers of a duodecohedron plus another 30 points +// 12 points for the face centers of a dodecahedron plus another 30 points // for the midpoints the edges, for a total of 42. const uint32_t NUM_UNIT_SPHERE_DIRECTIONS = 42; static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = { @@ -247,6 +247,124 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { delete dataArray; } +ShapeType validateShapeType(ShapeType type, const glm::vec3 &halfExtents, btCollisionShape *outCollisionShape = nullptr) +{ + if ((type == SHAPE_TYPE_SPHERE) || (type == SHAPE_TYPE_ELLIPSOID)) + { + float radius = halfExtents.x; + const float MIN_RADIUS = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (radius > MIN_RADIUS + && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + // close enough to true sphere + if (outCollisionShape) { + outCollisionShape = new btSphereShape(radius); + } + + return SHAPE_TYPE_SPHERE; + } + else { + ShapeInfo::PointList points; + points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); + for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { + points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); + } + if (outCollisionShape) { + outCollisionShape = createConvexHull(points); + } + + return SHAPE_TYPE_ELLIPSOID; + } + } + else if ((type == SHAPE_TYPE_CYLINDER_X) || (type == SHAPE_TYPE_CYLINDER_Y) || (type == SHAPE_TYPE_CYLINDER_Z)) + { + const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { + if (outCollisionShape) { + outCollisionShape = new btCylinderShape(btHalfExtents); + } + + return SHAPE_TYPE_CYLINDER_Y; + } + else if (halfExtents.x > halfExtents.z) { + if (outCollisionShape) { + outCollisionShape = new btCylinderShapeX(btHalfExtents); + } + + return SHAPE_TYPE_CYLINDER_X; + } + else if (halfExtents.z > halfExtents.x) { + if (outCollisionShape) { + outCollisionShape = new btCylinderShapeZ(btHalfExtents); + } + + return SHAPE_TYPE_CYLINDER_Z; + } + else //...there was no major axis, treat as a sphere + { + ShapeType cylinderFallback = validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, outCollisionShape); + return cylinderFallback; + } + } + + //Got here, then you are what you are along with outCollisionShape + return type; +} + +ShapeType ShapeFactory::computeShapeType(entity::Shape shape, const glm::vec3 &entityDimensions) { + if ( shape == entity::Shape::NUM_SHAPES ) { + //--EARLY EXIT-- + return SHAPE_TYPE_NONE; + } + + const glm::vec3 halfExtents = entityDimensions * 0.5f; + switch (shape){ + case entity::Shape::Triangle: { + //TODO_CUSACK: Implement this + return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); + } + + //Note: Intentional Fallthrough from Quad to Cube + case entity::Shape::Quad: + case entity::Shape::Cube: { + return SHAPE_TYPE_BOX; + } + + //Note: Intentional Fallthrough from Hexagon to Sphere + case entity::Shape::Hexagon: + case entity::Shape::Octagon: + case entity::Shape::Circle: + case entity::Shape::Sphere: { + return validateShapeType(SHAPE_TYPE_SPHERE, halfExtents); + } + + case entity::Shape::Cylinder: { + return validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents); + } + + //Note: Intentional Fallthrough from Tetrahedron to Icosahedron + case entity::Shape::Tetrahedron: + case entity::Shape::Octahedron: + case entity::Shape::Dodecahedron: + case entity::Shape::Icosahedron: { + + //TODO_CUSACK: Implement the hedrons + return validateShapeType( SHAPE_TYPE_ELLIPSOID, halfExtents ); + } + + //Note: Intentional Fallthrough from Torus to default. + case entity::Shape::Torus: + case entity::Shape::Cone: { + + // These types are currently unsupported + } + default: + return SHAPE_TYPE_NONE; + } + +} + const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); @@ -255,30 +373,33 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btBoxShape(glmToBullet(info.getHalfExtents())); } break; - case SHAPE_TYPE_SPHERE: { - glm::vec3 halfExtents = info.getHalfExtents(); - float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z)); - shape = new btSphereShape(radius); - } - break; + //case SHAPE_TYPE_SPHERE: { + // glm::vec3 halfExtents = info.getHalfExtents(); + // float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z)); + // shape = new btSphereShape(radius); + //} + //break; + case SHAPE_TYPE_SPHERE: case SHAPE_TYPE_ELLIPSOID: { glm::vec3 halfExtents = info.getHalfExtents(); - float radius = halfExtents.x; - const float MIN_RADIUS = 0.001f; - const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - if (radius > MIN_RADIUS - && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR - && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { - // close enough to true sphere - shape = new btSphereShape(radius); - } else { - ShapeInfo::PointList points; - points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); - for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { - points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); - } - shape = createConvexHull(points); - } + //float radius = halfExtents.x; + //const float MIN_RADIUS = 0.001f; + //const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + //if (radius > MIN_RADIUS + // && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + // && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + // // close enough to true sphere + // shape = new btSphereShape(radius); + //} else { + // ShapeInfo::PointList points; + // points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); + // for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { + // points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); + // } + // shape = createConvexHull(points); + //} + + validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, shape); } break; case SHAPE_TYPE_CAPSULE_Y: { @@ -288,6 +409,42 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btCapsuleShape(radius, height); } break; + case SHAPE_TYPE_CAPSULE_X: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = halfExtents.y; + float height = 2.0f * halfExtents.x; + shape = new btCapsuleShapeX(radius, height); + } + break; + case SHAPE_TYPE_CAPSULE_Z: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = halfExtents.x; + float height = 2.0f * halfExtents.z; + shape = new btCapsuleShapeZ(radius, height); + } + break; + case SHAPE_TYPE_CYLINDER_X: + case SHAPE_TYPE_CYLINDER_Z: + case SHAPE_TYPE_CYLINDER_Y: { + // TODO_CUSACK: Should allow for minor variance along axes. + const glm::vec3 halfExtents = info.getHalfExtents(); + //const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + //if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { + // shape = new btCylinderShape(btHalfExtents); + //} + //else if (halfExtents.x > halfExtents.z) { + // shape = new btCylinderShapeX(btHalfExtents); + //} + //else if (halfExtents.z > halfExtents.x) { + // shape = new btCylinderShapeZ(btHalfExtents); + //} + //else //...there was no major axis, treat as a sphere + //{ + // //TODO_CUSACK: Shunt to ELLIPSOID handling + //} + validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents, shape); + } + break; case SHAPE_TYPE_COMPOUND: case SHAPE_TYPE_SIMPLE_HULL: { const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 2bf79f390c..52b448ee1d 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -15,11 +15,14 @@ #include #include +#include //< Needed for entity::Shape #include // translates between ShapeInfo and btShape namespace ShapeFactory { + + ShapeType computeShapeType( entity::Shape shape, const glm::vec3 &entityDimensions); const btCollisionShape* createShapeFromInfo(const ShapeInfo& info); void deleteShape(const btCollisionShape* shape); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 496e94f8bd..e40d91379c 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -136,7 +136,10 @@ float ShapeInfo::computeVolume() const { } case SHAPE_TYPE_CAPSULE_Y: { float radius = _halfExtents.x; - volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f); + // Need to offset halfExtents.y by x to account for the system treating + // the y extent of the capsule as the cylindrical height + spherical radius. + float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x); + volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f); break; } default: diff --git a/scripts/developer/tests/basicEntityTest/entitySpawner.js b/scripts/developer/tests/basicEntityTest/entitySpawner.js index 538e9145f5..fa5c9291cb 100644 --- a/scripts/developer/tests/basicEntityTest/entitySpawner.js +++ b/scripts/developer/tests/basicEntityTest/entitySpawner.js @@ -8,7 +8,9 @@ var SCRIPT_URL = Script.resolvePath("myEntityScript.js") var myEntity = Entities.addEntity({ - type: "Sphere", + name: "Cusack_Testing", + type: "Shape", + shapeType: "Cylinder", color: { red: 200, green: 10, diff --git a/scripts/developer/tests/basicEntityTest/shapeSpawner.js b/scripts/developer/tests/basicEntityTest/shapeSpawner.js new file mode 100644 index 0000000000..f93072a582 --- /dev/null +++ b/scripts/developer/tests/basicEntityTest/shapeSpawner.js @@ -0,0 +1,33 @@ + var orientation = Camera.getOrientation(); + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation))); + + // Math.random ensures no caching of script + var SCRIPT_URL = Script.resolvePath("myEntityScript.js") + + var myEntity = Entities.addEntity({ + name: "ShapeSpawnTest", + type: "Shape", + shape: "Cylinder", + color: { + red: 200, + green: 10, + blue: 200 + }, + position: center, + dimensions: { + x: 1, + y: 1, + z: 1 + }, + script: SCRIPT_URL + }) + + + function cleanup() { + // Entities.deleteEntity(myEntity); + } + + Script.scriptEnding.connect(cleanup); From 75403124b621835b1bb2c4b9a060980324ab7e1b Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 18 Jul 2017 17:15:02 -0400 Subject: [PATCH 07/38] [WL21389] Addresses physics library dependency and has some other fixes (details below). * Addresses physics library dependency by moving computeShapeInfo override from ShapeEntityItem (which is within Entities Library) to RenderableShapeEntityItem (which is in Entities-Renderer Library). ** Entities-Renderer library already links against the physic library. ** Per discussion with Andrew Meadows: In order to ShapeEntityItem to be utilized the library dependency between the Entity and Physics library would need to be resolved to avoid the cyclical reliance which isn't in the scope of this ticket. * Updates shapeSpawner test script from the default clone of basicEntityTest\entitySpawner.js ** Objects now have a finite lifetime ** Script now cleans up the objects created when the script ends ** Also moved some adjustable properties out into var aliases at the top of the file for easier/less error prone tweaking. Should probably add one for the shapeType. * Fixes some issues with validateShapeType helper function * Removed naive attempt at including physics library within entities library. * Transferred some todos from notes * Fixed some formatting NOTE(s): This compiles and runs. Cylinder is spawned and treated as CYLINDER_Y. TODO(s): * Add tweakable var for shapeType within shapeSpawner.js * Vet and verify other shapes. * Add in edge case handling. * Add in support for other shapes to ShapeInfo infrastructure. Changes to be committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities-renderer/src/RenderableShapeEntityItem.h modified: libraries/entities/CMakeLists.txt modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.h modified: libraries/physics/src/ShapeFactory.cpp modified: libraries/shared/src/ShapeInfo.cpp modified: scripts/developer/tests/basicEntityTest/shapeSpawner.js --- .../src/RenderableShapeEntityItem.cpp | 25 +- .../src/RenderableShapeEntityItem.h | 2 + libraries/entities/CMakeLists.txt | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 61 ++-- libraries/entities/src/ShapeEntityItem.h | 1 - libraries/physics/src/ShapeFactory.cpp | 277 +++++++++--------- libraries/shared/src/ShapeInfo.cpp | 14 +- .../tests/basicEntityTest/shapeSpawner.js | 53 ++-- 8 files changed, 226 insertions(+), 209 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index b197e0b9e6..f071518b42 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -48,11 +49,12 @@ RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const } EntityItemPointer RenderableShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - auto result = baseFactory(entityID, properties); + auto result = baseFactory(entityID, properties); - qCDebug(entities) << "Creating RenderableShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; + //TODO_CUSACK: Remove this before final PN + qCDebug(entities) << "Creating RenderableShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; - return result; + return result; } EntityItemPointer RenderableShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -86,6 +88,23 @@ bool RenderableShapeEntityItem::isTransparent() { } } +void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { + + if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) { + if (_shape == entity::Shape::NUM_SHAPES) + { + EntityItem::computeShapeInfo(info); + + //--EARLY EXIT--( allow default handling to process ) + return; + } + + _collisionShapeType = ShapeFactory::computeShapeType(getShape(), getDimensions()); + } + + return EntityItem::computeShapeInfo(info); +} + void RenderableShapeEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); //Q_ASSERT(getType() == EntityTypes::Shape); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 0cc6a54f81..96f450f523 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -28,6 +28,8 @@ public: bool isTransparent() override; + void computeShapeInfo(ShapeInfo& info); + private: std::unique_ptr _procedural { nullptr }; diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 90de43b5f8..84906a48df 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) -link_hifi_libraries(shared networking octree avatars physics) +link_hifi_libraries(shared networking octree avatars) diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index d9c48f8593..854be7df1e 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -12,7 +12,6 @@ #include #include -#include #include "EntitiesLogging.h" #include "EntityItemProperties.h" @@ -59,11 +58,12 @@ ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entity } EntityItemPointer ShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - auto result = baseFactory(entityID, properties); + auto result = baseFactory(entityID, properties); - qCDebug(entities) << "Creating ShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; + //TODO_CUSACK: Remove this before final PN + qCDebug(entities) << "Creating ShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; - return result; + return result; } EntityItemPointer ShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -96,9 +96,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { switch (_shape) { case entity::Shape::Cube: _type = EntityTypes::Box; + _collisionShapeType = ShapeType::SHAPE_TYPE_BOX; break; case entity::Shape::Sphere: _type = EntityTypes::Sphere; + _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; break; default: _type = EntityTypes::Shape; @@ -170,46 +172,29 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); } -void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { - - if ( _collisionShapeType == ShapeType::SHAPE_TYPE_NONE ) { - if (_shape == entity::Shape::NUM_SHAPES) - { - EntityItem::computeShapeInfo(info); - - //--EARLY EXIT--( allow default handling to process ) - return; - } - - _collisionShapeType = ShapeFactory::computeShapeType(getShape(), getDimensions()); - } - - return EntityItem::computeShapeInfo(info); -} - // This value specifes how the shape should be treated by physics calculations. // For now, all polys will act as spheres ShapeType ShapeEntityItem::getShapeType() const { - //TODO_CUSACK: This needs to be retrieved from properties if possible - // or stored within a new member and set during parsing of - // the properties like setShape via set/get/readEntityProperties. - // Perhaps if the _actual_ collisionShapeType is needed (the version that's in use - // based on analysis of the shape's halfExtents when BulletLibrary collision shape was - // created as opposed to the desired ShapeType is it possible to retrieve that information)? - //if (_shape == entity::Shape::Cylinder) { - // return SHAPE_TYPE_CYLINDER_Y; - //} + //TODO_CUSACK: This needs to be retrieved from properties if possible + // or stored within a new member and set during parsing of + // the properties like setShape via set/get/readEntityProperties. + // Perhaps if the _actual_ collisionShapeType is needed (the version that's in use + // based on analysis of the shape's halfExtents when BulletLibrary collision shape was + // created as opposed to the desired ShapeType is it possible to retrieve that information)? + //if (_shape == entity::Shape::Cylinder) { + // return SHAPE_TYPE_CYLINDER_Y; + //} - //// Original functionality: Everything not a cube, is treated like an ellipsoid/sphere - //return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; + //// Original functionality: Everything not a cube, is treated like an ellipsoid/sphere + //return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; - if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) - { - //--EARLY EXIT--( Maintain previous behavior of treating invalid as Ellipsoid/Sphere ) - return SHAPE_TYPE_ELLIPSOID; - } + //if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) + //{ + // //--EARLY EXIT--( Maintain previous behavior of treating invalid as Ellipsoid/Sphere ) + // return SHAPE_TYPE_ELLIPSOID; + //} - return _collisionShapeType; + return _collisionShapeType; } void ShapeEntityItem::setColor(const rgbColor& value) { diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index f021fcf957..435d22a6b2 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -84,7 +84,6 @@ public: QColor getQColor() const; void setColor(const QColor& value); - void computeShapeInfo(ShapeInfo& info); ShapeType getShapeType() const override; bool shouldBePhysical() const override { return !isDead(); } diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index a9bc8b2e05..74aff45e55 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -247,121 +247,120 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { delete dataArray; } -ShapeType validateShapeType(ShapeType type, const glm::vec3 &halfExtents, btCollisionShape *outCollisionShape = nullptr) +ShapeType validateShapeType(ShapeType type, const glm::vec3 &halfExtents, btCollisionShape **outCollisionShape = NULL) { - if ((type == SHAPE_TYPE_SPHERE) || (type == SHAPE_TYPE_ELLIPSOID)) - { - float radius = halfExtents.x; - const float MIN_RADIUS = 0.001f; - const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - if (radius > MIN_RADIUS - && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR - && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { - // close enough to true sphere - if (outCollisionShape) { - outCollisionShape = new btSphereShape(radius); - } + if ((type == SHAPE_TYPE_SPHERE) || (type == SHAPE_TYPE_ELLIPSOID)) + { + float radius = halfExtents.x; + const float MIN_RADIUS = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (radius > MIN_RADIUS + && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + // close enough to true sphere + if (outCollisionShape) { + (*outCollisionShape) = new btSphereShape(radius); + } - return SHAPE_TYPE_SPHERE; - } - else { - ShapeInfo::PointList points; - points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); - for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { - points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); - } - if (outCollisionShape) { - outCollisionShape = createConvexHull(points); - } + return SHAPE_TYPE_SPHERE; + } + else { + ShapeInfo::PointList points; + points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); + for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { + points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); + } + if (outCollisionShape) { + (*outCollisionShape) = createConvexHull(points); + } - return SHAPE_TYPE_ELLIPSOID; - } - } - else if ((type == SHAPE_TYPE_CYLINDER_X) || (type == SHAPE_TYPE_CYLINDER_Y) || (type == SHAPE_TYPE_CYLINDER_Z)) - { - const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); - if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { - if (outCollisionShape) { - outCollisionShape = new btCylinderShape(btHalfExtents); - } + return SHAPE_TYPE_ELLIPSOID; + } + } + else if ((type == SHAPE_TYPE_CYLINDER_X) || (type == SHAPE_TYPE_CYLINDER_Y) || (type == SHAPE_TYPE_CYLINDER_Z)) + { + // TODO_CUSACK: Should allow for minor variance along axes? + const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + if ((halfExtents.y >= halfExtents.x) && (halfExtents.y >= halfExtents.z)) { + if (outCollisionShape) { + (*outCollisionShape) = new btCylinderShape(btHalfExtents); + } - return SHAPE_TYPE_CYLINDER_Y; - } - else if (halfExtents.x > halfExtents.z) { - if (outCollisionShape) { - outCollisionShape = new btCylinderShapeX(btHalfExtents); - } + return SHAPE_TYPE_CYLINDER_Y; + } + else if (halfExtents.x >= halfExtents.z) { + if (outCollisionShape) { + (*outCollisionShape) = new btCylinderShapeX(btHalfExtents); + } - return SHAPE_TYPE_CYLINDER_X; - } - else if (halfExtents.z > halfExtents.x) { - if (outCollisionShape) { - outCollisionShape = new btCylinderShapeZ(btHalfExtents); - } + return SHAPE_TYPE_CYLINDER_X; + } + else if (halfExtents.z > halfExtents.x) { + if (outCollisionShape) { + (*outCollisionShape) = new btCylinderShapeZ(btHalfExtents); + } - return SHAPE_TYPE_CYLINDER_Z; - } - else //...there was no major axis, treat as a sphere - { - ShapeType cylinderFallback = validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, outCollisionShape); - return cylinderFallback; - } - } + return SHAPE_TYPE_CYLINDER_Z; + } + else //...there was no major axis, treat as a sphere + { + ShapeType cylinderFallback = validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, outCollisionShape); + return cylinderFallback; + } + } - //Got here, then you are what you are along with outCollisionShape - return type; + //Got here, then you are what you are along with outCollisionShape + return type; } ShapeType ShapeFactory::computeShapeType(entity::Shape shape, const glm::vec3 &entityDimensions) { - if ( shape == entity::Shape::NUM_SHAPES ) { - //--EARLY EXIT-- - return SHAPE_TYPE_NONE; - } + if (shape == entity::Shape::NUM_SHAPES) { + //--EARLY EXIT-- + return SHAPE_TYPE_NONE; + } - const glm::vec3 halfExtents = entityDimensions * 0.5f; - switch (shape){ - case entity::Shape::Triangle: { - //TODO_CUSACK: Implement this - return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); - } + const glm::vec3 halfExtents = entityDimensions * 0.5f; + switch (shape){ + case entity::Shape::Triangle: { + //TODO_CUSACK: Implement this + return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); + } + //Note: Intentional Fallthrough from Quad to Cube + case entity::Shape::Quad: + case entity::Shape::Cube: { + return SHAPE_TYPE_BOX; + } + //Note: Intentional Fallthrough from Hexagon to Sphere + case entity::Shape::Hexagon: + case entity::Shape::Octagon: + case entity::Shape::Circle: + case entity::Shape::Sphere: { + return validateShapeType(SHAPE_TYPE_SPHERE, halfExtents); + } - //Note: Intentional Fallthrough from Quad to Cube - case entity::Shape::Quad: - case entity::Shape::Cube: { - return SHAPE_TYPE_BOX; - } + case entity::Shape::Cylinder: { + return validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents); + } - //Note: Intentional Fallthrough from Hexagon to Sphere - case entity::Shape::Hexagon: - case entity::Shape::Octagon: - case entity::Shape::Circle: - case entity::Shape::Sphere: { - return validateShapeType(SHAPE_TYPE_SPHERE, halfExtents); - } + //Note: Intentional Fallthrough from Tetrahedron to Icosahedron + case entity::Shape::Tetrahedron: + case entity::Shape::Octahedron: + case entity::Shape::Dodecahedron: + case entity::Shape::Icosahedron: { - case entity::Shape::Cylinder: { - return validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents); - } + //TODO_CUSACK: Implement the hedrons + return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); + } - //Note: Intentional Fallthrough from Tetrahedron to Icosahedron - case entity::Shape::Tetrahedron: - case entity::Shape::Octahedron: - case entity::Shape::Dodecahedron: - case entity::Shape::Icosahedron: { + //Note: Intentional Fallthrough from Torus to default. + case entity::Shape::Torus: + case entity::Shape::Cone: { - //TODO_CUSACK: Implement the hedrons - return validateShapeType( SHAPE_TYPE_ELLIPSOID, halfExtents ); - } - - //Note: Intentional Fallthrough from Torus to default. - case entity::Shape::Torus: - case entity::Shape::Cone: { - - // These types are currently unsupported - } - default: - return SHAPE_TYPE_NONE; - } + // These types are currently unsupported + } + default: + return SHAPE_TYPE_NONE; + } } @@ -379,7 +378,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) // shape = new btSphereShape(radius); //} //break; - case SHAPE_TYPE_SPHERE: + case SHAPE_TYPE_SPHERE: case SHAPE_TYPE_ELLIPSOID: { glm::vec3 halfExtents = info.getHalfExtents(); //float radius = halfExtents.x; @@ -399,9 +398,11 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) // shape = createConvexHull(points); //} - validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, shape); + validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, &shape); } break; + //TODO_CUSACK: Add Capsules to vetting/validation process for + // type checks. case SHAPE_TYPE_CAPSULE_Y: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.x; @@ -409,42 +410,44 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btCapsuleShape(radius, height); } break; - case SHAPE_TYPE_CAPSULE_X: { - glm::vec3 halfExtents = info.getHalfExtents(); - float radius = halfExtents.y; - float height = 2.0f * halfExtents.x; - shape = new btCapsuleShapeX(radius, height); - } - break; - case SHAPE_TYPE_CAPSULE_Z: { - glm::vec3 halfExtents = info.getHalfExtents(); - float radius = halfExtents.x; - float height = 2.0f * halfExtents.z; - shape = new btCapsuleShapeZ(radius, height); - } - break; - case SHAPE_TYPE_CYLINDER_X: - case SHAPE_TYPE_CYLINDER_Z: - case SHAPE_TYPE_CYLINDER_Y: { - // TODO_CUSACK: Should allow for minor variance along axes. - const glm::vec3 halfExtents = info.getHalfExtents(); - //const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); - //if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { - // shape = new btCylinderShape(btHalfExtents); - //} - //else if (halfExtents.x > halfExtents.z) { - // shape = new btCylinderShapeX(btHalfExtents); - //} - //else if (halfExtents.z > halfExtents.x) { - // shape = new btCylinderShapeZ(btHalfExtents); - //} - //else //...there was no major axis, treat as a sphere - //{ - // //TODO_CUSACK: Shunt to ELLIPSOID handling - //} - validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents, shape); - } - break; + case SHAPE_TYPE_CAPSULE_X: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = halfExtents.y; + float height = 2.0f * halfExtents.x; + shape = new btCapsuleShapeX(radius, height); + } + break; + case SHAPE_TYPE_CAPSULE_Z: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = halfExtents.x; + float height = 2.0f * halfExtents.z; + shape = new btCapsuleShapeZ(radius, height); + } + break; + case SHAPE_TYPE_CYLINDER_X: + case SHAPE_TYPE_CYLINDER_Z: + case SHAPE_TYPE_CYLINDER_Y: { + // TODO_CUSACK: Should allow for minor variance along axes. + const glm::vec3 halfExtents = info.getHalfExtents(); + //const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + //if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { + // shape = new btCylinderShape(btHalfExtents); + //} + //else if (halfExtents.x > halfExtents.z) { + // shape = new btCylinderShapeX(btHalfExtents); + //} + //else if (halfExtents.z > halfExtents.x) { + // shape = new btCylinderShapeZ(btHalfExtents); + //} + //else //...there was no major axis, treat as a sphere + //{ + // //TODO_CUSACK: Shunt to ELLIPSOID handling + //} + validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents, &shape); + } + break; + //TODO_CUSACK: Add compound and simple hull to vetting/validation + // process for types. case SHAPE_TYPE_COMPOUND: case SHAPE_TYPE_SIMPLE_HULL: { const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index e40d91379c..57e927eaf3 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -29,7 +29,8 @@ void ShapeInfo::clear() { } void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { - _url = ""; + //TODO_CUSACK: Does this need additional cases and handling added? + _url = ""; _type = type; setHalfExtents(halfExtents); switch(type) { @@ -55,6 +56,8 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString } void ShapeInfo::setBox(const glm::vec3& halfExtents) { + //TODO_CUSACK: Should this pointlist clearance added in case + // this is a re-purposed instance? _url = ""; _type = SHAPE_TYPE_BOX; setHalfExtents(halfExtents); @@ -62,6 +65,8 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) { } void ShapeInfo::setSphere(float radius) { + //TODO_CUSACK: Should this pointlist clearance added in case + // this is a re-purposed instance? _url = ""; _type = SHAPE_TYPE_SPHERE; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -70,12 +75,17 @@ void ShapeInfo::setSphere(float radius) { } void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { + //TODO_CUSACK: Should this have protection against inadvertant clearance and type + // resetting? If for some reason this was called and point list was and is emtpy + // would we still wish to clear out everything? _pointCollection = pointCollection; _type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; _doubleHashKey.clear(); } void ShapeInfo::setCapsuleY(float radius, float halfHeight) { + //TODO_CUSACK: Should this pointlist clearance added in case + // this is a re-purposed instance? _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -117,6 +127,7 @@ int ShapeInfo::getLargestSubshapePointCount() const { } float ShapeInfo::computeVolume() const { + //TODO_CUSACK: Add support for other ShapeTypes. const float DEFAULT_VOLUME = 1.0f; float volume = DEFAULT_VOLUME; switch(_type) { @@ -150,6 +161,7 @@ float ShapeInfo::computeVolume() const { } bool ShapeInfo::contains(const glm::vec3& point) const { + //TODO_CUSACK: Add support for other ShapeTypes like Ellipsoid/Compound. switch(_type) { case SHAPE_TYPE_SPHERE: return glm::length(point) <= _halfExtents.x; diff --git a/scripts/developer/tests/basicEntityTest/shapeSpawner.js b/scripts/developer/tests/basicEntityTest/shapeSpawner.js index f93072a582..9fcaf3a3db 100644 --- a/scripts/developer/tests/basicEntityTest/shapeSpawner.js +++ b/scripts/developer/tests/basicEntityTest/shapeSpawner.js @@ -1,33 +1,30 @@ - var orientation = Camera.getOrientation(); - orientation = Quat.safeEulerAngles(orientation); - orientation.x = 0; - orientation = Quat.fromVec3Degrees(orientation); - var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation))); +// compute a position to create the object relative to avatar +var forwardOffset = Vec3.multiply(2.0, Quat.getFront(MyAvatar.orientation)); +var objectPosition = Vec3.sum(MyAvatar.position, forwardOffset); - // Math.random ensures no caching of script - var SCRIPT_URL = Script.resolvePath("myEntityScript.js") +var LIFETIME = 1800; //seconds +var DIM_HEIGHT = 1, DIM_WIDTH = 1, DIM_DEPTH = 1; +var COLOR_R = 100, COLOR_G = 10, COLOR_B = 200; - var myEntity = Entities.addEntity({ - name: "ShapeSpawnTest", - type: "Shape", - shape: "Cylinder", - color: { - red: 200, - green: 10, - blue: 200 - }, - position: center, - dimensions: { - x: 1, - y: 1, - z: 1 - }, - script: SCRIPT_URL - }) +var properties = { + name: "ShapeSpawnTest", + type: "Shape", + shape: "Cylinder", + dimensions: {x: DIM_WIDTH, y: DIM_HEIGHT, z: DIM_DEPTH}, + color: {red: COLOR_R, green: COLOR_G, blue: COLOR_B}, + position: objectPosition, + lifetime: LIFETIME, +}; + +// create the object +var entityId = Entities.addEntity(properties); + +function cleanup() { + Entities.deleteEntity(entityId); +} + +// delete the object when this script is stopped +Script.scriptEnding.connect(cleanup); - function cleanup() { - // Entities.deleteEntity(myEntity); - } - Script.scriptEnding.connect(cleanup); From d155c0264030c3eec0c231d7f80072b6ab63662b Mon Sep 17 00:00:00 2001 From: Leander Hasty <1p-cusack@1stplayable.com> Date: Mon, 24 Jul 2017 17:02:40 -0400 Subject: [PATCH 08/38] [WL21389] wip and modifications based on comments https://github.com/highfidelity/hifi/pull/11024#pullrequestreview-51611518 Cleans up tabs, moves new functionality out of ShapeFactory directly to RenderableShapeEntityItem's computeShapeInfo override, begins to break down where we will need pointlists. Still need to determine how rotation is handled for pointlists, and check for axis alignment on cylinders before deciding on a shape. Changes to be committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities-renderer/src/RenderableShapeEntityItem.h modified: libraries/entities/CMakeLists.txt modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.h modified: libraries/physics/src/ShapeFactory.cpp modified: libraries/physics/src/ShapeFactory.h modified: libraries/shared/src/ShapeInfo.cpp modified: scripts/developer/tests/basicEntityTest/entitySpawner.js --- .../src/RenderableShapeEntityItem.cpp | 92 ++++++-- .../src/RenderableShapeEntityItem.h | 2 +- libraries/entities/CMakeLists.txt | 1 - libraries/entities/src/ShapeEntityItem.cpp | 37 +--- libraries/entities/src/ShapeEntityItem.h | 4 +- libraries/physics/src/ShapeFactory.cpp | 202 ++++-------------- libraries/physics/src/ShapeFactory.h | 3 - libraries/shared/src/ShapeInfo.cpp | 4 +- .../tests/basicEntityTest/entitySpawner.js | 4 +- 9 files changed, 122 insertions(+), 227 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index f071518b42..a305b201d6 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -49,23 +49,18 @@ RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const } EntityItemPointer RenderableShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - auto result = baseFactory(entityID, properties); - - //TODO_CUSACK: Remove this before final PN - qCDebug(entities) << "Creating RenderableShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; - - return result; + return baseFactory(entityID, properties); } EntityItemPointer RenderableShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Shape::Cube); + result->setShape(entity::Cube); return result; } EntityItemPointer RenderableShapeEntityItem::sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Shape::Sphere); + result->setShape(entity::Sphere); return result; } @@ -90,19 +85,84 @@ bool RenderableShapeEntityItem::isTransparent() { void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { - if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) { - if (_shape == entity::Shape::NUM_SHAPES) - { - EntityItem::computeShapeInfo(info); + // This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc) + // is set. - //--EARLY EXIT--( allow default handling to process ) - return; + const glm::vec3 entityDimensions = getDimensions(); + + switch (_shape){ + case entity::Shape::Quad: + case entity::Shape::Cube: { + _collisionShapeType = SHAPE_TYPE_BOX; + } + break; + case entity::Shape::Sphere: { + + float diameter = entityDimensions.x; + const float MIN_DIAMETER = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (diameter > MIN_DIAMETER + && fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { + + _collisionShapeType = SHAPE_TYPE_SPHERE; } + else { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + } + } + break; + case entity::Shape::Cylinder: { + _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; + // TODO_CUSACK: determine if rotation is axis-aligned + //const Transform::Quat & rot = _transform.getRotation(); - _collisionShapeType = ShapeFactory::computeShapeType(getShape(), getDimensions()); +#if 0 + // TODO: some way to tell apart SHAPE_TYPE_CYLINDER_Y + // TODO_CUSACK: Should allow for minor variance along axes? + if ((entityDimensions.y >= entityDimensions.x) && (entityDimensions.y >= entityDimensions.z)) { + } + else if (entityDimensions.x >= entityDimensions.z) { + _collisionShapeType = SHAPE_TYPE_CYLINDER_X; + } + else if (entityDimensions.z >= entityDimensions.x) { + _collisionShapeType = SHAPE_TYPE_CYLINDER_Z; + } + else //...there was no major axis, treat as a hull + { + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + //TODO_CUSACK: pointCollection + } +#endif + } + break; + case entity::Shape::Triangle: + case entity::Shape::Hexagon: + case entity::Shape::Octagon: + case entity::Shape::Circle: + case entity::Shape::Tetrahedron: + case entity::Shape::Octahedron: + case entity::Shape::Dodecahedron: + case entity::Shape::Icosahedron: + case entity::Shape::Cone: { + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + //TODO_CUSACK: pointCollection + } + break; + case entity::Shape::Torus: + { + // Not in GeometryCache::buildShapes, unsupported. + _collisionShapeType = SHAPE_TYPE_NONE; + //TODO_CUSACK: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) + } + break; + default:{ + //_collisionShapeType = SHAPE_TYPE_NONE; // Remains SHAPE_TYPE_NONE. + } + break; } - return EntityItem::computeShapeInfo(info); + EntityItem::computeShapeInfo(info); } void RenderableShapeEntityItem::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 96f450f523..2a841df57e 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -28,7 +28,7 @@ public: bool isTransparent() override; - void computeShapeInfo(ShapeInfo& info); + virtual void computeShapeInfo(ShapeInfo& info); private: std::unique_ptr _procedural { nullptr }; diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 84906a48df..19341ec3e2 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,4 +1,3 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) link_hifi_libraries(shared networking octree avatars) - diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 854be7df1e..58799de807 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -58,12 +58,7 @@ ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entity } EntityItemPointer ShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - auto result = baseFactory(entityID, properties); - - //TODO_CUSACK: Remove this before final PN - qCDebug(entities) << "Creating ShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id; - - return result; + return baseFactory(entityID, properties); } EntityItemPointer ShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -93,14 +88,14 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP void ShapeEntityItem::setShape(const entity::Shape& shape) { _shape = shape; - switch (_shape) { + switch (_shape) { // TODO_CUSACK fill out? case entity::Shape::Cube: _type = EntityTypes::Box; _collisionShapeType = ShapeType::SHAPE_TYPE_BOX; break; case entity::Shape::Sphere: _type = EntityTypes::Sphere; - _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; + _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; // TODO_CUSACK defer? Check to see if sphere is more appropriate? break; default: _type = EntityTypes::Shape; @@ -108,11 +103,6 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { } } -//TODO_CUSACK: Move back to header prior to PN -void ShapeEntityItem::setShape( const QString &shape ) { - setShape(entity::shapeFromString(shape)); -} - bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class @@ -175,25 +165,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit // This value specifes how the shape should be treated by physics calculations. // For now, all polys will act as spheres ShapeType ShapeEntityItem::getShapeType() const { - //TODO_CUSACK: This needs to be retrieved from properties if possible - // or stored within a new member and set during parsing of - // the properties like setShape via set/get/readEntityProperties. - // Perhaps if the _actual_ collisionShapeType is needed (the version that's in use - // based on analysis of the shape's halfExtents when BulletLibrary collision shape was - // created as opposed to the desired ShapeType is it possible to retrieve that information)? - //if (_shape == entity::Shape::Cylinder) { - // return SHAPE_TYPE_CYLINDER_Y; - //} - - //// Original functionality: Everything not a cube, is treated like an ellipsoid/sphere - //return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; - - //if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE) - //{ - // //--EARLY EXIT--( Maintain previous behavior of treating invalid as Ellipsoid/Sphere ) - // return SHAPE_TYPE_ELLIPSOID; - //} - return _collisionShapeType; } @@ -254,7 +225,7 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const void ShapeEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " name:" << _name; qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getPosition()); diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 435d22a6b2..42a92f7bd7 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -70,7 +70,7 @@ public: entity::Shape getShape() const { return _shape; } void setShape(const entity::Shape& shape); - void setShape(const QString& shape); + void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } float getAlpha() const { return _alpha; }; void setAlpha(float alpha) { _alpha = alpha; } @@ -100,7 +100,7 @@ protected: float _alpha { 1 }; rgbColor _color; entity::Shape _shape { entity::Shape::Sphere }; - ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_NONE }; + ShapeType _collisionShapeType { ShapeType::SHAPE_TYPE_NONE }; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 74aff45e55..87580c6726 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -247,123 +247,6 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { delete dataArray; } -ShapeType validateShapeType(ShapeType type, const glm::vec3 &halfExtents, btCollisionShape **outCollisionShape = NULL) -{ - if ((type == SHAPE_TYPE_SPHERE) || (type == SHAPE_TYPE_ELLIPSOID)) - { - float radius = halfExtents.x; - const float MIN_RADIUS = 0.001f; - const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - if (radius > MIN_RADIUS - && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR - && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { - // close enough to true sphere - if (outCollisionShape) { - (*outCollisionShape) = new btSphereShape(radius); - } - - return SHAPE_TYPE_SPHERE; - } - else { - ShapeInfo::PointList points; - points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); - for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { - points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); - } - if (outCollisionShape) { - (*outCollisionShape) = createConvexHull(points); - } - - return SHAPE_TYPE_ELLIPSOID; - } - } - else if ((type == SHAPE_TYPE_CYLINDER_X) || (type == SHAPE_TYPE_CYLINDER_Y) || (type == SHAPE_TYPE_CYLINDER_Z)) - { - // TODO_CUSACK: Should allow for minor variance along axes? - const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); - if ((halfExtents.y >= halfExtents.x) && (halfExtents.y >= halfExtents.z)) { - if (outCollisionShape) { - (*outCollisionShape) = new btCylinderShape(btHalfExtents); - } - - return SHAPE_TYPE_CYLINDER_Y; - } - else if (halfExtents.x >= halfExtents.z) { - if (outCollisionShape) { - (*outCollisionShape) = new btCylinderShapeX(btHalfExtents); - } - - return SHAPE_TYPE_CYLINDER_X; - } - else if (halfExtents.z > halfExtents.x) { - if (outCollisionShape) { - (*outCollisionShape) = new btCylinderShapeZ(btHalfExtents); - } - - return SHAPE_TYPE_CYLINDER_Z; - } - else //...there was no major axis, treat as a sphere - { - ShapeType cylinderFallback = validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, outCollisionShape); - return cylinderFallback; - } - } - - //Got here, then you are what you are along with outCollisionShape - return type; -} - -ShapeType ShapeFactory::computeShapeType(entity::Shape shape, const glm::vec3 &entityDimensions) { - if (shape == entity::Shape::NUM_SHAPES) { - //--EARLY EXIT-- - return SHAPE_TYPE_NONE; - } - - const glm::vec3 halfExtents = entityDimensions * 0.5f; - switch (shape){ - case entity::Shape::Triangle: { - //TODO_CUSACK: Implement this - return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); - } - //Note: Intentional Fallthrough from Quad to Cube - case entity::Shape::Quad: - case entity::Shape::Cube: { - return SHAPE_TYPE_BOX; - } - //Note: Intentional Fallthrough from Hexagon to Sphere - case entity::Shape::Hexagon: - case entity::Shape::Octagon: - case entity::Shape::Circle: - case entity::Shape::Sphere: { - return validateShapeType(SHAPE_TYPE_SPHERE, halfExtents); - } - - case entity::Shape::Cylinder: { - return validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents); - } - - //Note: Intentional Fallthrough from Tetrahedron to Icosahedron - case entity::Shape::Tetrahedron: - case entity::Shape::Octahedron: - case entity::Shape::Dodecahedron: - case entity::Shape::Icosahedron: { - - //TODO_CUSACK: Implement the hedrons - return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents); - } - - //Note: Intentional Fallthrough from Torus to default. - case entity::Shape::Torus: - case entity::Shape::Cone: { - - // These types are currently unsupported - } - default: - return SHAPE_TYPE_NONE; - } - -} - const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); @@ -372,37 +255,32 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btBoxShape(glmToBullet(info.getHalfExtents())); } break; - //case SHAPE_TYPE_SPHERE: { - // glm::vec3 halfExtents = info.getHalfExtents(); - // float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z)); - // shape = new btSphereShape(radius); - //} - //break; - case SHAPE_TYPE_SPHERE: - case SHAPE_TYPE_ELLIPSOID: { + case SHAPE_TYPE_SPHERE: { glm::vec3 halfExtents = info.getHalfExtents(); - //float radius = halfExtents.x; - //const float MIN_RADIUS = 0.001f; - //const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - //if (radius > MIN_RADIUS - // && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR - // && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { - // // close enough to true sphere - // shape = new btSphereShape(radius); - //} else { - // ShapeInfo::PointList points; - // points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); - // for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { - // points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); - // } - // shape = createConvexHull(points); - //} - - validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, &shape); + float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z)); + shape = new btSphereShape(radius); + } + break; + case SHAPE_TYPE_ELLIPSOID: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = halfExtents.x; + const float MIN_RADIUS = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (radius > MIN_RADIUS + && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + // close enough to true sphere + shape = new btSphereShape(radius); + } else { + ShapeInfo::PointList points; + points.reserve(NUM_UNIT_SPHERE_DIRECTIONS); + for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) { + points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents); + } + shape = createConvexHull(points); + } } break; - //TODO_CUSACK: Add Capsules to vetting/validation process for - // type checks. case SHAPE_TYPE_CAPSULE_Y: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.x; @@ -424,30 +302,22 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) shape = new btCapsuleShapeZ(radius, height); } break; - case SHAPE_TYPE_CYLINDER_X: - case SHAPE_TYPE_CYLINDER_Z: - case SHAPE_TYPE_CYLINDER_Y: { - // TODO_CUSACK: Should allow for minor variance along axes. + case SHAPE_TYPE_CYLINDER_X: { const glm::vec3 halfExtents = info.getHalfExtents(); - //const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); - //if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) { - // shape = new btCylinderShape(btHalfExtents); - //} - //else if (halfExtents.x > halfExtents.z) { - // shape = new btCylinderShapeX(btHalfExtents); - //} - //else if (halfExtents.z > halfExtents.x) { - // shape = new btCylinderShapeZ(btHalfExtents); - //} - //else //...there was no major axis, treat as a sphere - //{ - // //TODO_CUSACK: Shunt to ELLIPSOID handling - //} - validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents, &shape); + const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + shape = new btCylinderShapeX(btHalfExtents); + } + case SHAPE_TYPE_CYLINDER_Z: { + const glm::vec3 halfExtents = info.getHalfExtents(); + const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + shape = new btCylinderShapeZ(btHalfExtents); + } + case SHAPE_TYPE_CYLINDER_Y: { + const glm::vec3 halfExtents = info.getHalfExtents(); + const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); + shape = new btCylinderShape(btHalfExtents); } break; - //TODO_CUSACK: Add compound and simple hull to vetting/validation - // process for types. case SHAPE_TYPE_COMPOUND: case SHAPE_TYPE_SIMPLE_HULL: { const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 52b448ee1d..2bf79f390c 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -15,14 +15,11 @@ #include #include -#include //< Needed for entity::Shape #include // translates between ShapeInfo and btShape namespace ShapeFactory { - - ShapeType computeShapeType( entity::Shape shape, const glm::vec3 &entityDimensions); const btCollisionShape* createShapeFromInfo(const ShapeInfo& info); void deleteShape(const btCollisionShape* shape); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 57e927eaf3..5d6b4ece7a 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -29,8 +29,8 @@ void ShapeInfo::clear() { } void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { - //TODO_CUSACK: Does this need additional cases and handling added? - _url = ""; + //TODO_CUSACK: Does this need additional cases and handling added? + _url = ""; _type = type; setHalfExtents(halfExtents); switch(type) { diff --git a/scripts/developer/tests/basicEntityTest/entitySpawner.js b/scripts/developer/tests/basicEntityTest/entitySpawner.js index fa5c9291cb..538e9145f5 100644 --- a/scripts/developer/tests/basicEntityTest/entitySpawner.js +++ b/scripts/developer/tests/basicEntityTest/entitySpawner.js @@ -8,9 +8,7 @@ var SCRIPT_URL = Script.resolvePath("myEntityScript.js") var myEntity = Entities.addEntity({ - name: "Cusack_Testing", - type: "Shape", - shapeType: "Cylinder", + type: "Sphere", color: { red: 200, green: 10, From ef1e426273b3412e63ee511495f8013375250245 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 25 Jul 2017 14:09:46 -0400 Subject: [PATCH 09/38] [WL21389] Some code and todo cleanup in prep for PR1. Changes to be committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/physics/src/ShapeFactory.cpp modified: libraries/shared/src/ShapeInfo.cpp --- .../src/RenderableShapeEntityItem.cpp | 29 +++++-------------- libraries/entities/src/ShapeEntityItem.cpp | 7 ++--- libraries/physics/src/ShapeFactory.cpp | 2 ++ libraries/shared/src/ShapeInfo.cpp | 20 ++++++------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index a305b201d6..5fa2354bd5 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -114,26 +114,13 @@ void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { break; case entity::Shape::Cylinder: { _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; - // TODO_CUSACK: determine if rotation is axis-aligned + // TODO WL21389: determine if rotation is axis-aligned //const Transform::Quat & rot = _transform.getRotation(); -#if 0 - // TODO: some way to tell apart SHAPE_TYPE_CYLINDER_Y - // TODO_CUSACK: Should allow for minor variance along axes? - if ((entityDimensions.y >= entityDimensions.x) && (entityDimensions.y >= entityDimensions.z)) { - } - else if (entityDimensions.x >= entityDimensions.z) { - _collisionShapeType = SHAPE_TYPE_CYLINDER_X; - } - else if (entityDimensions.z >= entityDimensions.x) { - _collisionShapeType = SHAPE_TYPE_CYLINDER_Z; - } - else //...there was no major axis, treat as a hull - { - _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; - //TODO_CUSACK: pointCollection - } -#endif + // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and + // hull ( or dimensions, need circular cross section) + // Should allow for minor variance along axes? + } break; case entity::Shape::Triangle: @@ -145,15 +132,15 @@ void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { case entity::Shape::Dodecahedron: case entity::Shape::Icosahedron: case entity::Shape::Cone: { - _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; - //TODO_CUSACK: pointCollection + //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) + //_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; } break; case entity::Shape::Torus: { // Not in GeometryCache::buildShapes, unsupported. _collisionShapeType = SHAPE_TYPE_NONE; - //TODO_CUSACK: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) + //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) } break; default:{ diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 58799de807..157e3afab3 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -88,14 +88,14 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP void ShapeEntityItem::setShape(const entity::Shape& shape) { _shape = shape; - switch (_shape) { // TODO_CUSACK fill out? + switch (_shape) { // TODO WL21389: fill out with other shapes? case entity::Shape::Cube: _type = EntityTypes::Box; _collisionShapeType = ShapeType::SHAPE_TYPE_BOX; break; case entity::Shape::Sphere: _type = EntityTypes::Sphere; - _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; // TODO_CUSACK defer? Check to see if sphere is more appropriate? + _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; break; default: _type = EntityTypes::Shape; @@ -162,8 +162,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); } -// This value specifes how the shape should be treated by physics calculations. -// For now, all polys will act as spheres +// This value specifes how the shape should be treated by physics calculations. ShapeType ShapeEntityItem::getShapeType() const { return _collisionShapeType; } diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 87580c6726..97174b2216 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -307,11 +307,13 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); shape = new btCylinderShapeX(btHalfExtents); } + break; case SHAPE_TYPE_CYLINDER_Z: { const glm::vec3 halfExtents = info.getHalfExtents(); const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); shape = new btCylinderShapeZ(btHalfExtents); } + break; case SHAPE_TYPE_CYLINDER_Y: { const glm::vec3 halfExtents = info.getHalfExtents(); const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 5d6b4ece7a..5930880859 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -29,7 +29,7 @@ void ShapeInfo::clear() { } void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { - //TODO_CUSACK: Does this need additional cases and handling added? + //TODO WL21389: Does this need additional cases and handling added? _url = ""; _type = type; setHalfExtents(halfExtents); @@ -56,8 +56,9 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString } void ShapeInfo::setBox(const glm::vec3& halfExtents) { - //TODO_CUSACK: Should this pointlist clearance added in case + //TODO WL21389: Should this pointlist clearance added in case // this is a re-purposed instance? + // See https://github.com/highfidelity/hifi/pull/11024#discussion_r128885491 _url = ""; _type = SHAPE_TYPE_BOX; setHalfExtents(halfExtents); @@ -65,8 +66,7 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) { } void ShapeInfo::setSphere(float radius) { - //TODO_CUSACK: Should this pointlist clearance added in case - // this is a re-purposed instance? + //TODO WL21389: See comment in setBox regarding clearance _url = ""; _type = SHAPE_TYPE_SPHERE; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -75,17 +75,14 @@ void ShapeInfo::setSphere(float radius) { } void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { - //TODO_CUSACK: Should this have protection against inadvertant clearance and type - // resetting? If for some reason this was called and point list was and is emtpy - // would we still wish to clear out everything? + //TODO WL21389: May need to skip resetting type here. _pointCollection = pointCollection; _type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; _doubleHashKey.clear(); } void ShapeInfo::setCapsuleY(float radius, float halfHeight) { - //TODO_CUSACK: Should this pointlist clearance added in case - // this is a re-purposed instance? + //TODO WL21389: See comment in setBox regarding clearance _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; radius = glm::max(radius, MIN_HALF_EXTENT); @@ -127,7 +124,7 @@ int ShapeInfo::getLargestSubshapePointCount() const { } float ShapeInfo::computeVolume() const { - //TODO_CUSACK: Add support for other ShapeTypes. + //TODO WL21389: Add support for other ShapeTypes. const float DEFAULT_VOLUME = 1.0f; float volume = DEFAULT_VOLUME; switch(_type) { @@ -161,7 +158,7 @@ float ShapeInfo::computeVolume() const { } bool ShapeInfo::contains(const glm::vec3& point) const { - //TODO_CUSACK: Add support for other ShapeTypes like Ellipsoid/Compound. + //TODO WL21389: Add support for other ShapeTypes like Ellipsoid/Compound. switch(_type) { case SHAPE_TYPE_SPHERE: return glm::length(point) <= _halfExtents.x; @@ -206,6 +203,7 @@ bool ShapeInfo::contains(const glm::vec3& point) const { } const DoubleHashKey& ShapeInfo::getHash() const { + //TODO WL21389: Need to include the pointlist for SIMPLE_HULL in hash // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) { bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET; From 6b5cabf00af08e4278828da0ac3fceec45a6f717 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper <1p-cusack@1stplayable.com> Date: Tue, 25 Jul 2017 18:12:07 -0400 Subject: [PATCH 10/38] [WL21389] Minor: Mark RenderableShapeEntityItem::computeShapeInfo as an override. Changes Committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.h --- libraries/entities-renderer/src/RenderableShapeEntityItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 2a841df57e..f93e4b991e 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -28,7 +28,7 @@ public: bool isTransparent() override; - virtual void computeShapeInfo(ShapeInfo& info); + virtual void computeShapeInfo(ShapeInfo& info) override; private: std::unique_ptr _procedural { nullptr }; From 33ff5917be70f26b4b5472c52661fcfd8ddfc9c5 Mon Sep 17 00:00:00 2001 From: "scromie@turnmeupgames.com" Date: Wed, 26 Jul 2017 19:34:20 +0300 Subject: [PATCH 11/38] fix --- scripts/system/html/js/entityProperties.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 777ef54085..7ef1a6974b 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -475,6 +475,15 @@ function unbindAllInputs() { } } +function clearSelection() { + if(document.selection && document.selection.empty) { + document.selection.empty(); + } else if(window.getSelection) { + var sel = window.getSelection(); + sel.removeAllRanges(); + } +} + function loaded() { openEventBridge(function() { @@ -1051,6 +1060,7 @@ function loaded() { activeElement.select(); } } + clearSelection(); } }); } From 5bd6dac66c87a3369e2e2360d689ec5ce46aa6ff Mon Sep 17 00:00:00 2001 From: Liv Date: Wed, 26 Jul 2017 13:24:56 -0700 Subject: [PATCH 12/38] wrap text if longer than 1m text entity --- scripts/system/chat.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/system/chat.js b/scripts/system/chat.js index 58a1849f1f..65c7567b30 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -43,6 +43,7 @@ var speechBubbleOffset = {x: 0, y: 0.3, z: 0.0}; // The offset from the joint to whic the speech bubble is attached. var speechBubbleJointName = 'Head'; // The name of the joint to which the speech bubble is attached. var speechBubbleLineHeight = 0.05; // The height of a line of text in the speech bubble. + var SPEECH_BUBBLE_MAX_WIDTH = 1; // meters // Load the persistent variables from the Settings, with defaults. function loadSettings() { @@ -645,8 +646,16 @@ //print("updateSpeechBubble:", "speechBubbleMessage", speechBubbleMessage, "textSize", textSize.width, textSize.height); var fudge = 0.02; + var width = textSize.width + fudge; - var height = textSize.height + fudge; + var height = speechBubbleLineHeight + fudge; + + if(textSize.width >= SPEECH_BUBBLE_MAX_WIDTH) { + var numLines = Math.ceil(width); + height = speechBubbleLineHeight * numLines + fudge; + width = SPEECH_BUBBLE_MAX_WIDTH; + }; + dimensions = { x: width, y: height, @@ -672,6 +681,7 @@ Vec3.sum( headPosition, rotatedOffset); + position.y += height / 2; // offset based on wrapped height of bubble speechBubbleParams.position = position; if (!speechBubbleTextID) { From 256853f79b4d15370540950c3e2041c961ab5d1e Mon Sep 17 00:00:00 2001 From: Liv Date: Wed, 26 Jul 2017 13:28:52 -0700 Subject: [PATCH 13/38] syntax and clarification on magic number 2 as half height --- scripts/system/chat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/chat.js b/scripts/system/chat.js index 65c7567b30..85de9fd0ac 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -650,7 +650,7 @@ var width = textSize.width + fudge; var height = speechBubbleLineHeight + fudge; - if(textSize.width >= SPEECH_BUBBLE_MAX_WIDTH) { + if (textSize.width >= SPEECH_BUBBLE_MAX_WIDTH) { var numLines = Math.ceil(width); height = speechBubbleLineHeight * numLines + fudge; width = SPEECH_BUBBLE_MAX_WIDTH; @@ -681,7 +681,7 @@ Vec3.sum( headPosition, rotatedOffset); - position.y += height / 2; // offset based on wrapped height of bubble + position.y += height / 2; // offset based on half of bubble height speechBubbleParams.position = position; if (!speechBubbleTextID) { From dd76c30de5b703a5250fddd4978e869b517922ce Mon Sep 17 00:00:00 2001 From: rabelaiis Date: Thu, 27 Jul 2017 17:31:30 +0700 Subject: [PATCH 14/38] Make Xylophone mallets equipable, make the mallets provide haptic feedback, fix a closing bracket bug stopping the xylophone from working and clean up code according to coding standards --- .../marketplace/xylophone/pUtils.js | 34 ----- .../marketplace/xylophone/xylophoneKey.js | 48 +++++-- .../marketplace/xylophone/xylophoneRezzer.js | 117 +++++++++++------- 3 files changed, 111 insertions(+), 88 deletions(-) delete mode 100644 unpublishedScripts/marketplace/xylophone/pUtils.js diff --git a/unpublishedScripts/marketplace/xylophone/pUtils.js b/unpublishedScripts/marketplace/xylophone/pUtils.js deleted file mode 100644 index 2cafbc1f50..0000000000 --- a/unpublishedScripts/marketplace/xylophone/pUtils.js +++ /dev/null @@ -1,34 +0,0 @@ -// -// pUtils.js -// -// Created by Patrick Gosch on 03/28/2017 -// Copyright 2017 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 -// - -getEntityTextures = function(id) { - var results = null; - var properties = Entities.getEntityProperties(id, "textures"); - if (properties.textures) { - try { - results = JSON.parse(properties.textures); - } catch (err) { - logDebug(err); - logDebug(properties.textures); - } - } - return results ? results : {}; -}; - -setEntityTextures = function(id, textureList) { - var json = JSON.stringify(textureList); - Entities.editEntity(id, {textures: json}); -}; - -editEntityTextures = function(id, textureName, textureURL) { - var textureList = getEntityTextures(id); - textureList[textureName] = textureURL; - setEntityTextures(id, textureList); -}; diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js index afba7e8075..38b8552b6e 100644 --- a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js +++ b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js @@ -11,8 +11,9 @@ (function() { Script.include(Script.resolvePath("pUtils.js")); var TIMEOUT = 150; - var TEXGRAY = Script.resolvePath("xylotex_bar_gray.png"); - var TEXBLACK = Script.resolvePath("xylotex_bar_black.png"); + var TEXTURE_GRAY = Script.resolvePath("xylotex_bar_gray.png"); + var TEXTURE_BLACK = Script.resolvePath("xylotex_bar_black.png"); + var IS_DEBUG = false; var _this; function XylophoneKey() { @@ -22,7 +23,7 @@ XylophoneKey.prototype = { sound: null, isWaiting: false, - homePos: null, + homePosition: null, injector: null, preload: function(entityID) { @@ -45,20 +46,51 @@ hit: function() { if (!_this.isWaiting) { _this.isWaiting = true; - _this.homePos = Entities.getEntityProperties(_this.entityID, ["position"]).position; - _this.injector = Audio.playSound(_this.sound, {position: _this.homePos, volume: 1}); - editEntityTextures(_this.entityID, "file5", TEXGRAY); + _this.homePosition = Entities.getEntityProperties(_this.entityID, ["position"]).position; + _this.injector = Audio.playSound(_this.sound, {position: _this.homePosition, volume: 1}); + _this.editEntityTextures(_this.entityID, "file5", TEXTURE_GRAY); + var HAPTIC_STRENGTH = 1; + var HAPTIC_DURATION = 20; + var HAPTIC_HAND = 2; // Both hands + Controller.triggerHapticPulse(HAPTIC_STRENGTH, HAPTIC_DURATION, HAPTIC_HAND); _this.timeout(); } }, timeout: function() { Script.setTimeout(function() { - editEntityTextures(_this.entityID, "file5", TEXBLACK); + _this.editEntityTextures(_this.entityID, "file5", TEXTURE_BLACK); _this.isWaiting = false; }, TIMEOUT); + }, + + getEntityTextures: function(id) { + var results = null; + var properties = Entities.getEntityProperties(id, "textures"); + if (properties.textures) { + try { + results = JSON.parse(properties.textures); + } catch (err) { + if (IS_DEBUG) { + print(err); + print(properties.textures); + } + } + } + return results ? results : {}; + }, + + setEntityTextures: function(id, textureList) { + var json = JSON.stringify(textureList); + Entities.editEntity(id, {textures: json}); + }, + + editEntityTextures: function(id, textureName, textureURL) { + var textureList = _this.getEntityTextures(id); + textureList[textureName] = textureURL; + _this.setEntityTextures(id, textureList); + } }; return new XylophoneKey(); - }); diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js b/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js index 6416f81037..e99341bb19 100644 --- a/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js +++ b/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js @@ -8,65 +8,69 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var soundFiles = ["C4.wav", "D4.wav", "E4.wav", "F4.wav", "G4.wav", "A4.wav", "B4.wav", "C5.wav"]; -var keyModelURL = Script.resolvePath("xyloKey_2_a_e.fbx"); -var keyScriptURL = Script.resolvePath("xylophoneKey.js"); -var TEXBLACK = Script.resolvePath("xylotex_bar_black.png"); -var malletModelURL = Script.resolvePath("Mallet3-2pc.fbx"); -var malletModelColliderURL = Script.resolvePath("Mallet3-2bpc_phys.obj"); +var SOUND_FILES = ["C4.wav", "D4.wav", "E4.wav", "F4.wav", "G4.wav", "A4.wav", "B4.wav", "C5.wav"]; +var KEY_MODEL_URL = Script.resolvePath("xyloKey_2_a_e.fbx"); +var KEY_SCRIPT_URL = Script.resolvePath("xylophoneKey.js"); +var TEXTURE_BLACK = Script.resolvePath("xylotex_bar_black.png"); +var MALLET_MODEL_URL = Script.resolvePath("Mallet3-2pc.fbx"); +var MALLET_MODEL_COLLIDER_URL = Script.resolvePath("Mallet3-2bpc_phys.obj"); +var FORWARD = { x: 0, y: 0, z: -1 }; var center = MyAvatar.position; -var fwd = {x:0, y:0, z:-1}; -var xyloFramePos = Vec3.sum(center, Vec3.multiply(fwd, 0.8)); -var xyloFrameID = Entities.addEntity( { +var XYLOPHONE_FORWARD_OFFSET = 0.8; +var xylophoneFramePosition = Vec3.sum(center, Vec3.multiply(FORWARD, XYLOPHONE_FORWARD_OFFSET)); +var xylophoneFrameID = Entities.addEntity({ name: "Xylophone", type: "Model", modelURL: Script.resolvePath("xylophoneFrameWithWave.fbx"), - position: xyloFramePos, - rotation: Quat.fromVec3Radians({x:0, y:Math.PI, z:0}), + position: xylophoneFramePosition, + rotation: Quat.fromVec3Radians({ x: 0, y: Math.PI, z: 0 }), shapeType: "static-mesh" }); -center.y += (0.45); // key Y offset from frame -var keyPos, keyRot, ud, td, keyID; -for (var i = 1; i <= soundFiles.length; i++) { +var KEY_Y_OFFSET = 0.45; +center.y += KEY_Y_OFFSET; +var keyPosition, keyRotation, userData, textureData, keyID; +var ROTATION_START = 0.9; +var ROTATION_DELTA = 0.2; +for (var i = 1; i <= SOUND_FILES.length; i++) { + + keyRotation = Quat.fromVec3Radians({ x: 0, y: ROTATION_START - (i*ROTATION_DELTA), z: 0 }); + keyPosition = Vec3.sum(center, Vec3.multiplyQbyV(keyRotation, FORWARD)); - keyRot = Quat.fromVec3Radians({x:0, y:(0.9 - (i*0.2)), z:0}); - keyPos = Vec3.sum(center, Vec3.multiplyQbyV(keyRot, fwd)); - - ud = { - soundFile: soundFiles[i-1] + userData = { + soundFile: SOUND_FILES[i-1] }; - td = { + textureData = { "file4": Script.resolvePath("xylotex_bar" + i + ".png"), - "file5": TEXBLACK + "file5": TEXTURE_BLACK }; - keyID = Entities.addEntity( { + keyID = Entities.addEntity({ name: ("XyloKey" + i), type: "Model", - modelURL: keyModelURL, - position: keyPos, - rotation: keyRot, + modelURL: KEY_MODEL_URL, + position: keyPosition, + rotation: keyRotation, shapeType: "static-mesh", - script: keyScriptURL, - textures: JSON.stringify(td), - userData: JSON.stringify(ud), - parentID: xyloFrameID - } ); + script: KEY_SCRIPT_URL, + textures: JSON.stringify(textureData), + userData: JSON.stringify(userData), + parentID: xylophoneFrameID + }); } // if rezzed on/above something, wait until after model has loaded so you can read its dimensions then move object on to that surface. -var pickRay = {origin: center, direction: {x:0, y:-1, z:0}}; +var pickRay = {origin: center, direction: {x: 0, y: -1, z: 0}}; var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects && (intersection.distance < 10)) { var surfaceY = intersection.intersection.y; Script.setTimeout( function() { // should add loop to check for fbx loaded instead of delay - var xyloDimensions = Entities.getEntityProperties(xyloFrameID, ["dimensions"]).dimensions; - xyloFramePos.y = surfaceY + (xyloDimensions.y/2); - Entities.editEntity(xyloFrameID, {position: xyloFramePos}); + var xylophoneDimensions = Entities.getEntityProperties(xylophoneFrameID, ["dimensions"]).dimensions; + xylophoneFramePosition.y = surfaceY + (xylophoneDimensions.y/2); + Entities.editEntity(xylophoneFrameID, {position: xylophoneFramePosition}); rezMallets(); }, 2000); } else { @@ -75,28 +79,49 @@ if (intersection.intersects && (intersection.distance < 10)) { } function rezMallets() { - var malletProps = { + var malletProperties = { name: "Xylophone Mallet", type: "Model", - modelURL: malletModelURL, - compoundShapeURL: malletModelColliderURL, - collidesWith: "static,dynamic,kinematic,", + modelURL: MALLET_MODEL_URL, + compoundShapeURL: MALLET_MODEL_COLLIDER_URL, + collidesWith: "static,dynamic,kinematic", collisionMask: 7, collisionsWillMove: 1, dynamic: 1, damping: 1, angularDamping: 1, shapeType: "compound", - userData: "{\"grabbableKey\":{\"grabbable\":true}}", - dimensions: {"x": 0.057845603674650192, "y": 0.057845607399940491, "z": 0.30429631471633911} // not being set from fbx for some reason. + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + }, + wearable: { + joints: { + LeftHand: [ + { x: 0, y: 0.2, z: 0.04 }, + Quat.fromVec3Degrees({ x: 0, y: 90, z: 90 }) + ], + RightHand: [ + { x: 0, y: 0.2, z: 0.04 }, + Quat.fromVec3Degrees({ x: 0, y: 90, z: 90 }) + ] + } + } + }), + dimensions: { "x": 0.057845603674650192, "y": 0.057845607399940491, "z": 0.30429631471633911 } // not being set from fbx for some reason. }; - malletProps.position = Vec3.sum(xyloFramePos, {x: 0.1, y: 0.55, z: 0}); - malletProps.rotation = Quat.fromVec3Radians({x:0, y:Math.PI - 0.1, z:0}); - Entities.addEntity(malletProps); + var LEFT_MALLET_POSITION = { x: 0.1, y: 0.55, z: 0 }; + var LEFT_MALLET_ROTATION = { x: 0, y: Math.PI - 0.1, z: 0 }; + var RIGHT_MALLET_POSITION = { x: -0.1, y: 0.55, z: 0 }; + var RIGHT_MALLET_ROTATION = { x: 0, y: Math.PI + 0.1, z: 0 }; - malletProps.position = Vec3.sum(xyloFramePos, {x: -0.1, y: 0.55, z: 0}); - malletProps.rotation = Quat.fromVec3Radians({x:0, y:Math.PI + 0.1, z:0}); - Entities.addEntity(malletProps); + malletProperties.position = Vec3.sum(xylophoneFramePosition, LEFT_MALLET_POSITION); + malletProperties.rotation = Quat.fromVec3Radians(LEFT_MALLET_ROTATION); + Entities.addEntity(malletProperties); + + malletProperties.position = Vec3.sum(xylophoneFramePosition, RIGHT_MALLET_POSITION); + malletProperties.rotation = Quat.fromVec3Radians(RIGHT_MALLET_ROTATION); + Entities.addEntity(malletProperties); Script.stop(); } \ No newline at end of file From 8b7a29c3f3250ebfd777bf93f8d0153981feb3b2 Mon Sep 17 00:00:00 2001 From: rabelaiis Date: Fri, 28 Jul 2017 06:22:29 +0700 Subject: [PATCH 15/38] remove putils reference --- unpublishedScripts/marketplace/xylophone/xylophoneKey.js | 1 - 1 file changed, 1 deletion(-) diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js index 38b8552b6e..5cff66e557 100644 --- a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js +++ b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js @@ -9,7 +9,6 @@ // (function() { - Script.include(Script.resolvePath("pUtils.js")); var TIMEOUT = 150; var TEXTURE_GRAY = Script.resolvePath("xylotex_bar_gray.png"); var TEXTURE_BLACK = Script.resolvePath("xylotex_bar_black.png"); From 45934cb53e2b1622ef3a0366f6703b68f563ca33 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 28 Jul 2017 18:04:29 +0200 Subject: [PATCH 16/38] Fix Landscape mode, when menu pushed in Create mode. Fix pages gets white in Create mode --- interface/src/ui/overlays/Web3DOverlay.cpp | 2 ++ libraries/ui/src/ui/TabletScriptingInterface.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index acba15d2ec..080c72f3bb 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -205,6 +205,8 @@ void Web3DOverlay::loadSourceURL() { _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../"); + _webSurface->getSurfaceContext()->setContextProperty("Paths", DependencyManager::get().data()); + tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data()); // mark the TabletProxy object as cpp ownership. diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 6ff5e46cea..b74d9fcb5c 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -483,6 +483,11 @@ bool TabletProxy::pushOntoStack(const QVariant& path) { return result; } + //set landscape off when pushing menu items while in Create mode + if (_landscape) { + setLandscape(false); + } + QObject* root = nullptr; if (!_toolbarMode && _qmlTabletRoot) { root = _qmlTabletRoot; From 3ec9640ea1e8bdf201dd56e8043432bf9b4262e2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 28 Jul 2017 09:22:47 -0700 Subject: [PATCH 17/38] fix calculation of walk motor for HMD --- interface/src/avatar/MyAvatar.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b644defde2..83d170300b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1586,9 +1586,14 @@ void MyAvatar::updateMotors() { motorRotation = getMyHead()->getHeadOrientation(); } else { // non-hovering = walking: follow camera twist about vertical but not lift - // so we decompose camera's rotation and store the twist part in motorRotation + // we decompose camera's rotation and store the twist part in motorRotation + // however, we need to perform the decomposition in the avatar-frame + // using the local UP axis and then transform back into world-frame + glm::quat orientation = getOrientation(); + glm::quat headOrientation = glm::inverse(orientation) * getMyHead()->getHeadOrientation(); // avatar-frame glm::quat liftRotation; - motorRotation = getOrientation(); + swingTwistDecomposition(headOrientation, Vectors::UNIT_Y, liftRotation, motorRotation); + motorRotation = orientation * motorRotation; } const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f; From cc4fbc97cdab663701315f823e928e9fd2429646 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper <1p-cusack@1stplayable.com> Date: Fri, 28 Jul 2017 15:59:17 -0400 Subject: [PATCH 18/38] [WL21389] PR1 Update based on code review discussion & feedback (details below). * Removed some left overs from prior approach. * Moved _collisionShapeType & getShapeType override from ShapeEntityItem to RenderableShapeEntityItem (see thread: https://github.com/highfidelity/hifi/pull/11048#discussion_r130154903) * Switched _collisionShapeType default from SHAPE_TYPE_NONE to SHAPE_TYPE_ELLIPSOID ** see thread: https://github.com/highfidelity/hifi/pull/11048#discussion_r129982909 Note(s): * Retested and the cylinder behaves as expected along with the Box & Sphere shapes save from the previously mentioned caveats in the PR notes (https://github.com/highfidelity/hifi/pull/11048) * Confirmed that currently unsupported shapes (hedrons, polygons, & cone) fallback to ellipsoid behavior given default change. Changes Committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities-renderer/src/RenderableShapeEntityItem.h modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.h modified: libraries/shared/src/ShapeInfo.cpp --- .../src/RenderableShapeEntityItem.cpp | 112 +++++++++--------- .../src/RenderableShapeEntityItem.h | 7 ++ libraries/entities/src/ShapeEntityItem.cpp | 9 +- libraries/entities/src/ShapeEntityItem.h | 2 - libraries/shared/src/ShapeInfo.cpp | 2 +- 5 files changed, 67 insertions(+), 65 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 5fa2354bd5..c853335915 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -91,67 +90,72 @@ void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { const glm::vec3 entityDimensions = getDimensions(); switch (_shape){ - case entity::Shape::Quad: - case entity::Shape::Cube: { - _collisionShapeType = SHAPE_TYPE_BOX; - } - break; - case entity::Shape::Sphere: { - - float diameter = entityDimensions.x; - const float MIN_DIAMETER = 0.001f; - const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; - if (diameter > MIN_DIAMETER - && fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR - && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { - - _collisionShapeType = SHAPE_TYPE_SPHERE; + case entity::Shape::Quad: + case entity::Shape::Cube: { + _collisionShapeType = SHAPE_TYPE_BOX; } - else { + break; + case entity::Shape::Sphere: { + + float diameter = entityDimensions.x; + const float MIN_DIAMETER = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (diameter > MIN_DIAMETER + && fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { + + _collisionShapeType = SHAPE_TYPE_SPHERE; + } + else { + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + } + } + break; + case entity::Shape::Cylinder: { + _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; + // TODO WL21389: determine if rotation is axis-aligned + //const Transform::Quat & rot = _transform.getRotation(); + + // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and + // hull ( or dimensions, need circular cross section) + // Should allow for minor variance along axes? + + } + break; + case entity::Shape::Triangle: + case entity::Shape::Hexagon: + case entity::Shape::Octagon: + case entity::Shape::Circle: + case entity::Shape::Tetrahedron: + case entity::Shape::Octahedron: + case entity::Shape::Dodecahedron: + case entity::Shape::Icosahedron: + case entity::Shape::Cone: { + //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) + //_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + } + break; + case entity::Shape::Torus: + { + // Not in GeometryCache::buildShapes, unsupported. + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) + } + break; + default:{ _collisionShapeType = SHAPE_TYPE_ELLIPSOID; } - } - break; - case entity::Shape::Cylinder: { - _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; - // TODO WL21389: determine if rotation is axis-aligned - //const Transform::Quat & rot = _transform.getRotation(); - - // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and - // hull ( or dimensions, need circular cross section) - // Should allow for minor variance along axes? - - } - break; - case entity::Shape::Triangle: - case entity::Shape::Hexagon: - case entity::Shape::Octagon: - case entity::Shape::Circle: - case entity::Shape::Tetrahedron: - case entity::Shape::Octahedron: - case entity::Shape::Dodecahedron: - case entity::Shape::Icosahedron: - case entity::Shape::Cone: { - //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) - //_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; - } - break; - case entity::Shape::Torus: - { - // Not in GeometryCache::buildShapes, unsupported. - _collisionShapeType = SHAPE_TYPE_NONE; - //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) - } - break; - default:{ - //_collisionShapeType = SHAPE_TYPE_NONE; // Remains SHAPE_TYPE_NONE. - } - break; + break; } EntityItem::computeShapeInfo(info); } +// This value specifes how the shape should be treated by physics calculations. +ShapeType RenderableShapeEntityItem::getShapeType() const { + return _collisionShapeType; +} + void RenderableShapeEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); //Q_ASSERT(getType() == EntityTypes::Shape); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index f93e4b991e..d603cdedef 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -29,10 +29,17 @@ public: bool isTransparent() override; virtual void computeShapeInfo(ShapeInfo& info) override; + ShapeType getShapeType() const override; + private: std::unique_ptr _procedural { nullptr }; + //! This is SHAPE_TYPE_ELLIPSOID rather than SHAPE_TYPE_NONE to maintain + //! prior functionality where new or unsupported shapes are treated as + //! ellipsoids. + ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; + SIMPLE_RENDERABLE(); }; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 157e3afab3..eb1bed503c 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -88,14 +88,12 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP void ShapeEntityItem::setShape(const entity::Shape& shape) { _shape = shape; - switch (_shape) { // TODO WL21389: fill out with other shapes? + switch (_shape) { case entity::Shape::Cube: _type = EntityTypes::Box; - _collisionShapeType = ShapeType::SHAPE_TYPE_BOX; break; case entity::Shape::Sphere: _type = EntityTypes::Sphere; - _collisionShapeType = ShapeType::SHAPE_TYPE_ELLIPSOID; break; default: _type = EntityTypes::Shape; @@ -162,11 +160,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); } -// This value specifes how the shape should be treated by physics calculations. -ShapeType ShapeEntityItem::getShapeType() const { - return _collisionShapeType; -} - void ShapeEntityItem::setColor(const rgbColor& value) { memcpy(_color, value, sizeof(rgbColor)); } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 42a92f7bd7..60fcfd628a 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -84,7 +84,6 @@ public: QColor getQColor() const; void setColor(const QColor& value); - ShapeType getShapeType() const override; bool shouldBePhysical() const override { return !isDead(); } bool supportsDetailedRayIntersection() const override; @@ -100,7 +99,6 @@ protected: float _alpha { 1 }; rgbColor _color; entity::Shape _shape { entity::Shape::Sphere }; - ShapeType _collisionShapeType { ShapeType::SHAPE_TYPE_NONE }; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 5930880859..a556548b25 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -124,7 +124,7 @@ int ShapeInfo::getLargestSubshapePointCount() const { } float ShapeInfo::computeVolume() const { - //TODO WL21389: Add support for other ShapeTypes. + //TODO WL21389: Add support for other ShapeTypes( CYLINDER_X, CYLINDER_Y, etc). const float DEFAULT_VOLUME = 1.0f; float volume = DEFAULT_VOLUME; switch(_type) { From 3c9ab36416a187251a22947358a522dfdc4e6ace Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 29 Jul 2017 12:00:41 +0200 Subject: [PATCH 19/38] Remove already already implemented fix --- interface/src/ui/overlays/Web3DOverlay.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index ffb4faf83e..2bcb247df8 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -192,7 +192,6 @@ void Web3DOverlay::loadSourceURL() { _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../"); - _webSurface->getSurfaceContext()->setContextProperty("Paths", DependencyManager::get().data()); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data()); From 734330dc063311990e8308bed080582b8655fbc7 Mon Sep 17 00:00:00 2001 From: Menithal Date: Sat, 29 Jul 2017 15:48:31 +0300 Subject: [PATCH 20/38] Fixed Particle Editor Update event Particle Editor was agressively refreshing when ever a particle was be ing up dated Added a flag check to make sure the particle was always using the latest version --- scripts/system/edit.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 06260277fd..02cc35e645 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -14,7 +14,7 @@ Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */ (function() { // BEGIN LOCAL_SCOPE - + "use strict"; var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; @@ -67,7 +67,7 @@ gridTool.setVisible(false); var entityListTool = new EntityListTool(); -selectionManager.addEventListener(function () { +selectionManager.addEventListener(function (test) { selectionDisplay.updateHandles(); entityIconOverlayManager.updatePositions(); @@ -275,7 +275,8 @@ var toolBar = (function () { properties.userData = JSON.stringify({ grabbableKey: { grabbable: true } }); } entityID = Entities.addEntity(properties); - if (properties.type == "ParticleEffect") { + + if (properties.type === "ParticleEffect") { selectParticleEntity(entityID); } @@ -2229,10 +2230,9 @@ var particleExplorerTool = new ParticleExplorerTool(); var selectedParticleEntity = 0; var selectedParticleEntityID = null; - function selectParticleEntity(entityID) { var properties = Entities.getEntityProperties(entityID); - + selectedParticleEntityID = entityID; if (properties.emitOrientation) { properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation); } @@ -2274,7 +2274,6 @@ entityListTool.webView.webEventReceived.connect(function (data) { return; } // Destroy the old particles web view first - selectParticleEntity(ids[0]); } else { selectedParticleEntity = 0; particleExplorerTool.destroyWebView(); From 861b33a84563185027a559473909b36b613a470f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 29 Jul 2017 17:22:25 -0700 Subject: [PATCH 21/38] Fix potential nullptr access in EntityTreeElement --- libraries/entities/src/EntityTreeElement.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 108cb39222..487bf60f61 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -1001,7 +1001,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int if (!bestFitBefore && bestFitAfter) { // This is the case where the entity existed, and is in some element in our tree... if (currentContainingElement.get() != this) { - currentContainingElement->removeEntityItem(entityItem); + // if the currentContainingElement is non-null, remove the entity from it + if (currentContainingElement) { + currentContainingElement->removeEntityItem(entityItem); + } addEntityItem(entityItem); } } From 5fab6c37a3daec1beb0302af43fff7ce2f46f05a Mon Sep 17 00:00:00 2001 From: Matti Lahtinen Date: Mon, 31 Jul 2017 08:56:04 +0300 Subject: [PATCH 22/38] Removed stray variable test --- scripts/system/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 02cc35e645..300db5d50a 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -67,7 +67,7 @@ gridTool.setVisible(false); var entityListTool = new EntityListTool(); -selectionManager.addEventListener(function (test) { +selectionManager.addEventListener(function () { selectionDisplay.updateHandles(); entityIconOverlayManager.updatePositions(); From 1f6b92a5190966886712a5356ecef593215eb75b Mon Sep 17 00:00:00 2001 From: rabelaiis Date: Mon, 31 Jul 2017 17:27:49 +0700 Subject: [PATCH 23/38] Vibrate only the controller that hits the key and decrease timeout so that the xylophone can be played faster --- .../marketplace/xylophone/xylophoneKey.js | 22 +++++++++++-------- .../marketplace/xylophone/xylophoneRezzer.js | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js index 5cff66e557..3d131252c8 100644 --- a/unpublishedScripts/marketplace/xylophone/xylophoneKey.js +++ b/unpublishedScripts/marketplace/xylophone/xylophoneKey.js @@ -9,12 +9,12 @@ // (function() { - var TIMEOUT = 150; + var TIMEOUT = 50; // at 30 ms, the key's color sometimes fails to switch when hit var TEXTURE_GRAY = Script.resolvePath("xylotex_bar_gray.png"); var TEXTURE_BLACK = Script.resolvePath("xylotex_bar_black.png"); var IS_DEBUG = false; var _this; - + function XylophoneKey() { _this = this; } @@ -34,24 +34,28 @@ collisionWithEntity: function(thisEntity, otherEntity, collision) { if (collision.type === 0) { - _this.hit(); + _this.hit(otherEntity); } }, - clickDownOnEntity: function() { - _this.hit(); + clickDownOnEntity: function(otherEntity) { + _this.hit(otherEntity); }, - hit: function() { + hit: function(otherEntity) { if (!_this.isWaiting) { _this.isWaiting = true; _this.homePosition = Entities.getEntityProperties(_this.entityID, ["position"]).position; _this.injector = Audio.playSound(_this.sound, {position: _this.homePosition, volume: 1}); _this.editEntityTextures(_this.entityID, "file5", TEXTURE_GRAY); + var HAPTIC_STRENGTH = 1; - var HAPTIC_DURATION = 20; - var HAPTIC_HAND = 2; // Both hands - Controller.triggerHapticPulse(HAPTIC_STRENGTH, HAPTIC_DURATION, HAPTIC_HAND); + var HAPTIC_DURATION = 20; + var userData = JSON.parse(Entities.getEntityProperties(otherEntity, 'userData').userData); + if (userData.hasOwnProperty('hand')){ + Controller.triggerHapticPulse(HAPTIC_STRENGTH, HAPTIC_DURATION, userData.hand); + } + _this.timeout(); } }, diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js b/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js index e99341bb19..6adf8710a7 100644 --- a/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js +++ b/unpublishedScripts/marketplace/xylophone/xylophoneRezzer.js @@ -11,6 +11,7 @@ var SOUND_FILES = ["C4.wav", "D4.wav", "E4.wav", "F4.wav", "G4.wav", "A4.wav", "B4.wav", "C5.wav"]; var KEY_MODEL_URL = Script.resolvePath("xyloKey_2_a_e.fbx"); var KEY_SCRIPT_URL = Script.resolvePath("xylophoneKey.js"); +var MALLET_SCRIPT_URL = Script.resolvePath("xylophoneMallet.js"); var TEXTURE_BLACK = Script.resolvePath("xylotex_bar_black.png"); var MALLET_MODEL_URL = Script.resolvePath("Mallet3-2pc.fbx"); var MALLET_MODEL_COLLIDER_URL = Script.resolvePath("Mallet3-2bpc_phys.obj"); @@ -91,6 +92,7 @@ function rezMallets() { damping: 1, angularDamping: 1, shapeType: "compound", + script: MALLET_SCRIPT_URL, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true From ed9ea17917d2f2d49630d8a8329dab97ccbe0730 Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Mon, 31 Jul 2017 08:02:18 -0700 Subject: [PATCH 24/38] remove semi-colon --- scripts/system/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/chat.js b/scripts/system/chat.js index 85de9fd0ac..fa997e20cc 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -654,7 +654,7 @@ var numLines = Math.ceil(width); height = speechBubbleLineHeight * numLines + fudge; width = SPEECH_BUBBLE_MAX_WIDTH; - }; + } dimensions = { x: width, From 60201548670ca5549691dbab2091b93e14e4042d Mon Sep 17 00:00:00 2001 From: Menithal Date: Mon, 31 Jul 2017 22:49:11 +0300 Subject: [PATCH 25/38] Removed some whitespaces to trigger new build --- scripts/system/edit.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 300db5d50a..b5e54e7a57 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -26,11 +26,8 @@ Script.include([ "libraries/stringHelpers.js", "libraries/dataViewHelpers.js", "libraries/progressDialog.js", - "libraries/entitySelectionTool.js", - "libraries/ToolTip.js", - "libraries/entityCameraTool.js", "libraries/gridTool.js", "libraries/entityList.js", From 0b79809f547c9ec90c3b611a02972feabdaa3584 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper <1p-cusack@1stplayable.com> Date: Mon, 31 Jul 2017 17:08:30 -0400 Subject: [PATCH 26/38] [WL21389] PR1 Feedback: Small change missed last commit (details below). Until they're properly implemented, default the hedrons and polygons to SHAPE_TYPE_ELLIPSOID within RenderableShapeEntity::computeShapeInfo. Changes committed: modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp --- libraries/entities-renderer/src/RenderableShapeEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index c853335915..3f9497741f 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -132,7 +132,7 @@ void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) { case entity::Shape::Icosahedron: case entity::Shape::Cone: { //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later) - //_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; } break; case entity::Shape::Torus: From 46966b11321254fd96e5b14d0a052f85b68e0857 Mon Sep 17 00:00:00 2001 From: Marko Kudjerski Date: Mon, 31 Jul 2017 16:19:34 -0700 Subject: [PATCH 27/38] switching from LZMA (default) to BZIP2 for NSIS compression --- cmake/macros/GenerateInstallers.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 0def701739..0296ad9901 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,6 +22,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Beta-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) + set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) if (WIN32) From 6855dcbacf253d630e15c1d82340434da1a4c9e0 Mon Sep 17 00:00:00 2001 From: Marko Kudjerski Date: Mon, 31 Jul 2017 17:17:11 -0700 Subject: [PATCH 28/38] use bzip2 compression only for PR builds (so that we internally benefit from faster builds) --- cmake/macros/GenerateInstallers.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 0296ad9901..aa681e27b4 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,7 +22,9 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Beta-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) - set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2") + if (PR_BUILD) + set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2") + endif () set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) if (WIN32) From 9b28d546e037f5dc1a9b1a4cd729ea26f4deb73d Mon Sep 17 00:00:00 2001 From: "Scromie@turnmeupgames.com" Date: Tue, 1 Aug 2017 12:32:27 +0300 Subject: [PATCH 29/38] Test plan --- Test Plan 2.docx | Bin 0 -> 7305 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Test Plan 2.docx diff --git a/Test Plan 2.docx b/Test Plan 2.docx new file mode 100644 index 0000000000000000000000000000000000000000..da60821b53e86ea9383e166da7f1d63dba588740 GIT binary patch literal 7305 zcmaKRWmp_ruhxxxyQt50eftRLb;_hGa=-*>-7q`i6obI~u09 zS^X?VV`Ygmjg1v#rM3{s0L((Ne{TIbVH89$@6 zt%i_E@gJCFYZ+(==A^6h_ℜHr^16?r6-Yt^lIBVxkg z?6mrQLCS5A9E?!v^!?sAG)eZA0aJ}};hV<-A)MLNe$2Nj@`yTYh|nwR8j^G<*MyNs+Qo`Ph}BrQwSCLIgr#MAiX8C*23}v&RqEK}auuF>G4lPv%LENVZ%q3bKtLMmx5wyru z)l1niSjXhnXVgPnca2@k9);t@EMb^rq63D+$JYj>?qbkh4nCu{yHZh*-JgfmHDvlG zoynJmAAF8v)z$XG=4bj`3$1lfUUV?G7uJ442=&&~?bW#-l2V^ylTm<>ak=(XuhwWS z4(zZ}`U(kso~$=%W4y$z=qN#k#rk=YRM~3=Jrq*_1DI>X8#jbF{O`BZ0jbaI$0`Y#)`_+ zj6mUzfKP!{Af>Oh_O7f=o>^)LZpZz2@DS zN+G({7EwIb*%C}A!6iS(HLktgp}0AJDrf2NvY|J`IIyrM z+z@Pn-cWTEQqZ)vEd}0lKebC*uEhu@su(IHHO{A{chSD;py|&~(06%jAZFqdpM>{A z7j+Xejtv>lOLP-#^-B56+?06jKIN!=xMjosWuse+p3+2E+r+-*G}U%$0_wNk{e5kc zhyTwnSpw%wX$2O^wUeLoI!6V1VJ$_#yJLd=(HuoV{ImiDR}@9ggV z2PgHYaU`*A8)6tw^dK$KPQ+3hB$R8-Kj_w*omQ~nBQ;E$0(XO}c3F~@Lu=vaS=}9l zQ*}pvlu^@UJJ}(unngT8>4ixnR(oaa`@GR%vcj@}XWHmOVB>gQ*9Z6%IAsyW_ntri z;O0N+i1{}iT|8~g{vhL#)&g{i7xzBs8d2gT(stpLP%4MYb;2z`L3cXCvnz=q8eI}Z zV>WYrla$0TqAOUALqU{x5!~07El)-U@w$AF7MBvBp)q&aR)BmOLz)Z-O^0fYiC~hm z;E&0G^C+>TCWjZO_u9K2HeWTRSSu%x?D>GxWNVy^i>{_z&9DmKwrDpatS$Opz{v6R z&nk)v7T-}BAtQ$RD%32tt#}B!%Mms?sfnf0_DKf8_RvJ9$m-NF^a8=;+!APIdWFk% z6pC0Ho|0M=`M2GrF>Go0&-n-x1x!%u1h^tziQDQAgsY>%n|iT>)NqH>ky?y^Nosob zs1~8TM3@v4qUuBvtq%HME@*%XOoY_22r3%4YI6|Tk#`udd=8XD330gZ1rAZMZrxbc z(1Z`JNifwMVZ|)U)YXFo5vd}?7*IvW#3-0OUaS-EVu0Dgm&BZ)6rqGoFiF8O+bpAp zrppN=6mP_B>`GT0Y#~N4s#POH&k<{`Ft)i;)ZBwi6P7_sWr58Y^0jI+)*n|yR zb!HSc=x}OZWze`@`be1Joe(n^>bd7>@Iw}xCsUEJ>JT7VZnWR2tqEbJ(o1cxt7H7? zG{@^x8*LZWZ1TM1AqrlIT0C&}Wv5wa-n|H*U ztUCg)3i)=?!kP7Kj^U|ixfu2DB+{wD1C7#7NC~nWC(7IMY@GTaWtGA($r}a6RJ3S3 zk7t;nl3Y9BjHp)G}iYOHr%{Cny)$7(D`2=nLds>JEN8B92h6jmPYz zfe$HppxOyaE>|>JGb!P^A40w2LKv;1;OSig-#C*h1DAxY^4FE`p{ST@~pjh6nLiG^Ore)5VWwJ(5{ z%{|JcJq@wi98=`AQXzNf`MVydcNL{xM>Y{d7Ie9BJz3a~`z*`J*em|V9`tNK;%S8n zzW_7etN>t2fH9Bi!jfSPe(r8l&y_7kz_)4eTle@A_CQyZ!Oo$BKg#|j;>|V_8~`9o z_+JI$@3L=dZ{lia26cI=4@Wt#oR)Y&0m?P*MtfEtz}%AipQ3EC%VIc)?B68IEv#%g zqELxpv&pam7<4={gAa2}RxcTxli+0%ZrHZpomA%Y7>d!wv%j&x4oI+{r#8}?8;FQb>TZJ#k_v(9PU)ABe*Wmx7ZH7C zY`T1@DBuHO4cBMy%p^ylrgW%c2b?q_u8LtKr+b^4d0bn3Z$&5@8$8P3-pCiXs}H(H zeHZUDQw6*#fg5i3J~Yhth>HEYFEHewe65@fP#(6Q=r zOr@*hK@pYMQ9idYRvg3Yy32~zT)Jyim=aJRr}y*9b~(d9WGJfJ_)IUHmacIbd4L(; z4-y%~om_(REPoCDNVvDJ+ax@GHWDUTmrNghA}Q{!Qm7x*&$+bKG%|ek^75tQYP?>D zn6tXMEWz;@WMpL5ACdx>a!pTy`uS7y`3?rEm2W=7Y}&A(gr7+4NlnI!Wt7O~w&Ohh znd(W(S)gm5R<+EUDeiEc`(X~!U8!V?dl_kviuuiU*)IB7X8Z9^@+Fhp3#xX5ui0EK zHwf{OWI%1L7cv7SZ@`f7X`l4Eu%DVrjF9qH35h60fteN-@GJPV;GTmOE4Kot%u=~~ z#D-;bT*SK17tud1ta+12*{Vdz3My0LAfFn9A0NK@4536JkB&^zzRz$SEHs_W%-}Gp z%1G;z!~Q-a)gn^;X33A{in2rMW$JL<9L$e^`?~n|L~Sg1m8;Nk6h^L19wnc9*Fs?y zqEXi#SN;J6f+W(*O0C4@J#~X4{(H9t(5q3ih>gTq@r{G5B|X@~7O%siS>{{~L+2J; z&B5xL$rOdK4!>FYbw#;1m5J>GGK2Y1RPkw#EOEK^^cH4a2fUdZ-!kM}k8ftxa=My& z)XhGmZLj%?`p{v0tvzz1_5Q3V;wb59qOAXt({G#BZGp~v))nyt_j30*_h@j1GLk7f zO{o5DT4R1J2}U|r`oyu~uCp)^nkJkkoMuBOb#Lz`O`?(P)5y}ET2c>-sph8g=5F=6 zW}8KD#%As2x3;kzgKHAtbzLkOTY%nA$&U^P61A5SEt_QfsJqn^-t%8)_GvR0DMyUc zr476A7RZ+*8Q$?x&S_PDv;4wQ>~eq`y$!e7Jl214`0!%4A{qE@pIMHUiRGL@YQQQQ z#K@qMyNt`*2i%n8O4+4nU9R_YG$P4?On$~X@M=gPTNY?!D9dEIohI&3ijGz$y=C3*Q8z z_iSV~tS??;yheNt$pN+*xD0>-cmkevqpu`TM3M90RA3k=QQ-d9#dreroY&2FPJT*vq6t>ko%`qnO@AiB8h%$kC5YK}Z-(M_ z%f;8capXTwx>t0=r87Ugi9+20o5z7Fk&B)4c^SHH-4;Bx0J)tT#Vax#es!%Z#PI#4eShzl*xu+iN&^M;E{SFrFeiiZ5{7t$g9#cDhXdVNQRl z`e{pQp>VRp1)g`EBe6)ymhRC(IbVz=`4EnH^6*5+OSTNqoMSLHqd1PchUEsCwdIDm z<&U(c@&`BCBBAp$mccf1$J7D8;AYr{2i1;MJfhH9Z@fZPs*>4N2~dK+_KV#?bZVs% zdhvX0&DRkG12J`z)A^Q`>)~+D`P7|zeHJG)Y;Y(2;bKeSkvnFnLGwu1~`2SnC#Nh?%8t#g{EXgKq|7k%stLekNTFvx(WXf3ai>K17DWBGg3Qs64I~Gj|IhIJEWb+gGKj zXJ|pH>#|-Ig0d&9Lb8a0L$!jRl7y(;nfQ`CIPI_uF+KsccgB&bRU+QZbu|t|;4qhX zRVEY|;3|p5DhhUNlUx|;Bqw;h7B(GnGVk=+qyG|>xRV&ejtRlAoZ1qSK^M<_9>)0* zf{B31i(PO!M^(62jbe2ZPBi60S;&`~u!De_>Vz4MP`f>tO{!2z=F%0kMUilg4NEj0 zpKL!(8sWD~5cqkaTy*D<6*hwmj$Nde`LX2A)9L{B-SFGG=Gw`zg*BN4=*qYjIo(+T z#NiSHosoOosLa{0(l#=tXU(mGhCSBKQYL5}w@9F6H)2x8+DW zh#YLlK6Ao~+ku~ec$ntvQspCErh4z@ttnGR)aAHwP)&XAnem*CeNtJ?CFVT~O`DQg z-C66`3OO=dtt@MZ1a5qdMms~>2ZVX&^LhCy9YKNX=zc53h}zA5tBSOZz;i4Ah|qxj zYVyt3uC)GC0lp-e$IPi7P2a!;um>2Cwt~irS+6paY<{E0 zMQ1w|Um9LOQ3K`zINjc0R;Ya}pZ+`V{++d#xYsnDK@KAE`nIC7>99{}7?_e3_`~VE zkD)I-K&YF{=!CEqG1&08{7xO9H=5DG;n9vMgIoxwM#jg;VpG}uey)@;tzZ(lY~on} zbLBWB3hzpt&qF~QyxSm)DIe4l*uvGl40Xt_q^W-vpRdl)@2uQvME^9-+^D`2I=^_H z@!THv0(b$uV6!KGygeB+DCR5PE+;-4n550;JiEauDz4OjUu#?sYeZUup^aE6U^E-5 zU_TYa9EW>A#UVCPI22HFF~!$xcF`?}@kP+Mm*@dNcprt@ zaA-b5XM`ihvY0efDt+h^n5*>kLcVxJvd(JikoE(#OD3aZE42i#gZ*UyrO74s#^tr< z1d-pWjUtC`2}ZT5CvJgE<4^ao;ChF{R;4vp7xq&Y-QZs6*@oY!y617<*u{R8^O8-e zh5zYjlb!A`TgPK_Jpsk#^k{j`i)v(!!e;9)Ko204G=>Ld{y40g``9PE`B;74G`ERV zzl4z*?B(Hbr&Qg2exT9p*TJJ--FejLa0IBf5Eqy5u2xvFHe6X_>q$m%gtzqBQp@UR zi*AC2fop^<>xh`f52dQ1SB&9loiU(SS1RS%HQzpv<(WIePgX0yl=%R8D>k*l-X&LO z>XtBGiz{uOS;UK`v6eo*mJTCQJo%M#GO%dkb=s-_MWs&D`?0s?hCVw**m2ugkFZa= zPLA}{3L82AU@i*$51EzZFI~sb$;{UIU%M{I)0wIyd23iUv@qof0m37JT$-X3kTN%I zf?Wn#cgCb(#PetJj5$klxIcohTGNaC3Y6a_%w>_EO!Lr@!4hfX(lQj%HBg@;bnYLW zJ!8O^uW}8X=ng^4+PAuo9Fsdkb^WN`HY>W=h^lgqdn$4`;c600{*KR!riDYCBWkOkm&0yf6)ii7s$O(e zOM9$r0zPT+nACt|Y?3;1CL84P(_6vwB)X5!i{_O5fX&p&!#AqyhSOlxr)Hnv$yFwy zIi%|V0H74+zqY2R007{By!3}>V#ftAdRfsB)^Hrc2L%*I0<%B(4N3$+HU5WcN9uK;CrcxlZ~5_*D=`8%zZ zd875+rcA}D;2k4-Qk>^sW^RRO77io2n6ckjNkHjd`o(o(O+ie8xQ=l33oB7cZ|&n?HPY5@QM z82DdriUR-u^d#(|E@n^{Lv>FFGv`-N+wjI@#V46I^hu_*SKa7^p`30&^-Jx}Co$Sr z&_#V5;$S>F%4ndBE|;kp9NXkMTltnKXn5SgOMiy`PYPLWH4S@!Z*KBJ(r8kP03Sg6d+rP)&+w0ZzK|d|qeH=y5}2 zAe+NbN4W0iw>6<-j;9{2Csj7^jC?i$q4Log;M_~9T-ICN$JbDTOpbIXKpA_h38tN0 z{=peQwM^L~dDL`it&7TdNjF%LGbb%^pJ|6~+cH5Wb^n#*Aae=jIVpQr5P{xT_kHq4 zVlqB-7;=&a1czz5So?k(c$@GvWGPRzh>2@1b3Vf`!fjbfss3Q}G_iryKne1$m5pal zUlQQqc#Iqf0JOqB`4`yYuKb8*svxoI-ujF_5 zuR8C)Zx4n26aFtz{&)PZ`puIX{EyMY|8@Jnwc+2vzb2!9KYKj#pWt5wpWorX67(r! z{bP^#f5QKd{Pp`vzY^ey(Ek{i@L%-)9r$ZxpZM{Q;S&9?Y*CSiM|hfq1V92j0s#OQ I;wQ-e1EA-uc>n+a literal 0 HcmV?d00001 From f1d7ef76e7f28cce1bee01f47af6229903327bd9 Mon Sep 17 00:00:00 2001 From: rabelaiis Date: Tue, 1 Aug 2017 23:41:16 +0700 Subject: [PATCH 30/38] Add the mallet js file --- .../marketplace/xylophone/xylophoneMallet.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 unpublishedScripts/marketplace/xylophone/xylophoneMallet.js diff --git a/unpublishedScripts/marketplace/xylophone/xylophoneMallet.js b/unpublishedScripts/marketplace/xylophone/xylophoneMallet.js new file mode 100644 index 0000000000..061d1303bb --- /dev/null +++ b/unpublishedScripts/marketplace/xylophone/xylophoneMallet.js @@ -0,0 +1,25 @@ +// +// xylophoneMallet.js +// +// Created by Johnathan Franck on 07/30/2017 +// Copyright 2017 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 + +(function() { + function XylophoneMallet() { + } + + XylophoneMallet.prototype = { + startEquip: function(entityID, args) { + var LEFT_HAND = 0; + var RIGHT_HAND = 1; + var userData = JSON.parse(Entities.getEntityProperties(entityID, 'userData').userData); + userData.hand = args[0] === "left" ? LEFT_HAND : RIGHT_HAND; + Entities.editEntity(entityID, {userData: JSON.stringify(userData)}); + } + }; + + return new XylophoneMallet(); +}); From 3a9b8c02a6532f4c414897bd8d28ee5d271db482 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 1 Aug 2017 13:41:28 -0400 Subject: [PATCH 31/38] * disable Avatar "follow" / recentering behavior when using HMD + "View > Mirror" * restore access to "View > Mirror" from HMD mode --- interface/src/Application.cpp | 6 ++---- interface/src/avatar/MyAvatar.cpp | 3 ++- scripts/system/hmd.js | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 94d9d6e885..69359660af 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4483,11 +4483,9 @@ void Application::cameraModeChanged() { void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { - if (isHMDMode()) { - menu->setIsOptionChecked(MenuOption::FullscreenMirror, false); - menu->setIsOptionChecked(MenuOption::FirstPerson, true); - } else if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { + if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { _myCamera.setMode(CAMERA_MODE_MIRROR); + getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers } } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 490f22ed8b..160235d77e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2849,7 +2849,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - if (myAvatar.getHMDLeanRecenterEnabled()) { + if (myAvatar.getHMDLeanRecenterEnabled() && + qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); } diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index c545e6bcee..3598b461a4 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -40,9 +40,8 @@ function updateControllerDisplay() { var button; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); -// Independent and Entity mode make people sick. Third Person and Mirror have traps that we need to work through. -// Disable them in hmd. -var desktopOnlyViews = ['Mirror', 'Independent Mode', 'Entity Mode']; +// Independent and Entity mode make people sick; disable them in hmd. +var desktopOnlyViews = ['Independent Mode', 'Entity Mode']; function onHmdChanged(isHmd) { HMD.closeTablet(); From c22e08f3e8ac3e4a550f0d7f7e4316bd090109dc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 1 Aug 2017 19:58:23 +0100 Subject: [PATCH 32/38] loacked script engine in EntityEditPacketSender --- libraries/entities/src/EntityEditPacketSender.cpp | 1 + libraries/entities/src/EntityEditPacketSender.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 7845b0d5e3..ee0fcf8218 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -54,6 +54,7 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type, EntityItemProperties entityProperties = entity->getProperties(); entityProperties.merge(properties); + std::lock_guard lock(_mutex); QScriptValue scriptProperties = EntityItemNonDefaultPropertiesToScriptValue(&_scriptEngine, entityProperties); QVariant variantProperties = scriptProperties.toVariant(); QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index 9190a8296a..81efaa865c 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -14,6 +14,8 @@ #include +#include + #include "EntityItem.h" #include "AvatarData.h" @@ -49,6 +51,7 @@ private: EntityItemID entityItemID, const EntityItemProperties& properties); private: + std::mutex _mutex; AvatarData* _myAvatar { nullptr }; QScriptEngine _scriptEngine; }; From cca29e849b50a8b982144439b3ca46d2cb2f73d9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 1 Aug 2017 23:18:42 +0100 Subject: [PATCH 33/38] fix issue of tablet begin blank when switching between HMD and Desktop mode --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 43c460fd23..e7b736d232 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -236,7 +236,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { _desktopWindow = nullptr; } } - loadHomeScreen(true); emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL)); } From 1b6feb63c8d901d484dfac389fbf7bb4d1ff46b5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Aug 2017 18:40:43 -0700 Subject: [PATCH 34/38] Fix for crash when attempting to teleport while avatar was loading The fix had two parts. * Make Avatar::getAbsoluteDefaultJointXXXInObjectFrame thread safe * Make teleport.js handle a zero foot offset more gracefully, to prevent the avatar from teleporting into the floor. --- .../src/avatars-renderer/Avatar.cpp | 33 ++++++++++++++----- scripts/system/controllers/teleport.js | 8 ++++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 06814c2707..d775fe05f0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -899,17 +899,34 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const { } glm::quat Avatar::getAbsoluteDefaultJointRotationInObjectFrame(int index) const { - glm::quat rotation; - glm::quat rot = _skeletonModel->getRig().getAnimSkeleton()->getAbsoluteDefaultPose(index).rot(); - return Quaternions::Y_180 * rot; + // To make this thread safe, we hold onto the model by smart ptr, which prevents it from being deleted while we are accessing it. + auto model = getSkeletonModel(); + if (model) { + auto skeleton = model->getRig().getAnimSkeleton(); + if (skeleton && index >= 0 && index < skeleton->getNumJoints()) { + // The rotation part of the geometry-to-rig transform is always identity so we can skip it. + // Y_180 is to convert from rig-frame into avatar-frame + return Quaternions::Y_180 * skeleton->getAbsoluteDefaultPose(index).rot(); + } + } + return Quaternions::Y_180; } glm::vec3 Avatar::getAbsoluteDefaultJointTranslationInObjectFrame(int index) const { - glm::vec3 translation; - const Rig& rig = _skeletonModel->getRig(); - glm::vec3 trans = rig.getAnimSkeleton()->getAbsoluteDefaultPose(index).trans(); - glm::mat4 y180Mat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3()); - return transformPoint(y180Mat * rig.getGeometryToRigTransform(), trans); + // To make this thread safe, we hold onto the model by smart ptr, which prevents it from being deleted while we are accessing it. + auto model = getSkeletonModel(); + if (model) { + const Rig& rig = model->getRig(); + auto skeleton = rig.getAnimSkeleton(); + if (skeleton && index >= 0 && index < skeleton->getNumJoints()) { + // trans is in geometry frame. + glm::vec3 trans = skeleton->getAbsoluteDefaultPose(index).trans(); + // Y_180 is to convert from rig-frame into avatar-frame + glm::mat4 geomToAvatarMat = Matrices::Y_180 * rig.getGeometryToRigTransform(); + return transformPoint(geomToAvatarMat, trans); + } + } + return Vectors::ZERO; } glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index b058ec670f..15ba314a1d 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -381,7 +381,13 @@ function getAvatarFootOffset() { } if (footJointIndex != -1) { // default vertical offset from foot to avatar root. - return -MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex).y; + var footPos = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex); + if (footPos.x === 0 && footPos.y === 0 && footPos.z === 0.0) { + // if footPos is exactly zero, it's probably wrong because avatar is currently loading, fall back to default. + return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; + } else { + return -footPos.y; + } } else { return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; } From 4330e312122448354b9f892ec5e306812d54fbf4 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 2 Aug 2017 16:32:09 +0200 Subject: [PATCH 35/38] Toolbar mode: 1. Fixed switching between different apps. 2. Fixed switching from Create --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- libraries/ui/src/ui/TabletScriptingInterface.cpp | 13 ++++++------- scripts/system/edit.js | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 03d27e3831..93742e39a5 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -33,7 +33,7 @@ Rectangle { // only show the title if loaded through a "loader" function showTitle() { - return root.parent.objectName == "loader"; + return (root.parent !== null) && root.parent.objectName == "loader"; } Column { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 37a2bae0bf..2bdad096f4 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -237,7 +237,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { } } loadHomeScreen(true); - emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL)); } static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) { @@ -463,14 +462,14 @@ void TabletProxy::loadQMLSource(const QVariant& path) { } if (root) { - if (_state != State::QML) { - removeButtonsFromHomeScreen(); - QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path)); - _state = State::QML; + removeButtonsFromHomeScreen(); //works only in Tablet + QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path)); + _state = State::QML; + if (path != _currentPathLoaded) { emit screenChanged(QVariant("QML"), path); - _currentPathLoaded = path; - QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); } + _currentPathLoaded = path; + QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); } else { qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null"; } diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 06260277fd..046cd2e66a 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -419,7 +419,7 @@ var toolBar = (function () { createButton = activeButton; tablet.screenChanged.connect(function (type, url) { if (isActive && (type !== "QML" || url !== "Edit.qml")) { - that.toggle(); + that.setActive(false) } }); tablet.fromQml.connect(fromQml); From 05f1caab01b8fa1a0e872c92898559a81c0148b4 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 2 Aug 2017 16:35:58 +0100 Subject: [PATCH 36/38] better solution to help and blank tablet issues --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index e7b736d232..603b85c160 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -228,7 +228,12 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml); } else { removeButtonsFromToolbar(); - addButtonsToHomeScreen(); + + if (_currentPathLoaded == TABLET_SOURCE_URL) { + addButtonsToHomeScreen(); + } else { + loadHomeScreen(true); + } // destroy desktop window if (_desktopWindow) { From 7d361c69c2493e6198c19a5fe750be87f60d3e4d Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 2 Aug 2017 19:52:47 +0200 Subject: [PATCH 37/38] Audio mic bar show only rectangle on mouse over --- interface/resources/qml/hifi/audio/MicBar.qml | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index 10e12551b7..e757d7cadf 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -27,7 +27,7 @@ Rectangle { color: "#00000000"; border { - width: (standalone || Audio.muted || mouseArea.containsMouse) ? 2 : 0; + width: mouseArea.containsMouse || mouseArea.containsPress ? 2 : 0; color: colors.border; } @@ -61,7 +61,7 @@ Rectangle { drag.target: dragTarget; } - Item { + QtObject { id: colors; readonly property string unmuted: "#FFF"; @@ -72,7 +72,7 @@ Rectangle { readonly property string red: colors.muted; readonly property string fill: "#55000000"; readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF"; - readonly property string icon: (Audio.muted && !mouseArea.containsMouse) ? muted : unmuted; + readonly property string icon: Audio.muted ? muted : unmuted; } Item { @@ -92,10 +92,8 @@ Rectangle { readonly property string unmutedIcon: "../../../icons/tablet-icons/mic-unmute-i.svg"; readonly property string mutedIcon: "../../../icons/tablet-icons/mic-mute-i.svg"; - function exclusiveOr(a, b) { return (a || b) && !(a && b); } - id: image; - source: exclusiveOr(Audio.muted, mouseArea.containsMouse) ? mutedIcon : unmutedIcon; + source: Audio.muted ? mutedIcon : unmutedIcon; width: 30; height: 30; @@ -118,9 +116,9 @@ Rectangle { Item { id: status; - readonly property string color: (Audio.muted && !mouseArea.containsMouse) ? colors.muted : colors.unmuted; + readonly property string color: Audio.muted ? colors.muted : colors.unmuted; - visible: Audio.muted || mouseArea.containsMouse; + visible: Audio.muted; anchors { left: parent.left; @@ -133,14 +131,14 @@ Rectangle { Text { anchors { - horizontalCenter: parent.horizontalCenter; + horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter; } color: parent.color; - text: Audio.muted ? (mouseArea.containsMouse ? "UNMUTE" : "MUTED") : "MUTE"; - font.pointSize: 12; + text: Audio.muted ? "MUTED" : "MUTE"; + font.pointSize: 12; } Rectangle { @@ -150,7 +148,7 @@ Rectangle { } width: 50; - height: 4; + height: 4; color: parent.color; } @@ -161,7 +159,7 @@ Rectangle { } width: 50; - height: 4; + height: 4; color: parent.color; } } From 3c1607715ecaec1952d9aadfdfcf7d562b79f5f2 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 2 Aug 2017 17:42:56 -0700 Subject: [PATCH 38/38] Updated WASAPI plugin --- cmake/externals/wasapi/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt index 1bf195fc84..4437024962 100644 --- a/cmake/externals/wasapi/CMakeLists.txt +++ b/cmake/externals/wasapi/CMakeLists.txt @@ -6,8 +6,8 @@ if (WIN32) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi8.zip - URL_MD5 b01510437ea15527156bc25cdf733bd9 + URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi9.zip + URL_MD5 94f4765bdbcd53cd099f349ae031e769 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ""