From 6c289b682d9877c40e6c1d9aa16af19d122ef1cf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 11:18:50 -0700 Subject: [PATCH 01/37] move #include to cpp file --- libraries/avatars/src/AvatarData.cpp | 1 + libraries/avatars/src/AvatarData.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index bbfff8f025..ead5967c78 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 79ca638585..50c1608be8 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -45,7 +45,6 @@ typedef unsigned long long quint64; #include #include -#include #include From 9fc1c765d37c32e422a3ef91d300faccf3a5231b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 11:40:00 -0700 Subject: [PATCH 02/37] overhaul of CollisionInfo store Cube info for sphereAACube collisions --- interface/src/avatar/Avatar.cpp | 10 ++++---- interface/src/renderer/Model.cpp | 18 ++++++------- .../particles/src/ParticleCollisionSystem.cpp | 2 +- libraries/shared/src/CollisionInfo.cpp | 13 +++++++--- libraries/shared/src/CollisionInfo.h | 25 +++++++++++++------ libraries/shared/src/ShapeCollider.cpp | 21 ++++++++++++++++ 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bad4083fcf..1b3957322d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -634,8 +634,8 @@ bool Avatar::findParticleCollisions(const glm::vec3& particleCenter, float parti penetration)) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { - collision->_type = PADDLE_HAND_COLLISION; - collision->_flags = jointIndex; + collision->_type = COLLISION_TYPE_PADDLE_HAND; + collision->_intData = jointIndex; collision->_penetration = penetration; collision->_addedVelocity = palm->getVelocity(); collided = true; @@ -844,11 +844,11 @@ float Avatar::getHeadHeight() const { } bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const { - if (!collision._data || collision._type != MODEL_COLLISION) { + if (!collision._data || collision._type != COLLISION_TYPE_MODEL) { return false; } Model* model = static_cast(collision._data); - int jointIndex = collision._flags; + int jointIndex = collision._intData; if (model == &(_skeletonModel) && jointIndex != -1) { // collision response of skeleton is temporarily disabled @@ -856,7 +856,7 @@ bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const { //return _skeletonModel.collisionHitsMoveableJoint(collision); } if (model == &(getHead()->getFaceModel())) { - // ATM we always handle MODEL_COLLISIONS against the face. + // ATM we always handle COLLISION_TYPE_MODEL against the face. return true; } return false; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b8b4f1f2a0..f6aa3e9354 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -743,9 +743,9 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi } if (ShapeCollider::collideShapes(&sphere, _jointShapes[i], collisions)) { CollisionInfo* collision = collisions.getLastCollision(); - collision->_type = MODEL_COLLISION; + collision->_type = COLLISION_TYPE_MODEL; collision->_data = (void*)(this); - collision->_flags = i; + collision->_intData = i; collided = true; } outerContinue: ; @@ -759,9 +759,9 @@ bool Model::findPlaneCollisions(const glm::vec4& plane, CollisionList& collision for (int i = 0; i < _jointShapes.size(); i++) { if (ShapeCollider::collideShapes(&planeShape, _jointShapes[i], collisions)) { CollisionInfo* collision = collisions.getLastCollision(); - collision->_type = MODEL_COLLISION; + collision->_type = COLLISION_TYPE_MODEL; collision->_data = (void*)(this); - collision->_flags = i; + collision->_intData = i; collided = true; } } @@ -1210,15 +1210,15 @@ void Model::renderBoundingCollisionShapes(float alpha) { } bool Model::collisionHitsMoveableJoint(CollisionInfo& collision) const { - if (collision._type == MODEL_COLLISION) { + if (collision._type == COLLISION_TYPE_MODEL) { // the joint is pokable by a collision if it exists and is free to move - const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._flags]; + const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._intData]; if (joint.parentIndex == -1 || _jointStates.isEmpty()) { return false; } // an empty freeLineage means the joint can't move const FBXGeometry& geometry = _geometry->getFBXGeometry(); - int jointIndex = collision._flags; + int jointIndex = collision._intData; const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return !freeLineage.isEmpty(); } @@ -1226,12 +1226,12 @@ bool Model::collisionHitsMoveableJoint(CollisionInfo& collision) const { } void Model::applyCollision(CollisionInfo& collision) { - if (collision._type != MODEL_COLLISION) { + if (collision._type != COLLISION_TYPE_MODEL) { return; } glm::vec3 jointPosition(0.f); - int jointIndex = collision._flags; + int jointIndex = collision._intData; if (getJointPosition(jointIndex, jointPosition)) { const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; if (joint.parentIndex != -1) { diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 57a339d81f..358c5a1b84 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -224,7 +224,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { // (doing this prevents some "collision snagging" when particle penetrates the object) // HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against them. - if (collision->_type == PADDLE_HAND_COLLISION) { + if (collision->_type == COLLISION_TYPE_PADDLE_HAND) { // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle. // TODO: make this less hacky when we have more per-collision details float elasticity = ELASTICITY; diff --git a/libraries/shared/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp index 22929fbd51..38e3a4b2db 100644 --- a/libraries/shared/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -38,19 +38,24 @@ CollisionInfo* CollisionList::getLastCollision() { } void CollisionList::clear() { + // we rely on the external context to properly set or clear the data members of a collision + // whenever it is used. + /* for (int i = 0; i < _size; ++i) { // we only clear the important stuff CollisionInfo& collision = _collisions[i]; - collision._type = BASE_COLLISION; - collision._data = NULL; // CollisionInfo does not own whatever this points to. - collision._flags = 0; - // we rely on the consumer to properly overwrite these fields when the collision is "created" + collision._type = COLLISION_TYPE_UNKNOWN; + //collision._data = NULL; + //collision._intData = 0; + //collision._floatDAta = 0.0f; + //collision._vecData = glm::vec3(0.0f); //collision._damping; //collision._elasticity; //collision._contactPoint; //collision._penetration; //collision._addedVelocity; } + */ _size = 0; } diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index f014a31f36..52d5298fde 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -18,9 +18,14 @@ #include enum CollisionType { - BASE_COLLISION = 0, - PADDLE_HAND_COLLISION, - MODEL_COLLISION, + COLLISION_TYPE_UNKNOWN = 0, + COLLISION_TYPE_PADDLE_HAND, + COLLISION_TYPE_MODEL, + // _data = pointer to Model that owns joint + // _intData = joint index + COLLISION_TYPE_AACUBE, + // _floatData = cube side + // _vecData = cube center }; const quint32 COLLISION_GROUP_ENVIRONMENT = 1U << 0; @@ -39,7 +44,7 @@ public: CollisionInfo() : _type(0), _data(NULL), - _flags(0), + _intData(0), _damping(0.f), _elasticity(1.f), _contactPoint(0.f), @@ -50,7 +55,7 @@ public: CollisionInfo(qint32 type) : _type(type), _data(NULL), - _flags(0), + _intData(0), _damping(0.f), _elasticity(1.f), _contactPoint(0.f), @@ -60,9 +65,13 @@ public: ~CollisionInfo() {} - qint32 _type; // type of Collision (will determine what is supposed to be in _data and _flags) - void* _data; // pointer to user supplied data - quint32 _flags; // 32 bits for whatever + int _type; // type of Collision + + // the value of the *Data fields depend on the type + void* _data; + int _intData; + float _floatData; + glm::vec3 _vecData; float _damping; // range [0,1] of friction coeficient float _elasticity; // range [0,1] of energy conservation diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 348f8ac97d..f5836f373b 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -132,6 +132,7 @@ bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, Collis // penetration points from A into B CollisionInfo* collision = collisions.getNewCollision(); if (collision) { + collision->_type = COLLISION_TYPE_UNKNOWN; collision->_penetration = BA * (totalRadius - distance); // contactPoint is on surface of A collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * BA; @@ -179,6 +180,7 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col collision->_penetration = (totalRadius - radialDistance) * radialAxis; // points from A into B // contactPoint is on surface of sphereA collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * radialAxis; + collision->_type = COLLISION_TYPE_UNKNOWN; } else { // A is on B's axis, so the penetration is undefined... if (absAxialDistance > capsuleB->getHalfHeight()) { @@ -200,6 +202,7 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col collision->_penetration = (sign * (totalRadius + capsuleB->getHalfHeight() - absAxialDistance)) * capsuleAxis; // contactPoint is on surface of sphereA collision->_contactPoint = sphereA->getPosition() + (sign * sphereA->getRadius()) * capsuleAxis; + collision->_type = COLLISION_TYPE_UNKNOWN; } return true; } @@ -215,6 +218,7 @@ bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, Collision } collision->_penetration = penetration; collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * glm::normalize(penetration); + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } return false; @@ -264,6 +268,7 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col collision->_penetration = (radialDistance - totalRadius) * radialAxis; // points from A into B // contactPoint is on surface of capsuleA collision->_contactPoint = closestApproach - capsuleA->getRadius() * radialAxis; + collision->_type = COLLISION_TYPE_UNKNOWN; } else { // A is on B's axis, so the penetration is undefined... if (absAxialDistance > capsuleA->getHalfHeight()) { @@ -284,6 +289,7 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col collision->_penetration = (sign * (totalRadius + capsuleA->getHalfHeight() - absAxialDistance)) * capsuleAxis; // contactPoint is on surface of sphereA collision->_contactPoint = closestApproach + (sign * capsuleA->getRadius()) * capsuleAxis; + collision->_type = COLLISION_TYPE_UNKNOWN; } } return true; @@ -355,6 +361,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, collision->_penetration = BA * (totalRadius - distance); // contactPoint is on surface of A collision->_contactPoint = centerA + distanceA * axisA + capsuleA->getRadius() * BA; + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } } else { @@ -420,6 +427,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, // average the internal pair, and then do the math from centerB collision->_contactPoint = centerB + (0.5f * (points[1] + points[2])) * axisB + (capsuleA->getRadius() - distance) * BA; + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } } @@ -439,6 +447,7 @@ bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, Collis 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); + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } return false; @@ -454,6 +463,7 @@ bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, Collision collision->_penetration = -penetration; collision->_contactPoint = sphereB->getPosition() + (sphereB->getRadius() / glm::length(penetration) - 1.0f) * penetration; + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } return false; @@ -472,6 +482,7 @@ bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, Collis 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; + collision->_type = COLLISION_TYPE_UNKNOWN; return true; } return false; @@ -656,9 +667,15 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: direction = glm::normalize(direction); // compute collision details + collision->_type = COLLISION_TYPE_AACUBE; + collision->_floatData = cubeSide; + collision->_vecData = cubeCenter; collision->_penetration = (halfCubeSide + sphereRadius - distance * glm::dot(BA, direction)) * direction; collision->_contactPoint = sphereCenter + sphereRadius * direction; } + collision->_type = COLLISION_TYPE_AACUBE; + collision->_floatData = cubeSide; + collision->_vecData = cubeCenter; return true; } else if (sphereRadius + halfCubeSide > distance) { // NOTE: for cocentric approximation we collide sphere and cube as two spheres which means @@ -669,6 +686,10 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: collision->_penetration = (sphereRadius + halfCubeSide) * glm::vec3(0.0f, -1.0f, 0.0f); // contactPoint is on surface of A collision->_contactPoint = sphereCenter + collision->_penetration; + + collision->_type = COLLISION_TYPE_AACUBE; + collision->_floatData = cubeSide; + collision->_vecData = cubeCenter; return true; } } From 37ca6efc7c30c68938992dbe0d115ed945cdb699 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 11:48:32 -0700 Subject: [PATCH 03/37] correctly handle SHADOW_RENDER_MODE in a bunch of places that were drawing shadows when they shouldn't --- interface/src/Application.cpp | 4 +-- interface/src/Menu.cpp | 5 +++- interface/src/Menu.h | 2 ++ interface/src/avatar/Avatar.cpp | 16 +++++++----- interface/src/avatar/Hand.cpp | 8 +++--- interface/src/avatar/Hand.h | 3 ++- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++-- interface/src/models/ModelTreeRenderer.cpp | 11 ++++---- interface/src/models/ModelTreeRenderer.h | 2 +- .../src/particles/ParticleTreeRenderer.cpp | 10 +++++--- .../src/particles/ParticleTreeRenderer.h | 2 +- libraries/octree/src/OctreeHeadlessViewer.h | 2 +- libraries/octree/src/OctreeRenderer.cpp | 4 +-- libraries/octree/src/OctreeRenderer.h | 25 +++++++++++-------- 15 files changed, 62 insertions(+), 40 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50e9ef1dc..b4853f54d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2348,8 +2348,8 @@ void Application::updateShadowMap() { updateUntranslatedViewMatrix(); _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); - _particles.render(); - _models.render(); + _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); + _models.render(OctreeRenderer::SHADOW_RENDER_MODE); glPopMatrix(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13b72bcdb3..2a00e414df 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -291,7 +291,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options"); @@ -308,6 +307,10 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD); + QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelProxies, 0, false); + QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 723d320905..d2d9ce7c7d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -303,6 +303,7 @@ namespace MenuOption { const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; + const QString DisplayModelProxies = "Display Model Proxies"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; @@ -337,6 +338,7 @@ namespace MenuOption { const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; const QString Models = "Models"; + const QString ModelOptions = "Model Options"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString NameLocation = "Name this location"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f7bf4595d6..2e8deb4b0a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -215,17 +215,20 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { renderBody(renderMode, glowLevel); } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { _skeletonModel.updateShapePositions(); _skeletonModel.renderJointCollisionShapes(0.7f); } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) { if (shouldRenderHead(cameraPosition, renderMode)) { getHead()->getFaceModel().updateShapePositions(); getHead()->getFaceModel().renderJointCollisionShapes(0.7f); } } - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) { + if (renderMode != SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) { if (shouldRenderHead(cameraPosition, renderMode)) { getHead()->getFaceModel().updateShapePositions(); getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f); @@ -234,7 +237,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { } } // If this is the avatar being looked at, render a little ball above their head - if (_isLookAtTarget) { + if (renderMode != SHADOW_RENDER_MODE &&_isLookAtTarget) { const float LOOK_AT_INDICATOR_RADIUS = 0.03f; const float LOOK_AT_INDICATOR_HEIGHT = 0.60f; const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.5f }; @@ -340,7 +343,8 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { void Avatar::renderBody(RenderMode renderMode, float glowLevel) { Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + { Glower glower(glowLevel); @@ -351,7 +355,7 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { } _skeletonModel.render(1.0f, modelRenderMode); renderAttachments(modelRenderMode); - getHand()->render(false); + getHand()->render(false, modelRenderMode); } getHead()->render(1.0f, modelRenderMode); } diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index c925e452b2..320a8477c1 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -192,11 +192,11 @@ void Hand::calculateGeometry() { } } -void Hand::render(bool isMine) { - +void Hand::render(bool isMine, Model::RenderMode renderMode) { _renderAlpha = 1.0; - if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { + if (renderMode != Model::SHADOW_RENDER_MODE && + Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { // draw a green sphere at hand joint location, which is actually near the wrist) for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; @@ -212,7 +212,7 @@ void Hand::render(bool isMine) { } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { + if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderLeapHands(isMine); } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 65a7dcb74a..ff21e9f5b2 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -24,6 +24,7 @@ #include #include "InterfaceConfig.h" +#include "renderer/model.h" #include "world.h" @@ -52,7 +53,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine); - void render(bool isMine); + void render(bool isMine, Model::RenderMode renderMode = Model::DEFAULT_RENDER_MODE); // getters const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 19aebba25c..9cb8ea3d9c 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -182,7 +182,7 @@ void Head::relaxLean(float deltaTime) { } void Head::render(float alpha, Model::RenderMode mode) { - if (_faceModel.render(alpha, mode) && _renderLookatVectors) { + if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e8782fa140..36e2d64667 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -333,7 +333,9 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { return; // exit early } Avatar::render(cameraPosition, renderMode); - if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) { + + // don't display IK constraints in shadow mode + if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && renderMode != SHADOW_RENDER_MODE) { _skeletonModel.renderIKConstraints(); } } @@ -582,7 +584,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) { getHead()->render(1.0f, modelRenderMode); } - getHand()->render(true); + getHand()->render(true, modelRenderMode); } const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 9546c7d1c4..3ade46fc4a 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -39,8 +39,8 @@ void ModelTreeRenderer::update() { } } -void ModelTreeRenderer::render() { - OctreeRenderer::render(); +void ModelTreeRenderer::render(RenderMode renderMode) { + OctreeRenderer::render(renderMode); } Model* ModelTreeRenderer::getModel(const QString& url) { @@ -94,11 +94,12 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // set the position model->setTranslation(position); - model->simulate(0.0f); - - model->render(alpha); // TODO: should we allow modelItems to have alpha on their models? + // TODO: should we allow modelItems to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); const bool wantDebugSphere = false; if (wantDebugSphere) { diff --git a/interface/src/models/ModelTreeRenderer.h b/interface/src/models/ModelTreeRenderer.h index 5ed4720391..7af5bbf317 100644 --- a/interface/src/models/ModelTreeRenderer.h +++ b/interface/src/models/ModelTreeRenderer.h @@ -46,7 +46,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); protected: Model* getModel(const QString& url); diff --git a/interface/src/particles/ParticleTreeRenderer.cpp b/interface/src/particles/ParticleTreeRenderer.cpp index aa498082d9..2983093564 100644 --- a/interface/src/particles/ParticleTreeRenderer.cpp +++ b/interface/src/particles/ParticleTreeRenderer.cpp @@ -39,8 +39,8 @@ void ParticleTreeRenderer::update() { } } -void ParticleTreeRenderer::render() { - OctreeRenderer::render(); +void ParticleTreeRenderer::render(RenderMode renderMode) { + OctreeRenderer::render(renderMode); } Model* ParticleTreeRenderer::getModel(const QString& url) { @@ -102,7 +102,11 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg model->setScale(scale * MODEL_SCALE * radius * modelScale); model->simulate(0.0f); - model->render(alpha); // TODO: should we allow particles to have alpha on their models? + + // TODO: should we allow particles to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); const bool wantDebugSphere = false; if (wantDebugSphere) { diff --git a/interface/src/particles/ParticleTreeRenderer.h b/interface/src/particles/ParticleTreeRenderer.h index ea52df3932..ccb8bfbdf3 100644 --- a/interface/src/particles/ParticleTreeRenderer.h +++ b/interface/src/particles/ParticleTreeRenderer.h @@ -43,7 +43,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); virtual void init(); - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); protected: Model* getModel(const QString& url); diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index ebabf1dbad..3509713d50 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -33,7 +33,7 @@ public: virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ }; virtual void init(); - virtual void render() { /* swallow these */ }; + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE) { /* swallow these */ }; void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 5c5da2250f..c1ce3cb218 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -154,8 +154,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { return false; } -void OctreeRenderer::render() { - RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust() }; +void OctreeRenderer::render(RenderMode renderMode) { + RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 652f9d0399..73e26c97f6 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -25,15 +25,7 @@ #include "ViewFrustum.h" class OctreeRenderer; - -class RenderArgs { -public: - int _renderedItems; - OctreeRenderer* _renderer; - ViewFrustum* _viewFrustum; - float _sizeScale; - int _boundaryLevelAdjust; -}; +class RenderArgs; // Generic client side Octree renderer class. @@ -59,8 +51,10 @@ public: /// initialize and GPU/rendering related resources virtual void init(); + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; + /// render the content of the octree - virtual void render(); + virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); ViewFrustum* getViewFrustum() const { return _viewFrustum; } void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } @@ -75,4 +69,15 @@ protected: ViewFrustum* _viewFrustum; }; +class RenderArgs { +public: + int _renderedItems; + OctreeRenderer* _renderer; + ViewFrustum* _viewFrustum; + float _sizeScale; + int _boundaryLevelAdjust; + OctreeRenderer::RenderMode _renderMode; +}; + + #endif // hifi_OctreeRenderer_h From 8ec493e85b9a8a9962c7457baf686da2ef2e70a1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 12:39:20 -0700 Subject: [PATCH 04/37] fix bad penetration depth for interior of cube --- libraries/shared/src/ShapeCollider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index f5836f373b..7c29fbae00 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -664,13 +664,14 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: glm::vec3 direction; BA /= maxBA; glm::modf(BA, direction); - direction = glm::normalize(direction); + float lengthDirection = glm::length(direction); + direction /= lengthDirection; // compute collision details collision->_type = COLLISION_TYPE_AACUBE; collision->_floatData = cubeSide; collision->_vecData = cubeCenter; - collision->_penetration = (halfCubeSide + sphereRadius - distance * glm::dot(BA, direction)) * direction; + collision->_penetration = (halfCubeSide * lengthDirection + sphereRadius - maxBA * glm::dot(BA, direction)) * direction; collision->_contactPoint = sphereCenter + sphereRadius * direction; } collision->_type = COLLISION_TYPE_AACUBE; From 55b677dd02b40150869d782d8387b57d807ed295 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 7 May 2014 12:53:38 -0700 Subject: [PATCH 05/37] Provide options for model translation: by default, pivot about mesh bounds' center; allow numeric translation or pivot about joint position. --- interface/src/ModelUploader.cpp | 52 +++++++++++++++++++++++++++++++-- interface/src/ModelUploader.h | 7 +++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 08719f0f25..ce8691998d 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -42,6 +43,9 @@ static const QString TEXDIR_FIELD = "texdir"; static const QString LOD_FIELD = "lod"; static const QString JOINT_INDEX_FIELD = "jointIndex"; static const QString SCALE_FIELD = "scale"; +static const QString TRANSLATION_X_FIELD = "tx"; +static const QString TRANSLATION_Y_FIELD = "ty"; +static const QString TRANSLATION_Z_FIELD = "tz"; static const QString JOINT_FIELD = "joint"; static const QString FREE_JOINT_FIELD = "freeJoint"; @@ -519,6 +523,14 @@ bool ModelUploader::addPart(const QFile& file, const QByteArray& contents, const return true; } +static QDoubleSpinBox* createTranslationBox() { + QDoubleSpinBox* box = new QDoubleSpinBox(); + const double MAX_TRANSLATION = 1000000.0; + box->setMinimum(-MAX_TRANSLATION); + box->setMaximum(MAX_TRANSLATION); + return box; +} + ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariantHash& originalMapping, const QString& basePath, const FBXGeometry& geometry) : _modelType(modelType), @@ -540,7 +552,18 @@ ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariant _scale->setMaximum(FLT_MAX); _scale->setSingleStep(0.01); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + QHBoxLayout* translation = new QHBoxLayout(); + form->addRow("Translation:", translation); + translation->addWidget(_translationX = createTranslationBox()); + translation->addWidget(_translationY = createTranslationBox()); + translation->addWidget(_translationZ = createTranslationBox()); + form->addRow("Pivot About Center:", _pivotAboutCenter = new QCheckBox()); + form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); + connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); + _pivotAboutCenter->setChecked(true); + + } else { form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); form->addRow("Neck Joint:", _neckJoint = createJointBox()); @@ -584,7 +607,19 @@ QVariantHash ModelPropertiesDialog::getMapping() const { mapping.insert(JOINT_INDEX_FIELD, jointIndices); QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + glm::vec3 pivot; + if (_pivotAboutCenter->isChecked()) { + pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; + + } else if (_pivotJoint->currentIndex() != 0) { + pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); + } + mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value()); + mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value()); + mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value()); + + } else { insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); @@ -617,7 +652,14 @@ void ModelPropertiesDialog::reset() { _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); - if (_modelType != ATTACHMENT_MODEL) { + if (_modelType == ATTACHMENT_MODEL) { + _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); + _translationY->setValue(_originalMapping.value(TRANSLATION_Y_FIELD).toDouble()); + _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); + _pivotAboutCenter->setChecked(true); + _pivotJoint->setCurrentIndex(0); + + } else { setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); setJointText(_neckJoint, jointHash.value("jointNeck").toString()); @@ -654,6 +696,10 @@ void ModelPropertiesDialog::chooseTextureDirectory() { _textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1)); } +void ModelPropertiesDialog::updatePivotJoint() { + _pivotJoint->setEnabled(!_pivotAboutCenter->isChecked()); +} + void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) { QWidget* freeJoint = new QWidget(); QHBoxLayout* freeJointLayout = new QHBoxLayout(); diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h index 499bfad03b..766bd55318 100644 --- a/interface/src/ModelUploader.h +++ b/interface/src/ModelUploader.h @@ -19,6 +19,7 @@ #include "ui/ModelsBrowser.h" +class QCheckBox; class QComboBox; class QDoubleSpinBox; class QFileInfo; @@ -83,6 +84,7 @@ public: private slots: void reset(); void chooseTextureDirectory(); + void updatePivotJoint(); void createNewFreeJoint(const QString& joint = QString()); private: @@ -96,6 +98,11 @@ private: QLineEdit* _name; QPushButton* _textureDirectory; QDoubleSpinBox* _scale; + QDoubleSpinBox* _translationX; + QDoubleSpinBox* _translationY; + QDoubleSpinBox* _translationZ; + QCheckBox* _pivotAboutCenter; + QComboBox* _pivotJoint; QComboBox* _leftEyeJoint; QComboBox* _rightEyeJoint; QComboBox* _neckJoint; From 40ed72989cecb380863ece849c28286e63aabea4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 12:57:11 -0700 Subject: [PATCH 06/37] mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 10 ++++++++ interface/src/DatagramProcessor.cpp | 14 +++++++++++ interface/src/Menu.cpp | 28 ++++++++++++++++++++++ interface/src/Menu.h | 2 ++ libraries/networking/src/PacketHeaders.h | 2 +- 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 63b2083aae..9007c55abb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -348,6 +348,16 @@ void AudioMixer::readPendingDatagrams() { || mixerPacketType == PacketTypeSilentAudioFrame) { nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); + } else if (mixerPacketType == PacketTypeMuteEnvironnement) { + QByteArray packet = receivedPacket; + populatePacketHeader(packet, PacketTypeMuteEnvironnement); + + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { + if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { + nodeList->writeDatagram(packet, packet.size(), node); + } + } + } else { // let processNodeData handle it. nodeList->processNodeData(senderSockAddr, receivedPacket); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 287744eba2..5251b5d8ee 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -131,6 +131,20 @@ void DatagramProcessor::processDatagrams() { break; } + case PacketTypeMuteEnvironnement: { + glm::vec3 position; + float radius; + + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3)); + memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float)); + + if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), position) < radius + && !Application::getInstance()->getAudio()->getMuted()) { + Application::getInstance()->getAudio()->toggleMute(); + } + break; + } default: nodeList->processNodeData(senderSockAddr, incomingPacket); break; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13b72bcdb3..ec9c47ecbf 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -68,6 +68,7 @@ const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; +const float MUTE_RADIUS = 10; Menu::Menu() : _actionHash(), @@ -397,6 +398,11 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleMute())); + addActionToQMenuAndActionHash(audioDebugMenu, + MenuOption::MuteEnvironment, + 0, + this, + SLOT(muteEnvironment())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection, 0, false, @@ -1000,6 +1006,28 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson disconnect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } +void Menu::muteEnvironment() { + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float); + + glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); + + char packet[packetSize]; + populatePacketHeader(packet, PacketTypeMuteEnvironnement); + memcpy(packet + headerSize, &position, sizeof(glm::vec3)); + memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); + + QByteArray mutePacket(packet, packetSize); + + // grab our audio mixer from the NodeList, if it exists + SharedNodePointer audioMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer); + + if (audioMixer) { + // send off this mute packet + NodeList::getInstance()->writeDatagram(mutePacket, audioMixer); + } +} + void Menu::goToLocation() { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 723d320905..d1097929f7 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -191,6 +191,7 @@ private slots: void audioMuteToggled(); void namedLocationCreated(LocationManager::NamedLocationCreateResponse response); void multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData); + void muteEnvironment(); private: static Menu* _instance; @@ -339,6 +340,7 @@ namespace MenuOption { const QString Models = "Models"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; + const QString MuteEnvironment = "Mute Environment"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 844fce77fe..ac8a187034 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -39,7 +39,7 @@ enum PacketType { PacketTypeRequestAssignment, PacketTypeCreateAssignment, PacketTypeDomainOAuthRequest, - PacketTypeDataServerGet, // reusable + PacketTypeMuteEnvironnement, PacketTypeDataServerSend, // reusable PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From 6308c39aab3112848e83b52d09466f51d5140441 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 14:03:30 -0700 Subject: [PATCH 07/37] Fix for windows --- interface/src/Menu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ec9c47ecbf..b98bd985e2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1012,7 +1012,7 @@ void Menu::muteEnvironment() { glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); - char packet[packetSize]; + char* packet = (char*)malloc(packetSize); populatePacketHeader(packet, PacketTypeMuteEnvironnement); memcpy(packet + headerSize, &position, sizeof(glm::vec3)); memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); @@ -1026,6 +1026,8 @@ void Menu::muteEnvironment() { // send off this mute packet NodeList::getInstance()->writeDatagram(mutePacket, audioMixer); } + + free(packet); } void Menu::goToLocation() { From 31aedb4aa8779dda51714c6a856bb8a10a448ec1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 14:39:26 -0700 Subject: [PATCH 08/37] fixed overlay not moving on resize in editModels.js --- examples/editModels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index ecf398edfa..384d2f75a8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -370,7 +370,7 @@ function moveOverlays() { toolsX = windowDimensions.x - 8 - toolWidth; toolsY = (windowDimensions.y - toolsHeight) / 2; - Overlays.addOverlay(firstModel, { + Overlays.editOverlay(firstModel, { x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight, }); } From 03faff359f1772cd587ea37360981409c46fa968 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 7 May 2014 14:48:25 -0700 Subject: [PATCH 09/37] Fix for certain models with textures not parented to materials. --- libraries/fbx/src/FBXReader.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index d637526067..1fc03ceb66 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -826,7 +826,7 @@ ExtractedMesh extractMesh(const FBXNode& object) { while (endIndex < data.polygonIndices.size() && data.polygonIndices.at(endIndex++) >= 0); QPair materialTexture((polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0, - (polygonIndex < textures.size()) ? textures.at(polygonIndex) : -1); + (polygonIndex < textures.size()) ? textures.at(polygonIndex) : 0); int& partIndex = materialTextureParts[materialTexture]; if (partIndex == 0) { data.extracted.partMaterialTextures.append(materialTexture); @@ -972,6 +972,18 @@ FBXTexture getTexture(const QString& textureID, const QHash return texture; } +bool checkMaterialsHaveTextures(const QHash& materials, + const QHash& textureFilenames, const QMultiHash& childMap) { + foreach (const QString& materialID, materials.keys()) { + foreach (const QString& childID, childMap.values(materialID)) { + if (textureFilenames.contains(childID)) { + return true; + } + } + } + return false; +} + FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) { QHash meshes; QVector blendshapes; @@ -1515,6 +1527,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.bindExtents.reset(); geometry.meshExtents.reset(); + // see if any materials have texture children + bool materialsHaveTextures = checkMaterialsHaveTextures(materials, textureFilenames, childMap); + for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); @@ -1587,7 +1602,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } else if (textureFilenames.contains(childID)) { FBXTexture texture = getTexture(childID, textureFilenames, textureContent); for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { - if (extracted.partMaterialTextures.at(j).second == textureIndex) { + int partTexture = extracted.partMaterialTextures.at(j).second; + if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) { extracted.mesh.parts[j].diffuseTexture = texture; } } From fd1f6befffb942d0e9b2c9e8557c2fc75cbce9cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 7 May 2014 15:19:32 -0700 Subject: [PATCH 10/37] CR --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- interface/src/DatagramProcessor.cpp | 4 ++-- interface/src/Menu.cpp | 6 +++--- libraries/networking/src/PacketHeaders.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9007c55abb..158eabe27b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -348,9 +348,9 @@ void AudioMixer::readPendingDatagrams() { || mixerPacketType == PacketTypeSilentAudioFrame) { nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); - } else if (mixerPacketType == PacketTypeMuteEnvironnement) { + } else if (mixerPacketType == PacketTypeMuteEnvironment) { QByteArray packet = receivedPacket; - populatePacketHeader(packet, PacketTypeMuteEnvironnement); + populatePacketHeader(packet, PacketTypeMuteEnvironment); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 5251b5d8ee..56078c1a8d 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -131,11 +131,11 @@ void DatagramProcessor::processDatagrams() { break; } - case PacketTypeMuteEnvironnement: { + case PacketTypeMuteEnvironment: { glm::vec3 position; float radius; - int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment); memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3)); memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float)); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b98bd985e2..0587e979f6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -68,7 +68,7 @@ const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; -const float MUTE_RADIUS = 10; +const float MUTE_RADIUS = 50; Menu::Menu() : _actionHash(), @@ -1007,13 +1007,13 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson } void Menu::muteEnvironment() { - int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironnement); + int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment); int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float); glm::vec3 position = Application::getInstance()->getAvatar()->getPosition(); char* packet = (char*)malloc(packetSize); - populatePacketHeader(packet, PacketTypeMuteEnvironnement); + populatePacketHeader(packet, PacketTypeMuteEnvironment); memcpy(packet + headerSize, &position, sizeof(glm::vec3)); memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float)); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index ac8a187034..d5b1e8301c 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -39,7 +39,7 @@ enum PacketType { PacketTypeRequestAssignment, PacketTypeCreateAssignment, PacketTypeDomainOAuthRequest, - PacketTypeMuteEnvironnement, + PacketTypeMuteEnvironment, PacketTypeDataServerSend, // reusable PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From b92bbafc26a95af5e0980c81b17a8bcc20a328c0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 15:21:12 -0700 Subject: [PATCH 11/37] prevent avatar from getting trapped in voxels --- interface/src/avatar/MyAvatar.cpp | 80 +++++++++++++------------------ interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 46357b1e76..50d9c4cef2 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,7 @@ MyAvatar::MyAvatar() : _distanceToNearestAvatar(std::numeric_limits::max()), _wasPushing(false), _isPushing(false), + _wasStuck(false), _thrust(0.0f), _motorVelocity(0.0f), _motorTimescale(DEFAULT_MOTOR_TIMESCALE), @@ -212,6 +214,8 @@ void MyAvatar::simulate(float deltaTime) { } if (_collisionGroups & COLLISION_GROUP_VOXELS) { updateCollisionWithVoxels(deltaTime, radius); + } else { + _wasStuck = false; } if (_collisionGroups & COLLISION_GROUP_AVATARS) { updateCollisionWithAvatars(deltaTime); @@ -958,65 +962,49 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { static CollisionList myCollisions(64); void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { + const float MIN_STUCK_SPEED = 100.0f; + float speed = glm::length(_velocity); + if (speed > MIN_STUCK_SPEED) { + // don't even bother to try to collide against voxles when moving very fast + return; + } myCollisions.clear(); const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) { const float VOXEL_ELASTICITY = 0.0f; const float VOXEL_DAMPING = 0.0f; + float capsuleRadius = boundingShape.getRadius(); - if (glm::length2(_gravity) > EPSILON) { - if (myCollisions.size() == 1) { - // trivial case - CollisionInfo* collision = myCollisions[0]; - applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - _lastFloorContactPoint = collision->_contactPoint - collision->_penetration; - } else { - // This is special collision handling for when walking on a voxel field which - // prevents snagging at corners and seams. - - // sift through the collisions looking for one against the "floor" - int floorIndex = 0; - float distanceToFloor = 0.0f; - float penetrationWithFloor = 0.0f; - for (int i = 0; i < myCollisions.size(); ++i) { - CollisionInfo* collision = myCollisions[i]; - float distance = glm::dot(_gravity, collision->_contactPoint - _position); - if (distance > distanceToFloor) { - distanceToFloor = distance; - penetrationWithFloor = glm::dot(_gravity, collision->_penetration); - floorIndex = i; - } - } - - // step through the collisions again and apply each that is not redundant - glm::vec3 oldPosition = _position; - for (int i = 0; i < myCollisions.size(); ++i) { - CollisionInfo* collision = myCollisions[i]; - if (i == floorIndex) { - applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - _lastFloorContactPoint = collision->_contactPoint - collision->_penetration; - } else { - float distance = glm::dot(_gravity, collision->_contactPoint - oldPosition); - float penetration = glm::dot(_gravity, collision->_penetration); - if (fabsf(distance - distanceToFloor) > penetrationWithFloor || penetration > penetrationWithFloor) { - // resolution of the deepest penetration would not resolve this one - // so we apply the collision - applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } + glm::vec3 totalPenetration(0.0f); + bool isStuck = false; + for (int i = 0; i < myCollisions.size(); ++i) { + CollisionInfo* collision = myCollisions[i]; + float depth = glm::length(collision->_penetration); + if (depth > capsuleRadius) { + isStuck = true; + if (_wasStuck) { + glm::vec3 cubeCenter = collision->_vecData; + float cubeSide = collision->_floatData; + float distance = glm::dot(boundingShape.getPosition() - cubeCenter, _worldUpDirection); + if (distance < 0.0f) { + distance = fabsf(distance) + 0.5f * cubeSide; } + distance += capsuleRadius + boundingShape.getHalfHeight(); + totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection); + } else { + totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } } - } else { - // no gravity -- apply all collisions - for (int i = 0; i < myCollisions.size(); ++i) { - CollisionInfo* collision = myCollisions[i]; - applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } + totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } + applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + _wasStuck = isStuck; const float VOXEL_COLLISION_FREQUENCY = 0.5f; updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - } + } else { + _wasStuck = false; + } } void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f893cc4f47..1c80d3b969 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -125,6 +125,7 @@ private: bool _wasPushing; bool _isPushing; + bool _wasStuck; glm::vec3 _thrust; // final acceleration from outside sources for the current frame glm::vec3 _motorVelocity; // intended velocity of avatar motion From 5e9036b3fec64b282cda0e58e06c55ce61edbaab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 15:37:41 -0700 Subject: [PATCH 12/37] tweak audio constants to be less agressive on cutoff --- assignment-client/src/audio/AudioMixer.cpp | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 63b2083aae..6ee044a709 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -54,7 +54,7 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const float LOUDNESS_TO_DISTANCE_RATIO = 0.00305f; +const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 70da363267..6fc16c57a9 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -89,7 +89,7 @@ void PositionalAudioRingBuffer::updateNextOutputTrailingLoudness() { const int TRAILING_AVERAGE_FRAMES = 100; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - const float LOUDNESS_EPSILON = 0.01f; + const float LOUDNESS_EPSILON = 0.000001f; if (nextLoudness >= _nextOutputTrailingLoudness) { _nextOutputTrailingLoudness = nextLoudness; From 2d3592e3673a493eb6d9b14e7b3b2ae7423b4186 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 15:58:00 -0700 Subject: [PATCH 13/37] avoid resolving penetration twice --- interface/src/avatar/MyAvatar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 50d9c4cef2..08cdca2a25 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -994,8 +994,9 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { } else { totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } + } else { + totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } - totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); _wasStuck = isStuck; From a11b996a5104161b788de6c2fe39c987dbe6adaa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 7 May 2014 16:00:39 -0700 Subject: [PATCH 14/37] cleaner way to achieve the last commit --- interface/src/avatar/MyAvatar.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 08cdca2a25..dd68201b46 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -991,12 +991,10 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { } distance += capsuleRadius + boundingShape.getHalfHeight(); totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection); - } else { - totalPenetration = addPenetrations(totalPenetration, collision->_penetration); + continue; } - } else { - totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } + totalPenetration = addPenetrations(totalPenetration, collision->_penetration); } applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); _wasStuck = isStuck; From 99ee6ae8af86874170a04c6598a2b04a51712621 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 16:26:32 -0700 Subject: [PATCH 15/37] return an injector from playSound and allow user to stop it --- libraries/audio/src/AudioInjector.cpp | 8 +++++++- libraries/audio/src/AudioInjector.h | 13 +++++++++---- libraries/audio/src/AudioScriptingInterface.cpp | 4 +++- libraries/audio/src/AudioScriptingInterface.h | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 11 +++++++++++ 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index eed41ac849..364d14cfbb 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,6 +21,12 @@ #include "AudioInjector.h" +AudioInjector::AudioInjector(QObject* parent) : + QObject(parent) +{ + +} + AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : _sound(sound), _options(injectorOptions) @@ -80,7 +86,7 @@ void AudioInjector::injectAudio() { int numPreAudioDataBytes = injectAudioPacket.size(); // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks - while (currentSendPosition < soundByteArray.size()) { + while (currentSendPosition < soundByteArray.size() && !_shouldStop) { int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, soundByteArray.size() - currentSendPosition); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index abaa804fb0..08fe544255 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -24,14 +24,19 @@ class AudioInjector : public QObject { Q_OBJECT public: + AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); +public slots: + void injectAudio(); + void stop() { _shouldStop = true; } +signals: + void finished(); private: Sound* _sound; AudioInjectorOptions _options; -public slots: - void injectAudio(); -signals: - void finished(); + bool _shouldStop; }; +Q_DECLARE_METATYPE(AudioInjector*) + #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 0d76a42757..944ae49adf 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -11,7 +11,7 @@ #include "AudioScriptingInterface.h" -void AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { AudioInjector* injector = new AudioInjector(sound, *injectorOptions); @@ -28,6 +28,8 @@ void AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions connect(injectorThread, SIGNAL(finished()), injectorThread, SLOT(deleteLater())); injectorThread->start(); + + return injector; } void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay, diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index f2e9b02e9a..de8e57090a 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -20,7 +20,7 @@ const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; class AudioScriptingInterface : public QObject { Q_OBJECT public slots: - static void playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + static AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); static void startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions = NULL); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 402f1a2885..9be2cb5252 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ return QScriptValue(); } +QScriptValue injectorToScriptValue(QScriptEngine *engine, AudioInjector* const &in) { + return engine->newQObject(in); +} + +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { + out = qobject_cast(object.toQObject()); +} + ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, AbstractControllerScriptingInterface* controllerScriptingInterface) : @@ -226,6 +235,8 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject(); _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); + + qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); From e6a8c79f9fde066c95c3fd3137f139bfee93c31c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 16:51:22 -0700 Subject: [PATCH 16/37] Added more arrow controls to move camera when in mirror mode, new guitar chords. --- examples/airGuitar.js | 21 +++++++++++++++------ interface/src/Application.cpp | 28 ++++++++++++++++++++++------ interface/src/Application.h | 2 ++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index a54ef82e7e..08898579a7 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -27,9 +27,18 @@ function vMinus(a, b) { // First, load two percussion sounds to be used on the sticks -var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); -var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); -var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); +var guitarType = 2; + +if (guitarType == 1) { + var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); + var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); + var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); +} else { + var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+A+short.raw"); + var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+B+short.raw"); + var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+E+short.raw"); +} + var whichChord = chord1; @@ -56,7 +65,7 @@ function checkHands(deltaTime) { if (palm == strumHand) { - var STRUM_HEIGHT_ABOVE_PELVIS = 0.15; + var STRUM_HEIGHT_ABOVE_PELVIS = -0.30; var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS; //printVector(position); if ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) { @@ -72,9 +81,9 @@ function checkHands(deltaTime) { // This is the chord controller var distanceFromPelvis = Vec3.length(Vec3.subtract(position, myPelvis)); //print(distanceFromPelvis); - if (distanceFromPelvis > 0.50) { + if (distanceFromPelvis > 0.63) { whichChord = chord3; - } else if (distanceFromPelvis > 0.35) { + } else if (distanceFromPelvis > 0.55) { whichChord = chord2; } else { whichChord = chord1; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 10f113ad11..e4adb38cd4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -572,8 +572,8 @@ void Application::paintGL() { glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); float headHeight = eyePosition.y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale() * _scaleMirror); - _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); + _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * @@ -870,7 +870,11 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Up: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _scaleMirror *= 0.95; + if (!isShifted) { + _scaleMirror *= 0.95f; + } else { + _raiseMirror += 0.05f; + } } else { _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f); } @@ -878,18 +882,30 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Down: if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _scaleMirror *= 1.05; + if (!isShifted) { + _scaleMirror *= 1.05f; + } else { + _raiseMirror -= 0.05f; + } } else { _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f); } break; case Qt::Key_Left: - _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _rotateMirror += PI / 20.f; + } else { + _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f); + } break; case Qt::Key_Right: - _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f); + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _rotateMirror -= PI / 20.f; + } else { + _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f); + } break; case Qt::Key_I: diff --git a/interface/src/Application.h b/interface/src/Application.h index 1d38a11357..54e6bcdcac 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -457,6 +457,8 @@ private: glm::mat4 _projectionMatrix; float _scaleMirror; + float _rotateMirror; + float _raiseMirror; glm::mat4 _shadowMatrix; From 128e4a13de641cd1a85dfee9772d56465bb1bf06 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 17:32:51 -0700 Subject: [PATCH 17/37] place models in proper containing voxel --- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 4 +- interface/src/models/ModelTreeRenderer.cpp | 145 +++++++++++++----- libraries/models/src/ModelItem.h | 12 ++ libraries/models/src/ModelTree.cpp | 34 ++-- libraries/models/src/ModelTreeElement.cpp | 56 +++++-- libraries/models/src/ModelTreeElement.h | 5 +- libraries/octree/src/Octree.cpp | 8 +- libraries/octree/src/Octree.h | 1 + libraries/octree/src/OctreeElement.cpp | 87 +++++++++++ libraries/octree/src/OctreeElement.h | 8 +- .../particles/src/ParticleTreeElement.cpp | 2 +- libraries/particles/src/ParticleTreeElement.h | 2 +- libraries/voxels/src/VoxelTreeElement.cpp | 2 +- libraries/voxels/src/VoxelTreeElement.h | 2 +- 15 files changed, 303 insertions(+), 69 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2a00e414df..4bc6bea107 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -309,7 +309,9 @@ Menu::Menu() : QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); - addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelProxies, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelBounds, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementProxy, 0, false); + addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementChildProxies, 0, false); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d2d9ce7c7d..3667674f80 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -303,7 +303,9 @@ namespace MenuOption { const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; - const QString DisplayModelProxies = "Display Model Proxies"; + const QString DisplayModelBounds = "Display Model Bounds"; + const QString DisplayModelElementProxy = "Display Model Element Bounds"; + const QString DisplayModelElementChildProxies = "Display Model Element Children"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 3ade46fc4a..c762182290 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -66,55 +66,130 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) const QList& modelItems = modelTreeElement->getModels(); uint16_t numberOfModels = modelItems.size(); + + bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE; + + bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds); + bool displayElementProxy = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementProxy); + bool displayElementChildProxies = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementChildProxies); + + + if (!isShadowMode && displayElementProxy && numberOfModels > 0) { + glm::vec3 elementCenter = modelTreeElement->getAABox().calcCenter() * (float)TREE_SCALE; + float elementSize = modelTreeElement->getScale() * (float)TREE_SCALE; + glColor3f(1.0f, 0.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x, elementCenter.y, elementCenter.z); + glutWireCube(elementSize); + glPopMatrix(); + + if (displayElementChildProxies) { + // draw the children + float halfSize = elementSize / 2.0f; + float quarterSize = elementSize / 4.0f; + glColor3f(1.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(1.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(1.0f, 1.0f, 1.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.5f, 0.5f); + glPushMatrix(); + glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.5f, 0.0f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + + glColor3f(0.0f, 0.5f, 0.0f); + glPushMatrix(); + glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize); + glutWireCube(halfSize); + glPopMatrix(); + } + + } for (uint16_t i = 0; i < numberOfModels; i++) { const ModelItem& modelItem = modelItems[i]; // render modelItem aspoints - glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE; - glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); - float radius = modelItem.getRadius() * (float)TREE_SCALE; - //glm::vec3 center = position + glm::vec3(radius, radius, radius); // center it around the position + AABox modelBox = modelItem.getAABox(); + modelBox.scale(TREE_SCALE); + if (args->_viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) { + glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE; + float radius = modelItem.getRadius() * (float)TREE_SCALE; + float size = modelItem.getSize() * (float)TREE_SCALE; - bool drawAsModel = modelItem.hasModel(); + bool drawAsModel = modelItem.hasModel(); - args->_renderedItems++; + args->_renderedItems++; - if (drawAsModel) { - glPushMatrix(); - const float alpha = 1.0f; + if (drawAsModel) { + glPushMatrix(); + const float alpha = 1.0f; - Model* model = getModel(modelItem.getModelURL()); + Model* model = getModel(modelItem.getModelURL()); - model->setScaleToFit(true, radius * 2.0f); - model->setSnapModelToCenter(true); + model->setScaleToFit(true, radius * 2.0f); + model->setSnapModelToCenter(true); - // set the rotation - glm::quat rotation = modelItem.getModelRotation(); - model->setRotation(rotation); + // set the rotation + glm::quat rotation = modelItem.getModelRotation(); + model->setRotation(rotation); - // set the position - model->setTranslation(position); - model->simulate(0.0f); + // set the position + model->setTranslation(position); + model->simulate(0.0f); - // TODO: should we allow modelItems to have alpha on their models? - Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - model->render(alpha, modelRenderMode); + // TODO: should we allow modelItems to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + model->render(alpha, modelRenderMode); - const bool wantDebugSphere = false; - if (wantDebugSphere) { - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glutWireSphere(radius, 15, 15); - glPopMatrix(); - } + if (!isShadowMode && displayModelBounds) { + glColor3f(0.0f, 1.0f, 0.0f); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutWireCube(size); + glPopMatrix(); + } - glPopMatrix(); - } else { - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glutSolidSphere(radius, 15, 15); - glPopMatrix(); + glPopMatrix(); + } else { + glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutSolidSphere(radius, 15, 15); + glPopMatrix(); + } } } } diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 76a78122ff..9edcf482c0 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -85,6 +85,9 @@ public: /// used by ModelScriptingInterface to return ModelItemProperties for unknown models void setIsUnknownID() { _id = UNKNOWN_MODEL_ID; _idSet = true; } + + glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } + glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } private: glm::vec3 _position; @@ -156,11 +159,20 @@ public: /// get position in domain scale units (0.0 - 1.0) const glm::vec3& getPosition() const { return _position; } + glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } + glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } + const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } /// get radius in domain scale units (0.0 - 1.0) float getRadius() const { return _radius; } + + /// get maximum dimension in domain scale units (0.0 - 1.0) + float getSize() const { return _radius * 2.0f; } + + /// get maximum dimension in domain scale units (0.0 - 1.0) + AABox getAABox() const { return AABox(getMinimumPoint(), getSize()); } // model related properties bool hasModel() const { return !_modelURL.isEmpty(); } diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index cef38a9422..45694b081d 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -113,13 +113,10 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send FindAndUpdateModelOperator theOperator(model); recurseTreeWithOperator(&theOperator); - // if we didn't find it in the tree, then store it... if (!theOperator.wasFound()) { - glm::vec3 position = model.getPosition(); - float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius()); - - ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); + AABox modelBox = model.getAABox(); + ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementContaining(model.getAABox()); element->storeModel(model); } // what else do we need to do here to get reaveraging to work @@ -494,12 +491,29 @@ void ModelTree::update() { lockForWrite(); _isDirty = true; - // TODO: we don't need to update models yet, but when we do, for example - // when we add animation support, we will revisit this code. - //ModelTreeUpdateArgs args = { }; - //recurseTreeWithOperation(updateOperation, &args); + ModelTreeUpdateArgs args = { }; + recurseTreeWithOperation(updateOperation, &args); - // Now is a reasonable time to prune the tree... + // now add back any of the particles that moved elements.... + int movingModels = args._movingModels.size(); + for (int i = 0; i < movingModels; i++) { + bool shouldDie = args._movingModels[i].getShouldDie(); + + // if the particle is still inside our total bounds, then re-add it + AABox treeBounds = getRoot()->getAABox(); + + if (!shouldDie && treeBounds.contains(args._movingModels[i].getPosition())) { + storeModel(args._movingModels[i]); + } else { + uint32_t modelItemID = args._movingModels[i].getID(); + quint64 deletedAt = usecTimestampNow(); + _recentlyDeletedModelsLock.lockForWrite(); + _recentlyDeletedModelItemIDs.insert(deletedAt, modelItemID); + _recentlyDeletedModelsLock.unlock(); + } + } + + // prune the tree... recurseTreeWithOperation(pruneOperation, NULL); unlock(); } diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index 0327d8a0c4..5c5d5100cf 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -47,15 +47,32 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) { } -bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const { +bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... - // write our models out... - uint16_t numberOfModels = _modelItems->size(); + // write our models out... first determine which of the models are in view based on our params + uint16_t numberOfModels = 0; + QVector indexesOfModelsToInclude; + + for (uint16_t i = 0; i < _modelItems->size(); i++) { + if (params.viewFrustum) { + const ModelItem& model = (*_modelItems)[i]; + AABox modelBox = model.getAABox(); + modelBox.scale(TREE_SCALE); + if (params.viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) { + indexesOfModelsToInclude << i; + numberOfModels++; + } + } else { + indexesOfModelsToInclude << i; + numberOfModels++; + } + } + success = packetData->appendValue(numberOfModels); if (success) { - for (uint16_t i = 0; i < numberOfModels; i++) { + foreach (uint16_t i, indexesOfModelsToInclude) { const ModelItem& model = (*_modelItems)[i]; success = model.appendModelData(packetData); if (!success) { @@ -66,10 +83,25 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const { return success; } -void ModelTreeElement::update(ModelTreeUpdateArgs& args) { - markWithChangedTime(); - // TODO: early exit when _modelItems is empty +bool ModelTreeElement::containsModelBounds(const ModelItem& model) const { + return _box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint()); +} +bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const { + if (_box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint())) { + int childForMinimumPoint = getMyChildContainingPoint(model.getMinimumPoint()); + int childForMaximumPoint = getMyChildContainingPoint(model.getMaximumPoint()); + + // If I contain both the minimum and maximum point, but two different children of mine + // contain those points, then I am the best fit for that model + if (childForMinimumPoint != childForMaximumPoint) { + return true; + } + } + return false; +} + +void ModelTreeElement::update(ModelTreeUpdateArgs& args) { // update our contained models QList::iterator modelItr = _modelItems->begin(); while(modelItr != _modelItems->end()) { @@ -78,19 +110,18 @@ void ModelTreeElement::update(ModelTreeUpdateArgs& args) { // If the model wants to die, or if it's left our bounding box, then move it // into the arguments moving models. These will be added back or deleted completely - if (model.getShouldDie() || !_box.contains(model.getPosition())) { + if (model.getShouldDie() || !bestFitModelBounds(model)) { args._movingModels.push_back(model); // erase this model modelItr = _modelItems->erase(modelItr); + + // this element has changed so mark it... + markWithChangedTime(); } else { ++modelItr; } } - // TODO: if _modelItems is empty after while loop consider freeing memory in _modelItems if - // internal array is too big (QList internal array does not decrease size except in dtor and - // assignment operator). Otherwise _modelItems could become a "resource leak" for large - // roaming piles of models. } bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radius, @@ -136,6 +167,7 @@ bool ModelTreeElement::updateModel(const ModelItem& model) { (localOlder ? "OLDER" : "NEWER"), difference, debug::valueOf(model.isNewlyCreated()) ); } + thisModel.copyChangedProperties(model); markWithChangedTime(); } else { diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index ce03d50065..ce9e2dec7e 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -74,7 +74,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. @@ -118,6 +118,9 @@ public: bool removeModelWithID(uint32_t id); + bool containsModelBounds(const ModelItem& model) const; + bool bestFitModelBounds(const ModelItem& model) const; + protected: virtual void init(unsigned char * octalCode); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d308d007cd..5b766ecdd7 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -578,6 +578,10 @@ OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, floa return getRoot()->getOrCreateChildElementAt(x, y, z, s); } +OctreeElement* Octree::getOrCreateChildElementContaining(const AABox& box) { + return getRoot()->getOrCreateChildElementContaining(box); +} + // combines the ray cast arguments into a single object class RayArgs { @@ -1001,7 +1005,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // Keep track of how deep we've encoded. currentEncodeLevel++; - params.maxLevelReached = std::max(currentEncodeLevel,params.maxLevelReached); + params.maxLevelReached = std::max(currentEncodeLevel, params.maxLevelReached); // If we've reached our max Search Level, then stop searching. if (currentEncodeLevel >= params.maxEncodeLevel) { @@ -1342,7 +1346,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, OctreeElement* childElement = element->getChildAtIndex(i); if (childElement) { int bytesBeforeChild = packetData->getUncompressedSize(); - continueThisLevel = childElement->appendElementData(packetData); + continueThisLevel = childElement->appendElementData(packetData, params); int bytesAfterChild = packetData->getUncompressedSize(); if (!continueThisLevel) { diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 6e0693dc23..4a17cb3c1d 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -227,6 +227,7 @@ public: OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const; OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElement* getOrCreateChildElementContaining(const AABox& box); void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL); void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index d54f7aa94b..edba26f2a7 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1379,3 +1379,90 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float // Now that we have the child to recurse down, let it answer the original question... return child->getOrCreateChildElementAt(x, y, z, s); } + + +OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { + OctreeElement* child = NULL; + + float ourScale = getScale(); + float boxScale = box.getScale(); + + if(boxScale > ourScale) { + qDebug("UNEXPECTED -- OctreeElement::getOrCreateChildElementContaining() " + "boxScale=[%f] > ourScale=[%f] ", boxScale, ourScale); + } + + // Determine which of our children the minimum and maximum corners of the box live in... + glm::vec3 boxCornerMinimum = box.getCorner(); + glm::vec3 boxCornerMaximum = box.calcTopFarLeft(); + + int childIndexBoxMinimum = getMyChildContainingPoint(boxCornerMinimum); + int childIndexBoxMaximum = getMyChildContainingPoint(boxCornerMaximum); + + // If the minimum and maximum corners of the box are in two different children's boxes, then we are the containing element + if (childIndexBoxMinimum != childIndexBoxMaximum) { + return this; + } + + // otherwise, they are the same and that child should be considered as the correct element + int childIndex = childIndexBoxMinimum; // both the same... + + // Now, check if we have a child at that location + child = getChildAtIndex(childIndex); + if (!child) { + child = addChildAtIndex(childIndex); + } + + // Now that we have the child to recurse down, let it answer the original question... + return child->getOrCreateChildElementContaining(box); +} + +int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { + glm::vec3 ourCenter = _box.calcCenter(); + int childIndex = CHILD_UNKNOWN; + // left half + if (point.x > ourCenter.x) { + if (point.y > ourCenter.y) { + // top left + if (point.z > ourCenter.z) { + // top left far + childIndex = CHILD_TOP_LEFT_FAR; + } else { + // top left near + childIndex = CHILD_TOP_LEFT_NEAR; + } + } else { + // bottom left + if (point.z > ourCenter.z) { + // bottom left far + childIndex = CHILD_BOTTOM_LEFT_FAR; + } else { + // bottom left near + childIndex = CHILD_BOTTOM_LEFT_NEAR; + } + } + } else { + // right half + if (point.y > ourCenter.y) { + // top right + if (point.z > ourCenter.z) { + // top right far + childIndex = CHILD_TOP_RIGHT_FAR; + } else { + // top right near + childIndex = CHILD_TOP_RIGHT_NEAR; + } + } else { + // bottom right + if (point.z > ourCenter.z) { + // bottom right far + childIndex = CHILD_BOTTOM_RIGHT_FAR; + } else { + // bottom right near + childIndex = CHILD_BOTTOM_RIGHT_NEAR; + } + } + } + return childIndex; +} + diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index c5eec1c9e2..42c9abad46 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -23,14 +23,14 @@ #include "AABox.h" #include "ViewFrustum.h" #include "OctreeConstants.h" -//#include "Octree.h" +class EncodeBitstreamParams; class Octree; class OctreeElement; class OctreeElementDeleteHook; class OctreePacketData; -class VoxelSystem; class ReadBitstreamToTreeParams; +class VoxelSystem; // Callers who want delete hook callbacks should implement this class class OctreeElementDeleteHook { @@ -81,7 +81,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const { return true; } + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { return true; } /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. @@ -217,6 +217,8 @@ public: OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElement* getOrCreateChildElementContaining(const AABox& box); + int getMyChildContainingPoint(const glm::vec3& point) const; protected: diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index d28ccf2f5e..b6e59eb0ab 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -47,7 +47,7 @@ ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) { } -bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const { +bool ParticleTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = true; // assume the best... // write our particles out... diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h index 59f80d588a..4381cdd777 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -76,7 +76,7 @@ public: virtual bool requiresSplit() const { return false; } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index 2582980816..f72e628b74 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -65,7 +65,7 @@ void VoxelTreeElement::splitChildren() { } } -bool VoxelTreeElement::appendElementData(OctreePacketData* packetData) const { +bool VoxelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { return packetData->appendColor(getColor()); } diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 8733987df4..788a728f6f 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -43,7 +43,7 @@ public: virtual bool hasContent() const { return isColored(); } virtual void splitChildren(); virtual bool requiresSplit() const; - virtual bool appendElementData(OctreePacketData* packetData) const; + virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual void calculateAverageFromChildren(); virtual bool collapseChildren(); From f78c81e073e3dd2cf247beb794c3f39734602e60 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 May 2014 17:48:01 -0700 Subject: [PATCH 18/37] add interface to Audio to stop injector and see if playing --- libraries/audio/src/AudioScriptingInterface.cpp | 10 ++++++++++ libraries/audio/src/AudioScriptingInterface.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 944ae49adf..fa0d3a9565 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -32,6 +32,16 @@ AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjec return injector; } +void AudioScriptingInterface::stopInjector(AudioInjector* injector) { + if (injector) { + injector->stop(); + } +} + +bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) { + return (injector != NULL); +} + void AudioScriptingInterface::startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions) { diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index de8e57090a..343eac304c 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -21,6 +21,8 @@ class AudioScriptingInterface : public QObject { Q_OBJECT public slots: static AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + static void stopInjector(AudioInjector* injector); + static bool isInjectorPlaying(AudioInjector* injector); static void startDrumSound(float volume, float frequency, float duration, float decay, const AudioInjectorOptions* injectorOptions = NULL); From c56f0accec5895625ed45235883a42d0c231d81c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 7 May 2014 20:01:02 -0700 Subject: [PATCH 19/37] fix unix build buster --- interface/src/avatar/Hand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index ff21e9f5b2..757a74db29 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -24,7 +24,7 @@ #include #include "InterfaceConfig.h" -#include "renderer/model.h" +#include "renderer/Model.h" #include "world.h" From 01e5b009eee25fb0d9cb891d8c279a1ee035990b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 20:43:23 -0700 Subject: [PATCH 20/37] scope menus better, pause hotkey, no stay paused, remove menu for shared face culling ops --- interface/src/Audio.cpp | 1 + interface/src/Menu.cpp | 22 ++++--------------- interface/src/Menu.h | 2 -- interface/src/voxels/VoxelSystem.cpp | 32 ---------------------------- interface/src/voxels/VoxelSystem.h | 4 +--- 5 files changed, 6 insertions(+), 55 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 68e38615bf..bef6f4c2da 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1068,6 +1068,7 @@ void Audio::toggleScope() { memset(_scopeInput.data(), 0, width * sizeof(int16_t)); memset(_scopeOutputLeft.data(), 0, width * sizeof(int16_t)); memset(_scopeOutputRight.data(), 0, width * sizeof(int16_t)); + _scopeEnabledPause = false; } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0587e979f6..eecc18534c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -272,9 +272,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::AudioScope, 0, false, - appInstance->getAudio(), - SLOT(toggleScope())); QMenu* developerMenu = addMenu("Developer"); @@ -371,20 +368,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); - addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::CullSharedFaces, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - false, - appInstance->getVoxels(), - SLOT(cullSharedFaces())); - - addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::ShowCulledSharedFaces, - 0, - false, - appInstance->getVoxels(), - SLOT(showCulledSharedFaces())); - QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, @@ -408,8 +391,11 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleToneInjection())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, + appInstance->getAudio(), + SLOT(toggleScope())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScopePause, - Qt::CTRL | Qt::Key_P, + Qt::CTRL | Qt::SHIFT | Qt::Key_P , false, appInstance->getAudio(), SLOT(toggleScopePause())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d1097929f7..1e13d5ff2a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -297,7 +297,6 @@ namespace MenuOption { const QString CollideWithParticles = "Collide With Particles"; const QString CollideWithVoxels = "Collide With Voxels"; const QString Collisions = "Collisions"; - const QString CullSharedFaces = "Cull Shared Voxel Faces"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; @@ -363,7 +362,6 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; - const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; const QString ShowIKConstraints = "Show IK Constraints"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 0fac5a338c..8937cef7dd 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -1711,38 +1711,6 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, return true; } - -void VoxelSystem::cullSharedFaces() { - - if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - _useVoxelShader = false; - _usePrimitiveRenderer = true; - inspectForOcclusions(); - } else { - _usePrimitiveRenderer = false; - clearAllNodesBufferIndex(); - } - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); -} - -void VoxelSystem::showCulledSharedFaces() { - - _tree->lockForRead(); - if (Menu::getInstance()->isOptionChecked(MenuOption::ShowCulledSharedFaces)) { - _showCulledSharedFaces = true; - } else { - _showCulledSharedFaces = false; - } - _tree->unlock(); - if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); - } -} - void VoxelSystem::inspectForOcclusions() { if (_inOcclusions) { diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index b134fe1539..15e2b20a75 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -95,9 +95,7 @@ public slots: // Methods that recurse tree void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); - void cullSharedFaces(); - void showCulledSharedFaces(); - + void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline); void setUseVoxelShader(bool useVoxelShader); void setVoxelsAsPoints(bool voxelsAsPoints); From 8f4fb04021c192b3fdb078ed0fd0ac3148f3dc90 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 22:24:05 -0700 Subject: [PATCH 21/37] clearer visualization of controller hand target, remove hand paddles --- interface/src/avatar/Hand.cpp | 29 ++++++++++++++++++++++------- interface/src/avatar/Hand.h | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 320a8477c1..a6cd7ff10e 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -213,7 +213,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { - renderLeapHands(isMine); + renderHandTargets(isMine); } glEnable(GL_DEPTH_TEST); @@ -221,11 +221,11 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } -void Hand::renderLeapHands(bool isMine) { +void Hand::renderHandTargets(bool isMine) { const float alpha = 1.0f; - const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color + const glm::vec3 handColor(1.0, 0.0, 0.0); // Color the hand targets red to be different than skin glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); @@ -262,23 +262,37 @@ void Hand::renderLeapHands(bool isMine) { glPopMatrix(); } } - - // Draw the finger root cones + + const float PALM_BALL_RADIUS = 0.03f; + const float PALM_DISK_RADIUS = 0.06f; + const float PALM_DISK_THICKNESS = 0.01f; + const float PALM_FINGER_ROD_RADIUS = 0.003f; + + // Draw the palm ball and disk for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (palm.isActive()) { for (size_t f = 0; f < palm.getNumFingers(); ++f) { FingerData& finger = palm.getFingers()[f]; if (finger.isActive()) { - glColor4f(handColor.r, handColor.g, handColor.b, 0.5); + glColor4f(handColor.r, handColor.g, handColor.b, alpha); glm::vec3 tip = finger.getTipPosition(); glm::vec3 root = finger.getRootPosition(); - Avatar::renderJointConnectingCone(root, tip, 0.001f, 0.003f); + Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS); + // Render sphere at palm/finger root + glm::vec3 palmNormal = root + palm.getNormal() * PALM_DISK_THICKNESS; + Avatar::renderJointConnectingCone(root, palmNormal, PALM_DISK_RADIUS, 0.0f); + glPushMatrix(); + glTranslatef(root.x, root.y, root.z); + glutSolidSphere(PALM_BALL_RADIUS, 20.0f, 20.0f); + glPopMatrix(); + } } } } + /* // Draw the hand paddles int MAX_NUM_PADDLES = 2; // one for left and one for right glColor4f(handColor.r, handColor.g, handColor.b, 0.3f); @@ -309,6 +323,7 @@ void Hand::renderLeapHands(bool isMine) { Avatar::renderJointConnectingCone(root, tip, HAND_PADDLE_RADIUS, 0.f); } } + */ glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 757a74db29..9c2bc2c2c0 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -76,7 +76,7 @@ private: std::vector _leapFingerTipBalls; std::vector _leapFingerRootBalls; - void renderLeapHands(bool isMine); + void renderHandTargets(bool isMine); void renderLeapFingerTrails(); void calculateGeometry(); From e439694d72b5c791346a255af10178fe31ec424f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 22:56:06 -0700 Subject: [PATCH 22/37] =?UTF-8?q?reset=20only=20pitch=20and=20roll=20on=20?= =?UTF-8?q?spacebar=20so=20that=20you=20don=E2=80=99t=20turn=20away=20from?= =?UTF-8?q?=20someone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interface/src/avatar/MyAvatar.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1655a17f08..f320a2759d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -99,7 +99,11 @@ void MyAvatar::reset() { setVelocity(glm::vec3(0.0f)); setThrust(glm::vec3(0.0f)); - setOrientation(glm::quat(glm::vec3(0.0f))); + // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction + glm::vec3 eulers = safeEulerAngles(getOrientation()); + eulers.x = 0.f; + eulers.z = 0.f; + setOrientation(glm::quat(eulers)); } void MyAvatar::update(float deltaTime) { From 1e276f6dae1d87c8eeb526b74022fbba342916da Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 7 May 2014 23:41:58 -0700 Subject: [PATCH 23/37] Improved hydra idle detection by tracking total distance moved, fixed NaN in starting velocities --- interface/src/devices/SixenseManager.cpp | 24 ++++++++++++++++++------ interface/src/devices/SixenseManager.h | 1 + 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index f7c00411c1..0435519124 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -30,6 +30,7 @@ const float NECK_Z = 300.f; // millimeters SixenseManager::SixenseManager() { #ifdef HAVE_SIXENSE _lastMovement = 0; + _amountMoved = glm::vec3(0.0f); _calibrationState = CALIBRATION_STATE_IDLE; // By default we assume the _neckBase (in orb frame) is as high above the orb @@ -122,14 +123,21 @@ void SixenseManager::update(float deltaTime) { palm->setRawRotation(rotation); // Compute current velocity from position change - glm::vec3 rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; + glm::vec3 rawVelocity; + if (deltaTime > 0.f) { + rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; + } else { + rawVelocity = glm::vec3(0.0f); + } palm->setRawVelocity(rawVelocity); // meters/sec palm->setRawPosition(position); // use the velocity to determine whether there's any movement (if the hand isn't new) - const float MOVEMENT_SPEED_THRESHOLD = 0.05f; - if (glm::length(rawVelocity) > MOVEMENT_SPEED_THRESHOLD && foundHand) { + const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; + _amountMoved += rawVelocity * deltaTime; + if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) { _lastMovement = usecTimestampNow(); + _amountMoved = glm::vec3(0.0f); } // initialize the "finger" based on the direction @@ -143,7 +151,11 @@ void SixenseManager::update(float deltaTime) { // Store the one fingertip in the palm structure so we can track velocity glm::vec3 oldTipPosition = palm->getTipRawPosition(); - palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime / 1000.f); + if (deltaTime > 0.f) { + palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime / 1000.f); + } else { + palm->setTipVelocity(glm::vec3(0.f)); + } palm->setTipPosition(newTipPosition); // three fingers indicates to the skeleton that we have enough data to determine direction @@ -158,8 +170,8 @@ void SixenseManager::update(float deltaTime) { } // if the controllers haven't been moved in a while, disable - const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; - if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) { + const unsigned int MOVEMENT_DISABLE_SECONDS = 3; + if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * 1000 * 1000)) { for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { it->setActive(false); } diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 2fc6b3dcb3..a98d4c0e4e 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -64,6 +64,7 @@ private: #endif quint64 _lastMovement; + glm::vec3 _amountMoved; }; #endif // hifi_SixenseManager_h From 2797d0ab3b4d4498d4981800764874e25f70cf10 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 00:09:07 -0700 Subject: [PATCH 24/37] removed hand trying to follow mouse and other cruft --- interface/src/Application.cpp | 38 +-------------------------- interface/src/Application.h | 6 ----- interface/src/avatar/MyAvatar.cpp | 43 ++++++------------------------- interface/src/avatar/MyAvatar.h | 1 - 4 files changed, 9 insertions(+), 79 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fb414311ef..61666ccdeb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1217,10 +1217,6 @@ void Application::touchBeginEvent(QTouchEvent* event) { return; } - // put any application specific touch behavior below here.. - _lastTouchAvgX = _touchAvgX; - _lastTouchAvgY = _touchAvgY; - } void Application::touchEndEvent(QTouchEvent* event) { @@ -1875,34 +1871,6 @@ void Application::updateMyAvatarLookAtPosition() { _myAvatar->getHead()->setLookAtPosition(lookAtSpot); } -void Application::updateHandAndTouch(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()"); - - // Update from Touch - if (_isTouchPressed) { - _lastTouchAvgX = _touchAvgX; - _lastTouchAvgY = _touchAvgY; - } -} - -void Application::updateLeap(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateLeap()"); -} - -void Application::updateSixense(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateSixense()"); - - _sixenseManager.update(deltaTime); -} - -void Application::updateSerialDevices(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()"); -} - void Application::updateThreads(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateThreads()"); @@ -2016,11 +1984,7 @@ void Application::update(float deltaTime) { updateVisage(); _myAvatar->updateLookAtTargetAvatar(); updateMyAvatarLookAtPosition(); - - updateHandAndTouch(deltaTime); // Update state for touch sensors - updateLeap(deltaTime); // Leap finger-sensing device - updateSixense(deltaTime); // Razer Hydra controllers - updateSerialDevices(deltaTime); // Read serial port interface devices + _sixenseManager.update(deltaTime); updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... diff --git a/interface/src/Application.h b/interface/src/Application.h index 54e6bcdcac..91a7ebd29b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -343,10 +343,6 @@ private: void updateFaceshift(); void updateVisage(); void updateMyAvatarLookAtPosition(); - void updateHandAndTouch(float deltaTime); - void updateLeap(float deltaTime); - void updateSixense(float deltaTime); - void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); @@ -477,8 +473,6 @@ private: float _touchAvgX; float _touchAvgY; - float _lastTouchAvgX; - float _lastTouchAvgY; float _touchDragStartedAvgX; float _touchDragStartedAvgY; bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f320a2759d..2f931b0a54 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -136,7 +136,14 @@ void MyAvatar::simulate(float deltaTime) { } // update the movement of the hand and process handshaking with other avatars... - updateHandMovementAndTouching(deltaTime); + bool pointing = false; + if (_mousePressed) { + _handState = HAND_STATE_GRASPING; + } else if (pointing) { + _handState = HAND_STATE_POINTING; + } else { + _handState = HAND_STATE_NULL; + } updateOrientation(deltaTime); @@ -915,40 +922,6 @@ void MyAvatar::updateThrust(float deltaTime) { } */ -void MyAvatar::updateHandMovementAndTouching(float deltaTime) { - glm::quat orientation = getOrientation(); - - // reset hand and arm positions according to hand movement - glm::vec3 up = orientation * IDENTITY_UP; - - bool pointing = false; - if (glm::length(_mouseRayDirection) > EPSILON && !Application::getInstance()->isMouseHidden()) { - // confine to the approximate shoulder plane - glm::vec3 pointDirection = _mouseRayDirection; - if (glm::dot(_mouseRayDirection, up) > 0.0f) { - glm::vec3 projectedVector = glm::cross(up, glm::cross(_mouseRayDirection, up)); - if (glm::length(projectedVector) > EPSILON) { - pointDirection = glm::normalize(projectedVector); - } - } - glm::vec3 shoulderPosition; - if (_skeletonModel.getRightShoulderPosition(shoulderPosition)) { - glm::vec3 farVector = _mouseRayOrigin + pointDirection * (float)TREE_SCALE - shoulderPosition; - const float ARM_RETRACTION = 0.75f; - float retractedLength = _skeletonModel.getRightArmLength() * ARM_RETRACTION; - setHandPosition(shoulderPosition + glm::normalize(farVector) * retractedLength); - pointing = true; - } - } - - if (_mousePressed) { - _handState = HAND_STATE_GRASPING; - } else if (pointing) { - _handState = HAND_STATE_POINTING; - } else { - _handState = HAND_STATE_NULL; - } -} void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1c80d3b969..f715a37db4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -147,7 +147,6 @@ private: float computeMotorTimescale(); void applyMotor(float deltaTime); void applyThrust(float deltaTime); - void updateHandMovementAndTouching(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); From 2c6c57eec2875823fadd14c0f5d4028ce26bc17d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 00:28:02 -0700 Subject: [PATCH 25/37] increase hand restoration rate, improve function name clarity --- interface/src/avatar/MyAvatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f931b0a54..c3591862d1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -109,7 +109,7 @@ void MyAvatar::reset() { void MyAvatar::update(float deltaTime) { Head* head = getHead(); head->relaxLean(deltaTime); - updateFromGyros(deltaTime); + updateFromFaceTracker(deltaTime); if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { // Faceshift drive is enabled, set the avatar drive based on the head position moveWithLean(); @@ -239,7 +239,7 @@ void MyAvatar::simulate(float deltaTime) { } // Update avatar head rotation with sensor data -void MyAvatar::updateFromGyros(float deltaTime) { +void MyAvatar::updateFromFaceTracker(float deltaTime) { glm::vec3 estimatedPosition, estimatedRotation; FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f715a37db4..c07c27033c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -38,7 +38,7 @@ public: void reset(); void update(float deltaTime); void simulate(float deltaTime); - void updateFromGyros(float deltaTime); + void updateFromFaceTracker(float deltaTime); void moveWithLean(); void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e4c796d3ce..8c21a3240f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -38,24 +38,23 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { Hand* hand = _owningAvatar->getHand(); hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - const float HAND_RESTORATION_PERIOD = 1.f; // seconds - float handRestorePercent = glm::clamp(deltaTime / HAND_RESTORATION_PERIOD, 0.f, 1.f); + const float HAND_RESTORATION_RATE = 0.25f; const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (leftPalmIndex == -1) { // no Leap data; set hands from mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { - restoreRightHandPosition(handRestorePercent); + restoreRightHandPosition(HAND_RESTORATION_RATE); } else { applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); } - restoreLeftHandPosition(handRestorePercent); + restoreLeftHandPosition(HAND_RESTORATION_RATE); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices, hand->getPalms()[leftPalmIndex]); - restoreLeftHandPosition(handRestorePercent); + restoreLeftHandPosition(HAND_RESTORATION_RATE); } else { applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices, From 4185faa82ad72aa632baacee17e40ab652f9f1a1 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 01:06:26 -0700 Subject: [PATCH 26/37] Tweaks to improve mouth and brow appearance when just audio driven --- interface/src/avatar/Head.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 9cb8ea3d9c..ce02bb8e55 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -106,15 +106,10 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { const float BROW_LIFT_THRESHOLD = 100.0f; if (_audioAttack > BROW_LIFT_THRESHOLD) { - _browAudioLift += sqrtf(_audioAttack) * 0.00005f; + _browAudioLift += sqrtf(_audioAttack) * 0.01f; } - - const float CLAMP = 0.01f; - if (_browAudioLift > CLAMP) { - _browAudioLift = CLAMP; - } - - _browAudioLift *= 0.7f; + _browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f); + qDebug() << _browAudioLift; const float BLINK_SPEED = 10.0f; const float FULLY_OPEN = 0.0f; @@ -147,12 +142,12 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // use data to update fake Faceshift blendshape coefficients - const float BROW_LIFT_SCALE = 500.0f; - const float JAW_OPEN_SCALE = 0.01f; - const float JAW_OPEN_DEAD_ZONE = 0.75f; - Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, - min(1.0f, _browAudioLift * BROW_LIFT_SCALE), glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients); + const float JAW_OPEN_SCALE = 10.f; + Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, + _rightEyeBlink, + _browAudioLift, + glm::clamp(log(_averageLoudness) / JAW_OPEN_SCALE, 0.0f, 1.0f), + _blendshapeCoefficients); } if (!isMine) { From 71789b65e71bd5c2f836ab0a7e6a7221d6b1f603 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 11:02:35 -0700 Subject: [PATCH 27/37] remove debug --- interface/src/avatar/Head.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ce02bb8e55..2d0599b31f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -109,8 +109,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _browAudioLift += sqrtf(_audioAttack) * 0.01f; } _browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f); - qDebug() << _browAudioLift; - + const float BLINK_SPEED = 10.0f; const float FULLY_OPEN = 0.0f; const float FULLY_CLOSED = 1.0f; From a8a53e35dd4762e7567aa9d27d68706ca235fbbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 8 May 2014 11:12:16 -0700 Subject: [PATCH 28/37] make sure shouldStop for injector defaults to false --- libraries/audio/src/AudioInjector.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 364d14cfbb..1fe9f1336f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -22,14 +22,18 @@ #include "AudioInjector.h" AudioInjector::AudioInjector(QObject* parent) : - QObject(parent) + QObject(parent), + _sound(NULL), + _options(), + _shouldStop(false) { } AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : _sound(sound), - _options(injectorOptions) + _options(injectorOptions), + _shouldStop(false) { } From f866828db2a2f4f3dd43ae742a7fb443e103f222 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 8 May 2014 15:20:14 -0700 Subject: [PATCH 29/37] Avatar attachment scripting bits. --- libraries/avatars/src/AvatarData.cpp | 114 ++++++++++++++++++- libraries/avatars/src/AvatarData.h | 46 +++++++- libraries/script-engine/src/ScriptEngine.cpp | 1 + 3 files changed, 155 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ead5967c78..b226da8b5c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -661,16 +661,66 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { updateJointMappings(); } -void AvatarData::setAttachmentData(const QVector& attachmentData) { - _attachmentData = attachmentData; -} - void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; qDebug() << "Changing display name for avatar to" << displayName; } +QVector AvatarData::getAttachmentData() const { + if (QThread::currentThread() != thread()) { + QVector result; + QMetaObject::invokeMethod(const_cast(this), "getAttachmentData", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVector, result)); + return result; + } + return _attachmentData; +} + +void AvatarData::setAttachmentData(const QVector& attachmentData) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setAttachmentData", Q_ARG(const QVector&, attachmentData)); + return; + } + _attachmentData = attachmentData; +} + +void AvatarData::attach(const QString& modelURL, const QString& jointName, + const glm::vec3& translation, const glm::quat& rotation, float scale) { + QVector attachmentData = getAttachmentData(); + AttachmentData data; + data.modelURL = modelURL; + data.jointName = jointName; + data.translation = translation; + data.rotation = rotation; + data.scale = scale; + attachmentData.append(data); + setAttachmentData(attachmentData); +} + +void AvatarData::detachOne(const QString& modelURL, const QString& jointName) { + QVector attachmentData = getAttachmentData(); + for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); it++) { + if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { + attachmentData.erase(it); + return; + } + } + setAttachmentData(attachmentData); +} + +void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { + QVector attachmentData = getAttachmentData(); + for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ) { + if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { + it = attachmentData.erase(it); + } else { + it++; + } + } + setAttachmentData(attachmentData); +} + void AvatarData::setBillboard(const QByteArray& billboard) { _billboard = billboard; @@ -793,3 +843,59 @@ QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) { attachment.translation >> attachment.rotation >> attachment.scale; } +void AttachmentDataObject::setModelURL(const QString& modelURL) const { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.modelURL = modelURL; + thisObject() = engine()->toScriptValue(data); +} + +QString AttachmentDataObject::getModelURL() const { + return qscriptvalue_cast(thisObject()).modelURL.toString(); +} + +void AttachmentDataObject::setJointName(const QString& jointName) const { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.jointName = jointName; + thisObject() = engine()->toScriptValue(data); +} + +QString AttachmentDataObject::getJointName() const { + return qscriptvalue_cast(thisObject()).jointName; +} + +void AttachmentDataObject::setTranslation(const glm::vec3& translation) const { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.translation = translation; + thisObject() = engine()->toScriptValue(data); +} + +glm::vec3 AttachmentDataObject::getTranslation() const { + return qscriptvalue_cast(thisObject()).translation; +} + +void AttachmentDataObject::setRotation(const glm::quat& rotation) const { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.rotation = rotation; + thisObject() = engine()->toScriptValue(data); +} + +glm::quat AttachmentDataObject::getRotation() const { + return qscriptvalue_cast(thisObject()).rotation; +} + +void AttachmentDataObject::setScale(float scale) const { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.scale = scale; + thisObject() = engine()->toScriptValue(data); +} + +float AttachmentDataObject::getScale() const { + return qscriptvalue_cast(thisObject()).scale; +} + +void registerAvatarTypes(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType >(engine); + engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( + new AttachmentDataObject(), QScriptEngine::ScriptOwnership)); +} + diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 50c1608be8..1fd8f6c425 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -41,6 +41,7 @@ typedef unsigned long long quint64; #include #include #include +#include #include #include @@ -123,6 +124,7 @@ class AvatarData : public QObject { Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName) Q_PROPERTY(QString faceModelURL READ getFaceModelURLFromScript WRITE setFaceModelURLFromScript) Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript) + Q_PROPERTY(QVector attachmentData READ getAttachmentData WRITE setAttachmentData) Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL) Q_PROPERTY(QStringList jointNames READ getJointNames) @@ -229,13 +231,21 @@ public: const QUrl& getFaceModelURL() const { return _faceModelURL; } QString getFaceModelURLString() const { return _faceModelURL.toString(); } const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } - const QVector& getAttachmentData() const { return _attachmentData; } const QString& getDisplayName() const { return _displayName; } virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); - virtual void setAttachmentData(const QVector& attachmentData); + virtual void setDisplayName(const QString& displayName); + Q_INVOKABLE QVector getAttachmentData() const; + Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData); + + Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f); + + Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); + Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString()); + virtual void setBillboard(const QByteArray& billboard); const QByteArray& getBillboard() const { return _billboard; } @@ -347,4 +357,36 @@ public: QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment); QDataStream& operator>>(QDataStream& in, AttachmentData& attachment); +Q_DECLARE_METATYPE(AttachmentData) +Q_DECLARE_METATYPE(QVector) + +/// Scriptable wrapper for attachments. +class AttachmentDataObject : public QObject, protected QScriptable { + Q_OBJECT + Q_PROPERTY(QString modelURL READ getModelURL WRITE setModelURL) + Q_PROPERTY(QString jointName READ getJointName WRITE setJointName) + Q_PROPERTY(glm::vec3 translation READ getTranslation WRITE setTranslation) + Q_PROPERTY(glm::quat rotation READ getRotation WRITE setRotation) + Q_PROPERTY(float scale READ getScale WRITE setScale) + +public: + + Q_INVOKABLE void setModelURL(const QString& modelURL) const; + Q_INVOKABLE QString getModelURL() const; + + Q_INVOKABLE void setJointName(const QString& jointName) const; + Q_INVOKABLE QString getJointName() const; + + Q_INVOKABLE void setTranslation(const glm::vec3& translation) const; + Q_INVOKABLE glm::vec3 getTranslation() const; + + Q_INVOKABLE void setRotation(const glm::quat& rotation) const; + Q_INVOKABLE glm::quat getRotation() const; + + Q_INVOKABLE void setScale(float scale) const; + Q_INVOKABLE float getScale() const; +}; + +void registerAvatarTypes(QScriptEngine* engine); + #endif // hifi_AvatarData_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 9be2cb5252..be97b37b46 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -210,6 +210,7 @@ void ScriptEngine::init() { registerEventTypes(&_engine); registerMenuItemProperties(&_engine); registerAnimationTypes(&_engine); + registerAvatarTypes(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); From c02b708ee5605db06caebd85548166b5ebc99989 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 8 May 2014 15:54:30 -0700 Subject: [PATCH 30/37] Provide the option to avoid making duplicate attachments. --- examples/gun.js | 7 ++++++- interface/src/avatar/Avatar.cpp | 4 +++- libraries/avatars/src/AvatarData.cpp | 27 ++++++++++++++++++++++++--- libraries/avatars/src/AvatarData.h | 3 ++- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/examples/gun.js b/examples/gun.js index 4bfdb140b8..6cdf634239 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -39,6 +39,8 @@ var impactSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-pub var targetHitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw"); var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw"); +var gunModel = "http://highfidelity-public.s3-us-west-1.amazonaws.com/models/attachments/Raygun2.fst"; + var audioOptions = new AudioInjectionOptions(); audioOptions.volume = 0.9; @@ -190,6 +192,8 @@ function keyPressEvent(event) { } } +MyAvatar.attach(gunModel, "RightHand", {x: -0.10, y: 0.0, z: 0.0}, Quat.fromPitchYawRollDegrees(-90, 180, 0), 0.14); + function update(deltaTime) { // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse @@ -303,7 +307,8 @@ function mouseMoveEvent(event) { function scriptEnding() { Overlays.deleteOverlay(reticle); - Overlays.deleteOverlay(text); + Overlays.deleteOverlay(text); + MyAvatar.detachOne(gunModel); } Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bc2bbb6712..bac339813f 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -709,7 +709,9 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setAttachmentData(const QVector& attachmentData) { AvatarData::setAttachmentData(attachmentData); - + if (QThread::currentThread() != thread()) { + return; + } // make sure we have as many models as attachments while (_attachmentModels.size() < attachmentData.size()) { Model* model = new Model(this); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b226da8b5c..26613e51d0 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -685,9 +685,22 @@ void AvatarData::setAttachmentData(const QVector& attachmentData _attachmentData = attachmentData; } -void AvatarData::attach(const QString& modelURL, const QString& jointName, - const glm::vec3& translation, const glm::quat& rotation, float scale) { +void AvatarData::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, + const glm::quat& rotation, float scale, bool allowDuplicates) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName), + Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), + Q_ARG(float, scale), Q_ARG(bool, allowDuplicates)); + return; + } QVector attachmentData = getAttachmentData(); + if (!allowDuplicates) { + foreach (const AttachmentData& data, attachmentData) { + if (data.modelURL == modelURL && (jointName.isEmpty() || data.jointName == jointName)) { + return; + } + } + } AttachmentData data; data.modelURL = modelURL; data.jointName = jointName; @@ -699,17 +712,25 @@ void AvatarData::attach(const QString& modelURL, const QString& jointName, } void AvatarData::detachOne(const QString& modelURL, const QString& jointName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "detachOne", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName)); + return; + } QVector attachmentData = getAttachmentData(); for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); it++) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { attachmentData.erase(it); + setAttachmentData(attachmentData); return; } } - setAttachmentData(attachmentData); } void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "detachAll", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName)); + return; + } QVector attachmentData = getAttachmentData(); for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fd8f6c425..cc5ab16e35 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -241,7 +241,8 @@ public: Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData); Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), - const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f); + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, + bool allowDuplicates = false); Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString()); From acab09b89a79ea04e1aa221040dd1c935a7753cd Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 8 May 2014 16:23:15 -0700 Subject: [PATCH 31/37] Update billboard when attachments change. --- interface/src/avatar/MyAvatar.cpp | 13 +++++++++++++ interface/src/avatar/MyAvatar.h | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c3591862d1..7bc35ebd6d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -584,6 +584,14 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _billboardValid = false; } +void MyAvatar::setAttachmentData(const QVector& attachmentData) { + Avatar::setAttachmentData(attachmentData); + if (QThread::currentThread() != thread()) { + return; + } + _billboardValid = false; +} + void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded @@ -1247,6 +1255,11 @@ void MyAvatar::maybeUpdateBillboard() { if (_billboardValid || !(_skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures())) { return; } + foreach (Model* model, _attachmentModels) { + if (!model->isLoadedWithTextures()) { + return; + } + } QImage image = Application::getInstance()->renderAvatarBillboard(); _billboard.clear(); QBuffer buffer(&_billboard); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c07c27033c..885d56b61f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -86,7 +86,8 @@ public: virtual void clearJointData(int index); virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); - + virtual void setAttachmentData(const QVector& attachmentData); + virtual void setCollisionGroups(quint32 collisionGroups); void setMotionBehaviorsByScript(quint32 flags); From f019e2366e1065c06042920a7adf6115207ff1a5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 8 May 2014 17:10:02 -0700 Subject: [PATCH 32/37] Add lift for walking up stairs Also some fixes for freeing avatars trapped in voxel collisions --- interface/src/avatar/MyAvatar.cpp | 97 ++++++++++++++++++++++++------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dd68201b46..8e44138679 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -46,6 +46,9 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; +const float MIN_KEYBOARD_CONTROL_SPEED = 2.0f; +const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED; + const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5.0f * 1000.0f; // TODO: normalize avatar speed for standard avatar size, then scale all motion logic @@ -64,7 +67,7 @@ MyAvatar::MyAvatar() : _distanceToNearestAvatar(std::numeric_limits::max()), _wasPushing(false), _isPushing(false), - _wasStuck(false), + _trapDuration(0.0f), _thrust(0.0f), _motorVelocity(0.0f), _motorTimescale(DEFAULT_MOTOR_TIMESCALE), @@ -215,7 +218,7 @@ void MyAvatar::simulate(float deltaTime) { if (_collisionGroups & COLLISION_GROUP_VOXELS) { updateCollisionWithVoxels(deltaTime, radius); } else { - _wasStuck = false; + _trapDuration = 0.0f; } if (_collisionGroups & COLLISION_GROUP_AVATARS) { updateCollisionWithAvatars(deltaTime); @@ -697,8 +700,6 @@ void MyAvatar::updateMotorFromKeyboard(float deltaTime, bool walking) { if (directionLength > EPSILON) { direction /= directionLength; // the finalMotorSpeed depends on whether we are walking or not - const float MIN_KEYBOARD_CONTROL_SPEED = 2.0f; - const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED; float finalMaxMotorSpeed = walking ? MAX_WALKING_SPEED : _maxMotorSpeed; float motorLength = glm::length(_motorVelocity); @@ -962,48 +963,102 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { static CollisionList myCollisions(64); void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { - const float MIN_STUCK_SPEED = 100.0f; + const float MAX_VOXEL_COLLISION_SPEED = 100.0f; float speed = glm::length(_velocity); - if (speed > MIN_STUCK_SPEED) { + if (speed > MAX_VOXEL_COLLISION_SPEED) { // don't even bother to try to collide against voxles when moving very fast + _trapDuration = 0.0f; return; } + bool isTrapped = false; myCollisions.clear(); const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) { + if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions, Octree::TryLock)) { const float VOXEL_ELASTICITY = 0.0f; const float VOXEL_DAMPING = 0.0f; float capsuleRadius = boundingShape.getRadius(); - + float capsuleHalfHeight = boundingShape.getHalfHeight(); + const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight; + const float MIN_STEP_HEIGHT = 0.0f; + glm::vec3 footBase = boundingShape.getPosition() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection; + float highestStep = 0.0f; + glm::vec3 stepPenetration(0.0f); glm::vec3 totalPenetration(0.0f); - bool isStuck = false; + for (int i = 0; i < myCollisions.size(); ++i) { CollisionInfo* collision = myCollisions[i]; - float depth = glm::length(collision->_penetration); - if (depth > capsuleRadius) { - isStuck = true; - if (_wasStuck) { - glm::vec3 cubeCenter = collision->_vecData; - float cubeSide = collision->_floatData; + glm::vec3 cubeCenter = collision->_vecData; + float cubeSide = collision->_floatData; + float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection); + float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection); + const float MAX_TRAP_PERIOD = 0.125f; + if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) { + isTrapped = true; + if (_trapDuration > MAX_TRAP_PERIOD) { float distance = glm::dot(boundingShape.getPosition() - cubeCenter, _worldUpDirection); if (distance < 0.0f) { distance = fabsf(distance) + 0.5f * cubeSide; } - distance += capsuleRadius + boundingShape.getHalfHeight(); + distance += capsuleRadius + capsuleHalfHeight; totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection); continue; } + } else if (_trapDuration > MAX_TRAP_PERIOD) { + // we're trapped, ignore this collision + continue; } totalPenetration = addPenetrations(totalPenetration, collision->_penetration); + if (glm::dot(collision->_penetration, _velocity) >= 0.0f) { + glm::vec3 cubeTop = cubeCenter + (0.5f * cubeSide) * _worldUpDirection; + float stepHeight = glm::dot(_worldUpDirection, cubeTop - footBase); + if (stepHeight > highestStep) { + highestStep = stepHeight; + stepPenetration = collision->_penetration; + } + } + } + + float penetrationLength = glm::length(totalPenetration); + if (penetrationLength < EPSILON) { + _trapDuration = 0.0f; + return; + } + float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection); + if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) { + // we're colliding against an edge + glm::vec3 targetVelocity = _motorVelocity; + if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) { + // rotate _motorVelocity into world frame + glm::quat rotation = getHead()->getCameraOrientation(); + targetVelocity = rotation * _motorVelocity; + } + if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) { + // we're puhing into the edge, so we want to lift + + // remove unhelpful horizontal component of the step's penetration + totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection); + + // further adjust penetration to help lift + float liftSpeed = glm::max(MAX_WALKING_SPEED, speed); + float thisStep = glm::min(liftSpeed * deltaTime, highestStep); + float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep; + if (extraStep > 0.0f) { + totalPenetration -= extraStep * _worldUpDirection; + } + + _position -= totalPenetration; + } else { + // we're not pushing into the edge, so let the avatar fall + applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + } + } else { + applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } - applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - _wasStuck = isStuck; const float VOXEL_COLLISION_FREQUENCY = 0.5f; updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - } else { - _wasStuck = false; - } + } + _trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f; } void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1c80d3b969..ec20f69d6a 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -125,7 +125,7 @@ private: bool _wasPushing; bool _isPushing; - bool _wasStuck; + float _trapDuration; // seconds that avatar has been trapped by collisions glm::vec3 _thrust; // final acceleration from outside sources for the current frame glm::vec3 _motorVelocity; // intended velocity of avatar motion From c424f6ce69b41f9b65bc2a320cbf700562d798fd Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 8 May 2014 18:00:41 -0700 Subject: [PATCH 33/37] Save attachment data for attachment model/skeleton model combinations, let scripts use those saved parameters so that you can tweak the location of (for example) the gun and have it saved appropriately. --- interface/src/avatar/MyAvatar.cpp | 66 ++++++++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 7 +++ interface/src/ui/AttachmentsDialog.cpp | 56 ++++++++++++++++------ interface/src/ui/AttachmentsDialog.h | 3 ++ libraries/avatars/src/AvatarData.cpp | 4 +- libraries/avatars/src/AvatarData.h | 2 +- 6 files changed, 120 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7bc35ebd6d..c46135f069 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -513,6 +513,55 @@ void MyAvatar::loadData(QSettings* settings) { settings->endGroup(); } +void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { + QSettings* settings = Application::getInstance()->lockSettings(); + settings->beginGroup("savedAttachmentData"); + settings->beginGroup(_skeletonModel.getURL().toString()); + settings->beginGroup(attachment.modelURL.toString()); + + settings->setValue("jointName", attachment.jointName); + settings->setValue("translation_x", attachment.translation.x); + settings->setValue("translation_y", attachment.translation.y); + settings->setValue("translation_z", attachment.translation.z); + glm::vec3 eulers = safeEulerAngles(attachment.rotation); + settings->setValue("rotation_x", eulers.x); + settings->setValue("rotation_y", eulers.y); + settings->setValue("rotation_z", eulers.z); + settings->setValue("scale", attachment.scale); + + settings->endGroup(); + settings->endGroup(); + settings->endGroup(); + Application::getInstance()->unlockSettings(); +} + +AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL) const { + QSettings* settings = Application::getInstance()->lockSettings(); + settings->beginGroup("savedAttachmentData"); + settings->beginGroup(_skeletonModel.getURL().toString()); + settings->beginGroup(modelURL.toString()); + + AttachmentData attachment; + attachment.modelURL = modelURL; + attachment.jointName = settings->value("jointName").toString(); + attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); + attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); + attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); + glm::vec3 eulers; + eulers.x = loadSetting(settings, "rotation_x", 0.0f); + eulers.y = loadSetting(settings, "rotation_y", 0.0f); + eulers.z = loadSetting(settings, "rotation_z", 0.0f); + attachment.rotation = glm::quat(eulers); + attachment.scale = loadSetting(settings, "scale", 1.0f); + + settings->endGroup(); + settings->endGroup(); + settings->endGroup(); + Application::getInstance()->unlockSettings(); + + return attachment; +} + int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { qDebug() << "Error: ignoring update packet for MyAvatar" << " packetLength = " << packet.size() @@ -592,6 +641,23 @@ void MyAvatar::setAttachmentData(const QVector& attachmentData) _billboardValid = false; } +void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, + const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { + if (QThread::currentThread() != thread()) { + Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); + return; + } + if (useSaved) { + AttachmentData attachment = loadAttachmentData(modelURL); + if (!attachment.jointName.isEmpty()) { + Avatar::attach(modelURL, attachment.jointName, attachment.translation, + attachment.rotation, attachment.scale, allowDuplicates, useSaved); + return; + } + } + Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); +} + void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 885d56b61f..b41c2b6d99 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -66,6 +66,9 @@ public: void saveData(QSettings* settings); void loadData(QSettings* settings); + void saveAttachmentData(const AttachmentData& attachment) const; + AttachmentData loadAttachmentData(const QUrl& modelURL) const; + // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; }; @@ -88,6 +91,10 @@ public: virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); + virtual void attach(const QString& modelURL, const QString& jointName = QString(), + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, + bool allowDuplicates = false, bool useSaved = true); + virtual void setCollisionGroups(quint32 collisionGroups); void setMotionBehaviorsByScript(quint32 flags); diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index 016098699b..f9f49738e9 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -76,27 +76,28 @@ void AttachmentsDialog::addAttachment(const AttachmentData& data) { _attachments->insertWidget(_attachments->count() - 1, new AttachmentPanel(this, data)); } -static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) { +static QDoubleSpinBox* createTranslationBox(AttachmentPanel* panel, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setSingleStep(0.01); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); box->setValue(value); - dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); return box; } -static QDoubleSpinBox* createRotationBox(AttachmentsDialog* dialog, float value) { +static QDoubleSpinBox* createRotationBox(AttachmentPanel* panel, float value) { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-180.0); box->setMaximum(180.0); box->setWrapping(true); box->setValue(value); - dialog->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + panel->connect(box, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); return box; } -AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) { +AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) : + _dialog(dialog) { setFrameStyle(QFrame::StyledPanel); QFormLayout* layout = new QFormLayout(); @@ -107,7 +108,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData layout->addRow("Model URL:", urlBox); urlBox->addWidget(_modelURL = new QLineEdit(data.modelURL.toString()), 1); _modelURL->setText(data.modelURL.toString()); - dialog->connect(_modelURL, SIGNAL(returnPressed()), SLOT(updateAttachmentData())); + connect(_modelURL, SIGNAL(returnPressed()), SLOT(modelURLChanged())); QPushButton* chooseURL = new QPushButton("Choose"); urlBox->addWidget(chooseURL); connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseModelURL())); @@ -120,26 +121,26 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData } } _jointName->setCurrentText(data.jointName); - dialog->connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); + connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); QHBoxLayout* translationBox = new QHBoxLayout(); - translationBox->addWidget(_translationX = createTranslationBox(dialog, data.translation.x)); - translationBox->addWidget(_translationY = createTranslationBox(dialog, data.translation.y)); - translationBox->addWidget(_translationZ = createTranslationBox(dialog, data.translation.z)); + translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x)); + translationBox->addWidget(_translationY = createTranslationBox(this, data.translation.y)); + translationBox->addWidget(_translationZ = createTranslationBox(this, data.translation.z)); layout->addRow("Translation:", translationBox); QHBoxLayout* rotationBox = new QHBoxLayout(); glm::vec3 eulers = glm::degrees(safeEulerAngles(data.rotation)); - rotationBox->addWidget(_rotationX = createRotationBox(dialog, eulers.x)); - rotationBox->addWidget(_rotationY = createRotationBox(dialog, eulers.y)); - rotationBox->addWidget(_rotationZ = createRotationBox(dialog, eulers.z)); + rotationBox->addWidget(_rotationX = createRotationBox(this, eulers.x)); + rotationBox->addWidget(_rotationY = createRotationBox(this, eulers.y)); + rotationBox->addWidget(_rotationZ = createRotationBox(this, eulers.z)); layout->addRow("Rotation:", rotationBox); layout->addRow("Scale:", _scale = new QDoubleSpinBox()); _scale->setSingleStep(0.01); _scale->setMaximum(FLT_MAX); _scale->setValue(data.scale); - dialog->connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); + connect(_scale, SIGNAL(valueChanged(double)), SLOT(updateAttachmentData())); QPushButton* remove = new QPushButton("Delete"); layout->addRow(remove); @@ -165,5 +166,30 @@ void AttachmentPanel::chooseModelURL() { void AttachmentPanel::setModelURL(const QString& url) { _modelURL->setText(url); - emit _modelURL->returnPressed(); + modelURLChanged(); +} + +void AttachmentPanel::modelURLChanged() { + // check for saved attachment data + AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData(_modelURL->text()); + if (!attachment.jointName.isEmpty()) { + _jointName->setCurrentText(attachment.jointName); + _translationX->setValue(attachment.translation.x); + _translationY->setValue(attachment.translation.y); + _translationZ->setValue(attachment.translation.z); + glm::vec3 eulers = glm::degrees(safeEulerAngles(attachment.rotation)); + _rotationX->setValue(eulers.x); + _rotationY->setValue(eulers.y); + _rotationZ->setValue(eulers.z); + _scale->setValue(attachment.scale); + } + _dialog->updateAttachmentData(); +} + +void AttachmentPanel::updateAttachmentData() { + // save the attachment data under the model URL (if any) + if (!_modelURL->text().isEmpty()) { + Application::getInstance()->getAvatar()->saveAttachmentData(getAttachmentData()); + } + _dialog->updateAttachmentData(); } diff --git a/interface/src/ui/AttachmentsDialog.h b/interface/src/ui/AttachmentsDialog.h index 4e67ae8882..7e9319fba8 100644 --- a/interface/src/ui/AttachmentsDialog.h +++ b/interface/src/ui/AttachmentsDialog.h @@ -60,9 +60,12 @@ private slots: void chooseModelURL(); void setModelURL(const QString& url); + void modelURLChanged(); + void updateAttachmentData(); private: + AttachmentsDialog* _dialog; QLineEdit* _modelURL; QComboBox* _jointName; QDoubleSpinBox* _translationX; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 26613e51d0..94066d9a1c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -686,11 +686,11 @@ void AvatarData::setAttachmentData(const QVector& attachmentData } void AvatarData::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, - const glm::quat& rotation, float scale, bool allowDuplicates) { + const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName), Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), - Q_ARG(float, scale), Q_ARG(bool, allowDuplicates)); + Q_ARG(float, scale), Q_ARG(bool, allowDuplicates), Q_ARG(bool, useSaved)); return; } QVector attachmentData = getAttachmentData(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cc5ab16e35..dd604d06f5 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -242,7 +242,7 @@ public: Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, - bool allowDuplicates = false); + bool allowDuplicates = false, bool useSaved = true); Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString()); From 95f6bcbbd65d2a2d5f758bbddae36d4c80fb841f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 22:54:35 -0700 Subject: [PATCH 34/37] finish air guitar, gun initial position on hand tweak --- examples/airGuitar.js | 85 ++++++++++++++++++++++++++++--------------- examples/gun.js | 2 +- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index 08898579a7..d7028b8ad7 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -25,22 +25,21 @@ function vMinus(a, b) { return rval; } -// First, load two percussion sounds to be used on the sticks +// Load sounds that will be played -var guitarType = 2; +var chords = new Array(); +// Nylon string guitar +chords[1] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); +chords[2] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); +chords[3] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); +// Electric guitar +chords[4] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+A+short.raw"); +chords[5] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+B+short.raw"); +chords[6] = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+E+short.raw"); -if (guitarType == 1) { - var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); - var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+B.raw"); - var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+E.raw"); -} else { - var chord1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+A+short.raw"); - var chord2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+B+short.raw"); - var chord3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Metal+E+short.raw"); -} +var guitarSelector = 3; - -var whichChord = chord1; +var whichChord = chords[guitarSelector + 1]; var leftHanded = false; if (leftHanded) { @@ -55,40 +54,66 @@ var lastPosition = { x: 0.0, y: 0.0, z: 0.0 }; +var soundPlaying = false; +var selectorPressed = false; function checkHands(deltaTime) { for (var palm = 0; palm < 2; palm++) { var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1); - var speed = length(palmVelocity); + var speed = length(palmVelocity) / 4.0; var position = Controller.getSpatialControlPosition(palm * 2 + 1); var myPelvis = MyAvatar.position; + var trigger = Controller.getTriggerValue(strumHand); + var chord = Controller.getTriggerValue(chordHand); + + if ((chord > 0.1) && Audio.isInjectorPlaying(soundPlaying)) { + // If chord finger trigger pulled, stop current chord + Audio.stopInjector(soundPlaying); + } + + var BUTTON_COUNT = 6; + + // Change guitars if button FWD (5) pressed + if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 5)) { + if (!selectorPressed) { + if (guitarSelector == 0) { + guitarSelector = 3; + } else { + guitarSelector = 0; + } + selectorPressed = true; + } + } else { + selectorPressed = false; + } + + if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 1)) { + whichChord = chords[guitarSelector + 1]; + } else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 2)) { + whichChord = chords[guitarSelector + 2]; + } else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 3)) { + whichChord = chords[guitarSelector + 3]; + } if (palm == strumHand) { - var STRUM_HEIGHT_ABOVE_PELVIS = -0.30; + var STRUM_HEIGHT_ABOVE_PELVIS = 0.00; var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS; //printVector(position); - if ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) { - // If hand passes downward through guitar strings, play a chord! + if ( ( ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) || + ((position.y > strumTriggerHeight) && (lastPosition.y <= strumTriggerHeight)) ) && (trigger > 0.1) ){ + // If hand passes downward or upward through 'strings', and finger trigger pulled, play var options = new AudioInjectionOptions(); options.position = position; if (speed > 1.0) { speed = 1.0; } options.volume = speed; - Audio.playSound(whichChord, options); + if (Audio.isInjectorPlaying(soundPlaying)) { + Audio.stopInjector(soundPlaying); + } + soundPlaying = Audio.playSound(whichChord, options); } lastPosition = Controller.getSpatialControlPosition(palm * 2 + 1); - } else { - // This is the chord controller - var distanceFromPelvis = Vec3.length(Vec3.subtract(position, myPelvis)); - //print(distanceFromPelvis); - if (distanceFromPelvis > 0.63) { - whichChord = chord3; - } else if (distanceFromPelvis > 0.55) { - whichChord = chord2; - } else { - whichChord = chord1; - } - } + } } } diff --git a/examples/gun.js b/examples/gun.js index 6cdf634239..07994bec48 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -192,7 +192,7 @@ function keyPressEvent(event) { } } -MyAvatar.attach(gunModel, "RightHand", {x: -0.10, y: 0.0, z: 0.0}, Quat.fromPitchYawRollDegrees(-90, 180, 0), 0.14); +MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); function update(deltaTime) { // Check for mouseLook movement, update rotation From 4a1672957e994e771e13a60acd95a53f39cd1ea0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 8 May 2014 23:23:44 -0700 Subject: [PATCH 35/37] guitar is now auto-attached --- examples/airGuitar.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index d7028b8ad7..b7c4b72948 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -25,6 +25,9 @@ function vMinus(a, b) { return rval; } +// The model file to be used for the guitar +var guitarModel = "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/attachments/guitar.fst"; + // Load sounds that will be played var chords = new Array(); @@ -57,6 +60,8 @@ var lastPosition = { x: 0.0, var soundPlaying = false; var selectorPressed = false; +MyAvatar.attach(guitarModel, "Hips", {x: -0.0, y: -0.0, z: 0.0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.0); + function checkHands(deltaTime) { for (var palm = 0; palm < 2; palm++) { var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1); @@ -117,5 +122,9 @@ function checkHands(deltaTime) { } } +function scriptEnding() { + MyAvatar.detachOne(guitarModel); +} // Connect a call back that happens every frame -Script.update.connect(checkHands); \ No newline at end of file +Script.update.connect(checkHands); +Script.scriptEnding.connect(scriptEnding); From a7f44bf2077737d72a88c9bd9e5c448ab307c8bd Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 9 May 2014 00:16:11 -0700 Subject: [PATCH 36/37] double fisted gun action --- examples/gun.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/gun.js b/examples/gun.js index 07994bec48..e404ae1d4d 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -28,7 +28,7 @@ var BULLET_VELOCITY = 5.0; var MIN_THROWER_DELAY = 1000; var MAX_THROWER_DELAY = 1000; var LEFT_BUTTON_3 = 3; -var RELOAD_INTERVAL = 9; +var RELOAD_INTERVAL = 5; var showScore = false; @@ -92,12 +92,12 @@ function printVector(string, vector) { } function shootBullet(position, velocity) { - var BULLET_SIZE = 0.02; + var BULLET_SIZE = 0.01; var BULLET_GRAVITY = -0.02; Particles.addParticle( { position: position, radius: BULLET_SIZE, - color: { red: 200, green: 0, blue: 0 }, + color: { red: 10, green: 10, blue: 10 }, velocity: velocity, gravity: { x: 0, y: BULLET_GRAVITY, z: 0 }, damping: 0 }); @@ -187,12 +187,23 @@ function keyPressEvent(event) { if (event.text == "t") { var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; Script.setTimeout(shootTarget, time); - } if (event.text == ".") { + } else if (event.text == ".") { shootFromMouse(); + } else if (event.text == "r") { + playLoadSound(); } } +function playLoadSound() { + audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + Audio.playSound(loadSound, audioOptions); +} + MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); +MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); + +// Give a bit of time to load before playing sound +Script.setTimeout(playLoadSound, 2000); function update(deltaTime) { // Check for mouseLook movement, update rotation @@ -309,6 +320,7 @@ function scriptEnding() { Overlays.deleteOverlay(reticle); Overlays.deleteOverlay(text); MyAvatar.detachOne(gunModel); + MyAvatar.detachOne(gunModel); } Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel); From 217080fe1db781821ffe044934a12d7d209d4e50 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 9 May 2014 10:27:01 -0700 Subject: [PATCH 37/37] cleanup - remove unused leap fingers --- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/Hand.cpp | 79 +------------------------------ interface/src/avatar/Hand.h | 12 ----- interface/src/avatar/MyAvatar.cpp | 1 - 4 files changed, 2 insertions(+), 91 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bac339813f..4de608fc6b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -73,7 +73,6 @@ const float BILLBOARD_LOD_DISTANCE = 40.0f; void Avatar::init() { getHead()->init(); - getHand()->init(); _skeletonModel.init(); _initialized = true; _shouldRenderBillboard = (getLODDistance() >= BILLBOARD_LOD_DISTANCE); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index a6cd7ff10e..576790714e 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -29,22 +29,11 @@ const float PALM_COLLISION_RADIUS = 0.03f; Hand::Hand(Avatar* owningAvatar) : HandData((AvatarData*)owningAvatar), - - _owningAvatar(owningAvatar), - _renderAlpha(1.0) + _owningAvatar(owningAvatar) { } -void Hand::init() { -} - -void Hand::reset() { -} - void Hand::simulate(float deltaTime, bool isMine) { - - calculateGeometry(); - if (isMine) { // Iterate hand controllers, take actions as needed for (size_t i = 0; i < getNumPalms(); ++i) { @@ -146,55 +135,7 @@ void Hand::resolvePenetrations() { } } -void Hand::calculateGeometry() { - // generate finger tip balls.... - _leapFingerTipBalls.clear(); - for (size_t i = 0; i < getNumPalms(); ++i) { - PalmData& palm = getPalms()[i]; - if (palm.isActive()) { - for (size_t f = 0; f < palm.getNumFingers(); ++f) { - FingerData& finger = palm.getFingers()[f]; - if (finger.isActive()) { - const float standardBallRadius = FINGERTIP_COLLISION_RADIUS; - HandBall ball; - ball.rotation = getBaseOrientation(); - ball.position = finger.getTipPosition(); - ball.radius = standardBallRadius; - ball.touchForce = 0.0; - ball.isCollidable = true; - ball.isColliding = false; - _leapFingerTipBalls.push_back(ball); - } - } - } - } - - // generate finger root balls.... - _leapFingerRootBalls.clear(); - for (size_t i = 0; i < getNumPalms(); ++i) { - PalmData& palm = getPalms()[i]; - if (palm.isActive()) { - for (size_t f = 0; f < palm.getNumFingers(); ++f) { - FingerData& finger = palm.getFingers()[f]; - if (finger.isActive()) { - const float standardBallRadius = 0.005f; - HandBall ball; - ball.rotation = getBaseOrientation(); - ball.position = finger.getRootPosition(); - ball.radius = standardBallRadius; - ball.touchForce = 0.0; - ball.isCollidable = true; - ball.isColliding = false; - _leapFingerRootBalls.push_back(ball); - } - } - } - } -} - void Hand::render(bool isMine, Model::RenderMode renderMode) { - _renderAlpha = 1.0; - if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { // draw a green sphere at hand joint location, which is actually near the wrist) @@ -218,7 +159,6 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); - } void Hand::renderHandTargets(bool isMine) { @@ -239,6 +179,7 @@ void Hand::renderHandTargets(bool isMine) { glm::vec3 targetPosition; palm.getBallHoldPosition(targetPosition); glPushMatrix(); + glTranslatef(targetPosition.x, targetPosition.y, targetPosition.z); const float collisionRadius = 0.05f; glColor4f(0.5f,0.5f,0.5f, alpha); @@ -247,22 +188,6 @@ void Hand::renderHandTargets(bool isMine) { } } - glPushMatrix(); - // Draw the leap balls - for (size_t i = 0; i < _leapFingerTipBalls.size(); i++) { - if (alpha > 0.0f) { - if (_leapFingerTipBalls[i].isColliding) { - glColor4f(handColor.r, 0, 0, alpha); - } else { - glColor4f(handColor.r, handColor.g, handColor.b, alpha); - } - glPushMatrix(); - glTranslatef(_leapFingerTipBalls[i].position.x, _leapFingerTipBalls[i].position.y, _leapFingerTipBalls[i].position.z); - glutSolidSphere(_leapFingerTipBalls[i].radius, 20.0f, 20.0f); - glPopMatrix(); - } - } - const float PALM_BALL_RADIUS = 0.03f; const float PALM_DISK_RADIUS = 0.06f; const float PALM_DISK_THICKNESS = 0.01f; diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 9c2bc2c2c0..5d171f2809 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -50,15 +50,9 @@ public: float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; - void init(); - void reset(); void simulate(float deltaTime, bool isMine); void render(bool isMine, Model::RenderMode renderMode = Model::DEFAULT_RENDER_MODE); - // getters - const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} - const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} - void collideAgainstAvatar(Avatar* avatar, bool isMyHand); void collideAgainstOurself(); @@ -72,14 +66,8 @@ private: int _controllerButtons; /// Button states read from hand-held controllers Avatar* _owningAvatar; - float _renderAlpha; - std::vector _leapFingerTipBalls; - std::vector _leapFingerRootBalls; void renderHandTargets(bool isMine); - void renderLeapFingerTrails(); - - void calculateGeometry(); }; #endif // hifi_Hand_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6d7962bff1..6ce362071b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -97,7 +97,6 @@ MyAvatar::~MyAvatar() { void MyAvatar::reset() { _skeletonModel.reset(); getHead()->reset(); - getHand()->reset(); _oculusYawOffset = 0.0f; setVelocity(glm::vec3(0.0f));