From 526664ac57c39113a357f50e5e5e5f52724a8b6d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 1 Dec 2014 22:11:34 -0800 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 11f10f95122f71dfe816d2e16f1d9c4ffd95423d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 10:54:04 -0800 Subject: [PATCH 6/7] 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 842ee714b82785d2ae93b55be9ac10b1119bc97f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 13:08:16 -0800 Subject: [PATCH 7/7] 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; }