diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h
index e26b91b9a2..11d77d9b49 100644
--- a/interface/src/raypick/PickScriptingInterface.h
+++ b/interface/src/raypick/PickScriptingInterface.h
@@ -52,6 +52,9 @@
* Read-only.
*
Warning: Not yet implemented.
*
+ * @property {FilterFlags} PICK_BYPASS_IGNORE - Allows pick to intersect entities even when their ignorePickIntersection property is 'true'.
+ * For debug purposes. Read-only.
+ *
* @property {IntersectionType} INTERSECTED_NONE - Intersected nothing. Read-only.
* @property {IntersectionType} INTERSECTED_ENTITY - Intersected an entity. Read-only.
* @property {IntersectionType} INTERSECTED_LOCAL_ENTITY - Intersected a local entity. Read-only.
@@ -87,6 +90,8 @@ class PickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT)
+ Q_PROPERTY(unsigned int PICK_BYPASS_IGNORE READ PICK_BYPASS_IGNORE 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_LOCAL_ENTITY READ INTERSECTED_LOCAL_ENTITY CONSTANT)
@@ -282,6 +287,8 @@ public:
unsigned int getPerFrameTimeBudget() const;
void setPerFrameTimeBudget(unsigned int numUsecs);
+ static constexpr unsigned int PICK_BYPASS_IGNORE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_BYPASS_IGNORE); }
+
public slots:
/**jsdoc
diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp
index d2147ac5cc..32f837668d 100644
--- a/interface/src/scripting/SelectionScriptingInterface.cpp
+++ b/interface/src/scripting/SelectionScriptingInterface.cpp
@@ -17,7 +17,7 @@ GameplayObjects::GameplayObjects() {
}
bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) {
- containsData = true;
+ _containsData = true;
if (std::find(_avatarIDs.begin(), _avatarIDs.end(), avatarID) == _avatarIDs.end()) {
_avatarIDs.push_back(avatarID);
}
@@ -29,7 +29,7 @@ bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) {
}
bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) {
- containsData = true;
+ _containsData = true;
if (std::find(_entityIDs.begin(), _entityIDs.end(), entityID) == _entityIDs.end()) {
_entityIDs.push_back(entityID);
}
diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h
index 4386ee5ee6..f477a25b42 100644
--- a/interface/src/scripting/SelectionScriptingInterface.h
+++ b/interface/src/scripting/SelectionScriptingInterface.h
@@ -26,7 +26,7 @@ class GameplayObjects {
public:
GameplayObjects();
- bool getContainsData() const { return containsData; }
+ bool getContainsData() const { return _containsData; }
std::vector getAvatarIDs() const { return _avatarIDs; }
bool addToGameplayObjects(const QUuid& avatarID);
@@ -37,7 +37,7 @@ public:
bool removeFromGameplayObjects(const EntityItemID& entityID);
private:
- bool containsData { false };
+ bool _containsData { false };
std::vector _avatarIDs;
std::vector _entityIDs;
};
diff --git a/interface/src/workload/GameWorkload.cpp b/interface/src/workload/GameWorkload.cpp
index afbd166c89..d9cda7f16a 100644
--- a/interface/src/workload/GameWorkload.cpp
+++ b/interface/src/workload/GameWorkload.cpp
@@ -9,6 +9,7 @@
//
#include "GameWorkload.h"
#include "GameWorkloadRenderer.h"
+#include "SelectedWorkloadRenderer.h"
#include
#include
#include
@@ -35,6 +36,7 @@ public:
model.addJob("PhysicsBoundary", regionTrackerOut);
model.addJob("SpaceToRender");
+ model.addJob("SelectedWorkloadRender");
out = regionTrackerOut;
}
diff --git a/interface/src/workload/GameWorkloadRenderer.cpp b/interface/src/workload/GameWorkloadRenderer.cpp
index 2bb73999f1..f65bf88754 100644
--- a/interface/src/workload/GameWorkloadRenderer.cpp
+++ b/interface/src/workload/GameWorkloadRenderer.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include "SelectedWorkloadRenderer.h"
void GameSpaceToRender::configure(const Config& config) {
_freezeViews = config.freezeViews;
diff --git a/interface/src/workload/SelectedWorkloadRenderer.cpp b/interface/src/workload/SelectedWorkloadRenderer.cpp
new file mode 100644
index 0000000000..29cdc46f35
--- /dev/null
+++ b/interface/src/workload/SelectedWorkloadRenderer.cpp
@@ -0,0 +1,88 @@
+//
+// SelectedWorkloadRenderer.cpp
+//
+// Created by Andrew Meadows 2019.11.08
+// Copyright 2019 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 "SelectedWorkloadRenderer.h"
+
+#include
+#include
+
+#include
+
+#include "Application.h"
+#include "GameWorkloadRenderer.h"
+#include "scripting/SelectionScriptingInterface.h"
+
+void SelectedWorkloadRenderer::run(const workload::WorkloadContextPointer& runContext, Outputs& outputs) {
+ auto gameWorkloadContext = std::dynamic_pointer_cast(runContext);
+ if (!gameWorkloadContext) {
+ return;
+ }
+ auto space = gameWorkloadContext->_space;
+ if (!space) {
+ return;
+ }
+
+ render::Transaction transaction;
+ auto scene = gameWorkloadContext->_scene;
+
+ auto selection = DependencyManager::get();
+ // Note: the "DebugWorkloadSelection" name is a secret hard-coded C++ debug feature.
+ // If you create such a named list using JS and the "Selection" API then it will be picked up here
+ // and the workload proxies for corresponding entities will be rendered.
+ GameplayObjects selectedObjects = selection->getList("DebugWorkloadSelection");
+
+ if (!selectedObjects.getContainsData()) {
+ // nothing to render
+ // clear item if it exists and bail
+ if (render::Item::isValidID(_spaceRenderItemID)) {
+ transaction.updateItem(_spaceRenderItemID, [](GameWorkloadRenderItem& item) {
+ item.setVisible(false);
+ });
+ scene->enqueueTransaction(transaction);
+ }
+ return;
+ }
+
+ std::vector entityIDs = selectedObjects.getEntityIDs();
+ workload::indexed_container::Indices indices;
+ indices.reserve(entityIDs.size());
+
+ auto entityTreeRenderer = qApp->getEntities();
+ auto entityTree = entityTreeRenderer->getTree();
+ for (auto id : entityIDs) {
+ EntityItemPointer entity = entityTree->findEntityByID(id);
+ if (entity) {
+ indices.push_back(entity->getSpaceIndex());
+ }
+ }
+
+ workload::Proxy::Vector proxies;
+ proxies.reserve(indices.size());
+ space->copySelectedProxyValues(proxies, indices);
+
+ if (!render::Item::isValidID(_spaceRenderItemID)) {
+ _spaceRenderItemID = scene->allocateID();
+ auto renderItem = std::make_shared();
+ renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
+ transaction.resetItem(_spaceRenderItemID, std::make_shared(renderItem));
+ }
+
+ bool showProxies = true;
+ bool showViews = false;
+ bool visible = true;
+ workload::Views views(0);
+ transaction.updateItem(_spaceRenderItemID, [visible, showProxies, proxies, showViews, views](GameWorkloadRenderItem& item) {
+ item.setVisible(visible);
+ item.showProxies(showProxies);
+ item.setAllProxies(proxies);
+ item.showViews(showViews);
+ item.setAllViews(views);
+ });
+ scene->enqueueTransaction(transaction);
+}
diff --git a/interface/src/workload/SelectedWorkloadRenderer.h b/interface/src/workload/SelectedWorkloadRenderer.h
new file mode 100644
index 0000000000..9b3ac1005e
--- /dev/null
+++ b/interface/src/workload/SelectedWorkloadRenderer.h
@@ -0,0 +1,32 @@
+//
+// GameWorkloadRender.h
+//
+// Created by Sam Gateau on 2/20/2018.
+// Copyright 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
+//
+#ifndef hifi_SelectedWorkloadRenderer_h
+#define hifi_SelectedWorkloadRenderer_h
+
+#include "GameWorkload.h"
+
+#include "GameWorkloadRenderer.h"
+
+class SelectedWorkloadRenderer {
+public:
+ using Config = GameSpaceToRenderConfig;
+ using Outputs = render::Transaction;
+ using JobModel = workload::Job::ModelO;
+
+ SelectedWorkloadRenderer() {}
+
+ void configure(const Config& config) {}
+ void run(const workload::WorkloadContextPointer& renderContext, Outputs& outputs);
+
+protected:
+ render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID };
+};
+
+#endif
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index 0096319081..9af0bbfdb6 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -197,7 +197,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
EntityItemID entityID;
forEachEntity([&](EntityItemPointer entity) {
- if (entity->getIgnorePickIntersection()) {
+ if (entity->getIgnorePickIntersection() && !searchFilter.bypassIgnore()) {
return;
}
@@ -341,7 +341,7 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
EntityItemID entityID;
forEachEntity([&](EntityItemPointer entity) {
- if (entity->getIgnorePickIntersection()) {
+ if (entity->getIgnorePickIntersection() && !searchFilter.bypassIgnore()) {
return;
}
diff --git a/libraries/shared/src/PickFilter.h b/libraries/shared/src/PickFilter.h
index 5e5f5db3bc..d3d6673f50 100644
--- a/libraries/shared/src/PickFilter.h
+++ b/libraries/shared/src/PickFilter.h
@@ -10,6 +10,7 @@
#define hifi_PickFilter_h
#include
+#include // adebug
class PickFilter {
public:
@@ -60,6 +61,8 @@ public:
// NOT YET IMPLEMENTED
PICK_ALL_INTERSECTIONS, // if not set, returns closest intersection, otherwise, returns list of all intersections
+ PICK_BYPASS_IGNORE, // for debug purposes
+
NUM_FLAGS, // Not a valid flag
};
typedef std::bitset Flags;
@@ -93,6 +96,8 @@ public:
bool doesWantAllIntersections() const { return _flags[PICK_ALL_INTERSECTIONS]; }
+ bool bypassIgnore() const { return _flags[PICK_BYPASS_IGNORE]; }
+
// Helpers for RayPickManager
Flags getEntityFlags() const {
unsigned int toReturn = 0;
diff --git a/libraries/workload/src/workload/Space.cpp b/libraries/workload/src/workload/Space.cpp
index f045c8311f..5704ba8c4d 100644
--- a/libraries/workload/src/workload/Space.cpp
+++ b/libraries/workload/src/workload/Space.cpp
@@ -127,6 +127,18 @@ uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const {
return numCopied;
}
+uint32_t Space::copySelectedProxyValues(Proxy::Vector& proxies, const workload::indexed_container::Indices& indices) const {
+ std::unique_lock lock(_proxiesMutex);
+ uint32_t numCopied = 0;
+ for (auto index : indices) {
+ if (isAllocatedID(index) && (index < (Index)_proxies.size())) {
+ proxies.push_back(_proxies[index]);
+ ++numCopied;
+ }
+ }
+ return numCopied;
+}
+
const Owner Space::getOwner(int32_t proxyID) const {
std::unique_lock lock(_proxiesMutex);
if (isAllocatedID(proxyID) && (proxyID < (Index)_proxies.size())) {
diff --git a/libraries/workload/src/workload/Space.h b/libraries/workload/src/workload/Space.h
index 7dcb2217f7..d189d48156 100644
--- a/libraries/workload/src/workload/Space.h
+++ b/libraries/workload/src/workload/Space.h
@@ -47,6 +47,7 @@ public:
void categorizeAndGetChanges(std::vector& changes);
uint32_t copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const;
+ uint32_t copySelectedProxyValues(Proxy::Vector& proxies, const workload::indexed_container::Indices& indices) const;
const Owner getOwner(int32_t proxyID) const;
uint8_t getRegion(int32_t proxyID) const;
diff --git a/scripts/developer/debugging/debugWorkloadWithMouseHover.js b/scripts/developer/debugging/debugWorkloadWithMouseHover.js
new file mode 100644
index 0000000000..eaff607359
--- /dev/null
+++ b/scripts/developer/debugging/debugWorkloadWithMouseHover.js
@@ -0,0 +1,124 @@
+//
+// debugWorkloadWithMouseHover.js - render workload proxy for entity under mouse hover
+//
+// Copyright 2019 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
+//
+
+"use strict";
+
+(function() {
+
+ Script.scriptEnding.connect(function () {
+ });
+
+ // Create a Laser pointer used to pick and add entity to selection
+ var END_DIMENSIONS = { x: 0.05, y: 0.05, z: 0.05 };
+ var COLOR1 = {red: 255, green: 0, blue: 255}; // magenta
+ var COLOR2 = {red: 255, green: 255, blue: 0}; // yellow
+ var end1 = {
+ type: "sphere",
+ dimensions: END_DIMENSIONS,
+ color: COLOR1,
+ ignorePickIntersection: true
+ }
+ var end2 = {
+ type: "sphere",
+ dimensions: END_DIMENSIONS,
+ color: COLOR2,
+ ignorePickIntersection: true
+ }
+ var laser = Pointers.createPointer(PickType.Ray, {
+ joint: "Mouse",
+ filter: Picks.PICK_ENTITIES | Picks.PICK_BYPASS_IGNORE | Picks.PICK_INCLUDE_COLLIDABLE | Picks.PICK_INCLUDE_NONCOLLIDABLE,
+ renderStates: [{name: "one", end: end1}],
+ defaultRenderStates: [{name: "one", end: end2, distance: 2.0}],
+ enabled: true
+ });
+ Pointers.setRenderState(laser, "one");
+ var hoveredObject = undefined;
+
+ var SelectionListName = "DebugWorkloadSelection"; // sekret undocumented selection list (hard coded in C++)
+ var selectionStyle = {
+ isOutlineSmooth: true,
+ outlineWidth: 5,
+ outlineUnoccludedColor: {red: 255, green: 128, blue: 128},
+ outlineUnoccludedAlpha: 0.88,
+ outlineOccludedColor: {red: 255, green: 128, blue: 128},
+ outlineOccludedAlpha:0.5,
+ fillUnoccludedColor: {red: 26, green: 0, blue: 0},
+ fillUnoccludedAlpha: 0.0,
+ fillOccludedColor: {red: 26, green: 0, blue: 0},
+ fillOccludedAlpha: 0.0
+ }
+ Selection.enableListHighlight(SelectionListName, selectionStyle)
+
+ var isSelectionEnabled = false
+
+ function setSelectionEnabled(enabled) {
+ if (isSelectionEnabled != enabled) {
+ isSelectionEnabled = enabled;
+ //print("isSelectionEnabled set to " + isSelectionEnabled.toString())
+ if (isSelectionEnabled) {
+ Pointers.enablePointer(laser)
+ } else {
+ Pointers.disablePointer(laser)
+ Selection.clearSelectedItemsList(SelectionListName)
+ }
+ }
+ }
+ setSelectionEnabled(true);
+
+ function getIntersectionTypeString(type) {
+ if (type === Picks.INTERSECTED_ENTITY) {
+ return "entity";
+ } else if (type === Picks.INTERSECTED_OVERLAY) {
+ return "overlay";
+ } else if (type === Picks.INTERSECTED_AVATAR) {
+ return "avatar";
+ }
+ }
+
+ function update() {
+ var result = Pointers.getPrevPickResult(laser);
+ if (result.intersects) {
+ if (hoveredObject !== undefined && result.objectID !== hoveredObject.objectID) {
+ // Hovering on something different
+ if (isSelectionEnabled) {
+ Selection.removeFromSelectedItemsList(SelectionListName, getIntersectionTypeString(hoveredObject.type), hoveredObject.objectID)
+ //print("remove helloDebugHighlight " + hoveredObject.objectID.toString());
+ }
+ }
+
+ if (isSelectionEnabled) {
+ if (hoveredObject === undefined || result.objectID !== hoveredObject.objectID) {
+ // Hovering over something new
+ Selection.addToSelectedItemsList(SelectionListName, getIntersectionTypeString(result.type), result.objectID);
+ hoveredObject = result;
+ //print("add helloDebugHighlight " + hoveredObject.objectID.toString() + " type = '" + getIntersectionTypeString(result.type) + "'");
+ }
+ }
+ } else if (hoveredObject !== undefined) {
+ // Stopped hovering
+ if (isSelectionEnabled) {
+ Selection.removeFromSelectedItemsList(SelectionListName, getIntersectionTypeString(hoveredObject.type), hoveredObject.objectID)
+ hoveredObject = undefined;
+ //print("clear helloDebugHighlight");
+ }
+ }
+ }
+ Script.update.connect(update);
+
+ function cleanup() {
+ Pointers.removePointer(laser);
+ Selection.disableListHighlight(SelectionListName)
+ Selection.removeListFromMap(SelectionListName)
+
+ }
+ Script.scriptEnding.connect(cleanup);
+
+}());
+
+