From 526664ac57c39113a357f50e5e5e5f52724a8b6d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 1 Dec 2014 22:11:34 -0800 Subject: [PATCH 01/20] delete old dead code --- interface/src/Application.cpp | 6 ------ interface/src/avatar/Avatar.cpp | 7 ------- interface/src/avatar/Avatar.h | 3 --- interface/src/avatar/AvatarManager.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 1 - interface/src/avatar/MyAvatar.h | 4 ---- 6 files changed, 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 20ae07b0c9..ab18c68a10 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2084,12 +2084,6 @@ void Application::updateMouseRay() { _mouseRayDirection -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), _mouseRayDirection) + _viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), _mouseRayDirection)); } - - // tell my avatar if the mouse is being pressed... - _myAvatar->setMousePressed(_mousePressed); - - // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position - _myAvatar->setMouseRay(_mouseRayOrigin, _mouseRayDirection); } void Application::updateFaceshift() { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 03243c1a83..c680c75056 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -66,8 +66,6 @@ Avatar::Avatar() : _leanScale(0.5f), _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), - _mouseRayOrigin(0.0f, 0.0f, 0.0f), - _mouseRayDirection(0.0f, 0.0f, 0.0f), _moving(false), _collisionGroups(0), _initialized(false), @@ -250,11 +248,6 @@ void Avatar::measureMotionDerivatives(float deltaTime) { _lastOrientation = getOrientation(); } -void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { - _mouseRayOrigin = origin; - _mouseRayDirection = direction; -} - enum TextRendererType { CHAT, DISPLAYNAME diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2d1a44403f..88ab3b12ca 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -85,7 +85,6 @@ public: //setters void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } - void setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction); void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; } bool getIsLookAtTarget() const { return _isLookAtTarget; } //getters @@ -213,8 +212,6 @@ protected: float _leanScale; float _scale; glm::vec3 _worldUpDirection; - glm::vec3 _mouseRayOrigin; - glm::vec3 _mouseRayDirection; float _stringLength; bool _moving; ///< set when position is changing diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ba5ba8141d..25916d761c 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -87,7 +87,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (!shouldKillAvatar(sharedAvatar)) { // this avatar's mixer is still around, go ahead and simulate it avatar->simulate(deltaTime); - avatar->setMouseRay(mouseOrigin, mouseDirection); ++avatarIterator; } else { // the mixer that owned this avatar is gone, give it to the vector of fades and kill it diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3301cf0347..880331deb9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -67,7 +67,6 @@ const int SCRIPTED_MOTOR_WORLD_FRAME = 2; MyAvatar::MyAvatar() : Avatar(), - _mousePressed(false), _bodyPitchDelta(0.0f), _bodyRollDelta(0.0f), _gravity(0.0f, 0.0f, 0.0f), diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index dd1178c7b5..7e05389102 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -55,15 +55,12 @@ public: void renderHeadMouse(int screenWidth, int screenHeight) const; // setters - void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; } void setLeanScale(float scale) { _leanScale = scale; } void setLocalGravity(glm::vec3 gravity); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } // getters float getLeanScale() const { return _leanScale; } - const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } - const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } glm::vec3 getGravity() const { return _gravity; } glm::vec3 getDefaultEyePosition() const; bool getShouldRenderLocally() const { return _shouldRender; } @@ -203,7 +200,6 @@ protected: virtual void renderAttachments(RenderMode renderMode); private: - bool _mousePressed; float _bodyPitchDelta; // degrees float _bodyRollDelta; // degrees glm::vec3 _gravity; From 6d385d9a75de786e0d1f583ad8448c30a9df2492 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Dec 2014 11:45:33 -0800 Subject: [PATCH 02/20] get rid of redundant _displayViewFrustum and use _viewFrustum --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 -- interface/src/MetavoxelSystem.cpp | 6 +++--- interface/src/renderer/DeferredLightingEffect.cpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab18c68a10..6a0ec5afdf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2903,7 +2903,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr // transform by eye offset // load the view frustum - loadViewFrustum(whichCamera, _displayViewFrustum); + loadViewFrustum(whichCamera, _viewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -3177,7 +3177,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { // allow 3DTV/Oculus to override parameters from camera - _displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); if (OculusManager::isConnected()) { OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9f2cdbd520..46f4cda0a6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -196,7 +196,6 @@ public: const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } - ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } @@ -515,7 +514,6 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) - ViewFrustum _displayViewFrustum; ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b98fea8eca..996b92e22d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -192,7 +192,7 @@ static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; void MetavoxelSystem::render() { // update the frustum - ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); + ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); @@ -1896,7 +1896,7 @@ private: SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), lod, - encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), + encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -1932,7 +1932,7 @@ private: BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : MetavoxelVisitor(QVector() << attribute), - _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), + _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index be4e457131..63d874cda7 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -232,8 +232,8 @@ void DeferredLightingEffect::render() { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft()); + const glm::vec3& eyePoint = Application::getInstance()->getViewFrustum()->getPosition(); + float nearRadius = glm::distance(eyePoint, Application::getInstance()->getViewFrustum()->getNearTopLeft()); if (!_pointLights.isEmpty()) { _pointLight.bind(); From cc012aad0012a96eafa5573c709128b1ae70a57f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Dec 2014 12:54:10 -0800 Subject: [PATCH 03/20] reset view frustum --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6a0ec5afdf..90f5a0bf96 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -895,6 +895,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Greater: case Qt::Key_Comma: case Qt::Key_Period: + case Qt::Key_QuoteDbl: Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key()); break; case Qt::Key_L: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6cfb3db35a..ae12b5ff26 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -835,6 +835,14 @@ void Menu::handleViewFrustumOffsetKeyModifier(int key) { const float VIEW_FRUSTUM_OFFSET_UP_DELTA = 0.05f; switch (key) { + case Qt::Key_QuoteDbl: + _viewFrustumOffset.yaw = 0.0f; + _viewFrustumOffset.pitch = 0.0f; + _viewFrustumOffset.roll = 0.0f; + _viewFrustumOffset.up = 0.0f; + _viewFrustumOffset.distance = 0.0f; + break; + case Qt::Key_BracketLeft: _viewFrustumOffset.yaw -= VIEW_FRUSTUM_OFFSET_DELTA; break; From 63d1ac83753a6620c1408660502eacd9c5d80e2e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Dec 2014 14:56:12 -0800 Subject: [PATCH 04/20] implement support for entity subclasses to implement their own detailed ray intersection, make likes light pickability toggle --- examples/editModels.js | 26 ++++++++++++------- .../entities/RenderableLightEntityItem.cpp | 11 ++++++++ .../src/entities/RenderableLightEntityItem.h | 4 +++ libraries/entities/src/EntityItem.h | 5 ++++ .../entities/src/EntityScriptingInterface.cpp | 13 ++++++++++ .../entities/src/EntityScriptingInterface.h | 2 ++ libraries/entities/src/EntityTree.cpp | 1 + libraries/entities/src/EntityTree.h | 5 ++++ libraries/entities/src/EntityTreeElement.cpp | 21 ++++++++++++--- 9 files changed, 75 insertions(+), 13 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 3f1863fef2..8e3503b9b2 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2807,6 +2807,7 @@ function mouseReleaseEvent(event) { // exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that // added it. var modelMenuAddedDelete = false; +var originalLightsArePickable = Entities.getLightsArePickable(); function setupModelMenus() { print("setupModelMenus()"); // adj our menuitems @@ -2824,15 +2825,18 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", - afterItem: "Allow Select Large Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", + afterItem: "Allow Selecting of Large Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", + afterItem: "Allow Selecting of Small Models", isCheckable: true }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); + Entities.setLightsArePickable(false); } @@ -2846,8 +2850,9 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); - Menu.removeMenuItem("Edit", "Allow Select Large Models"); - Menu.removeMenuItem("Edit", "Allow Select Small Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); Menu.removeSeparator("File", "Models"); Menu.removeMenuItem("File", "Export Models"); @@ -2865,6 +2870,7 @@ function scriptEnding() { if (exportMenu) { exportMenu.close(); } + Entities.setLightsArePickable(originalLightsArePickable); } Script.scriptEnding.connect(scriptEnding); @@ -2890,10 +2896,12 @@ function showPropertiesForm(editModelID) { function handeMenuEvent(menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == "Allow Select Small Models") { - allowSmallModels = Menu.isOptionChecked("Allow Select Small Models"); - } else if (menuItem == "Allow Select Large Models") { - allowLargeModels = Menu.isOptionChecked("Allow Select Large Models"); + if (menuItem == "Allow Selecting of Small Models") { + allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); + } else if (menuItem == "Allow Selecting of Large Models") { + allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); + } else if (menuItem == "Allow Selecting of Lights") { + Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); } else if (menuItem == "Delete") { if (leftController.grabbing) { print(" Delete Entity.... leftController.entityID="+ leftController.entityID); diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp index e3e8f61e58..91b2d35106 100644 --- a/interface/src/entities/RenderableLightEntityItem.cpp +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -90,3 +90,14 @@ void RenderableLightEntityItem::render(RenderArgs* args) { glPopMatrix(); } }; + +bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { + + // TODO: this isn't really correct because we don't know if we actually live in the main tree of the applications's + // EntityTreeRenderer. But we probably do. Technically we could be on the clipboard and someone might be trying to + // use the ray intersection API there. Anyway... if you ever try to do ray intersection testing off of trees other + // than the main tree of the main entity renderer, then you'll need to fix this mechanism. + return Application::getInstance()->getEntities()->getTree()->getLightsArePickable(); +} diff --git a/interface/src/entities/RenderableLightEntityItem.h b/interface/src/entities/RenderableLightEntityItem.h index cecd9b761e..40fa31a4ce 100644 --- a/interface/src/entities/RenderableLightEntityItem.h +++ b/interface/src/entities/RenderableLightEntityItem.h @@ -34,6 +34,10 @@ public: { } virtual void render(RenderArgs* args); + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const; }; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3f63c96c4e..2c6eb0fdee 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -134,6 +134,11 @@ public: virtual SimulationState computeSimulationState() const; virtual void debugDump() const; + + virtual bool supportsDetailedRayIntersection() const { return false; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { return true; } // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 29c4a8b19a..575a6c1a78 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -221,6 +221,19 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke return result; } +void EntityScriptingInterface::setLightsArePickable(bool value) { + if (_entityTree) { + _entityTree->setLightsArePickable(value); + } +} + +bool EntityScriptingInterface::getLightsArePickable() const { + if (_entityTree) { + return _entityTree->getLightsArePickable(); + } + return false; +} + RayToEntityIntersectionResult::RayToEntityIntersectionResult() : intersects(false), diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 2150fa51da..da0c6c9f1a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -96,6 +96,8 @@ public slots: /// order to return an accurate result Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray); + Q_INVOKABLE void setLightsArePickable(bool value); + Q_INVOKABLE bool getLightsArePickable() const; Q_INVOKABLE void dumpTree() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bb201b6f86..15d0dbddfb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -20,6 +20,7 @@ EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage) { _rootElement = createNewElement(); + _lightsArePickable = true; // assume they are by default } EntityTree::~EntityTree() { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 7370ebadc6..7adcc190b4 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -149,6 +149,9 @@ public: QList& getMovingEntities() { return _movingEntities; } + bool getLightsArePickable() const { return _lightsArePickable; } + void setLightsArePickable(bool value) { _lightsArePickable = value; } + signals: void deletingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID); @@ -181,6 +184,8 @@ private: QList _mortalEntities; // entities that need to be checked for expiry QSet _changedEntities; // entities that have changed in the last frame + + bool _lightsArePickable; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2646cc0dfd..506370a9f0 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -511,10 +511,23 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // and testing intersection there. if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { if (localDistance < distance) { - distance = localDistance; - face = localFace; - *intersectedObject = (void*)entity; - somethingIntersected = true; + // now ask the entity if we actually intersect + if (entity->supportsDetailedRayIntersection()) { + + if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, + localFace, intersectedObject)) { + distance = localDistance; + face = localFace; + *intersectedObject = (void*)entity; + somethingIntersected = true; + } + } else { + // if the entity type doesn't support a detailed intersection, then just return the non-AABox results + distance = localDistance; + face = localFace; + *intersectedObject = (void*)entity; + somethingIntersected = true; + } } } } From bb6e302d694db9a083b4a188ceaef8e8d4b2c8f9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Dec 2014 15:23:05 -0800 Subject: [PATCH 05/20] support toggle of light picking in newEditEntities.js --- examples/newEditEntities.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index bc2d87259e..96a8617cd9 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -626,6 +626,7 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent); // exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that // added it. var modelMenuAddedDelete = false; +var originalLightsArePickable = Entities.getLightsArePickable(); function setupModelMenus() { print("setupModelMenus()"); // adj our menuitems @@ -643,10 +644,12 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", - afterItem: "Allow Select Large Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", + afterItem: "Allow Selecting of Large Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", + afterItem: "Allow Selecting of Small Models", isCheckable: true }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); @@ -655,6 +658,8 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); + + Entities.setLightsArePickable(false); } setupModelMenus(); // do this when first running our script. @@ -669,8 +674,9 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); - Menu.removeMenuItem("Edit", "Allow Select Large Models"); - Menu.removeMenuItem("Edit", "Allow Select Small Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); Menu.removeSeparator("File", "Models"); Menu.removeMenuItem("File", "Export Models"); @@ -694,6 +700,7 @@ Script.scriptEnding.connect(function() { if (exportMenu) { exportMenu.close(); } + Entities.setLightsArePickable(originalLightsArePickable); }); // Do some stuff regularly, like check for placement of various overlays @@ -704,10 +711,12 @@ Script.update.connect(function (deltaTime) { }); function handeMenuEvent(menuItem) { - if (menuItem == "Allow Select Small Models") { - allowSmallModels = Menu.isOptionChecked("Allow Select Small Models"); - } else if (menuItem == "Allow Select Large Models") { - allowLargeModels = Menu.isOptionChecked("Allow Select Large Models"); + if (menuItem == "Allow Selecting of Small Models") { + allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); + } else if (menuItem == "Allow Selecting of Large Models") { + allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); + } else if (menuItem == "Allow Selecting of Lights") { + Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); } else if (menuItem == "Delete") { if (SelectionManager.hasSelection()) { print(" Delete Entities"); From ab011d5b30409aca9c0ab52dcd1a65f08ad16d0a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 3 Dec 2014 16:49:49 -0800 Subject: [PATCH 06/20] fix for non-animating models --- libraries/entities/src/ModelEntityItem.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 63fe3daa03..0de2035dec 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -374,17 +374,9 @@ bool ModelEntityItem::isAnimatingSomething() const { } EntityItem::SimulationState ModelEntityItem::computeSimulationState() const { - EntityItem::SimulationState baseClassState = EntityItem::computeSimulationState(); - - // if the base class is static, then consider our animation state, and upgrade to changing if - // we are animating. If the base class has a higher simulation state than static, then - // use the base class state. - if (baseClassState == EntityItem::Static) { - if (isAnimatingSomething()) { - return EntityItem::Moving; - } - } - return baseClassState; + // if we're animating then we need to have update() periodically called on this entity + // which means we need to categorized as Moving + return isAnimatingSomething() ? EntityItem::Moving : EntityItem::computeSimulationState(); } void ModelEntityItem::update(const quint64& updateTime) { From 74acf9513bd8863f825b14291217ba2c1eee1562 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 08:47:18 -0800 Subject: [PATCH 07/20] Fix entity tool selection when inactive --- examples/newEditEntities.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 92db9daab5..a95c542311 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -566,6 +566,10 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { + if (!isActive) { + return; + } + var result = findClickedEntity(event); if (result === null) { if (!event.isShifted) { From f48d304df02f21ae7e2bd0d56cd7e45512dc2f16 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:03:54 -0800 Subject: [PATCH 08/20] Add registrationPoint to SelectionManager --- examples/libraries/entitySelectionTool.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 40b5b78a31..0622e4c72c 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -33,10 +33,12 @@ SelectionManager = (function() { that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); that.localPosition = { x: 0, y: 0, z: 0 }; that.localDimensions = { x: 0, y: 0, z: 0 }; + that.localRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; that.worldRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); that.worldPosition = { x: 0, y: 0, z: 0 }; that.worldDimensions = { x: 0, y: 0, z: 0 }; + that.worldRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; that.centerPosition = { x: 0, y: 0, z: 0 }; that.saveProperties = function() { @@ -153,6 +155,7 @@ SelectionManager = (function() { that.localDimensions = properties.dimensions; that.localPosition = properties.position; that.localRotation = properties.rotation; + that.localRegistrationPoint = properties.registrationPoint; that.worldDimensions = properties.boundingBox.dimensions; that.worldPosition = properties.boundingBox.center; From 53f195eec413c54edb01ca3afb2e6b0c39bf924a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:05:34 -0800 Subject: [PATCH 09/20] Fix position of overlays when registrationPoint is not centered --- examples/libraries/entitySelectionTool.js | 81 +++++++++++++++-------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 0622e4c72c..3e50bff8f7 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -985,26 +985,40 @@ SelectionDisplay = (function () { that.updateRotationHandles(); that.highlightSelectable(); - var rotation, dimensions, position; + var rotation, dimensions, position, registrationPoint; if (spaceMode == SPACE_LOCAL) { rotation = SelectionManager.localRotation; dimensions = SelectionManager.localDimensions; position = SelectionManager.localPosition; + registrationPoint = SelectionManager.localRegistrationPoint; } else { rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); dimensions = SelectionManager.worldDimensions; position = SelectionManager.worldPosition; + registrationPoint = SelectionManager.worldRegistrationPoint; } - var halfDimensions = Vec3.multiply(0.5, dimensions); + var registrationPointDimensions = { + x: dimensions.x * registrationPoint.x, + y: dimensions.y * registrationPoint.y, + z: dimensions.z * registrationPoint.z, + }; - var left = -halfDimensions.x; - var right = halfDimensions.x; - var top = halfDimensions.y; - var bottom = -halfDimensions.y; - var front = far = halfDimensions.z; - var near = -halfDimensions.z; + // Center of entity, relative to registration point + var center = { + x: dimensions.x / 2 - registrationPointDimensions.x, + y: dimensions.y / 2 - registrationPointDimensions.y, + z: dimensions.z / 2 - registrationPointDimensions.z, + }; + + // Distances in world coordinates relative to the registration point + var left = -registrationPointDimensions.x; + var right = dimensions.x - registrationPointDimensions.x; + var bottom = -registrationPointDimensions.y; + var top = dimensions.y - registrationPointDimensions.y; + var near = -registrationPointDimensions.z; + var front = far = dimensions.z - registrationPointDimensions.z; var worldTop = SelectionManager.worldDimensions.y / 2; @@ -1017,25 +1031,25 @@ SelectionDisplay = (function () { var LTF = { x: left, y: top, z: far }; var RTF = { x: right, y: top, z: far }; - var TOP = { x: 0, y: top, z: 0 }; - var BOTTOM = { x: 0, y: bottom, z: 0 }; - var LEFT = { x: left, y: 0, z: 0 }; - var RIGHT = { x: right, y: 0, z: 0 }; - var NEAR = { x: 0, y: 0, z: near }; - var FAR = { x: 0, y: 0, z: far }; + var TOP = { x: center.x, y: top, z: center.z }; + var BOTTOM = { x: center.x, y: bottom, z: center.z }; + var LEFT = { x: left, y: center.y, z: center.z }; + var RIGHT = { x: right, y: center.y, z: center.z }; + var NEAR = { x: center.x, y: center.y, z: near }; + var FAR = { x: center.x, y: center.y, z: far }; - var EdgeTR = { x: right, y: top, z: 0 }; - var EdgeTL = { x: left, y: top, z: 0 }; - var EdgeTF = { x: 0, y: top, z: front }; - var EdgeTN = { x: 0, y: top, z: near }; - var EdgeBR = { x: right, y: bottom, z: 0 }; - var EdgeBL = { x: left, y: bottom, z: 0 }; - var EdgeBF = { x: 0, y: bottom, z: front }; - var EdgeBN = { x: 0, y: bottom, z: near }; - var EdgeNR = { x: right, y: 0, z: near }; - var EdgeNL = { x: left, y: 0, z: near }; - var EdgeFR = { x: right, y: 0, z: front }; - var EdgeFL = { x: left, y: 0, z: front }; + var EdgeTR = { x: right, y: top, z: center.z }; + var EdgeTL = { x: left, y: top, z: center.z }; + var EdgeTF = { x: center.x, y: top, z: front }; + var EdgeTN = { x: center.x, y: top, z: near }; + var EdgeBR = { x: right, y: bottom, z: center.z }; + var EdgeBL = { x: left, y: bottom, z: center.z }; + var EdgeBF = { x: center.x, y: bottom, z: front }; + var EdgeBN = { x: center.x, y: bottom, z: near }; + var EdgeNR = { x: right, y: center.y, z: near }; + var EdgeNL = { x: left, y: center.y, z: near }; + var EdgeFR = { x: right, y: center.y, z: front }; + var EdgeFL = { x: left, y: center.y, z: front }; LBN = Vec3.multiplyQbyV(rotation, LBN); RBN = Vec3.multiplyQbyV(rotation, RBN); @@ -1114,8 +1128,10 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberNEAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: NEAR }); Overlays.editOverlay(grabberFAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: FAR }); + var boxPosition = Vec3.multiplyQbyV(rotation, center); + boxPosition = Vec3.sum(position, boxPosition); Overlays.editOverlay(selectionBox, { - position: position, + position: boxPosition, dimensions: dimensions, rotation: rotation, visible: !(mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL"), @@ -1143,8 +1159,17 @@ SelectionDisplay = (function () { if (selectionManager.selections.length > 1) { for (; i < selectionManager.selections.length; i++) { var properties = Entities.getEntityProperties(selectionManager.selections[i]); + + // Adjust overlay position to take registrationPoint into account + // centeredRP = registrationPoint with range [-0.5, 0.5] + var centeredRP = Vec3.subtract(properties.registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + var offset = vec3Mult(properties.dimensions, centeredRP); + offset = Vec3.multiply(-1, offset); + offset = Vec3.multiplyQbyV(properties.rotation, offset); + var boxPosition = Vec3.sum(properties.position, offset); + Overlays.editOverlay(selectionBoxes[i], { - position: properties.position, + position: boxPosition, rotation: properties.rotation, dimensions: properties.dimensions, visible: true, From efdc8f54948f2a031b4b77d607dcfa104b7266d9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:19:51 -0800 Subject: [PATCH 10/20] Fix stretch tools to work correctly with registrationPoint --- examples/libraries/entitySelectionTool.js | 43 ++++++++++++++--------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 3e50bff8f7..16dc52b239 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1428,6 +1428,8 @@ SelectionDisplay = (function () { var initialDimensions = null; var initialIntersection = null; var initialProperties = null; + var registrationPoint = null; + var deltaPivot = null; var pickRayPosition = null; var rotation = null; @@ -1440,18 +1442,29 @@ SelectionDisplay = (function () { rotation = SelectionManager.localRotation; initialPosition = SelectionManager.localPosition; initialDimensions = SelectionManager.localDimensions; + registrationPoint = SelectionManager.localRegistrationPoint; } else { rotation = SelectionManager.worldRotation; initialPosition = SelectionManager.worldPosition; initialDimensions = SelectionManager.worldDimensions; + registrationPoint = SelectionManager.worldRegistrationPoint; } - var scaledOffset = { - x: initialDimensions.x * offset.x * 0.5, - y: initialDimensions.y * offset.y * 0.5, - z: initialDimensions.z * offset.z * 0.5, - }; - pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffset)); + // Modify range of registrationPoint to be [-0.5, 0.5] + var centeredRP = Vec3.subtract(registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + + // Scale pivot to be in the same range as registrationPoint + var scaledPivot = Vec3.multiply(0.5, pivot) + deltaPivot = Vec3.subtract(centeredRP, scaledPivot); + + var scaledOffset = Vec3.multiply(0.5, offset); + + // Offset from the registration point + offsetRP = Vec3.subtract(scaledOffset, centeredRP); + + // Scaled offset in world coordinates + var scaledOffsetWorld = vec3Mult(initialDimensions, offsetRP); + pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); if (numDimensions == 1 && mask.x) { var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 }); @@ -1578,8 +1591,7 @@ SelectionDisplay = (function () { newDimensions.y = Math.max(newDimensions.y, MINIMUM_DIMENSION); newDimensions.z = Math.max(newDimensions.z, MINIMUM_DIMENSION); - var p = Vec3.multiply(0.5, pivot); - var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(p, changeInDimensions)); + var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(deltaPivot, changeInDimensions)); var newPosition = Vec3.sum(initialPosition, changeInPosition); for (var i = 0; i < SelectionManager.selections.length; i++) { @@ -1617,20 +1629,19 @@ SelectionDisplay = (function () { function addStretchTool(overlay, mode, pivot, direction, offset) { if (!pivot) { - pivot = Vec3.multiply(-1, direction); - pivot.y = direction.y; + pivot = direction; } var tool = makeStretchTool(mode, direction, pivot, offset); addGrabberTool(overlay, tool); } - addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); - addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }); - addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }); - addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }); - addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }); - addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }); + addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); + addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }); + addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: -1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }); + addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: 1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }); + addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: -1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }); + addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: 1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }); addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1}, { x: -1, y: -1, z: -1 }); addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1}, { x: 1, y: -1, z: -1 }); From b2c5b19fd7228f569a4e86db585b335acee1c8bf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:20:02 -0800 Subject: [PATCH 11/20] Remove print --- examples/libraries/gridTool.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index aa412b1a76..7d98befec8 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -90,7 +90,6 @@ Grid = function(opts) { } that.snapToSpacing = function(delta, majorOnly) { - print('snaptogrid? ' + snapToGrid); if (!snapToGrid) { return delta; } From acd5495b2ab4a2ef33eb62312d27cff351a36a3a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:29:10 -0800 Subject: [PATCH 12/20] Add getRelativeCenterPosition --- examples/libraries/entitySelectionTool.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 16dc52b239..e30b9d2d95 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -218,6 +218,17 @@ function normalizeDegrees(degrees) { return degrees; } +// Return the enter position of an entity relative to it's registrationPoint +// A registration point of (0.5, 0.5, 0.5) will have an offset of (0, 0, 0) +// A registration point of (1.0, 1.0, 1.0) will have an offset of (-dimensions.x / 2, -dimensions.y / 2, -dimensions.z / 2) +function getRelativeCenterPosition(dimensions, registrationPoint) { + return { + x: -dimensions.x * (registrationPoint.x - 0.5), + y: -dimensions.y * (registrationPoint.y - 0.5), + z: -dimensions.z * (registrationPoint.z - 0.5), + } +} + SelectionDisplay = (function () { var that = {}; @@ -1005,12 +1016,7 @@ SelectionDisplay = (function () { z: dimensions.z * registrationPoint.z, }; - // Center of entity, relative to registration point - var center = { - x: dimensions.x / 2 - registrationPointDimensions.x, - y: dimensions.y / 2 - registrationPointDimensions.y, - z: dimensions.z / 2 - registrationPointDimensions.z, - }; + center = getRelativeCenterPosition(position, dimensions, registrationPoint); // Distances in world coordinates relative to the registration point var left = -registrationPointDimensions.x; From 1f82831bcc0ea6a01d4ea7d2748f173173557d6f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 10:47:09 -0800 Subject: [PATCH 13/20] Fix call to getRelativeCenterPosition --- examples/libraries/entitySelectionTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index e30b9d2d95..2953203fc6 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1016,7 +1016,8 @@ SelectionDisplay = (function () { z: dimensions.z * registrationPoint.z, }; - center = getRelativeCenterPosition(position, dimensions, registrationPoint); + // Center of entity, relative to registration point + center = getRelativeCenterPosition(dimensions, registrationPoint); // Distances in world coordinates relative to the registration point var left = -registrationPointDimensions.x; From 11f10f95122f71dfe816d2e16f1d9c4ffd95423d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 10:54:04 -0800 Subject: [PATCH 14/20] make sphere entities pick off their actual sphere, fix bug in ray picking multiple items with different distances --- libraries/entities/src/EntityTreeElement.cpp | 17 ++++++++++----- libraries/entities/src/SphereEntityItem.cpp | 23 ++++++++++++++++++++ libraries/entities/src/SphereEntityItem.h | 5 +++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 3f73a05679..e18f79276e 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -516,17 +516,22 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, localFace, intersectedObject)) { + + if (localDistance < distance) { + distance = localDistance; + face = localFace; + *intersectedObject = (void*)entity; + somethingIntersected = true; + } + } + } else { + // if the entity type doesn't support a detailed intersection, then just return the non-AABox results + if (localDistance < distance) { distance = localDistance; face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; } - } else { - // if the entity type doesn't support a detailed intersection, then just return the non-AABox results - distance = localDistance; - face = localFace; - *intersectedObject = (void*)entity; - somethingIntersected = true; } } } diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index f5b8eb27e9..12fdd7a8c4 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -93,3 +93,26 @@ void SphereEntityItem::recalculateCollisionShape() { float largestDiameter = glm::max(dimensionsInMeters.x, dimensionsInMeters.y, dimensionsInMeters.z); _sphereShape.setRadius(largestDiameter / 2.0f); } + +bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { + + // NOTE: origin and direction are in tree units. But our _sphereShape is in meters, so we need to + // do a little math to make these match each other. + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin * (float)TREE_SCALE; + rayInfo._rayDirection = direction; + + // TODO: Note this is really doing ray intersections against a sphere, which is fine except in cases + // where our dimensions actually make us an ellipsoid. But we'll live with this for now until we + // get a more full fledged physics library + if (_sphereShape.findRayIntersection(rayInfo)) { + distance = rayInfo._hitDistance / (float)TREE_SCALE; + return true; + } + return false; +} + + + diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 21cb58223b..bb4f41726c 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -56,6 +56,11 @@ public: // TODO: implement proper contains for 3D ellipsoid //virtual bool contains(const glm::vec3& point) const; + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const; + protected: virtual void recalculateCollisionShape(); From 1ee45e8bd1f5bdb26745eff045eff1f19c7de035 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 11:24:56 -0800 Subject: [PATCH 15/20] Fix entity tool rotation to rotate around registration point --- examples/libraries/entitySelectionTool.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 2953203fc6..fa97e9351f 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1786,17 +1786,27 @@ SelectionDisplay = (function () { } var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); + + // Entities should only reposition if we are rotating multiple selections around + // the selections center point. Otherwise, the rotation will be around the entities + // registration point which does not need repositioning. + var reposition = SelectionManager.selections.length > 1; for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; var properties = Entities.getEntityProperties(entityID); var initialProperties = SelectionManager.savedProperties[entityID.id]; - var dPos = Vec3.subtract(initialProperties.position, initialPosition); - dPos = Vec3.multiplyQbyV(yawChange, dPos); - Entities.editEntity(entityID, { - position: Vec3.sum(initialPosition, dPos), + var newProperties = { rotation: Quat.multiply(yawChange, initialProperties.rotation), - }); + }; + + if (reposition) { + var dPos = Vec3.subtract(initialProperties.position, initialPosition); + dPos = Vec3.multiplyQbyV(yawChange, dPos); + newProperties.position = Vec3.sum(initialPosition, dPos); + } + + Entities.editEntity(entityID, newProperties); } updateRotationDegreesOverlay(angleFromZero, yawHandleRotation, yawCenter); From e3a34f6db0c835c0bf1f24c13eb6bf7aee054386 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 12:17:31 -0800 Subject: [PATCH 16/20] Add multi-speed control to gamepad.js --- examples/gamepad.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/gamepad.js b/examples/gamepad.js index a2f1034e26..0012103c4e 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -16,6 +16,8 @@ var AXIS_STRAFE = Joysticks.AXIS_LEFT_X; var AXIS_FORWARD = Joysticks.AXIS_LEFT_Y; var AXIS_ROTATE = Joysticks.AXIS_RIGHT_X; +var BUTTON_SPRINT = Joysticks.BUTTON_LEFT_STICK; + var BUTTON_TURN_AROUND = Joysticks.BUTTON_RIGHT_STICK; var BUTTON_FLY_UP = Joysticks.BUTTON_RIGHT_SHOULDER; @@ -31,7 +33,8 @@ var BUTTON_WARP_RIGHT = Joysticks.BUTTON_DPAD_RIGHT; var WARP_DISTANCE = 1; // Walk speed in m/s -var MOVE_SPEED = 2; +var MOVE_SPEED = 0.5; +var MOVE_SPRINT_SPEED = 2; // Amount to rotate in radians var ROTATE_INCREMENT = Math.PI / 8; @@ -49,6 +52,7 @@ var flyUpButtonState = false; // Current move direction, axis aligned - that is, looking down and moving forward // will not move you into the ground, but instead will keep you on the horizontal plane. var moveDirection = { x: 0, y: 0, z: 0 }; +var sprintButtonState = false; var warpActive = false; var warpPosition = { x: 0, y: 0, z: 0 }; @@ -173,6 +177,8 @@ function reportButtonValue(button, newValue, oldValue) { MyAvatar.orientation = Quat.multiply( Quat.fromPitchYawRollRadians(0, Math.PI, 0), MyAvatar.orientation); } + } else if (button == BUTTON_SPRINT) { + sprintButtonState = newValue; } else if (newValue) { var direction = null; @@ -209,9 +215,10 @@ function update(dt) { var move = copyVec3(moveDirection); move.y = 0; if (Vec3.length(move) > 0) { + speed = sprintButtonState ? MOVE_SPRINT_SPEED : MOVE_SPEED; velocity = Vec3.multiplyQbyV(Camera.getOrientation(), move); velocity.y = 0; - velocity = Vec3.multiply(Vec3.normalize(velocity), MOVE_SPEED); + velocity = Vec3.multiply(Vec3.normalize(velocity), speed); } if (moveDirection.y != 0) { From 842ee714b82785d2ae93b55be9ac10b1119bc97f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 13:08:16 -0800 Subject: [PATCH 17/20] make text entities correctly ray pick --- libraries/entities/src/TextEntityItem.cpp | 49 ++++++++++++++++++++++- libraries/entities/src/TextEntityItem.h | 5 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 491240c178..17ef33ee1c 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -10,9 +10,12 @@ // +#include + #include #include +#include #include "EntityTree.h" #include "EntityTreeElement.h" @@ -110,4 +113,48 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, appendValue, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, appendColor, getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, appendColor, getBackgroundColor()); -} \ No newline at end of file +} + + +bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { + + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin; + rayInfo._rayDirection = direction; + rayInfo._rayLength = std::numeric_limits::max(); + + PlaneShape plane; + + const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); + glm::vec3 normal = _rotation * UNROTATED_NORMAL; + plane.setNormal(normal); + plane.setPoint(_position); // the position is definitely a point on our plane + + bool intersects = plane.findRayIntersection(rayInfo); + + if (intersects) { + glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance); + // now we know the point the ray hit our plane + + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 dimensions = getDimensions(); + glm::vec3 registrationPoint = getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); + AABox entityFrameBox(corner, dimensions); + + glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f)); + + intersects = entityFrameBox.contains(entityFrameHitAt); + } + + if (intersects) { + distance = rayInfo._hitDistance; + } + return intersects; +} diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 019d230c36..a3d323aefd 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -41,6 +41,11 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const; + static const QString DEFAULT_TEXT; void setText(const QString& value) { _text = value; } const QString& getText() const { return _text; } From 500b8a49d1969d4ab412af7164e008b903f02b57 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 14:17:24 -0800 Subject: [PATCH 18/20] Add button to gamepad.js to toggle mirror mode --- examples/gamepad.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/gamepad.js b/examples/gamepad.js index 0012103c4e..d8a7e33fe3 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -18,6 +18,8 @@ var AXIS_ROTATE = Joysticks.AXIS_RIGHT_X; var BUTTON_SPRINT = Joysticks.BUTTON_LEFT_STICK; +var BUTTON_TOGGLE_MIRROR = Joysticks.BUTTON_FACE_LEFT; + var BUTTON_TURN_AROUND = Joysticks.BUTTON_RIGHT_STICK; var BUTTON_FLY_UP = Joysticks.BUTTON_RIGHT_SHOULDER; @@ -49,6 +51,10 @@ var WARP_PICK_MAX_DISTANCE = 100; var flyDownButtonState = false; var flyUpButtonState = false; +// When toggling to mirror mode, this stores the mode the user was previously in +// so it can be toggled back to. +var toggledFromCameraMode = 'first person'; + // Current move direction, axis aligned - that is, looking down and moving forward // will not move you into the ground, but instead will keep you on the horizontal plane. var moveDirection = { x: 0, y: 0, z: 0 }; @@ -179,6 +185,16 @@ function reportButtonValue(button, newValue, oldValue) { } } else if (button == BUTTON_SPRINT) { sprintButtonState = newValue; + } else if (button == BUTTON_TOGGLE_MIRROR) { + if (newValue) { + var currentMode = Camera.mode; + if (currentMode == "mirror") { + Camera.mode = toggledFromCameraMode; + } else { + toggledFromCameraMode = currentMode; + Camera.mode = "mirror"; + } + } } else if (newValue) { var direction = null; From 3bbee640fbf4f78327ef1df7f6faf10c7c32ac66 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 14:48:03 -0800 Subject: [PATCH 19/20] Make gamepad mirror button toggle --- examples/gamepad.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gamepad.js b/examples/gamepad.js index d8a7e33fe3..e9033995d3 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -188,12 +188,12 @@ function reportButtonValue(button, newValue, oldValue) { } else if (button == BUTTON_TOGGLE_MIRROR) { if (newValue) { var currentMode = Camera.mode; - if (currentMode == "mirror") { - Camera.mode = toggledFromCameraMode; - } else { + if (currentMode != "mirror") { toggledFromCameraMode = currentMode; - Camera.mode = "mirror"; } + Camera.mode = "mirror"; + } else { + Camera.mode = toggledFromCameraMode; } } else if (newValue) { var direction = null; From ba3f051c8cf0fd952de55eca995489d644fbc427 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 4 Dec 2014 15:11:16 -0800 Subject: [PATCH 20/20] Disable the warp button in gamepad.js --- examples/gamepad.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gamepad.js b/examples/gamepad.js index e9033995d3..cc275e6267 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -24,7 +24,7 @@ var BUTTON_TURN_AROUND = Joysticks.BUTTON_RIGHT_STICK; var BUTTON_FLY_UP = Joysticks.BUTTON_RIGHT_SHOULDER; var BUTTON_FLY_DOWN = Joysticks.BUTTON_LEFT_SHOULDER; -var BUTTON_WARP = Joysticks.BUTTON_FACE_RIGHT; +var BUTTON_WARP = null; // Disable for now var BUTTON_WARP_FORWARD = Joysticks.BUTTON_DPAD_UP; var BUTTON_WARP_BACKWARD = Joysticks.BUTTON_DPAD_DOWN;