Merge pull request #11952 from samcake/light

Exposing multi highlight and selection feature to js api
This commit is contained in:
Sam Gateau 2017-12-12 01:09:15 +07:00 committed by GitHub
commit 0ff91e5926
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1200 additions and 519 deletions

View file

@ -18,7 +18,9 @@ GameplayObjects::GameplayObjects() {
bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) {
containsData = true;
_avatarIDs.push_back(avatarID);
if (std::find(_avatarIDs.begin(), _avatarIDs.end(), avatarID) == _avatarIDs.end()) {
_avatarIDs.push_back(avatarID);
}
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) {
@ -28,7 +30,9 @@ bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) {
bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) {
containsData = true;
_entityIDs.push_back(entityID);
if (std::find(_entityIDs.begin(), _entityIDs.end(), entityID) == _entityIDs.end()) {
_entityIDs.push_back(entityID);
}
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) {
@ -38,7 +42,9 @@ bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) {
bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) {
containsData = true;
_overlayIDs.push_back(overlayID);
if (std::find(_overlayIDs.begin(), _overlayIDs.end(), overlayID) == _overlayIDs.end()) {
_overlayIDs.push_back(overlayID);
}
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) {
@ -72,28 +78,125 @@ bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& lis
}
bool SelectionScriptingInterface::clearSelectedItemsList(const QString& listName) {
_selectedItemsListMap.insert(listName, GameplayObjects());
emit selectedItemsListChanged(listName);
{
QWriteLocker lock(&_selectionListsLock);
_selectedItemsListMap.insert(listName, GameplayObjects());
}
onSelectedItemsListChanged(listName);
return true;
}
QStringList SelectionScriptingInterface::getListNames() const {
QStringList list;
QReadLocker lock(&_selectionListsLock);
list = _selectedItemsListMap.keys();
return list;
}
QStringList SelectionScriptingInterface::getHighlightedListNames() const {
QStringList list;
QReadLocker lock(&_highlightStylesLock);
list = _highlightStyleMap.keys();
return list;
}
bool SelectionScriptingInterface::enableListHighlight(const QString& listName, const QVariantMap& highlightStyleValues) {
QWriteLocker lock(&_highlightStylesLock);
auto highlightStyle = _highlightStyleMap.find(listName);
if (highlightStyle == _highlightStyleMap.end()) {
highlightStyle = _highlightStyleMap.insert(listName, SelectionHighlightStyle());
}
if (!(*highlightStyle).isBoundToList()) {
setupHandler(listName);
(*highlightStyle).setBoundToList(true);
}
(*highlightStyle).fromVariantMap(highlightStyleValues);
auto mainScene = qApp->getMain3DScene();
if (mainScene) {
render::Transaction transaction;
transaction.resetSelectionHighlight(listName.toStdString(), (*highlightStyle).getStyle());
mainScene->enqueueTransaction(transaction);
}
else {
qWarning() << "SelectionToSceneHandler::highlightStyleChanged(), Unexpected null scene, possibly during application shutdown";
}
return true;
}
bool SelectionScriptingInterface::disableListHighlight(const QString& listName) {
QWriteLocker lock(&_highlightStylesLock);
auto highlightStyle = _highlightStyleMap.find(listName);
if (highlightStyle != _highlightStyleMap.end()) {
if ((*highlightStyle).isBoundToList()) {
}
_highlightStyleMap.erase(highlightStyle);
auto mainScene = qApp->getMain3DScene();
if (mainScene) {
render::Transaction transaction;
transaction.removeHighlightFromSelection(listName.toStdString());
mainScene->enqueueTransaction(transaction);
}
else {
qWarning() << "SelectionToSceneHandler::highlightStyleChanged(), Unexpected null scene, possibly during application shutdown";
}
}
return true;
}
QVariantMap SelectionScriptingInterface::getListHighlightStyle(const QString& listName) const {
QReadLocker lock(&_highlightStylesLock);
auto highlightStyle = _highlightStyleMap.find(listName);
if (highlightStyle == _highlightStyleMap.end()) {
return QVariantMap();
} else {
return (*highlightStyle).toVariantMap();
}
}
render::HighlightStyle SelectionScriptingInterface::getHighlightStyle(const QString& listName) const {
QReadLocker lock(&_highlightStylesLock);
auto highlightStyle = _highlightStyleMap.find(listName);
if (highlightStyle == _highlightStyleMap.end()) {
return render::HighlightStyle();
} else {
return (*highlightStyle).getStyle();
}
}
template <class T> bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
currentList.addToGameplayObjects(idToAdd);
_selectedItemsListMap.insert(listName, currentList);
emit selectedItemsListChanged(listName);
{
QWriteLocker lock(&_selectionListsLock);
GameplayObjects currentList = _selectedItemsListMap.value(listName);
currentList.addToGameplayObjects(idToAdd);
_selectedItemsListMap.insert(listName, currentList);
}
onSelectedItemsListChanged(listName);
return true;
}
template <class T> bool SelectionScriptingInterface::removeFromGameplayObjects(const QString& listName, T idToRemove) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
if (currentList.getContainsData()) {
currentList.removeFromGameplayObjects(idToRemove);
_selectedItemsListMap.insert(listName, currentList);
emit selectedItemsListChanged(listName);
bool listExist = false;
{
QWriteLocker lock(&_selectionListsLock);
auto currentList = _selectedItemsListMap.find(listName);
if (currentList != _selectedItemsListMap.end()) {
listExist = true;
(*currentList).removeFromGameplayObjects(idToRemove);
}
}
if (listExist) {
onSelectedItemsListChanged(listName);
return true;
} else {
}
else {
return false;
}
}
@ -102,50 +205,123 @@ template <class T> bool SelectionScriptingInterface::removeFromGameplayObjects(c
//
GameplayObjects SelectionScriptingInterface::getList(const QString& listName) {
QReadLocker lock(&_selectionListsLock);
return _selectedItemsListMap.value(listName);
}
void SelectionScriptingInterface::printList(const QString& listName) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
if (currentList.getContainsData()) {
QReadLocker lock(&_selectionListsLock);
auto currentList = _selectedItemsListMap.find(listName);
if (currentList != _selectedItemsListMap.end()) {
if ((*currentList).getContainsData()) {
qDebug() << "Avatar IDs:";
for (auto i : currentList.getAvatarIDs()) {
qDebug() << i << ';';
}
qDebug() << "";
qDebug() << "List named " << listName << ":";
qDebug() << "Avatar IDs:";
for (auto i : (*currentList).getAvatarIDs()) {
qDebug() << i << ';';
}
qDebug() << "";
qDebug() << "Entity IDs:";
for (auto j : currentList.getEntityIDs()) {
qDebug() << j << ';';
}
qDebug() << "";
qDebug() << "Entity IDs:";
for (auto j : (*currentList).getEntityIDs()) {
qDebug() << j << ';';
}
qDebug() << "";
qDebug() << "Overlay IDs:";
for (auto k : currentList.getOverlayIDs()) {
qDebug() << k << ';';
qDebug() << "Overlay IDs:";
for (auto k : (*currentList).getOverlayIDs()) {
qDebug() << k << ';';
}
qDebug() << "";
}
else {
qDebug() << "List named " << listName << " empty";
}
qDebug() << "";
} else {
qDebug() << "List named" << listName << "doesn't exist.";
qDebug() << "List named " << listName << " doesn't exist.";
}
}
QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& listName) const {
QReadLocker lock(&_selectionListsLock);
QVariantMap list;
auto currentList = _selectedItemsListMap.find(listName);
if (currentList != _selectedItemsListMap.end()) {
QList<QVariant> avatarIDs;
QList<QVariant> entityIDs;
QList<QVariant> overlayIDs;
if ((*currentList).getContainsData()) {
if (!(*currentList).getAvatarIDs().empty()) {
for (auto j : (*currentList).getAvatarIDs()) {
avatarIDs.push_back((QUuid)j);
}
}
if (!(*currentList).getEntityIDs().empty()) {
for (auto j : (*currentList).getEntityIDs()) {
entityIDs.push_back((QUuid)j );
}
}
if (!(*currentList).getOverlayIDs().empty()) {
for (auto j : (*currentList).getOverlayIDs()) {
overlayIDs.push_back((QUuid)j);
}
}
}
list["avatars"] = (avatarIDs);
list["entities"] = (entityIDs);
list["overlays"] = (overlayIDs);
return list;
}
else {
return list;
}
}
bool SelectionScriptingInterface::removeListFromMap(const QString& listName) {
if (_selectedItemsListMap.remove(listName)) {
emit selectedItemsListChanged(listName);
bool removed = false;
{
QWriteLocker lock(&_selectionListsLock);
removed = _selectedItemsListMap.remove(listName);
}
if (removed) {
onSelectedItemsListChanged(listName);
return true;
} else {
return false;
}
}
void SelectionScriptingInterface::setupHandler(const QString& selectionName) {
QWriteLocker lock(&_selectionHandlersLock);
auto handler = _handlerMap.find(selectionName);
if (handler == _handlerMap.end()) {
handler = _handlerMap.insert(selectionName, new SelectionToSceneHandler());
}
(*handler)->initialize(selectionName);
}
void SelectionScriptingInterface::onSelectedItemsListChanged(const QString& listName) {
{
QWriteLocker lock(&_selectionHandlersLock);
auto handler = _handlerMap.find(listName);
if (handler != _handlerMap.end()) {
(*handler)->updateSceneFromSelectedList();
}
}
emit selectedItemsListChanged(listName);
}
SelectionToSceneHandler::SelectionToSceneHandler() {
}
void SelectionToSceneHandler::initialize(const QString& listName) {
_listName = listName;
updateSceneFromSelectedList();
}
void SelectionToSceneHandler::selectedItemsListChanged(const QString& listName) {
@ -199,3 +375,85 @@ void SelectionToSceneHandler::updateSceneFromSelectedList() {
qWarning() << "SelectionToSceneHandler::updateRendererSelectedList(), Unexpected null scene, possibly during application shutdown";
}
}
bool SelectionHighlightStyle::fromVariantMap(const QVariantMap& properties) {
auto colorVariant = properties["outlineUnoccludedColor"];
if (colorVariant.isValid()) {
bool isValid;
auto color = xColorFromVariant(colorVariant, isValid);
if (isValid) {
_style._outlineUnoccluded.color = toGlm(color);
}
}
colorVariant = properties["outlineOccludedColor"];
if (colorVariant.isValid()) {
bool isValid;
auto color = xColorFromVariant(colorVariant, isValid);
if (isValid) {
_style._outlineOccluded.color = toGlm(color);
}
}
colorVariant = properties["fillUnoccludedColor"];
if (colorVariant.isValid()) {
bool isValid;
auto color = xColorFromVariant(colorVariant, isValid);
if (isValid) {
_style._fillUnoccluded.color = toGlm(color);
}
}
colorVariant = properties["fillOccludedColor"];
if (colorVariant.isValid()) {
bool isValid;
auto color = xColorFromVariant(colorVariant, isValid);
if (isValid) {
_style._fillOccluded.color = toGlm(color);
}
}
auto intensityVariant = properties["outlineUnoccludedAlpha"];
if (intensityVariant.isValid()) {
_style._outlineUnoccluded.alpha = intensityVariant.toFloat();
}
intensityVariant = properties["outlineOccludedAlpha"];
if (intensityVariant.isValid()) {
_style._outlineOccluded.alpha = intensityVariant.toFloat();
}
intensityVariant = properties["fillUnoccludedAlpha"];
if (intensityVariant.isValid()) {
_style._fillUnoccluded.alpha = intensityVariant.toFloat();
}
intensityVariant = properties["fillOccludedAlpha"];
if (intensityVariant.isValid()) {
_style._fillOccluded.alpha = intensityVariant.toFloat();
}
auto outlineWidth = properties["outlineWidth"];
if (outlineWidth.isValid()) {
_style._outlineWidth = outlineWidth.toFloat();
}
auto isOutlineSmooth = properties["isOutlineSmooth"];
if (isOutlineSmooth.isValid()) {
_style._isOutlineSmooth = isOutlineSmooth.toBool();
}
return true;
}
QVariantMap SelectionHighlightStyle::toVariantMap() const {
QVariantMap properties;
properties["outlineUnoccludedColor"] = xColorToVariant(xColorFromGlm(_style._outlineUnoccluded.color));
properties["outlineOccludedColor"] = xColorToVariant(xColorFromGlm(_style._outlineOccluded.color));
properties["fillUnoccludedColor"] = xColorToVariant(xColorFromGlm(_style._fillUnoccluded.color));
properties["fillOccludedColor"] = xColorToVariant(xColorFromGlm(_style._fillOccluded.color));
properties["outlineUnoccludedAlpha"] = _style._outlineUnoccluded.alpha;
properties["outlineOccludedAlpha"] = _style._outlineOccluded.alpha;
properties["fillUnoccludedAlpha"] = _style._fillUnoccluded.alpha;
properties["fillOccludedAlpha"] = _style._fillOccluded.alpha;
properties["outlineWidth"] = _style._outlineWidth;
properties["isOutlineSmooth"] = _style._isOutlineSmooth;
return properties;
}

View file

@ -21,22 +21,23 @@
#include "RenderableEntityItem.h"
#include "ui/overlays/Overlay.h"
#include <avatar/AvatarManager.h>
#include <render/HighlightStyle.h>
class GameplayObjects {
public:
GameplayObjects();
bool getContainsData() { return containsData; }
bool getContainsData() const { return containsData; }
std::vector<QUuid> getAvatarIDs() { return _avatarIDs; }
std::vector<QUuid> getAvatarIDs() const { return _avatarIDs; }
bool addToGameplayObjects(const QUuid& avatarID);
bool removeFromGameplayObjects(const QUuid& avatarID);
std::vector<EntityItemID> getEntityIDs() { return _entityIDs; }
std::vector<EntityItemID> getEntityIDs() const { return _entityIDs; }
bool addToGameplayObjects(const EntityItemID& entityID);
bool removeFromGameplayObjects(const EntityItemID& entityID);
std::vector<OverlayID> getOverlayIDs() { return _overlayIDs; }
std::vector<OverlayID> getOverlayIDs() const { return _overlayIDs; }
bool addToGameplayObjects(const OverlayID& overlayID);
bool removeFromGameplayObjects(const OverlayID& overlayID);
@ -48,20 +49,52 @@ private:
};
class SelectionToSceneHandler : public QObject {
Q_OBJECT
public:
SelectionToSceneHandler();
void initialize(const QString& listName);
void updateSceneFromSelectedList();
public slots:
void selectedItemsListChanged(const QString& listName);
private:
QString _listName{ "" };
};
using SelectionToSceneHandlerPointer = QSharedPointer<SelectionToSceneHandler>;
class SelectionHighlightStyle {
public:
SelectionHighlightStyle() {}
void setBoundToList(bool bound) { _isBoundToList = bound; }
bool isBoundToList() const { return _isBoundToList; }
bool fromVariantMap(const QVariantMap& properties);
QVariantMap toVariantMap() const;
render::HighlightStyle getStyle() const { return _style; }
protected:
bool _isBoundToList{ false };
render::HighlightStyle _style;
};
class SelectionScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
SelectionScriptingInterface();
GameplayObjects getList(const QString& listName);
/**jsdoc
* Prints out the list of avatars, entities and overlays stored in a particular selection.
* @function Selection.printList
* @param listName {string} name of the selection
* Query the names of all the selection lists
* @function Selection.getListNames
* @return An array of names of all the selection lists
*/
Q_INVOKABLE void printList(const QString& listName);
Q_INVOKABLE QStringList getListNames() const;
/**jsdoc
* Removes a named selection from the list of selections.
* @function Selection.removeListFromMap
@ -96,30 +129,103 @@ public:
*/
Q_INVOKABLE bool clearSelectedItemsList(const QString& listName);
/**jsdoc
* Prints out the list of avatars, entities and overlays stored in a particular selection.
* @function Selection.printList
* @param listName {string} name of the selection
*/
Q_INVOKABLE void printList(const QString& listName);
/**jsdoc
* Query the list of avatars, entities and overlays stored in a particular selection.
* @function Selection.getList
* @param listName {string} name of the selection
* @return a js object describing the content of a selection list with the following properties:
* - "entities": [ and array of the entityID of the entities in the selection]
* - "avatars": [ and array of the avatarID of the avatars in the selection]
* - "overlays": [ and array of the overlayID of the overlays in the selection]
* If the list name doesn't exist, the function returns an empty js object with no properties.
*/
Q_INVOKABLE QVariantMap getSelectedItemsList(const QString& listName) const;
/**jsdoc
* Query the names of the highlighted selection lists
* @function Selection.getHighlightedListNames
* @return An array of names of the selection list currently highlight enabled
*/
Q_INVOKABLE QStringList getHighlightedListNames() const;
/**jsdoc
* Enable highlighting for the named selection.
* If the Selection doesn't exist, it will be created.
* All objects in the list will be displayed with the highlight effect as specified from the highlightStyle.
* The function can be called several times with different values in the style to modify it.
*
* @function Selection.enableListHighlight
* @param listName {string} name of the selection
* @param highlightStyle {jsObject} highlight style fields (see Selection.getListHighlightStyle for a detailed description of the highlightStyle).
* @returns {bool} true if the selection was successfully enabled for highlight.
*/
Q_INVOKABLE bool enableListHighlight(const QString& listName, const QVariantMap& highlightStyle);
/**jsdoc
* Disable highlighting for the named selection.
* If the Selection doesn't exist or wasn't enabled for highliting then nothing happens simply returning false.
*
* @function Selection.disableListHighlight
* @param listName {string} name of the selection
* @returns {bool} true if the selection was successfully disabled for highlight, false otherwise.
*/
Q_INVOKABLE bool disableListHighlight(const QString& listName);
/**jsdoc
* Query the highlight style values for the named selection.
* If the Selection doesn't exist or hasn't been highlight enabled yet, it will return an empty object.
* Otherwise, the jsObject describes the highlight style properties:
* - outlineUnoccludedColor: {xColor} Color of the specified highlight region
* - outlineOccludedColor: {xColor} "
* - fillUnoccludedColor: {xColor} "
* - fillOccludedColor: {xColor} "
*
* - outlineUnoccludedAlpha: {float} Alpha value ranging from 0.0 (not visible) to 1.0 (fully opaque) for the specified highlight region
* - outlineOccludedAlpha: {float} "
* - fillUnoccludedAlpha: {float} "
* - fillOccludedAlpha: {float} "
*
* - outlineWidth: {float} width of the outline expressed in pixels
* - isOutlineSmooth: {bool} true to enable oultine smooth falloff
*
* @function Selection.getListHighlightStyle
* @param listName {string} name of the selection
* @returns {jsObject} highlight style as described above
*/
Q_INVOKABLE QVariantMap getListHighlightStyle(const QString& listName) const;
GameplayObjects getList(const QString& listName);
render::HighlightStyle getHighlightStyle(const QString& listName) const;
void onSelectedItemsListChanged(const QString& listName);
signals:
void selectedItemsListChanged(const QString& listName);
private:
mutable QReadWriteLock _selectionListsLock;
QMap<QString, GameplayObjects> _selectedItemsListMap;
mutable QReadWriteLock _selectionHandlersLock;
QMap<QString, SelectionToSceneHandler*> _handlerMap;
mutable QReadWriteLock _highlightStylesLock;
QMap<QString, SelectionHighlightStyle> _highlightStyleMap;
template <class T> bool addToGameplayObjects(const QString& listName, T idToAdd);
template <class T> bool removeFromGameplayObjects(const QString& listName, T idToRemove);
};
void setupHandler(const QString& selectionName);
class SelectionToSceneHandler : public QObject {
Q_OBJECT
public:
SelectionToSceneHandler();
void initialize(const QString& listName);
void updateSceneFromSelectedList();
public slots:
void selectedItemsListChanged(const QString& listName);
private:
QString _listName { "" };
};
#endif // hifi_SelectionScriptingInterface_h

View file

@ -35,6 +35,8 @@ public:
// getters
virtual bool is3D() const override { return true; }
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return (uint32_t) subItems.size(); }
// TODO: consider implementing registration points in this class
glm::vec3 getCenter() const { return getWorldPosition(); }

View file

@ -72,14 +72,7 @@ ContextOverlayInterface::ContextOverlayInterface() {
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
{
render::Transaction transaction;
initializeSelectionToSceneHandler(_selectionToSceneHandlers[0], "contextOverlayHighlightList", transaction);
for (auto i = 1; i < MAX_SELECTION_COUNT; i++) {
auto selectionName = QString("highlightList") + QString::number(i);
initializeSelectionToSceneHandler(_selectionToSceneHandlers[i], selectionName, transaction);
}
const render::ScenePointer& scene = qApp->getMain3DScene();
scene->enqueueTransaction(transaction);
_selectionScriptingInterface->enableListHighlight("contextOverlayHighlightList", QVariantMap());
}
auto nodeList = DependencyManager::get<NodeList>();
@ -88,12 +81,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
_challengeOwnershipTimeoutTimer.setSingleShot(true);
}
void ContextOverlayInterface::initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction) {
handler.initialize(selectionName);
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &handler, &SelectionToSceneHandler::selectedItemsListChanged);
transaction.resetSelectionHighlight(selectionName.toStdString());
}
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters
static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims

View file

@ -96,9 +96,6 @@ private:
void disableEntityHighlight(const EntityItemID& entityItemID);
void deletingEntity(const EntityItemID& entityItemID);
void initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction);
SelectionToSceneHandler _selectionToSceneHandlers[MAX_SELECTION_COUNT];
Q_INVOKABLE void startChallengeOwnershipTimer();
QTimer _challengeOwnershipTimeoutTimer;

View file

@ -79,6 +79,12 @@ void ModelOverlay::update(float deltatime) {
if (_model->needsFixupInScene()) {
_model->removeFromScene(scene, transaction);
_model->addToScene(scene, transaction);
auto newRenderItemIDs{ _model->fetchRenderItemIDs() };
transaction.updateItem<Overlay>(getRenderItemID(), [newRenderItemIDs](Overlay& data) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->setSubRenderItemIDs(newRenderItemIDs);
});
}
if (_visibleDirty) {
_visibleDirty = false;
@ -104,6 +110,10 @@ bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePoint
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
Volume3DOverlay::removeFromScene(overlay, scene, transaction);
_model->removeFromScene(scene, transaction);
transaction.updateItem<Overlay>(getRenderItemID(), [](Overlay& data) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->clearSubRenderItemIDs();
});
}
void ModelOverlay::setVisible(bool visible) {
@ -529,3 +539,19 @@ void ModelOverlay::copyAnimationJointDataToModel(QVector<JointData> jointsData)
_updateModel = true;
}
void ModelOverlay::clearSubRenderItemIDs() {
_subRenderItemIDs.clear();
}
void ModelOverlay::setSubRenderItemIDs(const render::ItemIDs& ids) {
_subRenderItemIDs = ids;
}
uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const {
if (_model) {
auto metaSubItems = _subRenderItemIDs;
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t)metaSubItems.size();
}
return 0;
}

View file

@ -30,6 +30,12 @@ public:
virtual void update(float deltatime) override;
virtual void render(RenderArgs* args) override {};
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override;
void clearSubRenderItemIDs();
void setSubRenderItemIDs(const render::ItemIDs& ids);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
@ -74,6 +80,8 @@ private:
ModelPointer _model;
QVariantMap _modelTextures;
render::ItemIDs _subRenderItemIDs;
QUrl _url;
bool _updateModel { false };
bool _scaleToFit { false };

View file

@ -53,6 +53,8 @@ public:
virtual const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); }
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const { return 0; }
// getters
virtual QString getType() const = 0;
virtual bool is3D() const = 0;
@ -130,6 +132,7 @@ namespace render {
template <> int payloadGetLayer(const Overlay::Pointer& overlay);
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
}
Q_DECLARE_METATYPE(OverlayID);

View file

@ -26,6 +26,8 @@ public:
virtual bool is3D() const override { return false; }
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return 1; }
// getters
int getX() const { return _bounds.x(); }
int getY() const { return _bounds.y(); }

View file

@ -87,4 +87,10 @@ namespace render {
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay) {
return overlay->getShapeKey();
}
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
return overlay->fetchMetaSubItems(subItems);
}
}

View file

@ -16,7 +16,7 @@
<@include Highlight_shared.slh@>
uniform highlightParamsBuffer {
HighlightParameters params;
HighlightParameters params;
};
uniform sampler2D sceneDepthMap;
@ -35,8 +35,7 @@ void main(void) {
// We offset by half a texel to be centered on the depth sample. If we don't do this
// the blur will have a different width between the left / right sides and top / bottom
// sides of the silhouette
float highlightedDepth = texture(highlightedDepthMap, varTexCoord0).x;
float intensity = 0.0;
float highlightedDepth = texture(highlightedDepthMap, varTexCoord0).x;
if (highlightedDepth < FAR_Z) {
// We're not on the far plane so we are on the highlighted object, thus no outline to do!
@ -47,10 +46,13 @@ void main(void) {
highlightedDepth = -evalZeyeFromZdb(highlightedDepth);
sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded?
intensity = sceneDepth < (highlightedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity;
if (sceneDepth < (highlightedDepth-LINEAR_DEPTH_BIAS)) {
outFragColor = vec4(params._fillOccludedColor, params._fillOccludedAlpha);
} else {
outFragColor = vec4(params._fillUnoccludedColor, params._fillUnoccludedAlpha);
}
<@else@>
discard;
discard;
<@endif@>
} else {
vec2 halfTexel = getInvWidthHeight() / 2;
@ -62,6 +64,10 @@ void main(void) {
int x;
int y;
float intensity = 0.0;
float outlinedDepth = 0.0;
float sumOutlineDepth = 0.0;
for (y=0 ; y<params._blurKernelSize ; y++) {
uv = lineStartUv;
lineStartUv.y += deltaUv.y;
@ -70,8 +76,10 @@ void main(void) {
for (x=0 ; x<params._blurKernelSize ; x++) {
if (uv.x>=0.0 && uv.x<=1.0)
{
highlightedDepth = texture(highlightedDepthMap, uv).x;
intensity += (highlightedDepth < FAR_Z) ? 1.0 : 0.0;
outlinedDepth = texture(highlightedDepthMap, uv).x;
float touch = (outlinedDepth < FAR_Z) ? 1.0 : 0.0;
sumOutlineDepth = max(outlinedDepth * touch, sumOutlineDepth);
intensity += touch;
weight += 1.0;
}
uv.x += deltaUv.x;
@ -79,15 +87,32 @@ void main(void) {
}
}
if (intensity > 0) {
// sumOutlineDepth /= intensity;
} else {
sumOutlineDepth = FAR_Z;
}
intensity /= weight;
if (intensity < OPACITY_EPSILON) {
discard;
}
intensity = min(1.0, intensity / params._threshold);
intensity = min(1.0, intensity / params._threshold) * params._intensity;
// But we need to check the scene depth against the depth of the outline
float sceneDepth = texture(sceneDepthMap, texCoord0).x;
// Transform to linear depth for better precision
outlinedDepth = -evalZeyeFromZdb(sumOutlineDepth);
sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded?
if (sceneDepth < (outlinedDepth/*-LINEAR_DEPTH_BIAS*/)) {
outFragColor = vec4(params._outlineOccludedColor, intensity * params._outlineOccludedAlpha);
} else {
outFragColor = vec4(params._outlineUnoccludedColor, intensity * params._outlineUnoccludedAlpha);
}
}
outFragColor = vec4(params._color.rgb, intensity);
}
<@endfunc@>

View file

@ -88,7 +88,7 @@ HighlightSharedParameters::HighlightSharedParameters() {
}
float HighlightSharedParameters::getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight) {
return ceilf(style.outlineWidth * frameBufferHeight / 400.0f);
return ceilf(style._outlineWidth * frameBufferHeight / 400.0f);
}
PrepareDrawHighlight::PrepareDrawHighlight() {
@ -267,14 +267,19 @@ void DrawHighlight::run(const render::RenderContextPointer& renderContext, const
{
auto& shaderParameters = _configuration.edit();
shaderParameters._color = highlight._style.color;
shaderParameters._intensity = highlight._style.outlineIntensity * (highlight._style.isOutlineSmooth ? 2.0f : 1.0f);
shaderParameters._unoccludedFillOpacity = highlight._style.unoccludedFillOpacity;
shaderParameters._occludedFillOpacity = highlight._style.occludedFillOpacity;
shaderParameters._threshold = highlight._style.isOutlineSmooth ? 1.0f : 1e-3f;
shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(highlight._style.outlineWidth * 3 + 0.5f)));
shaderParameters._outlineUnoccludedColor = highlight._style._outlineUnoccluded.color;
shaderParameters._outlineUnoccludedAlpha = highlight._style._outlineUnoccluded.alpha * (highlight._style._isOutlineSmooth ? 2.0f : 1.0f);
shaderParameters._outlineOccludedColor = highlight._style._outlineOccluded.color;
shaderParameters._outlineOccludedAlpha = highlight._style._outlineOccluded.alpha * (highlight._style._isOutlineSmooth ? 2.0f : 1.0f);
shaderParameters._fillUnoccludedColor = highlight._style._fillUnoccluded.color;
shaderParameters._fillUnoccludedAlpha = highlight._style._fillUnoccluded.alpha;
shaderParameters._fillOccludedColor = highlight._style._fillOccluded.color;
shaderParameters._fillOccludedAlpha = highlight._style._fillOccluded.alpha;
shaderParameters._threshold = highlight._style._isOutlineSmooth ? 1.0f : 1e-3f;
shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(highlight._style._outlineWidth * 3 + 0.5f)));
// Size is in normalized screen height. We decide that for highlight width = 1, this is equal to 1/400.
auto size = highlight._style.outlineWidth / 400.0f;
auto size = highlight._style._outlineWidth / 400.0f;
shaderParameters._size.x = (size * framebufferSize.y) / framebufferSize.x;
shaderParameters._size.y = size;
}
@ -432,19 +437,20 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext
outputs.clear();
_sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX);
for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) {
std::ostringstream stream;
if (i > 0) {
stream << "highlightList" << i;
} else {
stream << "contextOverlayHighlightList";
}
auto selectionName = stream.str();
if (!scene->isSelectionEmpty(selectionName)) {
auto highlightId = highlightStage->getHighlightIdBySelection(selectionName);
if (!render::HighlightStage::isIndexInvalid(highlightId)) {
_sharedParameters->_highlightIds[outputs.size()] = highlightId;
outputs.emplace_back(selectionName);
int numLayers = 0;
auto highlightList = highlightStage->getActiveHighlightIds();
for (auto styleId : highlightList) {
auto highlight = highlightStage->getHighlight(styleId);
if (!scene->isSelectionEmpty(highlight._selectionName)) {
auto highlightId = highlightStage->getHighlightIdBySelection(highlight._selectionName);
_sharedParameters->_highlightIds[outputs.size()] = highlightId;
outputs.emplace_back(highlight._selectionName);
numLayers++;
if (numLayers == HighlightSharedParameters::MAX_PASS_COUNT) {
break;
}
}
}

View file

@ -11,17 +11,18 @@
struct HighlightParameters
{
TVEC3 _color;
float _intensity;
TVEC3 _outlineUnoccludedColor;
float _outlineUnoccludedAlpha;
TVEC3 _outlineOccludedColor;
float _outlineOccludedAlpha;
TVEC3 _fillUnoccludedColor;
float _fillUnoccludedAlpha;
TVEC3 _fillOccludedColor;
float _fillOccludedAlpha;
TVEC2 _size;
float _unoccludedFillOpacity;
float _occludedFillOpacity;
float _threshold;
int _blurKernelSize;
float padding2;
float padding3;
float _threshold;
TVEC2 _size;
};
// <@if 1@>

View file

@ -61,42 +61,42 @@ void HighlightStageConfig::setSelectionName(const QString& name) {
}
void HighlightStageConfig::setOutlineSmooth(bool isSmooth) {
editStyle().isOutlineSmooth = isSmooth;
editStyle()._isOutlineSmooth = isSmooth;
emit dirty();
}
void HighlightStageConfig::setColorRed(float value) {
editStyle().color.r = value;
editStyle()._outlineUnoccluded.color.r = value;
emit dirty();
}
void HighlightStageConfig::setColorGreen(float value) {
editStyle().color.g = value;
editStyle()._outlineUnoccluded.color.g = value;
emit dirty();
}
void HighlightStageConfig::setColorBlue(float value) {
editStyle().color.b = value;
editStyle()._outlineUnoccluded.color.b = value;
emit dirty();
}
void HighlightStageConfig::setOutlineWidth(float value) {
editStyle().outlineWidth = value;
editStyle()._outlineWidth = value;
emit dirty();
}
void HighlightStageConfig::setOutlineIntensity(float value) {
editStyle().outlineIntensity = value;
editStyle()._outlineUnoccluded.alpha = value;
emit dirty();
}
void HighlightStageConfig::setUnoccludedFillOpacity(float value) {
editStyle().unoccludedFillOpacity = value;
editStyle()._fillUnoccluded.alpha = value;
emit dirty();
}
void HighlightStageConfig::setOccludedFillOpacity(float value) {
editStyle().occludedFillOpacity = value;
editStyle()._fillOccluded.alpha = value;
emit dirty();
}

View file

@ -51,6 +51,7 @@ namespace render {
HighlightIdList::iterator begin() { return _activeHighlightIds.begin(); }
HighlightIdList::iterator end() { return _activeHighlightIds.end(); }
const HighlightIdList& getActiveHighlightIds() const { return _activeHighlightIds; }
private:
@ -82,28 +83,28 @@ namespace render {
QString getSelectionName() const { return QString(_selectionName.c_str()); }
void setSelectionName(const QString& name);
bool isOutlineSmooth() const { return getStyle().isOutlineSmooth; }
bool isOutlineSmooth() const { return getStyle()._isOutlineSmooth; }
void setOutlineSmooth(bool isSmooth);
float getColorRed() const { return getStyle().color.r; }
float getColorRed() const { return getStyle()._outlineUnoccluded.color.r; }
void setColorRed(float value);
float getColorGreen() const { return getStyle().color.g; }
float getColorGreen() const { return getStyle()._outlineUnoccluded.color.g; }
void setColorGreen(float value);
float getColorBlue() const { return getStyle().color.b; }
float getColorBlue() const { return getStyle()._outlineUnoccluded.color.b; }
void setColorBlue(float value);
float getOutlineWidth() const { return getStyle().outlineWidth; }
float getOutlineWidth() const { return getStyle()._outlineWidth; }
void setOutlineWidth(float value);
float getOutlineIntensity() const { return getStyle().outlineIntensity; }
float getOutlineIntensity() const { return getStyle()._outlineUnoccluded.alpha; }
void setOutlineIntensity(float value);
float getUnoccludedFillOpacity() const { return getStyle().unoccludedFillOpacity; }
float getUnoccludedFillOpacity() const { return getStyle()._fillUnoccluded.alpha; }
void setUnoccludedFillOpacity(float value);
float getOccludedFillOpacity() const { return getStyle().occludedFillOpacity; }
float getOccludedFillOpacity() const { return getStyle()._fillOccluded.alpha; }
void setOccludedFillOpacity(float value);
std::string _selectionName{ "contextOverlayHighlightList" };

View file

@ -20,17 +20,24 @@ namespace render {
// This holds the configuration for a particular outline style
class HighlightStyle {
public:
struct RGBA {
glm::vec3 color{ 1.0f, 0.7f, 0.2f };
float alpha{ 0.9f };
RGBA(const glm::vec3& c, float a) : color(c), alpha(a) {}
};
RGBA _outlineUnoccluded{ { 1.0f, 0.7f, 0.2f }, 0.9f };
RGBA _outlineOccluded{ { 1.0f, 0.7f, 0.2f }, 0.9f };
RGBA _fillUnoccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f };
RGBA _fillOccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f };
float _outlineWidth{ 2.0f };
bool _isOutlineSmooth{ false };
bool isFilled() const {
return unoccludedFillOpacity > 5e-3f || occludedFillOpacity > 5e-3f;
return _fillUnoccluded.alpha > 5e-3f || _fillOccluded.alpha > 5e-3f;
}
glm::vec3 color{ 1.f, 0.7f, 0.2f };
float outlineWidth{ 2.0f };
float outlineIntensity{ 0.9f };
float unoccludedFillOpacity{ 0.0f };
float occludedFillOpacity{ 0.0f };
bool isOutlineSmooth{ false };
};
}

View file

@ -532,7 +532,7 @@ bool Scene::isSelectionEmpty(const Selection::Name& name) const {
std::unique_lock<std::mutex> lock(_selectionsMutex);
auto found = _selections.find(name);
if (found == _selections.end()) {
return false;
return true;
} else {
return (*found).second.isEmpty();
}

View file

@ -432,6 +432,12 @@ glm::vec3 toGlm(const xColor& color) {
return glm::vec3(color.red, color.green, color.blue) / MAX_COLOR;
}
xColor xColorFromGlm(const glm::vec3 & color) {
static const float MAX_COLOR = 255.0f;
return { (uint8_t)(color.x * MAX_COLOR), (uint8_t)(color.y * MAX_COLOR), (uint8_t)(color.z * MAX_COLOR) };
}
glm::vec4 toGlm(const QColor& color) {
return glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF());
}

View file

@ -177,6 +177,8 @@ vec4 toGlm(const QColor& color);
ivec4 toGlm(const QRect& rect);
vec4 toGlm(const xColor& color, float alpha);
xColor xColorFromGlm(const glm::vec3 & c);
QSize fromGlm(const glm::ivec2 & v);
QMatrix4x4 fromGlm(const glm::mat4 & m);

View file

@ -0,0 +1,212 @@
//
// Color.qml
//
// Created by Sam Gateau 12/4/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
Item {
HifiConstants { id: hifi }
id: root
height: 24
property var _color: Qt.rgba(1.0, 1.0, 1.0, 1.0 );
property var zoneWidth: width / 3;
property var hoveredOn: 0.0;
property var sliderHeight: height / 2;
signal newColor(color __color)
function setColor(color) {
_color = Qt.rgba(color.r, color.g, color.b, 1.0)
updateColor()
}
function setRed(r) {
_color.r = r;
updateColor()
}
function setGreen(g) {
_color.g = g;
updateColor()
}
function setBlue(b) {
_color.b = b;
updateColor()
}
function updateColor() {
repaint()
newColor(_color)
}
function repaint() {
current.color = _color
}
function resetSliders() {
redZone.set(_color.r)
greenZone.set(_color.g)
blueZone.set(_color.b)
}
function setXColor(xcolor) {
setColor(Qt.rgba(xcolor.red/255, xcolor.green/255, color.blue/255, 1.0))
}
function getXColor() {
return {red:_color.r * 255, green:_color.g * 255, blue:_color.b * 255}
}
Rectangle {
id: current
anchors.fill: root
color: root._color;
}
Rectangle {
id: sliderBack
height: root.sliderHeight
anchors.bottom: root.bottom
anchors.left: root.left
anchors.right: root.right
color: Qt.rgba(0.2, 0.2, 0.2, 1)
opacity: root.hoveredOn * 0.5
}
MouseArea {
id: all
anchors.fill: root
hoverEnabled: true
onEntered: {
root.hoveredOn = 1.0;
resetSliders();
}
onExited: {
root.hoveredOn = 0.0;
}
}
Component.onCompleted: {
}
Item {
id: redZone
anchors.top: root.top
anchors.bottom: root.bottom
anchors.left: root.left
width: root.zoneWidth
function update(r) {
if (r < 0.0) {
r = 0.0
} else if (r > 1.0) {
r = 1.0
}
root.setRed(r)
set(r)
}
function set(r) {
redRect.width = r * redZone.width
redRect.color = Qt.rgba(r, 0, 0, 1)
}
Rectangle {
id: redRect
anchors.bottom: parent.bottom
anchors.left: parent.left
height: root.sliderHeight
opacity: root.hoveredOn
}
MouseArea {
id: redArea
anchors.fill: parent
onPositionChanged: {
redZone.update(mouse.x / redArea.width)
}
}
}
Item {
id: greenZone
anchors.top: root.top
anchors.bottom: root.bottom
anchors.horizontalCenter: root.horizontalCenter
width: root.zoneWidth
function update(g) {
if (g < 0.0) {
g = 0.0
} else if (g > 1.0) {
g = 1.0
}
root.setGreen(g)
set(g)
}
function set(g) {
greenRect.width = g * greenZone.width
greenRect.color = Qt.rgba(0, g, 0, 1)
}
Rectangle {
id: greenRect
anchors.bottom: parent.bottom
anchors.left: parent.left
height: root.sliderHeight
opacity: root.hoveredOn
}
MouseArea {
id: greenArea
anchors.fill: parent
onPositionChanged: {
greenZone.update(mouse.x / greenArea.width)
}
}
}
Item {
id: blueZone
anchors.top: root.top
anchors.bottom: root.bottom
anchors.right: root.right
width: root.zoneWidth
function update(b) {
if (b < 0.0) {
b = 0.0
} else if (b > 1.0) {
b = 1.0
}
root.setBlue(b)
set(b)
}
function set(b) {
blueRect.width = b * blueZone.width
blueRect.color = Qt.rgba(0, 0, b, 1)
}
Rectangle {
id: blueRect
anchors.bottom: parent.bottom
anchors.left: parent.left
height: root.sliderHeight
opacity: root.hoveredOn
}
MouseArea {
id: blueArea
anchors.fill: parent
onPositionChanged: {
blueZone.update(mouse.x / blueArea.width)
}
}
}
}

View file

@ -1 +1,2 @@
PlotPerf 1.0 PlotPerf.qml
PlotPerf 1.0 PlotPerf.qml
Color 1.0 Color.qml

View file

@ -30,6 +30,8 @@ Item {
property alias min: sliderControl.minimumValue
property alias max: sliderControl.maximumValue
signal valueChanged(real value)
Component.onCompleted: {
// Binding favors qml value, so set it first
sliderControl.value = root.config[root.property];
@ -69,5 +71,7 @@ Item {
anchors.rightMargin: 0
anchors.top: root.top
anchors.topMargin: 0
onValueChanged: { root.valueChanged(value) }
}
}

View file

@ -9,152 +9,162 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Set up the qml ui
var qml = Script.resolvePath('highlight.qml');
var window = new OverlayWindow({
title: 'Highlight',
source: qml,
width: 400,
height: 400,
});
window.closed.connect(function() { Script.stop(); });
"use strict";
// Created by Sam Gondelman on 9/7/2017
// Copyright 2017 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
(function() {
var TABLET_BUTTON_NAME = "Highlight";
var QMLAPP_URL = Script.resolvePath("./highlight.qml");
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
(function() { // BEGIN LOCAL_SCOPE
var onLuciScreen = false;
var END_DIMENSIONS = {
x: 0.15,
y: 0.15,
z: 0.15
};
var COLOR = {red: 97, green: 247, blue: 255};
var end = {
type: "sphere",
dimensions: END_DIMENSIONS,
color: COLOR,
ignoreRayIntersection: true,
alpha: 1.0,
visible: true
}
var COLOR2 = {red: 247, green: 97, blue: 255};
var end2 = {
type: "sphere",
dimensions: END_DIMENSIONS,
color: COLOR2,
ignoreRayIntersection: true,
alpha: 1.0,
visible: true
}
var highlightGroupIndex = 0
var isSelectionAddEnabled = false
var isSelectionEnabled = false
var renderStates = [{name: "test", end: end}];
var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}];
var time = 0
var ray = LaserPointers.createLaserPointer({
joint: "Mouse",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS | RayPick.PICK_AVATARS | RayPick.PICK_INVISIBLE | RayPick.PICK_NONCOLLIDABLE,
renderStates: renderStates,
defaultRenderStates: defaultRenderStates,
enabled: false
});
function getSelectionName() {
var selectionName = "contextOverlayHighlightList"
if (highlightGroupIndex>0) {
selectionName += highlightGroupIndex
}
return selectionName
}
function fromQml(message) {
tokens = message.split(' ')
print("Received '"+message+"' from hightlight.qml")
if (tokens[0]=="highlight") {
highlightGroupIndex = parseInt(tokens[1])
print("Switching to highlight group "+highlightGroupIndex)
} else if (tokens[0]=="pick") {
isSelectionEnabled = tokens[1]=='true'
print("Ray picking set to "+isSelectionEnabled.toString())
if (isSelectionEnabled) {
LaserPointers.enableLaserPointer(ray)
function onClicked() {
if (onLuciScreen) {
tablet.gotoHomeScreen();
} else {
LaserPointers.disableLaserPointer(ray)
}
time = 0
} else if (tokens[0]=="add") {
isSelectionAddEnabled = tokens[1]=='true'
print("Add to selection set to "+isSelectionAddEnabled.toString())
if (!isSelectionAddEnabled) {
Selection.clearSelectedItemsList(getSelectionName())
tablet.loadQMLSource(QMLAPP_URL);
}
}
}
window.fromQml.connect(fromQml);
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: ICON_URL,
activeIcon: ACTIVE_ICON_URL,
sortOrder: 1
});
function cleanup() {
LaserPointers.removeLaserPointer(ray);
}
Script.scriptEnding.connect(cleanup);
var hasEventBridge = false;
var prevID = 0
var prevType = ""
var selectedID = 0
var selectedType = ""
function update(deltaTime) {
// you have to do this repeatedly because there's a bug but I'll fix it
LaserPointers.setRenderState(ray, "test");
var result = LaserPointers.getPrevRayPickResult(ray);
var selectionName = getSelectionName()
if (isSelectionEnabled && result.type != RayPick.INTERSECTED_NONE) {
time += deltaTime
if (result.objectID != prevID) {
var typeName = ""
if (result.type == RayPick.INTERSECTED_ENTITY) {
typeName = "entity"
} else if (result.type == RayPick.INTERSECTED_OVERLAY) {
typeName = "overlay"
} else if (result.type == RayPick.INTERSECTED_AVATAR) {
typeName = "avatar"
function wireEventBridge(on) {
if (!tablet) {
print("Warning in wireEventBridge(): 'tablet' undefined!");
return;
}
if (on) {
if (!hasEventBridge) {
tablet.fromQml.connect(fromQml);
hasEventBridge = true;
}
} else {
if (hasEventBridge) {
tablet.fromQml.disconnect(fromQml);
hasEventBridge = false;
}
}
}
function onScreenChanged(type, url) {
if (url === QMLAPP_URL) {
onLuciScreen = true;
} else {
onLuciScreen = false;
}
button.editProperties({isActive: onLuciScreen});
wireEventBridge(onLuciScreen);
}
button.clicked.connect(onClicked);
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(function () {
if (onLuciScreen) {
tablet.gotoHomeScreen();
}
button.clicked.disconnect(onClicked);
tablet.screenChanged.disconnect(onScreenChanged);
tablet.removeButton(button);
});
// Create a Laser pointer used to pick and add objects to selections
var END_DIMENSIONS = { x: 0.05, y: 0.05, z: 0.05 };
var COLOR1 = {red: 255, green: 0, blue: 0};
var COLOR2 = {red: 0, green: 255, blue: 0};
var end1 = {
type: "sphere",
dimensions: END_DIMENSIONS,
color: COLOR1,
ignoreRayIntersection: true
}
var end2 = {
type: "sphere",
dimensions: END_DIMENSIONS,
color: COLOR2,
ignoreRayIntersection: true
}
var laser = Pointers.createPointer(PickType.Ray, {
joint: "Mouse",
filter: Picks.PICK_ENTITIES,
renderStates: [{name: "one", end: end1}],
defaultRenderStates: [{name: "one", end: end2, distance: 2.0}],
enabled: true
});
Pointers.setRenderState(laser, "one");
var HoveringList = "Hovering"
var hoveringStyle = {
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(HoveringList, hoveringStyle)
var currentSelectionName = ""
var isSelectionEnabled = false
Pointers.disablePointer(laser)
function fromQml(message) {
tokens = message.split(' ')
print("Received '"+message+"' from hightlight.qml")
if (tokens[0]=="highlight") {
currentSelectionName = tokens[1];
print("Switching to highlight name "+currentSelectionName)
} else if (tokens[0]=="pick") {
isSelectionEnabled = tokens[1]=='true'
print("Ray picking set to "+isSelectionEnabled.toString())
if (isSelectionEnabled) {
Pointers.enablePointer(laser)
} else {
Pointers.disablePointer(laser)
Selection.clearSelectedItemsList(HoveringList)
}
prevID = result.objectID;
prevType = typeName;
time = 0
} else if (time>1.0 && prevID!=selectedID) {
if (prevID != 0 && !isSelectionAddEnabled) {
Selection.removeFromSelectedItemsList(selectionName, selectedType, selectedID)
}
selectedID = prevID
selectedType = prevType
Selection.addToSelectedItemsList(selectionName, selectedType, selectedID)
print("HIGHLIGHT " + highlightGroupIndex + " picked type: " + result.type + ", id: " + result.objectID);
}
} else {
if (prevID != 0 && !isSelectionAddEnabled) {
Selection.removeFromSelectedItemsList(selectionName, prevType, prevID)
}
prevID = 0
selectedID = 0
time = 0
}
}
Entities.hoverEnterEntity.connect(function (id, event) {
// print("hoverEnterEntity");
if (isSelectionEnabled) Selection.addToSelectedItemsList(HoveringList, "entity", id)
})
Entities.hoverOverEntity.connect(function (id, event) {
// print("hoverOverEntity");
})
Entities.hoverLeaveEntity.connect(function (id, event) {
if (isSelectionEnabled) Selection.removeFromSelectedItemsList(HoveringList, "entity", id)
// print("hoverLeaveEntity");
})
function cleanup() {
Pointers.removePointer(ray);
Selection.disableListHighlight(HoveringList)
Selection.removeListFromMap(HoveringList)
}
Script.scriptEnding.connect(cleanup);
}());
Script.update.connect(update);
}()); // END LOCAL_SCOPE

View file

@ -15,162 +15,184 @@ import QtQuick.Layouts 1.3
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
import "configSlider"
import "../lib/plotperf"
import "highlight"
Rectangle {
Item {
id: root
HifiConstants { id: hifi;}
color: hifi.colors.baseGray;
anchors.margins: hifi.dimensions.contentMargin.x
property var debugConfig: Render.getConfig("RenderMainView.HighlightDebug")
property var highlightConfig: Render.getConfig("UpdateScene.HighlightStageSetup")
anchors.margins: 0
property var listName: "contextOverlayHighlightList"
property var styleList: Selection.getHighlightedListNames()
signal sendToScript(var message);
Component.onCompleted: {
// Connect the signal from Selection when any selection content change and use it to refresh the current selection view
Selection.selectedItemsListChanged.connect(resetSelectionView)
}
function resetSelectionView() {
if (selectionView !== undefined) {
selectionView.resetSelectionView();
}
}
Column {
id: col
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
spacing: 5
anchors.fill: root
anchors.margins: hifi.dimensions.contentMargin.x
Row {
id: controlbar
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
height: 24
HifiControls.CheckBox {
HifiControls.Button {
id: debug
text: "View Mask"
checked: root.debugConfig["viewMask"]
onCheckedChanged: {
root.debugConfig["viewMask"] = checked;
text: "Refresh"
height: 24
width: 82
onClicked: {
print("list of highlight styles")
root.styleList = Selection.getHighlightedListNames()
print(root.styleList)
styleSelectorLoader.sourceComponent = undefined;
styleSelectorLoader.sourceComponent = selectorWidget;
}
}
HifiControls.CheckBox {
text: "Hover select"
checked: false
onCheckedChanged: {
sendToScript("pick "+checked.toString())
}
}
HifiControls.CheckBox {
text: "Add to selection"
checked: false
onCheckedChanged: {
sendToScript("add "+checked.toString())
Loader {
id: styleSelectorLoader
sourceComponent: selectorWidget
width: 300
//anchors.right: parent.right
}
Component {
id: selectorWidget
HifiControls.ComboBox {
id: box
z: 999
editable: true
colorScheme: hifi.colorSchemes.dark
model: root.styleList
label: ""
Timer {
id: postpone
interval: 100; running: false; repeat: false
onTriggered: {
styleWidgetLoader.sourceComponent = styleWidget
resetSelectionView();
}
}
onCurrentIndexChanged: {
root.listName = model[currentIndex];
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
// by setting the loader source to Null and then recreate it 100ms later
styleWidgetLoader.sourceComponent = undefined;
postpone.interval = 100
postpone.start()
}
}
}
}
HifiControls.ComboBox {
id: box
width: 350
z: 999
editable: true
colorScheme: hifi.colorSchemes.dark
model: [
"contextOverlayHighlightList",
"highlightList1",
"highlightList2",
"highlightList3",
"highlightList4"]
label: ""
Timer {
id: postpone
interval: 100; running: false; repeat: false
onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets }
}
onCurrentIndexChanged: {
root.highlightConfig["selectionName"] = model[currentIndex];
sendToScript("highlight "+currentIndex)
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
// by setting the loader source to Null and then recreate it 100ms later
paramWidgetLoader.sourceComponent = undefined;
postpone.interval = 100
postpone.start()
}
}
Separator {}
Loader {
id: paramWidgetLoader
sourceComponent: paramWidgets
width: 350
id: styleWidgetLoader
sourceComponent: styleWidget
anchors.left: parent.left
anchors.right: parent.right
height: 240
}
Separator {}
HifiControls.CheckBox {
text: "Highlight Hovered"
checked: false
onCheckedChanged: {
if (checked) {
root.sendToScript("pick true")
} else {
root.sendToScript("pick false")
}
}
}
Separator {}
Rectangle {
id: selectionView
anchors.left: parent.left
anchors.right: parent.right
height: 250
color: hifi.colors.lightGray
Component {
id: paramWidgets
Column {
spacing: 10
anchors.margins: hifi.dimensions.contentMargin.x
HifiControls.Label {
text: "Outline"
}
Column {
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
HifiControls.CheckBox {
text: "Smooth"
checked: root.highlightConfig["isOutlineSmooth"]
onCheckedChanged: {
root.highlightConfig["isOutlineSmooth"] = checked;
}
}
Repeater {
model: ["Width:outlineWidth:5.0:0.0",
"Intensity:outlineIntensity:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.highlightConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
}
function resetSelectionView() {
myModel.clear()
var entities = Selection.getSelectedItemsList(root.listName)["entities"]
if (entities !== undefined) {
myModel.append({ "objectID": "Entities" })
for (var i = 0; i < entities.length; i++) {
myModel.append({ "objectID": JSON.stringify(entities[i]) })
}
}
Separator {}
HifiControls.Label {
text: "Color"
}
Repeater {
model: ["Red:colorR:1.0:0.0",
"Green:colorG:1.0:0.0",
"Blue:colorB:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.highlightConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
var overlays = Selection.getSelectedItemsList(root.listName)["overlays"]
if (overlays !== undefined) {
myModel.append({ "objectID": "Overlays" })
for (var i = 0; i < overlays.length; i++) {
myModel.append({ "objectID": JSON.stringify(overlays[i]) })
}
}
Separator {}
HifiControls.Label {
text: "Fill Opacity"
}
Repeater {
model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0",
"Occluded:occludedFillOpacity:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.highlightConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
var avatars = Selection.getSelectedItemsList(root.listName)["avatars"]
if (avatars !== undefined) {
myModel.append({ "objectID": "Avatars" })
for (var i = 0; i < avatars.length; i++) {
myModel.append({ "objectID": JSON.stringify(avatars[i]) })
}
}
}
ListModel {
id: myModel
}
Component {
id: myDelegate
Row {
id: fruit
Text { text: objectID }
}
}
ListView {
id: selectionListView
anchors.fill: parent
anchors.topMargin: 30
model: myModel
delegate: myDelegate
}
}
}
Component {
id: styleWidget
HighlightStyle {
id: highlightStyle
anchors.left: parent.left
anchors.right: parent.right
highlightStyle: Selection.getListHighlightStyle(root.listName)
onNewStyle: {
var style = getStyle()
// print("new style " + JSON.stringify(style) )
Selection.enableListHighlight(root.listName, style)
}
}
}

View file

@ -0,0 +1,105 @@
//
// highlightStyle.qml
//
// Created by Sam Gateau 12/4/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "../configSlider"
import "../../lib/plotperf"
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
Item {
id: root
property var highlightStyle
height: 48
anchors.margins: 0
signal newStyle()
function getStyle() {
return highlightStyle;
}
Component.onCompleted: {
}
Column {
spacing: 5
anchors.left: root.left
anchors.right: root.right
anchors.margins: 0
ConfigSlider {
label: "Outline Width"
integral: false
config: root.highlightStyle
property: "outlineWidth"
max: 10
min: 0
anchors.left: parent.left
anchors.right: parent.right
onValueChanged: { root.highlightStyle["outlineWidth"] = value; newStyle() }
}
HifiControls.CheckBox {
id: isOutlineSmooth
text: "Smooth Outline"
checked: root.highlightStyle["isOutlineSmooth"]
onCheckedChanged: {
root.highlightStyle["isOutlineSmooth"] = checked;
newStyle();
}
}
Repeater {
model: [
"Outline Unoccluded:outlineUnoccludedColor:outlineUnoccludedAlpha",
"Outline Occluded:outlineOccludedColor:outlineOccludedAlpha",
"Fill Unoccluded:fillUnoccludedColor:fillUnoccludedAlpha",
"Fill Occluded:fillOccludedColor:fillOccludedAlpha"]
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 0
Color {
height: 20
anchors.right: parent.right
width: root.width / 2
_color: Qt.rgba(root.highlightStyle[modelData.split(":")[1]].red / 255, root.highlightStyle[modelData.split(":")[1]].green / 255, root.highlightStyle[modelData.split(":")[1]].blue / 255, 1.0)
onNewColor: {
root.highlightStyle[modelData.split(":")[1]] = getXColor()
newStyle()
}
}
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.highlightStyle
property: modelData.split(":")[2]
max: 1.0
min: 0.0
anchors.left: parent.left
anchors.right: parent.right
onValueChanged: { root.highlightStyle[modelData.split(":")[2]] = value; newStyle() }
}
}
}
}
}

View file

@ -0,0 +1 @@
HighlightStyle 1.0 HighlightStyle.qml

View file

@ -1,116 +0,0 @@
//
// highlightPage.qml
// developer/utilities/render
//
// Olivier Prat, created on 08/08/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "../configSlider"
import "qrc:///qml/styles-uit"
import "qrc:///qml/controls-uit" as HifiControls
Rectangle {
id: root
property var highlightIndex: 0
property var drawConfig: Render.getConfig("RenderMainView.HighlightEffect"+highlightIndex)
HifiConstants { id: hifi;}
anchors.margins: hifi.dimensions.contentMargin.x
Column {
spacing: 5
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: hifi.dimensions.contentMargin.x
HifiControls.CheckBox {
id: glow
text: "Glow"
checked: root.drawConfig["glow"]
onCheckedChanged: {
root.drawConfig["glow"] = checked;
}
}
Repeater {
model: ["Width:width:5.0:0.0",
"Intensity:intensity:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.drawConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
anchors.left: parent.left
anchors.right: parent.right
}
}
GroupBox {
title: "Color"
anchors.left: parent.left
anchors.right: parent.right
Column {
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: hifi.dimensions.contentMargin.x
Repeater {
model: ["Red:colorR:1.0:0.0",
"Green:colorG:1.0:0.0",
"Blue:colorB:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.drawConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
anchors.left: parent.left
anchors.right: parent.right
}
}
}
}
GroupBox {
title: "Fill Opacity"
anchors.left: parent.left
anchors.right: parent.right
Column {
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: hifi.dimensions.contentMargin.x
Repeater {
model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0",
"Occluded:occludedFillOpacity:1.0:0.0"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: false
config: root.drawConfig
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: modelData.split(":")[3]
anchors.left: parent.left
anchors.right: parent.right
}
}
}
}
}
}

View file

@ -1 +0,0 @@
HighlightPage 1.0 HighlightPage.qml