mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 02:03:57 +02:00
Merge pull request #11952 from samcake/light
Exposing multi highlight and selection feature to js api
This commit is contained in:
commit
0ff91e5926
28 changed files with 1200 additions and 519 deletions
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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@>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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@>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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" };
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
212
scripts/developer/utilities/lib/plotperf/Color.qml
Normal file
212
scripts/developer/utilities/lib/plotperf/Color.qml
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
PlotPerf 1.0 PlotPerf.qml
|
||||
PlotPerf 1.0 PlotPerf.qml
|
||||
Color 1.0 Color.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) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
105
scripts/developer/utilities/render/highlight/HighlightStyle.qml
Normal file
105
scripts/developer/utilities/render/highlight/HighlightStyle.qml
Normal 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() }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1
scripts/developer/utilities/render/highlight/qmldir
Normal file
1
scripts/developer/utilities/render/highlight/qmldir
Normal file
|
@ -0,0 +1 @@
|
|||
HighlightStyle 1.0 HighlightStyle.qml
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
HighlightPage 1.0 HighlightPage.qml
|
Loading…
Reference in a new issue