diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp index 1adf5650dd..233e61c8ae 100644 --- a/interface/src/scripting/SelectionScriptingInterface.cpp +++ b/interface/src/scripting/SelectionScriptingInterface.cpp @@ -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 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 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 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 avatarIDs; + QList entityIDs; + QList 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; +} \ No newline at end of file diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h index d9003c2c32..8295375870 100644 --- a/interface/src/scripting/SelectionScriptingInterface.h +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -21,22 +21,23 @@ #include "RenderableEntityItem.h" #include "ui/overlays/Overlay.h" #include +#include class GameplayObjects { public: GameplayObjects(); - bool getContainsData() { return containsData; } + bool getContainsData() const { return containsData; } - std::vector getAvatarIDs() { return _avatarIDs; } + std::vector getAvatarIDs() const { return _avatarIDs; } bool addToGameplayObjects(const QUuid& avatarID); bool removeFromGameplayObjects(const QUuid& avatarID); - std::vector getEntityIDs() { return _entityIDs; } + std::vector getEntityIDs() const { return _entityIDs; } bool addToGameplayObjects(const EntityItemID& entityID); bool removeFromGameplayObjects(const EntityItemID& entityID); - std::vector getOverlayIDs() { return _overlayIDs; } + std::vector 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; + +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 _selectedItemsListMap; + mutable QReadWriteLock _selectionHandlersLock; + QMap _handlerMap; + + mutable QReadWriteLock _highlightStylesLock; + QMap _highlightStyleMap; + template bool addToGameplayObjects(const QString& listName, T idToAdd); template 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 diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 556399c741..6323ff9dc8 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -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(); } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 3681f42381..de644f165b 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -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(); @@ -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 diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index 81e398e15d..990a7fe599 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -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; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index f27e26280a..0846599728 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -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(getRenderItemID(), [newRenderItemIDs](Overlay& data) { + auto modelOverlay = static_cast(&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(getRenderItemID(), [](Overlay& data) { + auto modelOverlay = static_cast(&data); + modelOverlay->clearSubRenderItemIDs(); + }); } void ModelOverlay::setVisible(bool visible) { @@ -529,3 +539,19 @@ void ModelOverlay::copyAnimationJointDataToModel(QVector 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; +} diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index c4506d9621..4f7f1e0cae 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -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 }; diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 39208f01a0..806fc1aa14 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -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); diff --git a/interface/src/ui/overlays/Overlay2D.h b/interface/src/ui/overlays/Overlay2D.h index a1efe8a6de..3175df92f1 100644 --- a/interface/src/ui/overlays/Overlay2D.h +++ b/interface/src/ui/overlays/Overlay2D.h @@ -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(); } diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 8d3e514a0f..fceb261503 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -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); + } } + diff --git a/libraries/render-utils/src/Highlight.slh b/libraries/render-utils/src/Highlight.slh index 2faa10682e..f4d4ad0e04 100644 --- a/libraries/render-utils/src/Highlight.slh +++ b/libraries/render-utils/src/Highlight.slh @@ -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=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@> diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 7c58e5ba66..fee1f4a568 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -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; } } } diff --git a/libraries/render-utils/src/Highlight_shared.slh b/libraries/render-utils/src/Highlight_shared.slh index 5efbde4d52..edc51e4ecb 100644 --- a/libraries/render-utils/src/Highlight_shared.slh +++ b/libraries/render-utils/src/Highlight_shared.slh @@ -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@> diff --git a/libraries/render/src/render/HighlightStage.cpp b/libraries/render/src/render/HighlightStage.cpp index ade3844321..c9f097b387 100644 --- a/libraries/render/src/render/HighlightStage.cpp +++ b/libraries/render/src/render/HighlightStage.cpp @@ -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(); } diff --git a/libraries/render/src/render/HighlightStage.h b/libraries/render/src/render/HighlightStage.h index b35fff654c..5e6574840f 100644 --- a/libraries/render/src/render/HighlightStage.h +++ b/libraries/render/src/render/HighlightStage.h @@ -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" }; diff --git a/libraries/render/src/render/HighlightStyle.h b/libraries/render/src/render/HighlightStyle.h index 6e7373c78b..8bef5c33c3 100644 --- a/libraries/render/src/render/HighlightStyle.h +++ b/libraries/render/src/render/HighlightStyle.h @@ -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 }; }; } diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 4b337a1046..bc75e5ad21 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -532,7 +532,7 @@ bool Scene::isSelectionEmpty(const Selection::Name& name) const { std::unique_lock lock(_selectionsMutex); auto found = _selections.find(name); if (found == _selections.end()) { - return false; + return true; } else { return (*found).second.isEmpty(); } diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 39fec45d90..ff1d29eed1 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -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()); } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 7248f4cb46..973998b927 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -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); diff --git a/scripts/developer/utilities/lib/plotperf/Color.qml b/scripts/developer/utilities/lib/plotperf/Color.qml new file mode 100644 index 0000000000..15d7f9fcc9 --- /dev/null +++ b/scripts/developer/utilities/lib/plotperf/Color.qml @@ -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) + } + } + } +} diff --git a/scripts/developer/utilities/lib/plotperf/qmldir b/scripts/developer/utilities/lib/plotperf/qmldir index 5668f5034c..20b3fc9fcf 100644 --- a/scripts/developer/utilities/lib/plotperf/qmldir +++ b/scripts/developer/utilities/lib/plotperf/qmldir @@ -1 +1,2 @@ -PlotPerf 1.0 PlotPerf.qml \ No newline at end of file +PlotPerf 1.0 PlotPerf.qml +Color 1.0 Color.qml diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index 830dc6de23..87e0e51726 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -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) } } } diff --git a/scripts/developer/utilities/render/debugHighlight.js b/scripts/developer/utilities/render/debugHighlight.js index 5175761978..e70565cec2 100644 --- a/scripts/developer/utilities/render/debugHighlight.js +++ b/scripts/developer/utilities/render/debugHighlight.js @@ -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 \ No newline at end of file diff --git a/scripts/developer/utilities/render/highlight.qml b/scripts/developer/utilities/render/highlight.qml index 6be74fcf40..88d6a807ae 100644 --- a/scripts/developer/utilities/render/highlight.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -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) } } } diff --git a/scripts/developer/utilities/render/highlight/HighlightStyle.qml b/scripts/developer/utilities/render/highlight/HighlightStyle.qml new file mode 100644 index 0000000000..371b7e81f7 --- /dev/null +++ b/scripts/developer/utilities/render/highlight/HighlightStyle.qml @@ -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() } + } + + } + } + + } +} diff --git a/scripts/developer/utilities/render/highlight/qmldir b/scripts/developer/utilities/render/highlight/qmldir new file mode 100644 index 0000000000..31fc576bbe --- /dev/null +++ b/scripts/developer/utilities/render/highlight/qmldir @@ -0,0 +1 @@ +HighlightStyle 1.0 HighlightStyle.qml \ No newline at end of file diff --git a/scripts/developer/utilities/render/highlightPage/HighlightPage.qml b/scripts/developer/utilities/render/highlightPage/HighlightPage.qml deleted file mode 100644 index 5669f90628..0000000000 --- a/scripts/developer/utilities/render/highlightPage/HighlightPage.qml +++ /dev/null @@ -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 - } - } - } - } - } -} diff --git a/scripts/developer/utilities/render/highlightPage/qmldir b/scripts/developer/utilities/render/highlightPage/qmldir deleted file mode 100644 index bb3de24b84..0000000000 --- a/scripts/developer/utilities/render/highlightPage/qmldir +++ /dev/null @@ -1 +0,0 @@ -HighlightPage 1.0 HighlightPage.qml \ No newline at end of file