From 5d812c8cb221253e160f1664609e05dfb9db129f Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 9 Apr 2014 23:44:40 +0200 Subject: [PATCH 1/9] Fixed loading local stored scripts on Windows machines --- libraries/script-engine/src/ScriptEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 7d3dd650ae..c5c1fdb2bf 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -92,8 +92,9 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, QUrl url(scriptURL); - // if the scheme is empty, maybe they typed in a file, let's try - if (url.scheme().isEmpty()) { + // if the scheme length is one or lower, maybe they typed in a file, let's try + const DWORD WINDOWS_DRIVE_LETTER_SIZE = 1; + if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { url = QUrl::fromLocalFile(scriptURLString); } From 9f58264cb692f6518013e7da8cecdfbba2c8974e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 9 Apr 2014 18:07:56 -0700 Subject: [PATCH 2/9] Working on plane collisions, pushing back camera from intersecting avatars. --- interface/src/Application.cpp | 13 ++++ interface/src/avatar/Avatar.cpp | 5 ++ interface/src/avatar/Avatar.h | 6 ++ interface/src/renderer/Model.cpp | 15 +++++ interface/src/renderer/Model.h | 2 + libraries/shared/src/PlaneShape.h | 30 +++++++++ libraries/shared/src/Shape.h | 1 + libraries/shared/src/ShapeCollider.cpp | 86 ++++++++++++++++++++++++++ libraries/shared/src/ShapeCollider.h | 43 +++++++++++++ 9 files changed, 201 insertions(+) create mode 100644 libraries/shared/src/PlaneShape.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6005ae085e..f91ede9f3e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -522,6 +522,19 @@ void Application::paintGL() { _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + // push camera out of any intersecting avatars + float pushback = 0.0f; + foreach (const AvatarSharedPointer& avatarData, _avatarManager.getAvatarHash()) { + Avatar* avatar = static_cast(avatarData.data()); + const float RADIUS_MULTIPLIER = 2.0f; + CollisionList collisions(4); + if (!avatar->isMyAvatar() && avatar->findSphereCollisions(_myCamera.getTargetPosition(), + _myCamera.getNearClip() * RADIUS_MULTIPLIER, collisions)) { + for (int i = 0; i < collisions.size(); i++) { + collisions.getCollision(i)->_penetration; + } + } + } } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 47ced025aa..70a328eeea 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -522,6 +522,11 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet //return getHead()->getFaceModel().findSphereCollisions(penetratorCenter, penetratorRadius, collisions); } +bool Avatar::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) { + return _skeletonModel.findPlaneCollisions(plane, collisions) || + getHead()->getFaceModel().findPlaneCollisions(plane, collisions); +} + void Avatar::updateShapePositions() { _skeletonModel.updateShapePositions(); Model& headModel = getHead()->getFaceModel(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 4e24c00c7e..78a815cca5 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -119,6 +119,12 @@ public: bool findSphereCollisions(const glm::vec3& penetratorCenter, float penetratorRadius, CollisionList& collisions, int skeletonSkipIndex = -1); + /// Checks for penetration between the described plane and the avatar. + /// \param plane the penetration plane + /// \param collisions[out] a list to which collisions get appended + /// \return whether or not the plane penetrated + bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions); + /// Checks for collision between the a spherical particle and the avatar (including paddle hands) /// \param collisionCenter the center of particle's bounding sphere /// \param collisionRadius the radius of particle's bounding sphere diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 819d1164c0..2635c6a8bc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -634,6 +634,21 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi return collided; } +bool Model::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) { + bool collided = false; + PlaneShape planeShape(plane); + for (int i = 0; i < _jointShapes.size(); i++) { + if (ShapeCollider::shapeShape(&planeShape, _jointShapes[i], collisions)) { + CollisionInfo* collision = collisions.getLastCollision(); + collision->_type = MODEL_COLLISION; + collision->_data = (void*)(this); + collision->_flags = i; + collided = true; + } + } + return collided; +} + class Blender : public QRunnable { public: diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 30625cc16f..65b79fffdd 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -176,6 +176,8 @@ public: bool findSphereCollisions(const glm::vec3& penetratorCenter, float penetratorRadius, CollisionList& collisions, int skipIndex = -1); + + bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions); /// \param collision details about the collisions /// \return true if the collision is against a moveable joint diff --git a/libraries/shared/src/PlaneShape.h b/libraries/shared/src/PlaneShape.h new file mode 100644 index 0000000000..11823da701 --- /dev/null +++ b/libraries/shared/src/PlaneShape.h @@ -0,0 +1,30 @@ +// +// PlaneShape.h +// libraries/shared/src +// +// Created by Andrzej Kapolka on 4/9/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PlaneShape_h +#define hifi_PlaneShape_h + +#include "Shape.h" + +class PlaneShape : public Shape { +public: + PlaneShape() : Shape(Shape::PLANE_SHAPE) {} + + PlaneShape(const glm::vec4& coefficients) : Shape(Shape::PLANE_SHAPE), _coefficients(coefficients) { } + + const glm::vec4& getCoefficients() const { return _coefficients; } + +private: + + glm::vec4 _coefficients; +}; + +#endif // hifi_PlaneShape_h diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index fd16eafeae..87b84ea73b 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -22,6 +22,7 @@ public: UNKNOWN_SHAPE = 0, SPHERE_SHAPE, CAPSULE_SHAPE, + PLANE_SHAPE, BOX_SHAPE, LIST_SHAPE }; diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index b13775dfa8..15b01719af 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -13,6 +13,7 @@ #include +#include "GeometryUtil.h" #include "ShapeCollider.h" // NOTE: @@ -33,6 +34,8 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi return sphereSphere(sphereA, static_cast(shapeB), collisions); } else if (typeB == Shape::CAPSULE_SHAPE) { return sphereCapsule(sphereA, static_cast(shapeB), collisions); + } else if (typeB == Shape::PLANE_SHAPE) { + return spherePlane(sphereA, static_cast(shapeB), collisions); } } else if (typeA == Shape::CAPSULE_SHAPE) { const CapsuleShape* capsuleA = static_cast(shapeA); @@ -40,6 +43,17 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi return capsuleSphere(capsuleA, static_cast(shapeB), collisions); } else if (typeB == Shape::CAPSULE_SHAPE) { return capsuleCapsule(capsuleA, static_cast(shapeB), collisions); + } else if (typeB == Shape::PLANE_SHAPE) { + return capsulePlane(capsuleA, static_cast(shapeB), collisions); + } + } else if (typeA == Shape::PLANE_SHAPE) { + const PlaneShape* planeA = static_cast(shapeA); + if (typeB == Shape::SPHERE_SHAPE) { + return planeSphere(planeA, static_cast(shapeB), collisions); + } else if (typeB == Shape::CAPSULE_SHAPE) { + return planeCapsule(planeA, static_cast(shapeB), collisions); + } else if (typeB == Shape::PLANE_SHAPE) { + return planePlane(planeA, static_cast(shapeB), collisions); } } else if (typeA == Shape::LIST_SHAPE) { const ListShape* listA = static_cast(shapeA); @@ -47,6 +61,8 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi return listSphere(listA, static_cast(shapeB), collisions); } else if (typeB == Shape::CAPSULE_SHAPE) { return listCapsule(listA, static_cast(shapeB), collisions); + } else if (typeB == Shape::PLANE_SHAPE) { + return listPlane(listA, static_cast(shapeB), collisions); } } return false; @@ -143,6 +159,20 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col return false; } +bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, CollisionList& collisions) { + glm::vec3 penetration; + if (findSpherePlanePenetration(sphereA->getPosition(), sphereA->getRadius(), planeB->getCoefficients(), penetration)) { + CollisionInfo* collision = collisions.getNewCollision(); + if (!collision) { + return false; // collision list is full + } + collision->_penetration = penetration; + collision->_contactPoint = glm::vec3(); + return true; + } + return false; +} + bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, CollisionList& collisions) { // find sphereB's closest approach to axis of capsuleA glm::vec3 AB = capsuleA->getPosition() - sphereB->getPosition(); @@ -349,6 +379,22 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, return false; } +bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, CollisionList& collisions) { + return false; +} + +bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, CollisionList& collisions) { + return false; +} + +bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, CollisionList& collisions) { + return false; +} + +bool planePlane(const PlaneShape* planeA, const PlaneShape* planeB, CollisionList& collisions) { + return false; +} + bool sphereList(const SphereShape* sphereA, const ListShape* listB, CollisionList& collisions) { bool touching = false; for (int i = 0; i < listB->size() && !collisions.isFull(); ++i) { @@ -358,6 +404,8 @@ bool sphereList(const SphereShape* sphereA, const ListShape* listB, CollisionLis touching = sphereSphere(sphereA, static_cast(subShape), collisions) || touching; } else if (subType == Shape::CAPSULE_SHAPE) { touching = sphereCapsule(sphereA, static_cast(subShape), collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = spherePlane(sphereA, static_cast(subShape), collisions) || touching; } } return touching; @@ -372,6 +420,24 @@ bool capsuleList(const CapsuleShape* capsuleA, const ListShape* listB, Collision touching = capsuleSphere(capsuleA, static_cast(subShape), collisions) || touching; } else if (subType == Shape::CAPSULE_SHAPE) { touching = capsuleCapsule(capsuleA, static_cast(subShape), collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = capsulePlane(capsuleA, static_cast(subShape), collisions) || touching; + } + } + return touching; +} + +bool planeList(const PlaneShape* planeA, const ListShape* listB, CollisionList& collisions) { + bool touching = false; + for (int i = 0; i < listB->size() && !collisions.isFull(); ++i) { + const Shape* subShape = listB->getSubShape(i); + int subType = subShape->getType(); + if (subType == Shape::SPHERE_SHAPE) { + touching = planeSphere(planeA, static_cast(subShape), collisions) || touching; + } else if (subType == Shape::CAPSULE_SHAPE) { + touching = planeCapsule(planeA, static_cast(subShape), collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = planePlane(planeA, static_cast(subShape), collisions) || touching; } } return touching; @@ -386,6 +452,8 @@ bool listSphere(const ListShape* listA, const SphereShape* sphereB, CollisionLis touching = sphereSphere(static_cast(subShape), sphereB, collisions) || touching; } else if (subType == Shape::CAPSULE_SHAPE) { touching = capsuleSphere(static_cast(subShape), sphereB, collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = planeSphere(static_cast(subShape), sphereB, collisions) || touching; } } return touching; @@ -400,6 +468,24 @@ bool listCapsule(const ListShape* listA, const CapsuleShape* capsuleB, Collision touching = sphereCapsule(static_cast(subShape), capsuleB, collisions) || touching; } else if (subType == Shape::CAPSULE_SHAPE) { touching = capsuleCapsule(static_cast(subShape), capsuleB, collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = planeCapsule(static_cast(subShape), capsuleB, collisions) || touching; + } + } + return touching; +} + +bool listPlane(const ListShape* listA, const PlaneShape* planeB, CollisionList& collisions) { + bool touching = false; + for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) { + const Shape* subShape = listA->getSubShape(i); + int subType = subShape->getType(); + if (subType == Shape::SPHERE_SHAPE) { + touching = spherePlane(static_cast(subShape), planeB, collisions) || touching; + } else if (subType == Shape::CAPSULE_SHAPE) { + touching = capsulePlane(static_cast(subShape), planeB, collisions) || touching; + } else if (subType == Shape::PLANE_SHAPE) { + touching = planePlane(static_cast(subShape), planeB, collisions) || touching; } } return touching; diff --git a/libraries/shared/src/ShapeCollider.h b/libraries/shared/src/ShapeCollider.h index 7f02acf15c..0e6dac208c 100644 --- a/libraries/shared/src/ShapeCollider.h +++ b/libraries/shared/src/ShapeCollider.h @@ -15,6 +15,7 @@ #include "CapsuleShape.h" #include "CollisionInfo.h" #include "ListShape.h" +#include "PlaneShape.h" #include "SharedUtil.h" #include "SphereShape.h" @@ -38,6 +39,12 @@ namespace ShapeCollider { /// \return true if shapes collide bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, CollisionList& collisions); + /// \param sphereA pointer to first shape + /// \param planeB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, CollisionList& collisions); + /// \param capsuleA pointer to first shape /// \param sphereB pointer to second shape /// \param[out] collisions where to append collision details @@ -50,6 +57,30 @@ namespace ShapeCollider { /// \return true if shapes collide bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, CollisionList& collisions); + /// \param capsuleA pointer to first shape + /// \param planeB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, CollisionList& collisions); + + /// \param planeA pointer to first shape + /// \param sphereB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, CollisionList& collisions); + + /// \param planeA pointer to first shape + /// \param capsuleB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, CollisionList& collisions); + + /// \param planeA pointer to first shape + /// \param planeB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool planePlane(const PlaneShape* planeA, const PlaneShape* planeB, CollisionList& collisions); + /// \param sphereA pointer to first shape /// \param listB pointer to second shape /// \param[out] collisions where to append collision details @@ -62,6 +93,12 @@ namespace ShapeCollider { /// \return true if shapes collide bool capsuleList(const CapsuleShape* capsuleA, const ListShape* listB, CollisionList& collisions); + /// \param planeA pointer to first shape + /// \param listB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool planeList(const PlaneShape* planeA, const ListShape* listB, CollisionList& collisions); + /// \param listA pointer to first shape /// \param sphereB pointer to second shape /// \param[out] collisions where to append collision details @@ -74,6 +111,12 @@ namespace ShapeCollider { /// \return true if shapes collide bool listCapsule(const ListShape* listA, const CapsuleShape* capsuleB, CollisionList& collisions); + /// \param listA pointer to first shape + /// \param planeB pointer to second shape + /// \param[out] collisions where to append collision details + /// \return true if shapes collide + bool listPlane(const ListShape* listA, const PlaneShape* planeB, CollisionList& collisions); + /// \param listA pointer to first shape /// \param capsuleB pointer to second shape /// \param[out] collisions where to append collision details From 825acbbd9cfe529745af12a45cf5a6e8efa1532d Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 10 Apr 2014 10:47:21 +0200 Subject: [PATCH 3/9] Update ScriptEngine.cpp DWORD is not defined in UNIX based systems. int should be fine --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c5c1fdb2bf..c857e1193a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -93,7 +93,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, QUrl url(scriptURL); // if the scheme length is one or lower, maybe they typed in a file, let's try - const DWORD WINDOWS_DRIVE_LETTER_SIZE = 1; + const int WINDOWS_DRIVE_LETTER_SIZE = 1; if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { url = QUrl::fromLocalFile(scriptURLString); } From a12dd916fafe29cdc532c267af84e169c1392ab0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 10 Apr 2014 11:24:45 -0700 Subject: [PATCH 4/9] More plane intersection bits. --- interface/src/renderer/Model.cpp | 2 +- libraries/shared/src/PlaneShape.h | 10 ++---- libraries/shared/src/ShapeCollider.cpp | 43 +++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a317ddc07a..2d47a077b7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -638,7 +638,7 @@ bool Model::findPlaneCollisions(const glm::vec4& plane, CollisionList& collision bool collided = false; PlaneShape planeShape(plane); for (int i = 0; i < _jointShapes.size(); i++) { - if (ShapeCollider::shapeShape(&planeShape, _jointShapes[i], collisions)) { + if (ShapeCollider::collideShapes(&planeShape, _jointShapes[i], collisions)) { CollisionInfo* collision = collisions.getLastCollision(); collision->_type = MODEL_COLLISION; collision->_data = (void*)(this); diff --git a/libraries/shared/src/PlaneShape.h b/libraries/shared/src/PlaneShape.h index 11823da701..524d53ec73 100644 --- a/libraries/shared/src/PlaneShape.h +++ b/libraries/shared/src/PlaneShape.h @@ -16,15 +16,9 @@ class PlaneShape : public Shape { public: - PlaneShape() : Shape(Shape::PLANE_SHAPE) {} - - PlaneShape(const glm::vec4& coefficients) : Shape(Shape::PLANE_SHAPE), _coefficients(coefficients) { } + PlaneShape(const glm::vec4& coefficients = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)); - const glm::vec4& getCoefficients() const { return _coefficients; } - -private: - - glm::vec4 _coefficients; + glm::vec4 getCoefficients() const; }; #endif // hifi_PlaneShape_h diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 10211f1d78..c53c7fab7d 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -191,7 +191,7 @@ bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, Collision return false; // collision list is full } collision->_penetration = penetration; - collision->_contactPoint = glm::vec3(); + collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * glm::normalize(penetration); return true; } return false; @@ -404,18 +404,59 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, } bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, CollisionList& collisions) { + glm::vec3 start, end, penetration; + capsuleA->getStartPoint(start); + capsuleA->getEndPoint(end); + glm::vec4 plane = planeB->getCoefficients(); + if (findCapsulePlanePenetration(start, end, capsuleA->getRadius(), plane, penetration)) { + CollisionInfo* collision = collisions.getNewCollision(); + if (!collision) { + return false; // collision list is full + } + collision->_penetration = penetration; + glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end; + collision->_contactPoint = deepestEnd + capsuleA->getRadius() * glm::normalize(penetration); + return true; + } return false; } bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, CollisionList& collisions) { + glm::vec3 penetration; + if (findSpherePlanePenetration(sphereB->getPosition(), sphereB->getRadius(), planeA->getCoefficients(), penetration)) { + CollisionInfo* collision = collisions.getNewCollision(); + if (!collision) { + return false; // collision list is full + } + collision->_penetration = -penetration; + collision->_contactPoint = sphereB->getPosition() + + (sphereB->getRadius() / glm::length(penetration) - 1.0f) * penetration; + return true; + } return false; } bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, CollisionList& collisions) { + glm::vec3 start, end, penetration; + capsuleB->getStartPoint(start); + capsuleB->getEndPoint(end); + glm::vec4 plane = planeA->getCoefficients(); + if (findCapsulePlanePenetration(start, end, capsuleB->getRadius(), plane, penetration)) { + CollisionInfo* collision = collisions.getNewCollision(); + if (!collision) { + return false; // collision list is full + } + collision->_penetration = -penetration; + glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end; + collision->_contactPoint = deepestEnd + (capsuleB->getRadius() / glm::length(penetration) - 1.0f) * penetration; + return true; + } return false; } bool planePlane(const PlaneShape* planeA, const PlaneShape* planeB, CollisionList& collisions) { + // technically, planes always collide unless they're parallel and not coincident; however, that's + // not going to give us any useful information return false; } From 873541dd7bcfae76691e6b9b12d0f429db8bdf32 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 10 Apr 2014 11:56:17 -0700 Subject: [PATCH 5/9] Trying out basic pushback for other avatars. --- interface/src/Application.cpp | 30 +++++++++++++++++------- libraries/shared/src/PlaneShape.cpp | 36 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 libraries/shared/src/PlaneShape.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index de612c80c0..d90b5835e5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -519,6 +519,7 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); + const float PUSHBACK_RADIUS = 0.2f; if (OculusManager::isConnected()) { _myCamera.setUpShift(0.0f); _myCamera.setDistance(0.0f); @@ -531,18 +532,32 @@ void Application::paintGL() { _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + glm::vec3 planeNormal = _myCamera.getTargetRotation() * IDENTITY_FRONT; + float combinedRadius = _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS; + glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - combinedRadius); + // push camera out of any intersecting avatars float pushback = 0.0f; foreach (const AvatarSharedPointer& avatarData, _avatarManager.getAvatarHash()) { Avatar* avatar = static_cast(avatarData.data()); - const float RADIUS_MULTIPLIER = 2.0f; - CollisionList collisions(4); - if (!avatar->isMyAvatar() && avatar->findSphereCollisions(_myCamera.getTargetPosition(), - _myCamera.getNearClip() * RADIUS_MULTIPLIER, collisions)) { - for (int i = 0; i < collisions.size(); i++) { - collisions.getCollision(i)->_penetration; - } + if (avatar->isMyAvatar()) { + continue; } + if (glm::distance(avatar->getPosition(), _myCamera.getTargetPosition()) > + avatar->getBoundingRadius() + combinedRadius) { + continue; + } + CollisionList collisions(4); + if (!avatar->findPlaneCollisions(plane, collisions)) { + continue; + } + for (int i = 0; i < collisions.size(); i++) { + pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration)); + } + } + if (pushback > 0.0f) { + _myCamera.setTargetPosition(_myCamera.getTargetPosition() + + _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); } } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing @@ -560,7 +575,6 @@ void Application::paintGL() { // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (eyePosition - _myCamera.getTargetPosition()); - const float PUSHBACK_RADIUS = 0.2f; float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS - _myCamera.getDistance(); if (pushback > 0.0f) { diff --git a/libraries/shared/src/PlaneShape.cpp b/libraries/shared/src/PlaneShape.cpp new file mode 100644 index 0000000000..a8b4468c93 --- /dev/null +++ b/libraries/shared/src/PlaneShape.cpp @@ -0,0 +1,36 @@ +// +// PlaneShape.cpp +// libraries/shared/src +// +// Created by Andrzej Kapolka on 4/10/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PlaneShape.h" +#include "SharedUtil.h" + +const glm::vec3 UNROTATED_NORMAL(0.0f, 1.0f, 0.0f); + +PlaneShape::PlaneShape(const glm::vec4& coefficients) : + Shape(Shape::PLANE_SHAPE) { + + glm::vec3 normal = glm::vec3(coefficients); + _position = -normal * coefficients.w; + + float angle = acosf(glm::dot(normal, UNROTATED_NORMAL)); + if (angle > EPSILON) { + if (angle > PI - EPSILON) { + _rotation = glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)); + } else { + _rotation = glm::angleAxis(angle, glm::normalize(glm::cross(UNROTATED_NORMAL, normal))); + } + } +} + +glm::vec4 PlaneShape::getCoefficients() const { + glm::vec3 normal = _rotation * UNROTATED_NORMAL; + return glm::vec4(normal.x, normal.y, normal.z, -glm::dot(normal, _position)); +} From 6cf971c849b6d9dd623aa4f40e29310709102202 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 10 Apr 2014 14:51:43 -0700 Subject: [PATCH 6/9] More intersection-avoidance tweaks. --- interface/src/Application.cpp | 21 ++++++++++++--------- interface/src/avatar/MyAvatar.cpp | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d90b5835e5..2ab73c9daf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -519,7 +519,6 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); - const float PUSHBACK_RADIUS = 0.2f; if (OculusManager::isConnected()) { _myCamera.setUpShift(0.0f); _myCamera.setDistance(0.0f); @@ -533,8 +532,9 @@ void Application::paintGL() { _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); glm::vec3 planeNormal = _myCamera.getTargetRotation() * IDENTITY_FRONT; - float combinedRadius = _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS; - glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - combinedRadius); + const float BASE_PUSHBACK_RADIUS = 0.25f; + float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS; + glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - pushbackRadius); // push camera out of any intersecting avatars float pushback = 0.0f; @@ -544,10 +544,11 @@ void Application::paintGL() { continue; } if (glm::distance(avatar->getPosition(), _myCamera.getTargetPosition()) > - avatar->getBoundingRadius() + combinedRadius) { + avatar->getBoundingRadius() + pushbackRadius) { continue; } - CollisionList collisions(4); + static CollisionList collisions(64); + collisions.clear(); if (!avatar->findPlaneCollisions(plane, collisions)) { continue; } @@ -555,10 +556,11 @@ void Application::paintGL() { pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration)); } } - if (pushback > 0.0f) { - _myCamera.setTargetPosition(_myCamera.getTargetPosition() + - _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); - } + const float MAX_PUSHBACK = 0.35f; + const float PUSHBACK_DECAY = 0.5f; + _myCamera.setDistance(qMax(qMin(pushback, MAX_PUSHBACK * _myAvatar->getScale()), + _myCamera.getDistance() * PUSHBACK_DECAY)); + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); @@ -575,6 +577,7 @@ void Application::paintGL() { // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (eyePosition - _myCamera.getTargetPosition()); + const float PUSHBACK_RADIUS = 0.2f; float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS - _myCamera.getDistance(); if (pushback > 0.0f) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7a05c593db..a4f4cce79d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -647,7 +647,7 @@ void MyAvatar::renderBody(RenderMode renderMode) { _skeletonModel.render(1.0f, modelRenderMode); // Render head so long as the camera isn't inside it - const float RENDER_HEAD_CUTOFF_DISTANCE = 0.40f; + const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; Camera* myCamera = Application::getInstance()->getCamera(); if (renderMode != NORMAL_RENDER_MODE || (glm::length(myCamera->getPosition() - getHead()->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale)) { From f0463a5679eb9ce774582403b1bd57ba5e7b88d8 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 11 Apr 2014 00:45:38 +0200 Subject: [PATCH 7/9] Fixed docking of ChatWindow Temporary Pin Icon, replace with a nice looking one please --- interface/resources/images/pin.svg | 98 ++++++++++++++++++++++++ interface/resources/images/pinned.svg | 106 ++++++++++++++++++++++++++ interface/resources/resources.qrc | 2 + interface/src/Menu.cpp | 2 +- interface/src/ui/ChatWindow.cpp | 19 ++++- interface/src/ui/ChatWindow.h | 2 + interface/ui/chatWindow.ui | 57 +++++++++++++- 7 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 interface/resources/images/pin.svg create mode 100644 interface/resources/images/pinned.svg diff --git a/interface/resources/images/pin.svg b/interface/resources/images/pin.svg new file mode 100644 index 0000000000..ec968a1ec1 --- /dev/null +++ b/interface/resources/images/pin.svg @@ -0,0 +1,98 @@ + + + + + + image/svg+xml + + Slice 1 + + + + + Slice 1 + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + diff --git a/interface/resources/images/pinned.svg b/interface/resources/images/pinned.svg new file mode 100644 index 0000000000..bda6f0e747 --- /dev/null +++ b/interface/resources/images/pinned.svg @@ -0,0 +1,106 @@ + + + + + + image/svg+xml + + Slice 1 + + + + + Slice 1 + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + diff --git a/interface/resources/resources.qrc b/interface/resources/resources.qrc index 35c0e40270..40428f0f80 100644 --- a/interface/resources/resources.qrc +++ b/interface/resources/resources.qrc @@ -4,5 +4,7 @@ images/kill-script.svg images/reload.svg images/stop.svg + images/pin.svg + images/pinned.svg diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8eead4acdc..9408f18c24 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1207,7 +1207,7 @@ void Menu::showMetavoxelEditor() { void Menu::showChat() { QMainWindow* mainWindow = Application::getInstance()->getWindow(); if (!_chatWindow) { - mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow()); + mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); } if (!_chatWindow->toggleViewAction()->isChecked()) { int width = _chatWindow->width(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 0060cb839c..8a83ba680b 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include "Application.h" #include "FlowLayout.h" @@ -35,7 +37,9 @@ ChatWindow::ChatWindow() : { ui->setupUi(this); - // remove the title bar (see the Qt docs on setTitleBarWidget) + // remove the title bar (see the Qt docs on setTitleBarWidget), but we keep it for undocking + // + titleBar = titleBarWidget(); setTitleBarWidget(new QWidget()); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); @@ -260,3 +264,16 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { } #endif + +void ChatWindow::togglePinned() { + QMainWindow* mainWindow = Application::getInstance()->getWindow(); + mainWindow->removeDockWidget(this); + if (ui->togglePinnedButton->isChecked()) { + mainWindow->addDockWidget(ui->togglePinnedButton->isChecked() ? Qt::RightDockWidgetArea : Qt::NoDockWidgetArea, this); + } + if (!this->toggleViewAction()->isChecked()) { + this->toggleViewAction()->trigger(); + } + this->setFloating(!ui->togglePinnedButton->isChecked()); + setTitleBarWidget(ui->togglePinnedButton->isChecked()?new QWidget():titleBar); +} \ No newline at end of file diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index cb9619cc42..614afc1ef1 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -50,12 +50,14 @@ private: void addTimeStamp(); Ui::ChatWindow* ui; + QWidget* titleBar; int numMessagesAfterLastTimeStamp; QDateTime lastMessageStamp; private slots: void connected(); void timeout(); + void togglePinned(); #ifdef HAVE_QXMPP void error(QXmppClient::Error error); void participantsChanged(); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 60a0c6badd..c46e692fc6 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -20,7 +20,7 @@ font-family: Helvetica, Arial, sans-serif; - QDockWidget::NoDockWidgetFeatures + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable Qt::NoDockWidgetArea @@ -79,6 +79,45 @@ + + + + + 0 + 0 + + + + + 16 + 16 + + + + Qt::NoFocus + + + + + + + :/images/pin.svg + :/images/pinned.svg:/images/pin.svg + + + true + + + true + + + false + + + true + + + @@ -204,6 +243,22 @@ + + togglePinnedButton + clicked() + ChatWindow + togglePinned() + + + 390 + 42 + + + 550 + 42 + + + closeButton clicked() From 197adce4debef454f373a40169341b8c8044723f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 10 Apr 2014 17:14:49 -0700 Subject: [PATCH 8/9] Fall intersection off with angle to other avatar. --- interface/src/Application.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8caf339a75..1f7ca11d71 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -547,13 +547,19 @@ void Application::paintGL() { avatar->getBoundingRadius() + pushbackRadius) { continue; } + float angle = angleBetween(avatar->getPosition() - _myCamera.getTargetPosition(), planeNormal); + if (angle > PI_OVER_TWO) { + continue; + } + float scale = qMax(angle / PI_OVER_TWO, 0.0f); + scale = 1.0f - powf(scale, 4.0f); static CollisionList collisions(64); collisions.clear(); if (!avatar->findPlaneCollisions(plane, collisions)) { continue; } for (int i = 0; i < collisions.size(); i++) { - pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration)); + pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration) * scale); } } const float MAX_PUSHBACK = 0.35f; From d712588b3616d20ef865267cf3633d07f728fe34 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 10 Apr 2014 17:35:47 -0700 Subject: [PATCH 9/9] Better rolloff. --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1f7ca11d71..84ce1f7efe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -551,8 +551,8 @@ void Application::paintGL() { if (angle > PI_OVER_TWO) { continue; } - float scale = qMax(angle / PI_OVER_TWO, 0.0f); - scale = 1.0f - powf(scale, 4.0f); + float scale = 1.0f - angle / PI_OVER_TWO; + scale = qMin(1.0f, scale * 2.5f); static CollisionList collisions(64); collisions.clear(); if (!avatar->findPlaneCollisions(plane, collisions)) {