add workload job to help debug entity proxies

This commit is contained in:
Andrew Meadows 2019-11-11 16:50:59 -08:00
parent 5f2f647dfb
commit cf08a4162a
12 changed files with 275 additions and 6 deletions

View file

@ -87,6 +87,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 +284,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

View file

@ -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);
}

View file

@ -26,7 +26,7 @@ class GameplayObjects {
public:
GameplayObjects();
bool getContainsData() const { return containsData; }
bool getContainsData() const { return _containsData; }
std::vector<QUuid> 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<QUuid> _avatarIDs;
std::vector<EntityItemID> _entityIDs;
};

View file

@ -9,6 +9,7 @@
//
#include "GameWorkload.h"
#include "GameWorkloadRenderer.h"
#include "SelectedWorkloadRenderer.h"
#include <ViewFrustum.h>
#include <workload/RegionTracker.h>
#include <workload/SpaceClassifier.h>
@ -35,6 +36,7 @@ public:
model.addJob<PhysicsBoundary>("PhysicsBoundary", regionTrackerOut);
model.addJob<GameSpaceToRender>("SpaceToRender");
model.addJob<SelectedWorkloadRenderer>("SelectedWorkloadRender");
out = regionTrackerOut;
}

View file

@ -16,6 +16,7 @@
#include <GeometryCache.h>
#include <shaders/Shaders.h>
#include "SelectedWorkloadRenderer.h"
void GameSpaceToRender::configure(const Config& config) {
_freezeViews = config.freezeViews;

View file

@ -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 <cstring>
#include <gpu/Context.h>
#include <workload/Space.h>
#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<GameWorkloadContext>(runContext);
if (!gameWorkloadContext) {
return;
}
auto space = gameWorkloadContext->_space;
if (!space) {
return;
}
render::Transaction transaction;
auto scene = gameWorkloadContext->_scene;
auto selection = DependencyManager::get<SelectionScriptingInterface>();
// 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<GameWorkloadRenderItem>(_spaceRenderItemID, [](GameWorkloadRenderItem& item) {
item.setVisible(false);
});
scene->enqueueTransaction(transaction);
}
return;
}
std::vector<EntityItemID> 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<GameWorkloadRenderItem>();
renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
transaction.resetItem(_spaceRenderItemID, std::make_shared<GameWorkloadRenderItem::Payload>(renderItem));
}
bool showProxies = true;
bool showViews = false;
bool visible = true;
workload::Views views(0);
transaction.updateItem<GameWorkloadRenderItem>(_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);
}

View file

@ -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, Outputs, Config>;
SelectedWorkloadRenderer() {}
void configure(const Config& config) {}
void run(const workload::WorkloadContextPointer& renderContext, Outputs& outputs);
protected:
render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID };
};
#endif

View file

@ -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;
}

View file

@ -10,6 +10,7 @@
#define hifi_PickFilter_h
#include <bitset>
#include <iostream> // 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<NUM_FLAGS> 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;

View file

@ -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<std::mutex> 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<std::mutex> lock(_proxiesMutex);
if (isAllocatedID(proxyID) && (proxyID < (Index)_proxies.size())) {

View file

@ -47,6 +47,7 @@ public:
void categorizeAndGetChanges(std::vector<Change>& 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;

View file

@ -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);
}());