diff --git a/android/apps/ui/proguard-rules.pro b/android/apps/interface/proguard-rules.pro
similarity index 100%
rename from android/apps/ui/proguard-rules.pro
rename to android/apps/interface/proguard-rules.pro
diff --git a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java
deleted file mode 100644
index 9ed2f1c7f5..0000000000
--- a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package io.highfidelity.hifiinterface.fragment;
-
-import android.app.Fragment;
-import android.content.Context;
-import android.os.Bundle;
-import android.text.Html;
-import android.text.Spanned;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import io.highfidelity.hifiinterface.R;
-
-public class SignedInFragment extends Fragment {
-
- private Button mGetStartedButton;
- private OnSignedInInteractionListener mListener;
-
- public SignedInFragment() {
- // Required empty public constructor
- }
-
- public static SignedInFragment newInstance() {
- SignedInFragment fragment = new SignedInFragment();
- return fragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment_signedin, container, false);
- mGetStartedButton = rootView.findViewById(R.id.getStarted);
-
- mGetStartedButton.setOnClickListener(view -> {
- getStarted();
- });
-
- return rootView;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (context instanceof SignedInFragment.OnSignedInInteractionListener) {
- mListener = (SignedInFragment.OnSignedInInteractionListener) context;
- } else {
- throw new RuntimeException(context.toString()
- + " must implement OnSignedInInteractionListener");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mListener = null;
- }
-
- public void getStarted() {
- if (mListener != null) {
- mListener.onGettingStarted();
- }
- }
-
- public interface OnSignedInInteractionListener {
- void onGettingStarted();
- }
-
-}
diff --git a/android/apps/ui/src/main/res/drawable/ic_launcher.xml b/android/apps/interface/src/main/res/drawable/ic_launcher.xml
similarity index 100%
rename from android/apps/ui/src/main/res/drawable/ic_launcher.xml
rename to android/apps/interface/src/main/res/drawable/ic_launcher.xml
diff --git a/android/apps/interface/src/main/res/drawable/rounded_button.xml b/android/apps/interface/src/main/res/drawable/rounded_button_color1.xml
similarity index 100%
rename from android/apps/interface/src/main/res/drawable/rounded_button.xml
rename to android/apps/interface/src/main/res/drawable/rounded_button_color1.xml
diff --git a/android/apps/interface/src/main/res/drawable/rounded_edit.xml b/android/apps/interface/src/main/res/drawable/rounded_edit.xml
deleted file mode 100644
index 3c1cac4d1d..0000000000
--- a/android/apps/interface/src/main/res/drawable/rounded_edit.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/apps/interface/src/main/res/layout/fragment_signedin.xml b/android/apps/interface/src/main/res/layout/fragment_signedin.xml
deleted file mode 100644
index 1c982b0e0d..0000000000
--- a/android/apps/interface/src/main/res/layout/fragment_signedin.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/apps/ui/CMakeLists.txt b/android/apps/ui/CMakeLists.txt
deleted file mode 100644
index f1f04eb829..0000000000
--- a/android/apps/ui/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(TARGET_NAME uiApp)
-setup_hifi_library(AndroidExtras)
-link_hifi_libraries(shared ktx shaders gl oculusMobile qml)
-target_link_libraries(${TARGET_NAME} android log m)
-target_opengl()
-target_oculus_mobile()
-
diff --git a/android/apps/ui/src/main/AndroidManifest.xml b/android/apps/ui/src/main/AndroidManifest.xml
deleted file mode 100644
index 81be094a3c..0000000000
--- a/android/apps/ui/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/apps/ui/src/main/cpp/PlayerWindow.cpp b/android/apps/ui/src/main/cpp/PlayerWindow.cpp
deleted file mode 100644
index 1030158daf..0000000000
--- a/android/apps/ui/src/main/cpp/PlayerWindow.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Created by Bradley Austin Davis on 2018/10/21
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "PlayerWindow.h"
-
-#include
-
-PlayerWindow::PlayerWindow() {
- installEventFilter(this);
- setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint);
- setSurfaceType(QSurface::OpenGLSurface);
- create();
- showFullScreen();
- QCoreApplication::processEvents();
- _renderThread.initialize(this);
-}
-
diff --git a/android/apps/ui/src/main/cpp/PlayerWindow.h b/android/apps/ui/src/main/cpp/PlayerWindow.h
deleted file mode 100644
index 5aa207b132..0000000000
--- a/android/apps/ui/src/main/cpp/PlayerWindow.h
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// Created by Bradley Austin Davis on 2018/10/21
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#pragma once
-#include
-#include
-
-#include "RenderThread.h"
-
-// Create a simple OpenGL window that renders text in various ways
-class PlayerWindow : public QWindow {
-public:
- PlayerWindow();
- virtual ~PlayerWindow() = default;
-
-protected:
- //bool eventFilter(QObject* obj, QEvent* event) override;
- //void keyPressEvent(QKeyEvent* event) override;
-
-private:
- RenderThread _renderThread;
-};
diff --git a/android/apps/ui/src/main/cpp/RenderThread.cpp b/android/apps/ui/src/main/cpp/RenderThread.cpp
deleted file mode 100644
index f309fb01a8..0000000000
--- a/android/apps/ui/src/main/cpp/RenderThread.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// Created by Bradley Austin Davis on 2018/10/21
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include "RenderThread.h"
-
-#include
-
-#include
-#include
-
-#include
-
-#include
-#include
-
-#define MARGIN 48
-
-void RenderThread::initialize(QWindow* window) {
- std::unique_lock lock(_frameLock);
- setObjectName("RenderThread");
- Parent::initialize();
-
- _thread->setObjectName("RenderThread");
- _size = window->size();
-
- _glContext.setWindow(window);
- _glContext.create();
- _glContext.makeCurrent();
-
- gl::setSwapInterval(0);
- glGenFramebuffers(1, &_readFbo);
- OffscreenSurface::setSharedContext(_glContext.qglContext());
-
- // GPU library init
- _glContext.doneCurrent();
- _glContext.moveToThread(_thread);
-
- _offscreen = std::make_shared();
- _offscreen->resize({ _size.width() - (MARGIN * 2), _size.height() - (MARGIN * 2)});
- _offscreen->load(QUrl("qrc://qml/main.qml"));
-}
-
-void RenderThread::releaseTexture() {
- if (_uiTexture != 0) {
- auto readFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
- CHECK_GL_ERROR();
- _discardLambda(_uiTexture, readFence);
- _uiTexture = 0;
- }
-}
-
-void RenderThread::setup() {
- // Wait until the context has been moved to this thread
- { std::unique_lock lock(_frameLock); }
- _glContext.makeCurrent();
-}
-
-void RenderThread::shutdown() {
- releaseTexture();
- _glContext.doneCurrent();
-}
-
-bool RenderThread::process() {
- float now = secTimestampNow();
- float red = fabsf(sinf(now * PI));
- _glContext.makeCurrent();
- {
- OffscreenSurface::TextureAndFence newTextureAndFence;
- if (_offscreen->fetchTexture(newTextureAndFence)) {
- releaseTexture();
- const auto& newTexture = newTextureAndFence.first;
- GLsync writeFence = static_cast(newTextureAndFence.second);
- _uiTexture = newTexture;
- glWaitSync(writeFence, 0, GL_TIMEOUT_IGNORED);
- glDeleteSync(writeFence);
- }
- }
-
- glClearColor(1, red, 1, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- if (_uiTexture != 0) {
- auto uiSize = _offscreen->size();
- glBindFramebuffer(GL_READ_FRAMEBUFFER, _readFbo);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _uiTexture, 0);
- glBlitFramebuffer(
- 0, 0, uiSize.width(), uiSize.height(),
- MARGIN, MARGIN, uiSize.width() + MARGIN, uiSize.height() + MARGIN,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
- }
- _glContext.swapBuffers();
- return true;
-}
diff --git a/android/apps/ui/src/main/cpp/RenderThread.h b/android/apps/ui/src/main/cpp/RenderThread.h
deleted file mode 100644
index e04715f7ca..0000000000
--- a/android/apps/ui/src/main/cpp/RenderThread.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Created by Bradley Austin Davis on 2018/10/21
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#pragma once
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-class RenderThread : public GenericThread {
- using Parent = GenericThread;
- using OffscreenSurface = hifi::qml::OffscreenSurface;
- using OffscreenPtr = std::shared_ptr;
- using DiscardLambda = std::function;
-public:
- gl::Context _glContext;
- std::mutex _mutex;
- std::atomic _presentCount{ 0 };
- std::mutex _frameLock;
- OffscreenPtr _offscreen;
- QSize _size;
- DiscardLambda _discardLambda { OffscreenSurface::getDiscardLambda() };
- GLuint _readFbo { 0 };
- GLuint _uiTexture { 0 };
-
- void setup() override;
- bool process() override;
- void shutdown() override;
- void initialize(QWindow* window);
-
-private:
- void releaseTexture();
-};
diff --git a/android/apps/ui/src/main/cpp/main.cpp b/android/apps/ui/src/main/cpp/main.cpp
deleted file mode 100644
index 611f652fad..0000000000
--- a/android/apps/ui/src/main/cpp/main.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-
-//
-// Created by Bradley Austin Davis on 2018/11/22
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include
-
-#include
-
-#include
-
-#include "PlayerWindow.h"
-
-void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
- if (!message.isEmpty()) {
- const char * local=message.toStdString().c_str();
- switch (type) {
- case QtDebugMsg:
- __android_log_write(ANDROID_LOG_DEBUG,"QQ",local);
- break;
- case QtInfoMsg:
- __android_log_write(ANDROID_LOG_INFO,"QQ",local);
- break;
- case QtWarningMsg:
- __android_log_write(ANDROID_LOG_WARN,"QQ",local);
- break;
- case QtCriticalMsg:
- __android_log_write(ANDROID_LOG_ERROR,"QQ",local);
- break;
- case QtFatalMsg:
- default:
- __android_log_write(ANDROID_LOG_FATAL,"QQ",local);
- abort();
- }
- }
-}
-
-void initWebView();
-
-int main(int argc, char** argv) {
- setupHifiApplication("uiApp");
- QGuiApplication app(argc, argv);
- initWebView();
- auto oldMessageHandler = qInstallMessageHandler(messageHandler);
- {
- DependencyManager::set();
- PlayerWindow window;
- app.exec();
- }
- qInstallMessageHandler(oldMessageHandler);
- return 0;
-}
-
-
diff --git a/android/apps/ui/src/main/cpp/main.qml b/android/apps/ui/src/main/cpp/main.qml
deleted file mode 100644
index 8a99918152..0000000000
--- a/android/apps/ui/src/main/cpp/main.qml
+++ /dev/null
@@ -1,21 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.2
-import QtWebView 1.1
-
-WebView {
- url: "https://old.reddit.com"
- width: 640; height: 480
-
- Rectangle {
- id: blue
- color: "blue"
- anchors { margins: 48; top: parent.top; bottom: parent.bottom; left: parent.left; }
- width: parent.width / 3
- ColorAnimation on color {
- from: "yellow";
- to: "red";
- loops: Animation.Infinite;
- duration: 1000;
- }
- }
-}
diff --git a/android/apps/ui/src/main/cpp/mainqt.cpp b/android/apps/ui/src/main/cpp/mainqt.cpp
deleted file mode 100644
index c4c05569c0..0000000000
--- a/android/apps/ui/src/main/cpp/mainqt.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include
-
-void initWebView() {
- QtWebView::initialize();
-}
\ No newline at end of file
diff --git a/android/apps/ui/src/main/cpp/resources.qrc b/android/apps/ui/src/main/cpp/resources.qrc
deleted file mode 100644
index f06d416800..0000000000
--- a/android/apps/ui/src/main/cpp/resources.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- main.qml
-
-
diff --git a/android/apps/ui/src/main/java/io/highfidelity/ui/UiActivity.java b/android/apps/ui/src/main/java/io/highfidelity/ui/UiActivity.java
deleted file mode 100644
index bc6dcb3cd3..0000000000
--- a/android/apps/ui/src/main/java/io/highfidelity/ui/UiActivity.java
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Created by Bradley Austin Davis on 2018/11/20
-// Copyright 2013-2018 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-package io.highfidelity.ui;
-
-import android.os.Bundle;
-import org.qtproject.qt5.android.bindings.QtActivity;
-
-
-
-public class UiActivity extends QtActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- //System.loadLibrary("uiApp");
- super.onCreate(savedInstanceState);
- }
-}
diff --git a/android/apps/ui/src/main/res/values/strings.xml b/android/apps/ui/src/main/res/values/strings.xml
deleted file mode 100644
index 8bf550f74e..0000000000
--- a/android/apps/ui/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- GPU Frame Player
-
diff --git a/android/apps/ui/src/main/uiApp.pro b/android/apps/ui/src/main/uiApp.pro
deleted file mode 100644
index 812ea8e1b8..0000000000
--- a/android/apps/ui/src/main/uiApp.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-TEMPLATE = app
-
-QT += gui qml quick xml webview widgets
-
-CONFIG += c++11
-
-SOURCES += \
- cpp/main.cpp \
- cpp/PlayerWindow.cpp \
- cpp/RenderThread.cpp \
- cpp/resources.qrc
-
-HEADERS += \
- cpp/PlayerWindow.h \
- cpp/RenderThread.h
-
-
-# Additional import path used to resolve QML modules in Qt Creator's code model
-QML_IMPORT_PATH = cpp
-
-#DISTFILES += \
-# cpp/*.qml
diff --git a/android/settings.gradle b/android/settings.gradle
index ffa2c93d6d..23e54b0457 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -25,5 +25,5 @@ project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterfa
//include ':framePlayer'
//project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer')
-//include ':ui'
-//project(':ui').projectDir = new File(settingsDir, 'apps/ui')
+//include ':questFramePlayer'
+//project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer')
diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp
index 1b53f9ab30..236512f2fe 100644
--- a/interface/src/raypick/LaserPointer.cpp
+++ b/interface/src/raypick/LaserPointer.cpp
@@ -125,7 +125,7 @@ LaserPointer::RenderState::RenderState(const OverlayID& startID, const OverlayID
StartEndRenderState(startID, endID), _pathID(pathID)
{
if (!_pathID.isNull()) {
- _pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool();
+ _pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignorePickIntersection").value.toBool();
_lineWidth = qApp->getOverlays().getProperty(_pathID, "lineWidth").value.toFloat();
}
}
@@ -142,7 +142,7 @@ void LaserPointer::RenderState::disable() {
if (!getPathID().isNull()) {
QVariantMap pathProps;
pathProps.insert("visible", false);
- pathProps.insert("ignoreRayIntersection", true);
+ pathProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getPathID(), pathProps);
}
}
@@ -156,7 +156,7 @@ void LaserPointer::RenderState::update(const glm::vec3& origin, const glm::vec3&
pathProps.insert("start", vec3toVariant(origin));
pathProps.insert("end", endVariant);
pathProps.insert("visible", true);
- pathProps.insert("ignoreRayIntersection", doesPathIgnoreRays());
+ pathProps.insert("ignorePickIntersection", doesPathIgnoreRays());
pathProps.insert("lineWidth", getLineWidth() * parentScale);
qApp->getOverlays().editOverlay(getPathID(), pathProps);
}
diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h
index 5aaacd7960..d85e329e9a 100644
--- a/interface/src/raypick/LaserPointerScriptingInterface.h
+++ b/interface/src/raypick/LaserPointerScriptingInterface.h
@@ -21,7 +21,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
SINGLETON_DEPENDENCY
/**jsdoc
- * Synonym for {@link Pointers} as used for laser pointers.
+ * Synonym for {@link Pointers} as used for laser pointers. Deprecated.
*
* @namespace LaserPointers
*
diff --git a/interface/src/raypick/ParabolaPick.cpp b/interface/src/raypick/ParabolaPick.cpp
index 571f4a6ea6..b93ced17c6 100644
--- a/interface/src/raypick/ParabolaPick.cpp
+++ b/interface/src/raypick/ParabolaPick.cpp
@@ -9,6 +9,7 @@
#include "Application.h"
#include "EntityScriptingInterface.h"
+#include "PickScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
@@ -57,10 +58,15 @@ PickParabola ParabolaPick::getMathematicalPick() const {
PickResultPointer ParabolaPick::getEntityIntersection(const PickParabola& pick) {
if (glm::length2(pick.acceleration) > EPSILON && glm::length2(pick.velocity) > EPSILON) {
- bool precisionPicking = !(getFilter().doesPickCoarse() || DependencyManager::get()->getForceCoarsePicking());
+ PickFilter searchFilter = getFilter();
+ if (DependencyManager::get()->getForceCoarsePicking()) {
+ searchFilter.setFlag(PickFilter::COARSE, true);
+ searchFilter.setFlag(PickFilter::PRECISE, false);
+ }
+
ParabolaToEntityIntersectionResult entityRes =
- DependencyManager::get()->findParabolaIntersectionVector(pick, precisionPicking,
- getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
+ DependencyManager::get()->evalParabolaIntersectionVector(pick, searchFilter,
+ getIncludeItemsAs(), getIgnoreItemsAs());
if (entityRes.intersects) {
return std::make_shared(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.parabolicDistance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
}
@@ -70,7 +76,7 @@ PickResultPointer ParabolaPick::getEntityIntersection(const PickParabola& pick)
PickResultPointer ParabolaPick::getOverlayIntersection(const PickParabola& pick) {
if (glm::length2(pick.acceleration) > EPSILON && glm::length2(pick.velocity) > EPSILON) {
- bool precisionPicking = !(getFilter().doesPickCoarse() || DependencyManager::get()->getForceCoarsePicking());
+ bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get()->getForceCoarsePicking());
ParabolaToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findParabolaIntersectionVector(pick, precisionPicking,
getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp
index 162c26276f..e45b11b479 100644
--- a/interface/src/raypick/ParabolaPointer.cpp
+++ b/interface/src/raypick/ParabolaPointer.cpp
@@ -404,7 +404,7 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
{
- gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola );
+ gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
auto state = std::make_shared();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
diff --git a/interface/src/raypick/PathPointer.cpp b/interface/src/raypick/PathPointer.cpp
index 8a6995936f..ae0ce4671b 100644
--- a/interface/src/raypick/PathPointer.cpp
+++ b/interface/src/raypick/PathPointer.cpp
@@ -253,12 +253,12 @@ StartEndRenderState::StartEndRenderState(const OverlayID& startID, const Overlay
_startID(startID), _endID(endID) {
if (!_startID.isNull()) {
_startDim = vec3FromVariant(qApp->getOverlays().getProperty(_startID, "dimensions").value);
- _startIgnoreRays = qApp->getOverlays().getProperty(_startID, "ignoreRayIntersection").value.toBool();
+ _startIgnoreRays = qApp->getOverlays().getProperty(_startID, "ignorePickIntersection").value.toBool();
}
if (!_endID.isNull()) {
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);
_endRot = quatFromVariant(qApp->getOverlays().getProperty(_endID, "rotation").value);
- _endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignoreRayIntersection").value.toBool();
+ _endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignorePickIntersection").value.toBool();
}
}
@@ -275,13 +275,13 @@ void StartEndRenderState::disable() {
if (!getStartID().isNull()) {
QVariantMap startProps;
startProps.insert("visible", false);
- startProps.insert("ignoreRayIntersection", true);
+ startProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getStartID(), startProps);
}
if (!getEndID().isNull()) {
QVariantMap endProps;
endProps.insert("visible", false);
- endProps.insert("ignoreRayIntersection", true);
+ endProps.insert("ignorePickIntersection", true);
qApp->getOverlays().editOverlay(getEndID(), endProps);
}
_enabled = false;
@@ -294,7 +294,7 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
startProps.insert("position", vec3toVariant(origin));
startProps.insert("visible", true);
startProps.insert("dimensions", vec3toVariant(getStartDim() * parentScale));
- startProps.insert("ignoreRayIntersection", doesStartIgnoreRays());
+ startProps.insert("ignorePickIntersection", doesStartIgnoreRays());
qApp->getOverlays().editOverlay(getStartID(), startProps);
}
@@ -346,7 +346,7 @@ void StartEndRenderState::update(const glm::vec3& origin, const glm::vec3& end,
endProps.insert("position", vec3toVariant(position));
endProps.insert("rotation", quatToVariant(rotation));
endProps.insert("visible", true);
- endProps.insert("ignoreRayIntersection", doesEndIgnoreRays());
+ endProps.insert("ignorePickIntersection", doesEndIgnoreRays());
qApp->getOverlays().editOverlay(getEndID(), endProps);
}
_enabled = true;
diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp
index 6e979d2d91..e8f84e63fe 100644
--- a/interface/src/raypick/PickScriptingInterface.cpp
+++ b/interface/src/raypick/PickScriptingInterface.cpp
@@ -49,11 +49,17 @@ unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type,
}
}
+PickFilter getPickFilter(unsigned int filter) {
+ // FIXME: Picks always intersect visible and collidable things right now
+ filter = filter | (PickScriptingInterface::PICK_INCLUDE_VISIBLE() | PickScriptingInterface::PICK_INCLUDE_COLLIDABLE());
+ return PickFilter(filter);
+}
+
/**jsdoc
* A set of properties that can be passed to {@link Picks.createPick} to create a new Ray Pick.
* @typedef {object} Picks.RayPickProperties
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
- * @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
+ * @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
@@ -73,7 +79,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) {
PickFilter filter = PickFilter();
if (propMap["filter"].isValid()) {
- filter = PickFilter(propMap["filter"].toUInt());
+ filter = getPickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
@@ -111,7 +117,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) {
* @typedef {object} Picks.StylusPickProperties
* @property {number} [hand=-1] An integer. 0 == left, 1 == right. Invalid otherwise.
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
- * @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
+ * @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
*/
unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties) {
@@ -132,7 +138,7 @@ unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties
PickFilter filter = PickFilter();
if (propMap["filter"].isValid()) {
- filter = PickFilter(propMap["filter"].toUInt());
+ filter = getPickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
@@ -153,7 +159,7 @@ unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties
* A set of properties that can be passed to {@link Picks.createPick} to create a new Parabola Pick.
* @typedef {object} Picks.ParabolaPickProperties
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
- * @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
+ * @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {number} [maxDistance=0.0] The max distance at which this Pick will intersect. 0.0 = no max. < 0.0 is invalid.
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, an overlay, or a pick.
* @property {number} [parentJointIndex=0] - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
@@ -178,7 +184,7 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
PickFilter filter = PickFilter();
if (propMap["filter"].isValid()) {
- filter = PickFilter(propMap["filter"].toUInt());
+ filter = getPickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
@@ -250,7 +256,7 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
* @typedef {object} Picks.CollisionPickProperties
* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results.
-* @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
+* @property {number} [filter=0] The filter for this Pick to use, constructed using filter flags combined using bitwise OR.
* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are in world space, but will scale with the parent if defined.
* @property {Vec3} position - The position of the collision region, relative to a parent if defined.
* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined.
@@ -273,7 +279,7 @@ unsigned int PickScriptingInterface::createCollisionPick(const QVariant& propert
PickFilter filter = PickFilter();
if (propMap["filter"].isValid()) {
- filter = PickFilter(propMap["filter"].toUInt());
+ filter = getPickFilter(propMap["filter"].toUInt());
}
float maxDistance = 0.0f;
diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h
index 94112d5fae..e795068cd3 100644
--- a/interface/src/raypick/PickScriptingInterface.h
+++ b/interface/src/raypick/PickScriptingInterface.h
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
/**jsdoc
* The Picks API lets you create and manage objects for repeatedly calculating intersections in different ways.
@@ -23,41 +24,62 @@
* @hifi-interface
* @hifi-client-entity
*
- * @property {number} PICK_NOTHING A filter flag. Don't intersect with anything. Read-only.
- * @property {number} PICK_ENTITIES A filter flag. Include entities when intersecting. Read-only.
- * @property {number} PICK_OVERLAYS A filter flag. Include overlays when intersecting. Read-only.
- * @property {number} PICK_AVATARS A filter flag. Include avatars when intersecting. Read-only.
- * @property {number} PICK_HUD A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only.
- * @property {number} PICK_COARSE A filter flag. Pick against coarse meshes, instead of exact meshes. Read-only.
- * @property {number} PICK_INCLUDE_INVISIBLE A filter flag. Include invisible objects when intersecting. Read-only.
- * @property {number} PICK_INCLUDE_NONCOLLIDABLE A filter flag. Include non-collidable objects when intersecting.
- * Read-only.
- * @property {number} PICK_ALL_INTERSECTIONS Read-only.
- * @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags.
- * Read-only.
+ * @property {number} PICK_ENTITIES A filter flag. Include domain and avatar entities when intersecting. Read-only.. Deprecated.
+ * @property {number} PICK_OVERLAYS A filter flag. Include local entities when intersecting. Read-only.. Deprecated.
+ *
+ * @property {number} PICK_DOMAIN_ENTITIES A filter flag. Include domain entities when intersecting. Read-only..
+ * @property {number} PICK_AVATAR_ENTITIES A filter flag. Include avatar entities when intersecting. Read-only..
+ * @property {number} PICK_LOCAL_ENTITIES A filter flag. Include local entities when intersecting. Read-only..
+ * @property {number} PICK_AVATARS A filter flag. Include avatars when intersecting. Read-only..
+ * @property {number} PICK_HUD A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only..
+ *
+ * @property {number} PICK_INCLUDE_VISIBLE A filter flag. Include visible objects when intersecting. Read-only..
+ * @property {number} PICK_INCLUDE_INVISIBLE A filter flag. Include invisible objects when intersecting. Read-only..
+ *
+ * @property {number} PICK_INCLUDE_COLLIDABLE A filter flag. Include collidable objects when intersecting. Read-only..
+ * @property {number} PICK_INCLUDE_NONCOLLIDABLE A filter flag. Include non-collidable objects when intersecting. Read-only..
+ *
+ * @property {number} PICK_PRECISE A filter flag. Pick against exact meshes. Read-only..
+ * @property {number} PICK_COARSE A filter flag. Pick against coarse meshes. Read-only..
+ *
+ * @property {number} PICK_ALL_INTERSECTIONS Read-only..
+ *
+ * @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags. Read-only.
* @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. Read-only.
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. Read-only.
* @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. Read-only.
* @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. Read-only.
- * @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results. Read-only.
+ * @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results.
*/
class PickScriptingInterface : public QObject, public Dependency {
Q_OBJECT
- Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT)
Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT)
Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT)
+
+ Q_PROPERTY(unsigned int PICK_DOMAIN_ENTITIES READ PICK_DOMAIN_ENTITIES CONSTANT)
+ Q_PROPERTY(unsigned int PICK_AVATAR_ENTITIES READ PICK_AVATAR_ENTITIES CONSTANT)
+ Q_PROPERTY(unsigned int PICK_LOCAL_ENTITIES READ PICK_LOCAL_ENTITIES CONSTANT)
Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT)
Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT)
- Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT)
+
+ Q_PROPERTY(unsigned int PICK_INCLUDE_VISIBLE READ PICK_INCLUDE_VISIBLE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT)
+
+ Q_PROPERTY(unsigned int PICK_INCLUDE_COLLIDABLE READ PICK_INCLUDE_COLLIDABLE CONSTANT)
Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT)
+
+ Q_PROPERTY(unsigned int PICK_PRECISE READ PICK_PRECISE CONSTANT)
+ Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT)
+
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
+
Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT)
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
+ Q_PROPERTY(unsigned int perFrameTimeBudget READ getPerFrameTimeBudget WRITE setPerFrameTimeBudget)
SINGLETON_DEPENDENCY
public:
@@ -72,11 +94,13 @@ public:
* Adds a new Pick.
* Different {@link PickType}s use different properties, and within one PickType, the properties you choose can lead to a wide range of behaviors. For example,
* with PickType.Ray, depending on which optional parameters you pass, you could create a Static Ray Pick, a Mouse Ray Pick, or a Joint Ray Pick.
+ * Picks created with this method always intersect at least visible and collidable things
* @function Picks.createPick
* @param {PickType} type A PickType that specifies the method of picking to use
* @param {Picks.RayPickProperties|Picks.StylusPickProperties|Picks.ParabolaPickProperties|Picks.CollisionPickProperties} properties A PickProperties object, containing all the properties for initializing this Pick
* @returns {number} The ID of the created Pick. Used for managing the Pick. 0 if invalid.
*/
+ // TODO: expand Pointers to be able to be fully configurable with PickFilters
Q_INVOKABLE unsigned int createPick(const PickQuery::PickType type, const QVariant& properties);
/**jsdoc
@@ -227,61 +251,80 @@ public:
*/
Q_INVOKABLE bool isMouse(unsigned int uid);
- // FIXME: Move to other property definitions.
- Q_PROPERTY(unsigned int perFrameTimeBudget READ getPerFrameTimeBudget WRITE setPerFrameTimeBudget)
-
unsigned int getPerFrameTimeBudget() const;
void setPerFrameTimeBudget(unsigned int numUsecs);
public slots:
- /**jsdoc
- * @function Picks.PICK_NOTHING
- * @returns {number}
- */
- static constexpr unsigned int PICK_NOTHING() { return 0; }
-
/**jsdoc
* @function Picks.PICK_ENTITIES
* @returns {number}
*/
- static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); }
-
+ static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES); }
/**jsdoc
* @function Picks.PICK_OVERLAYS
* @returns {number}
*/
- static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); }
+ static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES); }
+ /**jsdoc
+ * @function Picks.PICK_DOMAIN_ENTITIES
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_DOMAIN_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES); }
+ /**jsdoc
+ * @function Picks.PICK_AVATAR_ENTITIES
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_AVATAR_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES); }
+ /**jsdoc
+ * @function Picks.PICK_LOCAL_ENTITIES
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_LOCAL_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES); }
/**jsdoc
* @function Picks.PICK_AVATARS
* @returns {number}
*/
- static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); }
-
+ static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::AVATARS); }
/**jsdoc
* @function Picks.PICK_HUD
* @returns {number}
*/
- static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); }
+ static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::HUD); }
/**jsdoc
- * @function Picks.PICK_COARSE
+ * @function Picks.PICK_INCLUDE_VISIBLE
* @returns {number}
*/
- static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); }
-
+ static constexpr unsigned int PICK_INCLUDE_VISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE); }
/**jsdoc
* @function Picks.PICK_INCLUDE_INVISIBLE
* @returns {number}
*/
- static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); }
+ static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::INVISIBLE); }
+ /**jsdoc
+ * @function Picks.PICK_INCLUDE_COLLIDABLE
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_INCLUDE_COLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::COLLIDABLE); }
/**jsdoc
* @function Picks.PICK_INCLUDE_NONCOLLIDABLE
* @returns {number}
*/
- static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); }
+ static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::NONCOLLIDABLE); }
+
+ /**jsdoc
+ * @function Picks.PICK_PRECISE
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_PRECISE() { return PickFilter::getBitMask(PickFilter::FlagBit::PRECISE); }
+ /**jsdoc
+ * @function Picks.PICK_COARSE
+ * @returns {number}
+ */
+ static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::COARSE); }
/**jsdoc
* @function Picks.PICK_ALL_INTERSECTIONS
diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h
index 2677f37fae..a21c1f2470 100644
--- a/interface/src/raypick/PointerScriptingInterface.h
+++ b/interface/src/raypick/PointerScriptingInterface.h
@@ -41,10 +41,12 @@ public:
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
* it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
*/
+
/**jsdoc
* Adds a new Pointer
* Different {@link PickType}s use different properties, and within one PickType, the properties you choose can lead to a wide range of behaviors. For example,
* with PickType.Ray, depending on which optional parameters you pass, you could create a Static Ray Pointer, a Mouse Ray Pointer, or a Joint Ray Pointer.
+ * Pointers created with this method always intersect at least visible and collidable things
* @function Pointers.createPointer
* @param {PickType} type A PickType that specifies the method of picking to use
* @param {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} properties A PointerProperties object, containing all the properties for initializing this Pointer and the {@link Picks.PickProperties} for the Pick that
@@ -58,21 +60,21 @@ public:
* dimensions: {x:0.5, y:0.5, z:0.5},
* solid: true,
* color: {red:0, green:255, blue:0},
- * ignoreRayIntersection: true
+ * ignorePickIntersection: true
* };
* var end2 = {
* type: "sphere",
* dimensions: {x:0.5, y:0.5, z:0.5},
* solid: true,
* color: {red:255, green:0, blue:0},
- * ignoreRayIntersection: true
+ * ignorePickIntersection: true
* };
*
* var renderStates = [ {name: "test", end: end} ];
* var defaultRenderStates = [ {name: "test", distance: 10.0, end: end2} ];
* var pointer = Pointers.createPointer(PickType.Ray, {
* joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
- * filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
+ * filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
* renderStates: renderStates,
* defaultRenderStates: defaultRenderStates,
* distanceScaleEnd: true,
@@ -82,6 +84,7 @@ public:
* });
* Pointers.setRenderState(pointer, "test");
*/
+ // TODO: expand Pointers to be able to be fully configurable with PickFilters
Q_INVOKABLE unsigned int createPointer(const PickQuery::PickType& type, const QVariant& properties);
/**jsdoc
diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp
index a48d858504..507e45b470 100644
--- a/interface/src/raypick/RayPick.cpp
+++ b/interface/src/raypick/RayPick.cpp
@@ -27,10 +27,15 @@ PickRay RayPick::getMathematicalPick() const {
}
PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
- bool precisionPicking = !(getFilter().doesPickCoarse() || DependencyManager::get()->getForceCoarsePicking());
+ PickFilter searchFilter = getFilter();
+ if (DependencyManager::get()->getForceCoarsePicking()) {
+ searchFilter.setFlag(PickFilter::COARSE, true);
+ searchFilter.setFlag(PickFilter::PRECISE, false);
+ }
+
RayToEntityIntersectionResult entityRes =
- DependencyManager::get()->findRayIntersectionVector(pick, precisionPicking,
- getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
+ DependencyManager::get()->evalRayIntersectionVector(pick, searchFilter,
+ getIncludeItemsAs(), getIgnoreItemsAs());
if (entityRes.intersects) {
return std::make_shared(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal, entityRes.extraInfo);
} else {
@@ -39,7 +44,7 @@ PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
}
PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
- bool precisionPicking = !(getFilter().doesPickCoarse() || DependencyManager::get()->getForceCoarsePicking());
+ bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get()->getForceCoarsePicking());
RayToOverlayIntersectionResult overlayRes =
qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking,
getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable());
diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h
index d5e224018e..3ad0efd439 100644
--- a/interface/src/raypick/RayPickScriptingInterface.h
+++ b/interface/src/raypick/RayPickScriptingInterface.h
@@ -19,14 +19,13 @@
#include "PickScriptingInterface.h"
/**jsdoc
- * Synonym for {@link Picks} as used for ray picks.
+ * Synonym for {@link Picks} as used for ray picks. Deprecated.
*
* @namespace RayPick
*
* @hifi-interface
* @hifi-client-entity
*
- * @property {number} PICK_NOTHING Read-only.
* @property {number} PICK_ENTITIES Read-only.
* @property {number} PICK_OVERLAYS Read-only.
* @property {number} PICK_AVATARS Read-only.
@@ -44,7 +43,6 @@
class RayPickScriptingInterface : public QObject, public Dependency {
Q_OBJECT
- Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT)
Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT)
Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT)
Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT)
@@ -140,12 +138,6 @@ public:
public slots:
- /**jsdoc
- * @function RayPick.PICK_NOTHING
- * @returns {number}
- */
- static unsigned int PICK_NOTHING() { return PickScriptingInterface::PICK_NOTHING(); }
-
/**jsdoc
* @function RayPick.PICK_ENTITIES
* @returns {number}
diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp
index 5595c54b71..867f896763 100644
--- a/interface/src/raypick/StylusPointer.cpp
+++ b/interface/src/raypick/StylusPointer.cpp
@@ -61,7 +61,7 @@ OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
overlayProperties["loadPriority"] = 10.0f;
overlayProperties["solid"] = true;
overlayProperties["visible"] = false;
- overlayProperties["ignoreRayIntersection"] = true;
+ overlayProperties["ignorePickIntersection"] = true;
overlayProperties["drawInFront"] = false;
return qApp->getOverlays().addOverlay("model", overlayProperties);
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
index 2fcaf72f2d..69590aae82 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
@@ -20,7 +20,7 @@ const QString& DisplayPlugin::MENU_PATH() {
return value;
}
-#if !defined(USE_QUEST)
+#if !defined(CUSTOM_DISPLAY_PLUGINS)
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
DisplayPluginList getDisplayPlugins() {
DisplayPlugin* PLUGIN_POOL[] = {
diff --git a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp
index 4d1dfa639b..b4527ff90c 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp
@@ -51,8 +51,6 @@ bool DebugHmdDisplayPlugin::internalActivate() {
}, true, _isAutoRotateEnabled);
_ipd = 0.0327499993f * 2.0f;
-
-
// Quest
_eyeProjections[0][0] = vec4{ 0.91729, 0.0, -0.17407, 0.0 };
_eyeProjections[0][1] = vec4{ 0.0, 0.083354, -0.106141, 0.0 };
@@ -62,17 +60,6 @@ bool DebugHmdDisplayPlugin::internalActivate() {
_eyeProjections[1][1] = vec4{ 0.0, 0.083354, -0.106141, 0.0 };
_eyeProjections[1][2] = vec4{ 0.0, 0.0, -1.0, -0.2 };
_eyeProjections[1][3] = vec4{ 0.0, 0.0, -1.0, 0.0 };
-
-
- // Would be nice to know why the left and right projection matrices are slightly dissymetrical
- _eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
- _eyeProjections[0][1] = vec4{ 0.000000000, 0.682773232, 0.000000000, 0.000000000 };
- _eyeProjections[0][2] = vec4{ -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 };
- _eyeProjections[0][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
- _eyeProjections[1][0] = vec4{ 0.752847493, 0.000000000, 0.000000000, 0.000000000 };
- _eyeProjections[1][1] = vec4{ 0.000000000, 0.678060353, 0.000000000, 0.000000000 };
- _eyeProjections[1][2] = vec4{ 0.0578232110, -0.00669418881, -1.00000489, -1.000000000 };
- _eyeProjections[1][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
// No need to do so here as this will done in Parent::internalActivate
//_eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]);
//_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 5bcf1e6205..c71b296a74 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -547,11 +547,12 @@ void EntityTreeRenderer::handleSpaceUpdate(std::pair proxyUp
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar) {
bool didUpdate = false;
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
- QVector foundEntities;
+ QVector entityIDs;
// find the entities near us
// don't let someone else change our tree while we search
_tree->withReadLock([&] {
+ auto entityTree = std::static_pointer_cast(_tree);
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
entityTree->evalEntitiesInSphere(_avatarPosition, radius, PickFilter(), entityIDs);
@@ -560,7 +561,12 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorfindEntityByID(entityID);
+ if (!entity) {
+ continue;
+ }
+
auto isZone = entity->getType() == EntityTypes::Zone;
auto hasScript = !entity->getScript().isEmpty();
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index cdcecb2b15..286f0dd650 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -1082,13 +1082,10 @@ QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float
EntityItemID result;
if (_entityTree) {
- EntityItemPointer closestEntity;
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->withReadLock([&] {
- closestEntity = _entityTree->findClosestEntity(center, radius);
+ result = _entityTree->evalClosestEntity(center, radius, PickFilter(searchFilter));
});
- if (closestEntity) {
- result = closestEntity->getEntityItemID();
- }
}
return result;
}
@@ -1107,14 +1104,10 @@ QVector EntityScriptingInterface::findEntities(const glm::vec3& center, f
QVector result;
if (_entityTree) {
- QVector entities;
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->withReadLock([&] {
- _entityTree->findEntities(center, radius, entities);
+ _entityTree->evalEntitiesInSphere(center, radius, PickFilter(searchFilter), result);
});
-
- foreach (EntityItemPointer entity, entities) {
- result << entity->getEntityItemID();
- }
}
return result;
}
@@ -1124,15 +1117,11 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn
QVector result;
if (_entityTree) {
- QVector entities;
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->withReadLock([&] {
AABox box(corner, dimensions);
- _entityTree->findEntities(box, entities);
+ _entityTree->evalEntitiesInBox(box, PickFilter(searchFilter), result);
});
-
- foreach (EntityItemPointer entity, entities) {
- result << entity->getEntityItemID();
- }
}
return result;
}
@@ -1167,14 +1156,10 @@ QVector EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frust
viewFrustum.calculate();
if (_entityTree) {
- QVector entities;
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->withReadLock([&] {
- _entityTree->findEntities(viewFrustum, entities);
+ _entityTree->evalEntitiesInFrustum(viewFrustum, PickFilter(searchFilter), result);
});
-
- foreach(EntityItemPointer entity, entities) {
- result << entity->getEntityItemID();
- }
}
}
@@ -1186,86 +1171,64 @@ QVector EntityScriptingInterface::findEntitiesByType(const QString entity
QVector result;
if (_entityTree) {
- QVector entities;
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
_entityTree->withReadLock([&] {
- _entityTree->findEntities(center, radius, entities);
+ _entityTree->evalEntitiesInSphereWithType(center, radius, type, PickFilter(searchFilter), result);
});
-
- foreach(EntityItemPointer entity, entities) {
- if (entity->getType() == type) {
- result << entity->getEntityItemID().toString();
- }
- }
}
return result;
}
QVector EntityScriptingInterface::findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, bool caseSensitiveSearch) const {
-
QVector result;
if (_entityTree) {
- QVector entities;
_entityTree->withReadLock([&] {
- _entityTree->findEntities(center, radius, entities);
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
+ _entityTree->evalEntitiesInSphereWithName(center, radius, entityName, caseSensitiveSearch, PickFilter(searchFilter), result);
});
-
- if (caseSensitiveSearch) {
- foreach(EntityItemPointer entity, entities) {
- if (entity->getName() == entityName) {
- result << entity->getEntityItemID();
- }
- }
-
- } else {
- QString entityNameLowerCase = entityName.toLower();
-
- foreach(EntityItemPointer entity, entities) {
- QString entityItemLowerCase = entity->getName().toLower();
- if (entityItemLowerCase == entityNameLowerCase) {
- result << entity->getEntityItemID();
- }
- }
- }
}
return result;
}
-RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking,
- const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) {
+RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking,
+ const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const {
+ PROFILE_RANGE(script_entities, __FUNCTION__);
QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard);
- return findRayIntersectionVector(ray, precisionPicking, entitiesToInclude, entitiesToDiscard, visibleOnly, collidableOnly);
+ unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES);
+
+ if (!precisionPicking) {
+ searchFilter = searchFilter | PickFilter::getBitMask(PickFilter::FlagBit::COARSE);
+ }
+
+ if (visibleOnly) {
+ searchFilter = searchFilter | PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE);
+ }
+
+ if (collidableOnly) {
+ searchFilter = searchFilter | PickFilter::getBitMask(PickFilter::FlagBit::COLLIDABLE);
+ }
+
+ return evalRayIntersectionWorker(ray, Octree::Lock, PickFilter(searchFilter), entitiesToInclude, entitiesToDiscard);
}
-RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
- const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) {
+RayToEntityIntersectionResult EntityScriptingInterface::evalRayIntersectionVector(const PickRay& ray, PickFilter searchFilter,
+ const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard) {
PROFILE_RANGE(script_entities, __FUNCTION__);
- return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly);
+ return evalRayIntersectionWorker(ray, Octree::Lock, searchFilter, entityIdsToInclude, entityIdsToDiscard);
}
-// FIXME - we should remove this API and encourage all users to use findRayIntersection() instead. We've changed
-// findRayIntersection() to be blocking because it never makes sense for a script to get back a non-answer
-RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking,
- const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) {
-
- qWarning() << "Entities.findRayIntersectionBlocking() is obsolete, use Entities.findRayIntersection() instead.";
- const QVector& entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
- const QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard);
- return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard);
-}
-
-RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray,
- Octree::lockType lockType, bool precisionPicking, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) {
-
+RayToEntityIntersectionResult EntityScriptingInterface::evalRayIntersectionWorker(const PickRay& ray,
+ Octree::lockType lockType, PickFilter searchFilter, const QVector& entityIdsToInclude,
+ const QVector& entityIdsToDiscard) const {
RayToEntityIntersectionResult result;
if (_entityTree) {
OctreeElementPointer element;
- result.entityID = _entityTree->findRayIntersection(ray.origin, ray.direction,
- entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly, precisionPicking,
+ result.entityID = _entityTree->evalRayIntersection(ray.origin, ray.direction,
+ entityIdsToInclude, entityIdsToDiscard, searchFilter,
element, result.distance, result.face, result.surfaceNormal,
result.extraInfo, lockType, &result.accurate);
result.intersects = !result.entityID.isNull();
@@ -1276,23 +1239,22 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke
return result;
}
-ParabolaToEntityIntersectionResult EntityScriptingInterface::findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking,
- const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) {
+ParabolaToEntityIntersectionResult EntityScriptingInterface::evalParabolaIntersectionVector(const PickParabola& parabola, PickFilter searchFilter,
+ const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard) {
PROFILE_RANGE(script_entities, __FUNCTION__);
- return findParabolaIntersectionWorker(parabola, Octree::Lock, precisionPicking, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly);
+ return evalParabolaIntersectionWorker(parabola, Octree::Lock, searchFilter, entityIdsToInclude, entityIdsToDiscard);
}
-ParabolaToEntityIntersectionResult EntityScriptingInterface::findParabolaIntersectionWorker(const PickParabola& parabola,
- Octree::lockType lockType, bool precisionPicking, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) {
-
+ParabolaToEntityIntersectionResult EntityScriptingInterface::evalParabolaIntersectionWorker(const PickParabola& parabola,
+ Octree::lockType lockType, PickFilter searchFilter, const QVector& entityIdsToInclude,
+ const QVector& entityIdsToDiscard) const {
ParabolaToEntityIntersectionResult result;
if (_entityTree) {
OctreeElementPointer element;
- result.entityID = _entityTree->findParabolaIntersection(parabola,
- entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly, precisionPicking,
+ result.entityID = _entityTree->evalParabolaIntersection(parabola,
+ entityIdsToInclude, entityIdsToDiscard, searchFilter,
element, result.intersection, result.distance, result.parabolicDistance, result.face, result.surfaceNormal,
result.extraInfo, lockType, &result.accurate);
result.intersects = !result.entityID.isNull();
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index add7e26c6c..0e96cb2d25 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
@@ -56,8 +57,7 @@ private:
};
/**jsdoc
- * The result of a {@link PickRay} search using {@link Entities.findRayIntersection|findRayIntersection} or
- * {@link Entities.findRayIntersectionBlocking|findRayIntersectionBlocking}.
+ * The result of a {@link PickRay} search using {@link Entities.findRayIntersection|findRayIntersection}.
* @typedef {object} Entities.RayToEntityIntersectionResult
* @property {boolean} intersects - true if the {@link PickRay} intersected an entity, otherwise
* false.
@@ -119,7 +119,6 @@ public:
/// handles scripting of Entity commands from JS passed to assigned clients
class EntityScriptingInterface : public OctreeScriptingInterface, public Dependency {
Q_OBJECT
-
Q_PROPERTY(QUuid keyboardFocusEntity READ getKeyboardFocusEntity WRITE setKeyboardFocusEntity)
friend EntityPropertyMetadataRequest;
@@ -144,10 +143,10 @@ public:
void resetActivityTracking();
ActivityTracking getActivityTracking() const { return _activityTracking; }
- // TODO: expose to script?
- ParabolaToEntityIntersectionResult findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking,
- const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly);
+ RayToEntityIntersectionResult evalRayIntersectionVector(const PickRay& ray, PickFilter searchFilter,
+ const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard);
+ ParabolaToEntityIntersectionResult evalParabolaIntersectionVector(const PickParabola& parabola, PickFilter searchFilter,
+ const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard);
/**jsdoc
* Get the properties of multiple entities.
@@ -394,9 +393,8 @@ public slots:
Q_INVOKABLE void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method,
const QStringList& params = QStringList());
-
/**jsdoc
- * Find the entity with a position closest to a specified point and within a specified radius.
+ * Find the non-local entity with a position closest to a specified point and within a specified radius.
* @function Entities.findClosestEntity
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
@@ -410,7 +408,7 @@ public slots:
Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const;
/**jsdoc
- * Find all entities that intersect a sphere defined by a center point and radius.
+ * Find all non-local entities that intersect a sphere defined by a center point and radius.
* @function Entities.findEntities
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
@@ -424,23 +422,23 @@ public slots:
Q_INVOKABLE QVector findEntities(const glm::vec3& center, float radius) const;
/**jsdoc
- * Find all entities whose axis-aligned boxes intersect a search axis-aligned box defined by its minimum coordinates corner
+ * Find all non-local entities whose axis-aligned boxes intersect a search axis-aligned box defined by its minimum coordinates corner
* and dimensions.
* @function Entities.findEntitiesInBox
* @param {Vec3} corner - The corner of the search AA box with minimum co-ordinate values.
* @param {Vec3} dimensions - The dimensions of the search AA box.
- * @returns {Uuid[]} An array of entity IDs whose AA boxes intersect the search AA box. The array is empty if no entities
+ * @returns {Uuid[]} An array of entity IDs whose AA boxes intersect the search AA box. The array is empty if no entities
* could be found.
*/
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
/**jsdoc
- * Find all entities whose axis-aligned boxes intersect a search frustum.
+ * Find all non-local entities whose axis-aligned boxes intersect a search frustum.
* @function Entities.findEntitiesInFrustum
* @param {ViewFrustum} frustum - The frustum to search in. The position, orientation,
* projection, and centerRadius properties must be specified.
- * @returns {Uuid[]} An array of entity IDs axis-aligned boxes intersect the frustum. The array is empty if no entities
+ * @returns {Uuid[]} An array of entity IDs axis-aligned boxes intersect the frustum. The array is empty if no entities
* could be found.
* @example
Report the number of entities in view.
* var entityIDs = Entities.findEntitiesInFrustum(Camera.frustum);
@@ -450,12 +448,12 @@ public slots:
Q_INVOKABLE QVector findEntitiesInFrustum(QVariantMap frustum) const;
/**jsdoc
- * Find all entities of a particular type that intersect a sphere defined by a center point and radius.
+ * Find all non-local entities of a particular type that intersect a sphere defined by a center point and radius.
* @function Entities.findEntitiesByType
* @param {Entities.EntityType} entityType - The type of entity to search for.
* @param {Vec3} center - The point about which to search.
* @param {number} radius - The radius within which to search.
- * @returns {Uuid[]} An array of entity IDs of the specified type that intersect the search sphere. The array is empty if
+ * @returns {Uuid[]} An array of entity IDs of the specified type that intersect the search sphere. The array is empty if
* no entities could be found.
* @example
Report the number of Model entities within 10m of your avatar.
* var entityIDs = Entities.findEntitiesByType("Model", MyAvatar.position, 10);
@@ -465,7 +463,7 @@ public slots:
Q_INVOKABLE QVector findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const;
/**jsdoc
- * Find all entities of a particular name that intersect a sphere defined by a center point and radius.
+ * Find all non-local entities with a particular name that intersect a sphere defined by a center point and radius.
* @function Entities.findEntitiesByName
* @param {string} entityName - The name of the entity to search for.
* @param {Vec3} center - The point about which to search.
@@ -475,13 +473,13 @@ public slots:
* if no entities could be found.
* @example
Report the number of entities with the name, "Light-Target".
* var entityIDs = Entities.findEntitiesByName("Light-Target", MyAvatar.position, 10, false);
- * print("Number of entities with the name "Light-Target": " + entityIDs.length);
+ * print("Number of entities with the name Light-Target: " + entityIDs.length);
*/
- Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius,
- bool caseSensitiveSearch = false ) const;
+ Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius,
+ bool caseSensitiveSearch = false) const;
/**jsdoc
- * Find the first entity intersected by a {@link PickRay}. Light and Zone entities are not
+ * Find the first non-local entity intersected by a {@link PickRay}. Light and Zone entities are not
* intersected unless they've been configured as pickable using {@link Entities.setLightsArePickable|setLightsArePickable}
* and {@link Entities.setZonesArePickable|setZonesArePickable}, respectively.
* @function Entities.findRayIntersection
@@ -512,33 +510,8 @@ public slots:
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
/// will be false.
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false,
- const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue(),
- bool visibleOnly = false, bool collidableOnly = false);
-
- /// Same as above but with QVectors
- RayToEntityIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
- const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly);
-
- /**jsdoc
- * Find the first entity intersected by a {@link PickRay}. Light and Zone entities are not
- * intersected unless they've been configured as pickable using {@link Entities.setLightsArePickable|setLightsArePickable}
- * and {@link Entities.setZonesArePickable|setZonesArePickable}, respectively.
- * This is a synonym for {@link Entities.findRayIntersection|findRayIntersection}.
- * @function Entities.findRayIntersectionBlocking
- * @param {PickRay} pickRay - The PickRay to use for finding entities.
- * @param {boolean} [precisionPicking=false] - If true and the intersected entity is a Model
- * entity, the result's extraInfo property includes more information than it otherwise would.
- * @param {Uuid[]} [entitiesToInclude=[]] - If not empty then the search is restricted to these entities.
- * @param {Uuid[]} [entitiesToDiscard=[]] - Entities to ignore during the search.
- * @deprecated This function is deprecated and will soon be removed. Use
- * {@link Entities.findRayIntersection|findRayIntersection} instead; it blocks and performs the same function.
- */
- /// If the scripting context has visible entities, this will determine a ray intersection, and will block in
- /// order to return an accurate result
- Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false,
- const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue());
-
+ const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue(),
+ bool visibleOnly = false, bool collidableOnly = false) const;
/**jsdoc
* Reloads an entity's server entity script such that the latest version re-downloaded.
@@ -603,9 +576,7 @@ public slots:
/**jsdoc
* Set whether or not ray picks intersect the bounding box of {@link Entities.EntityType|Light} entities. By default, Light
* entities are not intersected. The setting lasts for the Interface session. Ray picks are done using
- * {@link Entities.findRayIntersection|findRayIntersection} or
- * {@link Entities.findRayIntersectionBlocking|findRayIntersectionBlocking}, or the {@link Picks} and {@link RayPick}
- * APIs.
+ * {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.setLightsArePickable
* @param {boolean} value - Set true to make ray picks intersect the bounding box of
* {@link Entities.EntityType|Light} entities, otherwise false.
@@ -615,9 +586,7 @@ public slots:
/**jsdoc
* Get whether or not ray picks intersect the bounding box of {@link Entities.EntityType|Light} entities. Ray picks are
- * done using {@link Entities.findRayIntersection|findRayIntersection} or
- * {@link Entities.findRayIntersectionBlocking|findRayIntersectionBlocking}, or the {@link Picks} and {@link RayPick}
- * APIs.
+ * done using {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.getLightsArePickable
* @returns {boolean} true if ray picks intersect the bounding box of {@link Entities.EntityType|Light}
* entities, otherwise false.
@@ -628,9 +597,7 @@ public slots:
/**jsdoc
* Set whether or not ray picks intersect the bounding box of {@link Entities.EntityType|Zone} entities. By default, Light
* entities are not intersected. The setting lasts for the Interface session. Ray picks are done using
- * {@link Entities.findRayIntersection|findRayIntersection} or
- * {@link Entities.findRayIntersectionBlocking|findRayIntersectionBlocking}, or the {@link Picks} and {@link RayPick}
- * APIs.
+ * {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.setZonesArePickable
* @param {boolean} value - Set true to make ray picks intersect the bounding box of
* {@link Entities.EntityType|Zone} entities, otherwise false.
@@ -640,9 +607,7 @@ public slots:
/**jsdoc
* Get whether or not ray picks intersect the bounding box of {@link Entities.EntityType|Zone} entities. Ray picks are
- * done using {@link Entities.findRayIntersection|findRayIntersection} or
- * {@link Entities.findRayIntersectionBlocking|findRayIntersectionBlocking}, or the {@link Picks} and {@link RayPick}
- * APIs.
+ * done using {@link Entities.findRayIntersection|findRayIntersection}, or the {@link Picks} API.
* @function Entities.getZonesArePickable
* @returns {boolean} true if ray picks intersect the bounding box of {@link Entities.EntityType|Zone}
* entities, otherwise false.
@@ -2100,14 +2065,12 @@ private:
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
- RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
- bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly = false, bool collidableOnly = false);
+ RayToEntityIntersectionResult evalRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
+ PickFilter searchFilter, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard) const;
/// actually does the work of finding the parabola intersection, can be called in locking mode or tryLock mode
- ParabolaToEntityIntersectionResult findParabolaIntersectionWorker(const PickParabola& parabola, Octree::lockType lockType,
- bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly = false, bool collidableOnly = false);
+ ParabolaToEntityIntersectionResult evalParabolaIntersectionWorker(const PickParabola& parabola, Octree::lockType lockType,
+ PickFilter searchFilter, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard) const;
EntityTreePointer _entityTree;
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 98fcdc1db1..954462a9f2 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -43,50 +43,6 @@
static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50;
const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour
-// combines the ray cast arguments into a single object
-class RayArgs {
-public:
- // Inputs
- glm::vec3 origin;
- glm::vec3 direction;
- glm::vec3 invDirection;
- const QVector& entityIdsToInclude;
- const QVector& entityIdsToDiscard;
- bool visibleOnly;
- bool collidableOnly;
- bool precisionPicking;
-
- // Outputs
- OctreeElementPointer& element;
- float& distance;
- BoxFace& face;
- glm::vec3& surfaceNormal;
- QVariantMap& extraInfo;
- EntityItemID entityID;
-};
-
-class ParabolaArgs {
-public:
- // Inputs
- glm::vec3 origin;
- glm::vec3 velocity;
- glm::vec3 acceleration;
- const QVector& entityIdsToInclude;
- const QVector& entityIdsToDiscard;
- bool visibleOnly;
- bool collidableOnly;
- bool precisionPicking;
-
- // Outputs
- OctreeElementPointer& element;
- float& parabolicDistance;
- BoxFace& face;
- glm::vec3& surfaceNormal;
- QVariantMap& extraInfo;
- EntityItemID entityID;
-};
-
-
EntityTree::EntityTree(bool shouldReaverage) :
Octree(shouldReaverage)
{
@@ -816,59 +772,32 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
}
}
-
-class FindNearPointArgs {
+class RayArgs {
public:
- glm::vec3 position;
- float targetRadius;
- bool found;
- EntityItemPointer closestEntity;
- float closestEntityDistance;
+ // Inputs
+ glm::vec3 origin;
+ glm::vec3 direction;
+ glm::vec3 invDirection;
+ const QVector& entityIdsToInclude;
+ const QVector& entityIdsToDiscard;
+ PickFilter searchFilter;
+
+ // Outputs
+ OctreeElementPointer& element;
+ float& distance;
+ BoxFace& face;
+ glm::vec3& surfaceNormal;
+ QVariantMap& extraInfo;
+ EntityItemID entityID;
};
-
-bool EntityTree::findNearPointOperation(const OctreeElementPointer& element, void* extraData) {
- FindNearPointArgs* args = static_cast(extraData);
- EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
-
- glm::vec3 penetration;
- bool sphereIntersection = entityTreeElement->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
-
- // If this entityTreeElement contains the point, then search it...
- if (sphereIntersection) {
- EntityItemPointer thisClosestEntity = entityTreeElement->getClosestEntity(args->position);
-
- // we may have gotten NULL back, meaning no entity was available
- if (thisClosestEntity) {
- glm::vec3 entityPosition = thisClosestEntity->getWorldPosition();
- float distanceFromPointToEntity = glm::distance(entityPosition, args->position);
-
- // If we're within our target radius
- if (distanceFromPointToEntity <= args->targetRadius) {
- // we are closer than anything else we've found
- if (distanceFromPointToEntity < args->closestEntityDistance) {
- args->closestEntity = thisClosestEntity;
- args->closestEntityDistance = distanceFromPointToEntity;
- args->found = true;
- }
- }
- }
-
- // we should be able to optimize this...
- return true; // keep searching in case children have closer entities
- }
-
- // if this element doesn't contain the point, then none of its children can contain the point, so stop searching
- return false;
-}
-
-bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData) {
+bool evalRayIntersectionOp(const OctreeElementPointer& element, void* extraData) {
RayArgs* args = static_cast(extraData);
bool keepSearching = true;
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
- EntityItemID entityID = entityTreeElementPointer->findRayIntersection(args->origin, args->direction,
+ EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction,
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
- args->entityIdsToDiscard, args->visibleOnly, args->collidableOnly, args->extraInfo, args->precisionPicking);
+ args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
if (!entityID.isNull()) {
args->entityID = entityID;
// We recurse OctreeElements in order, so if we hit something, we can stop immediately
@@ -877,7 +806,7 @@ bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData)
return keepSearching;
}
-float findRayIntersectionSortingOp(const OctreeElementPointer& element, void* extraData) {
+float evalRayIntersectionSortingOp(const OctreeElementPointer& element, void* extraData) {
RayArgs* args = static_cast(extraData);
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
float distance = FLT_MAX;
@@ -898,19 +827,18 @@ float findRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex
return distance;
}
-EntityItemID EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+EntityItemID EntityTree::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
QVector entityIdsToInclude, QVector entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, bool precisionPicking,
- OctreeElementPointer& element, float& distance,
+ PickFilter searchFilter, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
Octree::lockType lockType, bool* accurateResult) {
RayArgs args = { origin, direction, 1.0f / direction, entityIdsToInclude, entityIdsToDiscard,
- visibleOnly, collidableOnly, precisionPicking, element, distance, face, surfaceNormal, extraInfo, EntityItemID() };
+ searchFilter, element, distance, face, surfaceNormal, extraInfo, EntityItemID() };
distance = FLT_MAX;
bool requireLock = lockType == Octree::Lock;
bool lockResult = withReadLock([&]{
- recurseTreeWithOperationSorted(findRayIntersectionOp, findRayIntersectionSortingOp, &args);
+ recurseTreeWithOperationSorted(evalRayIntersectionOp, evalRayIntersectionSortingOp, &args);
}, requireLock);
if (accurateResult) {
@@ -920,13 +848,32 @@ EntityItemID EntityTree::findRayIntersection(const glm::vec3& origin, const glm:
return args.entityID;
}
-bool findParabolaIntersectionOp(const OctreeElementPointer& element, void* extraData) {
+class ParabolaArgs {
+public:
+ // Inputs
+ glm::vec3 origin;
+ glm::vec3 velocity;
+ glm::vec3 acceleration;
+ const QVector& entityIdsToInclude;
+ const QVector& entityIdsToDiscard;
+ PickFilter searchFilter;
+
+ // Outputs
+ OctreeElementPointer& element;
+ float& parabolicDistance;
+ BoxFace& face;
+ glm::vec3& surfaceNormal;
+ QVariantMap& extraInfo;
+ EntityItemID entityID;
+};
+
+bool evalParabolaIntersectionOp(const OctreeElementPointer& element, void* extraData) {
ParabolaArgs* args = static_cast(extraData);
bool keepSearching = true;
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
- EntityItemID entityID = entityTreeElementPointer->findParabolaIntersection(args->origin, args->velocity, args->acceleration,
+ EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration,
args->element, args->parabolicDistance, args->face, args->surfaceNormal, args->entityIdsToInclude,
- args->entityIdsToDiscard, args->visibleOnly, args->collidableOnly, args->extraInfo, args->precisionPicking);
+ args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
if (!entityID.isNull()) {
args->entityID = entityID;
// We recurse OctreeElements in order, so if we hit something, we can stop immediately
@@ -935,7 +882,7 @@ bool findParabolaIntersectionOp(const OctreeElementPointer& element, void* extra
return keepSearching;
}
-float findParabolaIntersectionSortingOp(const OctreeElementPointer& element, void* extraData) {
+float evalParabolaIntersectionSortingOp(const OctreeElementPointer& element, void* extraData) {
ParabolaArgs* args = static_cast(extraData);
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
float distance = FLT_MAX;
@@ -956,20 +903,20 @@ float findParabolaIntersectionSortingOp(const OctreeElementPointer& element, voi
return distance;
}
-EntityItemID EntityTree::findParabolaIntersection(const PickParabola& parabola,
+EntityItemID EntityTree::evalParabolaIntersection(const PickParabola& parabola,
QVector entityIdsToInclude, QVector entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, bool precisionPicking,
+ PickFilter searchFilter,
OctreeElementPointer& element, glm::vec3& intersection, float& distance, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
Octree::lockType lockType, bool* accurateResult) {
ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, entityIdsToInclude, entityIdsToDiscard,
- visibleOnly, collidableOnly, precisionPicking, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
+ searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
parabolicDistance = FLT_MAX;
distance = FLT_MAX;
bool requireLock = lockType == Octree::Lock;
bool lockResult = withReadLock([&] {
- recurseTreeWithOperationSorted(findParabolaIntersectionOp, findParabolaIntersectionSortingOp, &args);
+ recurseTreeWithOperationSorted(evalParabolaIntersectionOp, evalParabolaIntersectionSortingOp, &args);
}, requireLock);
if (accurateResult) {
@@ -984,33 +931,80 @@ EntityItemID EntityTree::findParabolaIntersection(const PickParabola& parabola,
return args.entityID;
}
-
-EntityItemPointer EntityTree::findClosestEntity(const glm::vec3& position, float targetRadius) {
- FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
- withReadLock([&] {
- // NOTE: This should use recursion, since this is a spatial operation
- recurseTreeWithOperation(findNearPointOperation, &args);
- });
- return args.closestEntity;
-}
-
-class FindAllNearPointArgs {
+class FindClosestEntityArgs {
public:
+ // Inputs
glm::vec3 position;
float targetRadius;
- QVector entities;
+ PickFilter searchFilter;
+
+ // Outputs
+ QUuid closestEntity;
+ float closestEntityDistance;
};
-bool EntityTree::findInSphereOperation(const OctreeElementPointer& element, void* extraData) {
- FindAllNearPointArgs* args = static_cast(extraData);
+bool evalClosestEntityOperation(const OctreeElementPointer& element, void* extraData) {
+ FindClosestEntityArgs* args = static_cast(extraData);
+ EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
+
+ glm::vec3 penetration;
+ bool sphereIntersection = entityTreeElement->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
+
+ // If this entityTreeElement contains the point, then search it...
+ if (sphereIntersection) {
+ float closestDistanceSquared = FLT_MAX;
+ QUuid thisClosestEntity = entityTreeElement->evalClosetEntity(args->position, args->searchFilter, closestDistanceSquared);
+
+ // we may have gotten NULL back, meaning no entity was available
+ if (!thisClosestEntity.isNull()) {
+ float distanceFromPointToEntity = glm::sqrt(closestDistanceSquared);
+
+ // If we're within our target radius
+ if (distanceFromPointToEntity <= args->targetRadius) {
+ // we are closer than anything else we've found
+ if (distanceFromPointToEntity < args->closestEntityDistance) {
+ args->closestEntity = thisClosestEntity;
+ args->closestEntityDistance = distanceFromPointToEntity;
+ }
+ }
+ }
+
+ // we should be able to optimize this...
+ return true; // keep searching in case children have closer entities
+ }
+
+ // if this element doesn't contain the point, then none of its children can contain the point, so stop searching
+ return false;
+}
+
+// NOTE: assumes caller has handled locking
+QUuid EntityTree::evalClosestEntity(const glm::vec3& position, float targetRadius, PickFilter searchFilter) {
+ FindClosestEntityArgs args = { position, targetRadius, searchFilter, QUuid(), FLT_MAX };
+ recurseTreeWithOperation(evalClosestEntityOperation, &args);
+ return args.closestEntity;
+}
+
+class FindEntitiesInSphereArgs {
+public:
+ // Inputs
+ glm::vec3 position;
+ float targetRadius;
+ PickFilter searchFilter;
+
+ // Outputs
+ QVector entities;
+};
+
+bool evalInSphereOperation(const OctreeElementPointer& element, void* extraData) {
+ FindEntitiesInSphereArgs* args = static_cast(extraData);
glm::vec3 penetration;
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
// If this element contains the point, then search it...
if (sphereIntersection) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
- entityTreeElement->getEntities(args->position, args->targetRadius, args->entities);
+ entityTreeElement->evalEntitiesInSphere(args->position, args->targetRadius, args->searchFilter, args->entities);
return true; // keep searching in case children have closer entities
}
@@ -1019,102 +1013,166 @@ bool EntityTree::findInSphereOperation(const OctreeElementPointer& element, void
}
// NOTE: assumes caller has handled locking
-void EntityTree::findEntities(const glm::vec3& center, float radius, QVector& foundEntities) {
- FindAllNearPointArgs args = { center, radius, QVector() };
- // NOTE: This should use recursion, since this is a spatial operation
- recurseTreeWithOperation(findInSphereOperation, &args);
+void EntityTree::evalEntitiesInSphere(const glm::vec3& center, float radius, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInSphereArgs args = { center, radius, searchFilter, QVector() };
+ recurseTreeWithOperation(evalInSphereOperation, &args);
+ foundEntities.swap(args.entities);
+}
- // swap the two lists of entity pointers instead of copy
+class FindEntitiesInSphereWithTypeArgs {
+public:
+ // Inputs
+ glm::vec3 position;
+ float targetRadius;
+ EntityTypes::EntityType type;
+ PickFilter searchFilter;
+
+ // Outputs
+ QVector entities;
+};
+
+bool evalInSphereWithTypeOperation(const OctreeElementPointer& element, void* extraData) {
+ FindEntitiesInSphereWithTypeArgs* args = static_cast(extraData);
+ glm::vec3 penetration;
+ bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
+
+ // If this element contains the point, then search it...
+ if (sphereIntersection) {
+ EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
+ entityTreeElement->evalEntitiesInSphereWithType(args->position, args->targetRadius, args->type, args->searchFilter, args->entities);
+ return true; // keep searching in case children have closer entities
+ }
+
+ // if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
+ return false;
+}
+
+// NOTE: assumes caller has handled locking
+void EntityTree::evalEntitiesInSphereWithType(const glm::vec3& center, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInSphereWithTypeArgs args = { center, radius, type, searchFilter, QVector() };
+ recurseTreeWithOperation(evalInSphereWithTypeOperation, &args);
+ foundEntities.swap(args.entities);
+}
+
+class FindEntitiesInSphereWithNameArgs {
+public:
+ // Inputs
+ glm::vec3 position;
+ float targetRadius;
+ QString name;
+ bool caseSensitive;
+ PickFilter searchFilter;
+
+ // Outputs
+ QVector entities;
+};
+
+bool evalInSphereWithNameOperation(const OctreeElementPointer& element, void* extraData) {
+ FindEntitiesInSphereWithNameArgs* args = static_cast(extraData);
+ glm::vec3 penetration;
+ bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
+
+ // If this element contains the point, then search it...
+ if (sphereIntersection) {
+ EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
+ entityTreeElement->evalEntitiesInSphereWithName(args->position, args->targetRadius, args->name, args->caseSensitive, args->searchFilter, args->entities);
+ return true; // keep searching in case children have closer entities
+ }
+
+ // if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
+ return false;
+}
+
+// NOTE: assumes caller has handled locking
+void EntityTree::evalEntitiesInSphereWithName(const glm::vec3& center, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInSphereWithNameArgs args = { center, radius, name, caseSensitive, searchFilter, QVector() };
+ recurseTreeWithOperation(evalInSphereWithNameOperation, &args);
foundEntities.swap(args.entities);
}
class FindEntitiesInCubeArgs {
public:
- FindEntitiesInCubeArgs(const AACube& cube)
- : _cube(cube), _foundEntities() {
- }
+ // Inputs
+ AACube cube;
+ PickFilter searchFilter;
- AACube _cube;
- QVector _foundEntities;
+ // Outputs
+ QVector entities;
};
-bool EntityTree::findInCubeOperation(const OctreeElementPointer& element, void* extraData) {
+bool findInCubeOperation(const OctreeElementPointer& element, void* extraData) {
FindEntitiesInCubeArgs* args = static_cast(extraData);
- if (element->getAACube().touches(args->_cube)) {
+ if (element->getAACube().touches(args->cube)) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
- entityTreeElement->getEntities(args->_cube, args->_foundEntities);
+ entityTreeElement->evalEntitiesInCube(args->cube, args->searchFilter, args->entities);
return true;
}
return false;
}
// NOTE: assumes caller has handled locking
-void EntityTree::findEntities(const AACube& cube, QVector& foundEntities) {
- FindEntitiesInCubeArgs args(cube);
- // NOTE: This should use recursion, since this is a spatial operation
+void EntityTree::evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInCubeArgs args { cube, searchFilter, QVector() };
recurseTreeWithOperation(findInCubeOperation, &args);
- // swap the two lists of entity pointers instead of copy
- foundEntities.swap(args._foundEntities);
+ foundEntities.swap(args.entities);
}
class FindEntitiesInBoxArgs {
public:
- FindEntitiesInBoxArgs(const AABox& box)
- : _box(box), _foundEntities() {
- }
+ // Inputs
+ AABox box;
+ PickFilter searchFilter;
- AABox _box;
- QVector _foundEntities;
+ // Outputs
+ QVector entities;
};
-bool EntityTree::findInBoxOperation(const OctreeElementPointer& element, void* extraData) {
+bool findInBoxOperation(const OctreeElementPointer& element, void* extraData) {
FindEntitiesInBoxArgs* args = static_cast(extraData);
- if (element->getAACube().touches(args->_box)) {
+ if (element->getAACube().touches(args->box)) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
- entityTreeElement->getEntities(args->_box, args->_foundEntities);
+ entityTreeElement->evalEntitiesInBox(args->box, args->searchFilter, args->entities);
return true;
}
return false;
}
// NOTE: assumes caller has handled locking
-void EntityTree::findEntities(const AABox& box, QVector& foundEntities) {
- FindEntitiesInBoxArgs args(box);
+void EntityTree::evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInBoxArgs args { box, searchFilter, QVector() };
// NOTE: This should use recursion, since this is a spatial operation
recurseTreeWithOperation(findInBoxOperation, &args);
// swap the two lists of entity pointers instead of copy
- foundEntities.swap(args._foundEntities);
-}
-
-class FindInFrustumArgs {
-public:
- ViewFrustum frustum;
- QVector entities;
-};
-
-bool EntityTree::findInFrustumOperation(const OctreeElementPointer& element, void* extraData) {
- FindInFrustumArgs* args = static_cast(extraData);
- if (element->isInView(args->frustum)) {
- EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
- entityTreeElement->getEntities(args->frustum, args->entities);
- return true;
- }
- return false;
-}
-
-// NOTE: assumes caller has handled locking
-void EntityTree::findEntities(const ViewFrustum& frustum, QVector& foundEntities) {
- FindInFrustumArgs args = { frustum, QVector() };
- // NOTE: This should use recursion, since this is a spatial operation
- recurseTreeWithOperation(findInFrustumOperation, &args);
- // swap the two lists of entity pointers instead of copy
foundEntities.swap(args.entities);
}
+class FindEntitiesInFrustumArgs {
+public:
+ // Inputs
+ ViewFrustum frustum;
+ PickFilter searchFilter;
+
+ // Outputs
+ QVector entities;
+};
+
+bool findInFrustumOperation(const OctreeElementPointer& element, void* extraData) {
+ FindEntitiesInFrustumArgs* args = static_cast(extraData);
+ if (element->isInView(args->frustum)) {
+ EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element);
+ entityTreeElement->evalEntitiesInFrustum(args->frustum, args->searchFilter, args->entities);
+ return true;
+ }
+ return false;
+}
+
// NOTE: assumes caller has handled locking
-void EntityTree::findEntities(RecurseOctreeOperation& elementFilter,
- QVector& foundEntities) {
- recurseTreeWithOperation(elementFilter, nullptr);
+void EntityTree::evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector& foundEntities) {
+ FindEntitiesInFrustumArgs args = { frustum, searchFilter, QVector() };
+ // NOTE: This should use recursion, since this is a spatial operation
+ recurseTreeWithOperation(findInFrustumOperation, &args);
+ // swap the two lists of entity pointers instead of copy
+ foundEntities.swap(args.entities);
}
EntityItemPointer EntityTree::findEntityByID(const QUuid& id) const {
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 46c45714aa..f9b7b8d67f 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -45,7 +45,6 @@ public:
QHash* map;
};
-
class EntityTree : public Octree, public SpatialParentTree {
Q_OBJECT
public:
@@ -94,18 +93,16 @@ public:
virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override;
- virtual EntityItemID findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
QVector entityIdsToInclude, QVector entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, bool precisionPicking,
- OctreeElementPointer& element, float& distance,
+ PickFilter searchFilter, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
- virtual EntityItemID findParabolaIntersection(const PickParabola& parabola,
+ virtual EntityItemID evalParabolaIntersection(const PickParabola& parabola,
QVector entityIdsToInclude, QVector entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, bool precisionPicking,
- OctreeElementPointer& element, glm::vec3& intersection, float& distance, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
+ PickFilter searchFilter, OctreeElementPointer& element, glm::vec3& intersection,
+ float& distance, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
virtual bool rootElementHasData() const override { return true; }
@@ -130,44 +127,19 @@ public:
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true);
void deleteEntities(QSet entityIDs, bool force = false, bool ignoreWarnings = true);
- /// \param position point of query in world-frame (meters)
- /// \param targetRadius radius of query (meters)
- EntityItemPointer findClosestEntity(const glm::vec3& position, float targetRadius);
EntityItemPointer findEntityByID(const QUuid& id) const;
EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID) const;
virtual SpatiallyNestablePointer findByID(const QUuid& id) const override { return findEntityByID(id); }
EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID
-
- /// finds all entities that touch a sphere
- /// \param center the center of the sphere in world-frame (meters)
- /// \param radius the radius of the sphere in world-frame (meters)
- /// \param foundEntities[out] vector of EntityItemPointer
- /// \remark Side effect: any initial contents in foundEntities will be lost
- void findEntities(const glm::vec3& center, float radius, QVector& foundEntities);
-
- /// finds all entities that touch a cube
- /// \param cube the query cube in world-frame (meters)
- /// \param foundEntities[out] vector of non-EntityItemPointer
- /// \remark Side effect: any initial contents in entities will be lost
- void findEntities(const AACube& cube, QVector& foundEntities);
-
- /// finds all entities that touch a box
- /// \param box the query box in world-frame (meters)
- /// \param foundEntities[out] vector of non-EntityItemPointer
- /// \remark Side effect: any initial contents in entities will be lost
- void findEntities(const AABox& box, QVector& foundEntities);
-
- /// finds all entities within a frustum
- /// \parameter frustum the query frustum
- /// \param foundEntities[out] vector of EntityItemPointer
- void findEntities(const ViewFrustum& frustum, QVector& foundEntities);
-
- /// finds all entities that match scanOperator
- /// \parameter scanOperator function that scans entities that match criteria
- /// \parameter foundEntities[out] vector of EntityItemPointer
- void findEntities(RecurseOctreeOperation& scanOperator, QVector& foundEntities);
+ QUuid evalClosestEntity(const glm::vec3& position, float targetRadius, PickFilter searchFilter);
+ void evalEntitiesInSphere(const glm::vec3& center, float radius, PickFilter searchFilter, QVector& foundEntities);
+ void evalEntitiesInSphereWithType(const glm::vec3& center, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities);
+ void evalEntitiesInSphereWithName(const glm::vec3& center, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities);
+ void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities);
+ void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities);
+ void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector& foundEntities);
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
@@ -327,11 +299,6 @@ protected:
void processRemovedEntities(const DeleteEntityOperator& theOperator);
bool updateEntity(EntityItemPointer entity, const EntityItemProperties& properties,
const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
- static bool findNearPointOperation(const OctreeElementPointer& element, void* extraData);
- static bool findInSphereOperation(const OctreeElementPointer& element, void* extraData);
- static bool findInCubeOperation(const OctreeElementPointer& element, void* extraData);
- static bool findInBoxOperation(const OctreeElementPointer& element, void* extraData);
- static bool findInFrustumOperation(const OctreeElementPointer& element, void* extraData);
static bool sendEntitiesOperation(const OctreeElementPointer& element, void* extraData);
static void bumpTimestamp(EntityItemProperties& properties);
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index b6fdea4e0d..3b085457d1 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -139,10 +139,23 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3
return false;
}
-EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
- const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) {
+bool checkFilterSettings(const EntityItemPointer& entity, PickFilter searchFilter) {
+ bool visible = entity->isVisible();
+ bool collidable = !entity->getCollisionless() && (entity->getShapeType() != SHAPE_TYPE_NONE);
+ if ((!searchFilter.doesPickVisible() && visible) || (!searchFilter.doesPickInvisible() && !visible) ||
+ (!searchFilter.doesPickCollidable() && collidable) || (!searchFilter.doesPickNonCollidable() && !collidable) ||
+ (!searchFilter.doesPickDomainEntities() && entity->isDomainEntity()) ||
+ (!searchFilter.doesPickAvatarEntities() && entity->isAvatarEntity()) ||
+ (!searchFilter.doesPickLocalEntities() && entity->isLocalEntity())) {
+ return false;
+ }
+ return true;
+}
+
+EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
+ const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
+ PickFilter searchFilter, QVariantMap& extraInfo) {
EntityItemID result;
BoxFace localFace { UNKNOWN_FACE };
@@ -154,9 +167,8 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con
QVariantMap localExtraInfo;
float distanceToElementDetails = distance;
- EntityItemID entityID = findDetailedRayIntersection(origin, direction, element, distanceToElementDetails,
- localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly,
- localExtraInfo, precisionPicking);
+ EntityItemID entityID = evalDetailedRayIntersection(origin, direction, element, distanceToElementDetails,
+ localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
if (!entityID.isNull() && distanceToElementDetails < distance) {
distance = distanceToElementDetails;
face = localFace;
@@ -167,13 +179,12 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con
return result;
}
-EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard,
- bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) {
+ PickFilter searchFilter, QVariantMap& extraInfo) {
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
- int entityNumber = 0;
EntityItemID entityID;
forEachEntity([&](EntityItemPointer entity) {
if (entity->getIgnorePickIntersection()) {
@@ -191,11 +202,9 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori
return;
}
- // check RayPick filter settings
- if ((visibleOnly && !entity->isVisible())
- || (collidableOnly && (entity->getCollisionless() || entity->getShapeType() == SHAPE_TYPE_NONE))
- || (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID()))
- || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) {
+ if (!checkFilterSettings(entity, searchFilter) ||
+ (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) ||
+ (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) {
return;
}
@@ -226,7 +235,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori
if (entity->supportsDetailedIntersection()) {
QVariantMap localExtraInfo;
if (entity->findDetailedRayIntersection(origin, direction, element, localDistance,
- localFace, localSurfaceNormal, localExtraInfo, precisionPicking)) {
+ localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
if (localDistance < distance) {
distance = localDistance;
face = localFace;
@@ -248,7 +257,6 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori
}
}
}
- entityNumber++;
});
return entityID;
}
@@ -279,11 +287,10 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
return result;
}
-EntityItemID EntityTreeElement::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
+EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly,
- QVariantMap& extraInfo, bool precisionPicking) {
+ const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo) {
EntityItemID result;
BoxFace localFace;
@@ -304,9 +311,8 @@ EntityItemID EntityTreeElement::findParabolaIntersection(const glm::vec3& origin
}
// Get the normal of the plane, the cross product of two vectors on the plane
glm::vec3 normal = glm::normalize(glm::cross(vectorOnPlane, acceleration));
- EntityItemID entityID = findDetailedParabolaIntersection(origin, velocity, acceleration, normal, element, distanceToElementDetails,
- localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, visibleOnly, collidableOnly,
- localExtraInfo, precisionPicking);
+ EntityItemID entityID = evalDetailedParabolaIntersection(origin, velocity, acceleration, normal, element, distanceToElementDetails,
+ localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
if (!entityID.isNull() && distanceToElementDetails < parabolicDistance) {
parabolicDistance = distanceToElementDetails;
face = localFace;
@@ -317,13 +323,12 @@ EntityItemID EntityTreeElement::findParabolaIntersection(const glm::vec3& origin
return result;
}
-EntityItemID EntityTreeElement::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
+EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
const glm::vec3& normal, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard,
- bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) {
+ PickFilter searchFilter, QVariantMap& extraInfo) {
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
- int entityNumber = 0;
EntityItemID entityID;
forEachEntity([&](EntityItemPointer entity) {
if (entity->getIgnorePickIntersection()) {
@@ -346,11 +351,9 @@ EntityItemID EntityTreeElement::findDetailedParabolaIntersection(const glm::vec3
return;
}
- // check RayPick filter settings
- if ((visibleOnly && !entity->isVisible())
- || (collidableOnly && (entity->getCollisionless() || entity->getShapeType() == SHAPE_TYPE_NONE))
- || (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID()))
- || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) {
+ if (!checkFilterSettings(entity, searchFilter) ||
+ (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) ||
+ (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID()))) {
return;
}
@@ -382,7 +385,7 @@ EntityItemID EntityTreeElement::findDetailedParabolaIntersection(const glm::vec3
if (entity->supportsDetailedIntersection()) {
QVariantMap localExtraInfo;
if (entity->findDetailedParabolaIntersection(origin, velocity, acceleration, element, localDistance,
- localFace, localSurfaceNormal, localExtraInfo, precisionPicking)) {
+ localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
if (localDistance < parabolicDistance) {
parabolicDistance = localDistance;
face = localFace;
@@ -404,55 +407,56 @@ EntityItemID EntityTreeElement::findDetailedParabolaIntersection(const glm::vec3
}
}
}
- entityNumber++;
});
return entityID;
}
-EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const {
- EntityItemPointer closestEntity = NULL;
- float closestEntityDistance = FLT_MAX;
- withReadLock([&] {
- foreach(EntityItemPointer entity, _entityItems) {
- float distanceToEntity = glm::distance2(position, entity->getWorldPosition());
- if (distanceToEntity < closestEntityDistance) {
- closestEntity = entity;
- }
+QUuid EntityTreeElement::evalClosetEntity(const glm::vec3& position, PickFilter searchFilter, float& closestDistanceSquared) const {
+ QUuid closestEntity;
+ forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
+
+ float distanceToEntity = glm::distance2(position, entity->getWorldPosition());
+ if (distanceToEntity < closestDistanceSquared) {
+ closestEntity = entity->getID();
+ closestDistanceSquared = distanceToEntity;
}
});
return closestEntity;
}
-// TODO: change this to use better bounding shape for entity than sphere
-void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector& foundEntities) const {
+void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float radius, PickFilter searchFilter, QVector& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
bool success;
AABox entityBox = entity->getAABox(success);
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
glm::vec3 penetration;
- if (!success || entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
+ if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
glm::vec3 dimensions = entity->getRaycastDimensions();
// FIXME - consider allowing the entity to determine penetration so that
- // entities could presumably dull actuall hull testing if they wanted to
+ // entities could presumably do actual hull testing if they wanted to
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular
// can we handle the ellipsoid case better? We only currently handle perfect spheres
// with centered registration points
- if (entity->getShapeType() == SHAPE_TYPE_SPHERE &&
- (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
+ if (entity->getShapeType() == SHAPE_TYPE_SPHERE && (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
// NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
// maximum bounding sphere, which is actually larger than our actual radius
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
- if (findSphereSpherePenetration(searchPosition, searchRadius,
- entity->getCenterPosition(success), entityTrueRadius, penetration)) {
+ if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
if (success) {
- foundEntities.push_back(entity);
+ foundEntities.push_back(entity->getID());
}
}
} else {
@@ -468,17 +472,134 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
AABox entityFrameBox(corner, dimensions);
- glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(searchPosition, 1.0f));
- if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, searchRadius, penetration)) {
- foundEntities.push_back(entity);
+ glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(position, 1.0f));
+ if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, radius, penetration)) {
+ foundEntities.push_back(entity->getID());
}
}
}
});
}
-void EntityTreeElement::getEntities(const AACube& cube, QVector& foundEntities) {
+void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter) || type != entity->getType()) {
+ return;
+ }
+
+ bool success;
+ AABox entityBox = entity->getAABox(success);
+
+ // if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
+ glm::vec3 penetration;
+ if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
+
+ glm::vec3 dimensions = entity->getRaycastDimensions();
+
+ // FIXME - consider allowing the entity to determine penetration so that
+ // entities could presumably do actual hull testing if they wanted to
+ // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular
+ // can we handle the ellipsoid case better? We only currently handle perfect spheres
+ // with centered registration points
+ if (entity->getShapeType() == SHAPE_TYPE_SPHERE && (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
+
+ // NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
+ // maximum bounding sphere, which is actually larger than our actual radius
+ float entityTrueRadius = dimensions.x / 2.0f;
+
+ bool success;
+ if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
+ if (success) {
+ foundEntities.push_back(entity->getID());
+ }
+ }
+ } else {
+ // determine the worldToEntityMatrix that doesn't include scale because
+ // we're going to use the registration aware aa box in the entity frame
+ glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
+ glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::mat4 entityToWorldMatrix = translation * rotation;
+ glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
+
+ glm::vec3 registrationPoint = entity->getRegistrationPoint();
+ glm::vec3 corner = -(dimensions * registrationPoint);
+
+ AABox entityFrameBox(corner, dimensions);
+
+ glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(position, 1.0f));
+ if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, radius, penetration)) {
+ foundEntities.push_back(entity->getID());
+ }
+ }
+ }
+ });
+}
+
+void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) const {
+ forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
+
+ QString entityName = entity->getName();
+ if ((caseSensitive && name != entityName) || (!caseSensitive && name.toLower() != entityName.toLower())) {
+ return;
+ }
+
+ bool success;
+ AABox entityBox = entity->getAABox(success);
+
+ // if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
+ glm::vec3 penetration;
+ if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
+
+ glm::vec3 dimensions = entity->getRaycastDimensions();
+
+ // FIXME - consider allowing the entity to determine penetration so that
+ // entities could presumably do actual hull testing if they wanted to
+ // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular
+ // can we handle the ellipsoid case better? We only currently handle perfect spheres
+ // with centered registration points
+ if (entity->getShapeType() == SHAPE_TYPE_SPHERE && (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
+
+ // NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
+ // maximum bounding sphere, which is actually larger than our actual radius
+ float entityTrueRadius = dimensions.x / 2.0f;
+
+ bool success;
+ if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
+ if (success) {
+ foundEntities.push_back(entity->getID());
+ }
+ }
+ } else {
+ // determine the worldToEntityMatrix that doesn't include scale because
+ // we're going to use the registration aware aa box in the entity frame
+ glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
+ glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::mat4 entityToWorldMatrix = translation * rotation;
+ glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
+
+ glm::vec3 registrationPoint = entity->getRegistrationPoint();
+ glm::vec3 corner = -(dimensions * registrationPoint);
+
+ AABox entityFrameBox(corner, dimensions);
+
+ glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(position, 1.0f));
+ if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, radius, penetration)) {
+ foundEntities.push_back(entity->getID());
+ }
+ }
+ }
+ });
+}
+
+void EntityTreeElement::evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities) const {
+ forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
+
bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
@@ -497,14 +618,18 @@ void EntityTreeElement::getEntities(const AACube& cube, QVectorgetID());
}
});
}
-void EntityTreeElement::getEntities(const AABox& box, QVector& foundEntities) {
+void EntityTreeElement::evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
+
bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
@@ -523,19 +648,24 @@ void EntityTreeElement::getEntities(const AABox& box, QVector
//
// If the entities AABox touches the search cube then consider it to be found
- if (!success || entityBox.touches(box)) {
- foundEntities.push_back(entity);
+ if (success && entityBox.touches(box)) {
+ foundEntities.push_back(entity->getID());
}
});
}
-void EntityTreeElement::getEntities(const ViewFrustum& frustum, QVector& foundEntities) {
+void EntityTreeElement::evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector& foundEntities) const {
forEachEntity([&](EntityItemPointer entity) {
+ if (!checkFilterSettings(entity, searchFilter)) {
+ return;
+ }
+
bool success;
AABox entityBox = entity->getAABox(success);
+
// FIXME - See FIXMEs for similar methods above.
- if (!success || frustum.boxIntersectsFrustum(entityBox) || frustum.boxIntersectsKeyhole(entityBox)) {
- foundEntities.push_back(entity);
+ if (success && (frustum.boxIntersectsFrustum(entityBox) || frustum.boxIntersectsKeyhole(entityBox))) {
+ foundEntities.push_back(entity->getID());
}
});
}
diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h
index c65a4ebe05..3f1fda57bd 100644
--- a/libraries/entities/src/EntityTreeElement.h
+++ b/libraries/entities/src/EntityTreeElement.h
@@ -19,7 +19,8 @@
#include "EntityEditPacketSender.h"
#include "EntityItem.h"
-#include "EntityTree.h"
+
+#include
class EntityTree;
class EntityTreeElement;
@@ -77,7 +78,6 @@ public:
EntityEditPacketSender* packetSender;
};
-
class EntityTreeElement : public OctreeElement, ReadWriteLockable {
friend class EntityTree; // to allow createElement to new us...
@@ -135,28 +135,25 @@ public:
virtual bool deleteApproved() const override { return !hasEntities(); }
virtual bool canPickIntersect() const override { return hasEntities(); }
- virtual EntityItemID findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
- bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking = false);
- virtual EntityItemID findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ PickFilter searchFilter, QVariantMap& extraInfo);
+ virtual EntityItemID evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly,
- QVariantMap& extraInfo, bool precisionPicking);
+ const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const override;
- virtual EntityItemID findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
+ virtual EntityItemID evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly,
- QVariantMap& extraInfo, bool precisionPicking = false);
- virtual EntityItemID findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
+ const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
+ virtual EntityItemID evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& normal, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
- const QVector& entityIdsToDiscard, bool visibleOnly, bool collidableOnly,
- QVariantMap& extraInfo, bool precisionPicking);
+ const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
template
void forEachEntity(F f) const {
@@ -175,28 +172,13 @@ public:
void addEntityItem(EntityItemPointer entity);
- EntityItemPointer getClosestEntity(glm::vec3 position) const;
-
- /// finds all entities that touch a sphere
- /// \param position the center of the query sphere
- /// \param radius the radius of the query sphere
- /// \param entities[out] vector of const EntityItemPointer
- void getEntities(const glm::vec3& position, float radius, QVector& foundEntities) const;
-
- /// finds all entities that touch a box
- /// \param box the query box
- /// \param entities[out] vector of non-const EntityItemPointer
- void getEntities(const AACube& cube, QVector& foundEntities);
-
- /// finds all entities that touch a box
- /// \param box the query box
- /// \param entities[out] vector of non-const EntityItemPointer
- void getEntities(const AABox& box, QVector& foundEntities);
-
- /// finds all entities that touch a frustum
- /// \param frustum the query frustum
- /// \param entities[out] vector of non-const EntityItemPointer
- void getEntities(const ViewFrustum& frustum, QVector& foundEntities);
+ QUuid evalClosetEntity(const glm::vec3& position, PickFilter searchFilter, float& closestDistanceSquared) const;
+ void evalEntitiesInSphere(const glm::vec3& position, float radius, PickFilter searchFilter, QVector& foundEntities) const;
+ void evalEntitiesInSphereWithType(const glm::vec3& position, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities) const;
+ void evalEntitiesInSphereWithName(const glm::vec3& position, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) const;
+ void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities) const;
+ void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities) const;
+ void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector