mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:24:00 +02:00
Extend Overlays API to allow for 3D UI panels.
Currently, only BillboardOverlays can be added to a panel, but more types of overlays will be supported in the future.
This commit is contained in:
parent
dff6b0a456
commit
173a79867c
8 changed files with 530 additions and 41 deletions
173
examples/example/ui/floatingUIExample.js
Normal file
173
examples/example/ui/floatingUIExample.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// floatingUI.js
|
||||
// examples/example/ui
|
||||
//
|
||||
// Created by Alexander Otavka
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
Script.include(["../../libraries/globals.js"]);
|
||||
|
||||
var BG_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/card-bg.svg";
|
||||
var RED_DOT_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/red-dot.svg";
|
||||
var BLUE_SQUARE_IMAGE_URL = HIFI_PUBLIC_BUCKET + "images/blue-square.svg";
|
||||
|
||||
var BLANK_ROTATION = { x: 0, y: 0, z: 0, w: 0 };
|
||||
|
||||
function isBlank(rotation) {
|
||||
return rotation.x == BLANK_ROTATION.x &&
|
||||
rotation.y == BLANK_ROTATION.y &&
|
||||
rotation.z == BLANK_ROTATION.z &&
|
||||
rotation.w == BLANK_ROTATION.w;
|
||||
}
|
||||
|
||||
var panel = Overlays.addPanel({
|
||||
offsetPosition: { x: 0, y: 0, z: 1 },
|
||||
});
|
||||
|
||||
var panelChildren = [];
|
||||
|
||||
var bg = Overlays.addOverlay("billboard", {
|
||||
url: BG_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
});
|
||||
panelChildren.push(bg);
|
||||
|
||||
var redDot = Overlays.addOverlay("billboard", {
|
||||
url: RED_DOT_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
offsetPosition: {
|
||||
x: -0.15,
|
||||
y: -0.15,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
panelChildren.push(redDot);
|
||||
|
||||
var redDot2 = Overlays.addOverlay("billboard", {
|
||||
url: RED_DOT_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
offsetPosition: {
|
||||
x: -0.15,
|
||||
y: 0,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
panelChildren.push(redDot2);
|
||||
|
||||
var blueSquare = Overlays.addOverlay("billboard", {
|
||||
url: BLUE_SQUARE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
y: 0,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
panelChildren.push(blueSquare);
|
||||
|
||||
var blueSquare2 = Overlays.addOverlay("billboard", {
|
||||
url: BLUE_SQUARE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
offsetPosition: {
|
||||
x: 0.1,
|
||||
y: 0.11,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
panelChildren.push(blueSquare2);
|
||||
|
||||
var blueSquare3 = Overlays.addOverlay("billboard", {
|
||||
url: BLUE_SQUARE_IMAGE_URL,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
isFacingAvatar: false,
|
||||
visible: true,
|
||||
alpha: 1.0,
|
||||
ignoreRayIntersection: false,
|
||||
attachedPanel: panel,
|
||||
offsetPosition: {
|
||||
x: -0.01,
|
||||
y: 0.11,
|
||||
z: -0.001
|
||||
}
|
||||
});
|
||||
panelChildren.push(blueSquare3);
|
||||
|
||||
Controller.mousePressEvent.connect(function(event) {
|
||||
if (event.isRightButton) {
|
||||
var newOffsetRotation = BLANK_ROTATION;
|
||||
if (isBlank(Overlays.getPanelProperty(panel, "offsetRotation"))) {
|
||||
newOffsetRotation = Quat.multiply(MyAvatar.orientation, { x: 0, y: 1, z: 0, w: 0 });
|
||||
}
|
||||
Overlays.editPanel(panel, {
|
||||
offsetRotation: newOffsetRotation
|
||||
});
|
||||
} else if (event.isLeftButton) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y)
|
||||
var rayPickResult = Overlays.findRayIntersection(pickRay);
|
||||
print(String(rayPickResult.overlayID));
|
||||
if (rayPickResult.intersects) {
|
||||
for (var i in panelChildren) {
|
||||
if (panelChildren[i] == rayPickResult.overlayID) {
|
||||
var oldPos = Overlays.getProperty(rayPickResult.overlayID, "offsetPosition");
|
||||
var newPos = {
|
||||
x: Number(oldPos.x),
|
||||
y: Number(oldPos.y),
|
||||
z: Number(oldPos.z) + 0.1
|
||||
}
|
||||
Overlays.editOverlay(rayPickResult.overlayID, { offsetPosition: newPos });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Overlays.deletePanel(panel);
|
||||
});
|
|
@ -36,6 +36,13 @@ BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
|
|||
{
|
||||
}
|
||||
|
||||
void BillboardOverlay::update(float deltatime) {
|
||||
glm::vec3 newPos = getTranslatedPosition(Application::getInstance()->getAvatarPosition());
|
||||
if (newPos != glm::vec3()) {
|
||||
setPosition(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
void BillboardOverlay::render(RenderArgs* args) {
|
||||
if (!_texture) {
|
||||
_isLoaded = true;
|
||||
|
@ -46,15 +53,17 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
glm::vec3 newPos = getTranslatedPosition(Application::getInstance()->getAvatarPosition());
|
||||
if (newPos != glm::vec3()) {
|
||||
setPosition(newPos);
|
||||
}
|
||||
|
||||
glm::quat rotation;
|
||||
if (_isFacingAvatar) {
|
||||
// LOL, quaternions are hard.
|
||||
// rotate about vertical to face the camera
|
||||
// glm::vec3 dPos = getPosition() - args->_viewFrustum->getPosition();
|
||||
// dPos = glm::normalize(dPos);
|
||||
// rotation = glm::quat(0, dPos.x, dPos.y, dPos.z);
|
||||
rotation = args->_viewFrustum->getOrientation();
|
||||
rotation *= glm::angleAxis(glm::pi<float>(), IDENTITY_UP);
|
||||
// float horizontal = glm::sqrt(dPos.x * dPos.x + dPos.y + dPos.y);
|
||||
// glm::vec3 zAxis = glm::vec3(0, 0, 1);
|
||||
// rotation = rotationBetween(zAxis, dPos);
|
||||
|
@ -70,9 +79,24 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
// rotation = yawQuat * pitchQuat;
|
||||
// glm::vec3 pitch = glm::vec3(dPos.x, dPos.y, 0);
|
||||
// rotation = glm::quat(glm::vec3(pitch, yaw, 0));
|
||||
// rotate about vertical to be perpendicular to the camera
|
||||
rotation = args->_viewFrustum->getOrientation();
|
||||
rotation *= glm::angleAxis(glm::pi<float>(), IDENTITY_UP);
|
||||
rotation *= getRotation();
|
||||
} else {
|
||||
rotation = getRotation();
|
||||
if (getAttachedPanel()) {
|
||||
rotation *= getAttachedPanel()->getOffsetRotation() *
|
||||
getAttachedPanel()->getFacingRotation();
|
||||
// if (getAttachedPanel()->getFacingRotation() != glm::quat(0, 0, 0, 0)) {
|
||||
// rotation *= getAttachedPanel()->getFacingRotation();
|
||||
// } else if (getAttachedPanel()->getOffsetRotation() != glm::quat(0, 0, 0, 0)) {
|
||||
// rotation *= getAttachedPanel()->getOffsetRotation();
|
||||
// } else {
|
||||
// rotation *= Application::getInstance()->getCamera()->getOrientation() *
|
||||
// glm::quat(0, 0, 1, 0);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
float imageWidth = _texture->getWidth();
|
||||
|
@ -114,7 +138,7 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
Transform transform = _transform;
|
||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||
transform.setRotation(rotation);
|
||||
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||
|
||||
|
@ -171,6 +195,21 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
if (isFacingAvatarValue.isValid()) {
|
||||
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
|
||||
}
|
||||
|
||||
QScriptValue offsetPosition = properties.property("offsetPosition");
|
||||
if (offsetPosition.isValid()) {
|
||||
QScriptValue x = offsetPosition.property("x");
|
||||
QScriptValue y = offsetPosition.property("y");
|
||||
QScriptValue z = offsetPosition.property("z");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
setOffsetPosition(newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue BillboardOverlay::getProperty(const QString& property) {
|
||||
|
@ -183,6 +222,9 @@ QScriptValue BillboardOverlay::getProperty(const QString& property) {
|
|||
if (property == "isFacingAvatar") {
|
||||
return _isFacingAvatar;
|
||||
}
|
||||
if (property == "offsetPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
|
||||
}
|
||||
|
||||
return Planar3DOverlay::getProperty(property);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
#include <TextureCache.h>
|
||||
|
||||
#include "Planar3DOverlay.h"
|
||||
#include "PanelAttachable.h"
|
||||
|
||||
class BillboardOverlay : public Planar3DOverlay {
|
||||
class BillboardOverlay : public Planar3DOverlay, public PanelAttachable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
BillboardOverlay();
|
||||
|
@ -24,6 +25,8 @@ public:
|
|||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
virtual void update(float deltatime);
|
||||
|
||||
// setters
|
||||
void setURL(const QString& url);
|
||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
||||
|
|
89
interface/src/ui/overlays/FloatingUIPanel.cpp
Normal file
89
interface/src/ui/overlays/FloatingUIPanel.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// FloatingUIPanel.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
|
||||
glm::quat FloatingUIPanel::getOffsetRotation() const {
|
||||
if (getActualOffsetRotation() == glm::quat(0, 0, 0, 0)) {
|
||||
return Application::getInstance()->getCamera()->getOrientation() * glm::quat(0, 0, 1, 0);
|
||||
}
|
||||
return getActualOffsetRotation();
|
||||
}
|
||||
|
||||
QScriptValue FloatingUIPanel::getProperty(const QString &property) {
|
||||
if (property == "offsetPosition") {
|
||||
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
|
||||
}
|
||||
if (property == "offsetRotation") {
|
||||
return quatToScriptValue(_scriptEngine, getActualOffsetRotation());
|
||||
}
|
||||
if (property == "facingRotation") {
|
||||
return quatToScriptValue(_scriptEngine, getFacingRotation());
|
||||
}
|
||||
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
void FloatingUIPanel::setProperties(const QScriptValue &properties) {
|
||||
QScriptValue offsetPosition = properties.property("offsetPosition");
|
||||
if (offsetPosition.isValid()) {
|
||||
QScriptValue x = offsetPosition.property("x");
|
||||
QScriptValue y = offsetPosition.property("y");
|
||||
QScriptValue z = offsetPosition.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newPosition;
|
||||
newPosition.x = x.toVariant().toFloat();
|
||||
newPosition.y = y.toVariant().toFloat();
|
||||
newPosition.z = z.toVariant().toFloat();
|
||||
setOffsetPosition(newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue offsetRotation = properties.property("offsetRotation");
|
||||
if (offsetRotation.isValid()) {
|
||||
QScriptValue x = offsetRotation.property("x");
|
||||
QScriptValue y = offsetRotation.property("y");
|
||||
QScriptValue z = offsetRotation.property("z");
|
||||
QScriptValue w = offsetRotation.property("w");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
setOffsetRotation(newRotation);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue facingRotation = properties.property("facingRotation");
|
||||
if (offsetRotation.isValid()) {
|
||||
QScriptValue x = facingRotation.property("x");
|
||||
QScriptValue y = facingRotation.property("y");
|
||||
QScriptValue z = facingRotation.property("z");
|
||||
QScriptValue w = facingRotation.property("w");
|
||||
|
||||
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||
glm::quat newRotation;
|
||||
newRotation.x = x.toVariant().toFloat();
|
||||
newRotation.y = y.toVariant().toFloat();
|
||||
newRotation.z = z.toVariant().toFloat();
|
||||
newRotation.w = w.toVariant().toFloat();
|
||||
setFacingRotation(newRotation);
|
||||
}
|
||||
}
|
||||
}
|
47
interface/src/ui/overlays/FloatingUIPanel.h
Normal file
47
interface/src/ui/overlays/FloatingUIPanel.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// FloatingUIPanel.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_FloatingUIPanel_h
|
||||
#define hifi_FloatingUIPanel_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QScriptValue>
|
||||
|
||||
class FloatingUIPanel : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef std::shared_ptr<FloatingUIPanel> Pointer;
|
||||
|
||||
QList<unsigned int> children;
|
||||
|
||||
void init(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
glm::vec3 getOffsetPosition() const { return _offsetPosition; }
|
||||
glm::quat getOffsetRotation() const;
|
||||
glm::quat getActualOffsetRotation() const { return _offsetRotation; }
|
||||
glm::quat getFacingRotation() const { return _facingRotation; }
|
||||
|
||||
void setOffsetPosition(glm::vec3 position) { _offsetPosition = position; };
|
||||
void setOffsetRotation(glm::quat rotation) { _offsetRotation = rotation; };
|
||||
void setFacingRotation(glm::quat rotation) { _facingRotation = rotation; };
|
||||
|
||||
QScriptValue getProperty(const QString& property);
|
||||
void setProperties(const QScriptValue& properties);
|
||||
|
||||
private:
|
||||
glm::vec3 _offsetPosition = glm::vec3(0, 0, 0);
|
||||
glm::quat _offsetRotation = glm::quat(0, 0, 0, 0);
|
||||
glm::quat _facingRotation = glm::quat(1, 0, 0, 0);
|
||||
QScriptEngine* _scriptEngine;
|
||||
};
|
||||
|
||||
#endif // hifi_FloatingUIPanel_h
|
|
@ -48,6 +48,7 @@ Overlays::~Overlays() {
|
|||
}
|
||||
_overlaysHUD.clear();
|
||||
_overlaysWorld.clear();
|
||||
_panels.clear();
|
||||
}
|
||||
|
||||
cleanupOverlaysToDelete();
|
||||
|
@ -124,11 +125,36 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
Overlay::Pointer Overlays::getOverlay(unsigned int id) const {
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
return _overlaysHUD[id];
|
||||
}
|
||||
if (_overlaysWorld.contains(id)) {
|
||||
return _overlaysWorld[id];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Overlays::setAttachedPanel(Overlay* overlay, unsigned int overlayId, const QScriptValue& property) {
|
||||
if (PanelAttachable* attachable = dynamic_cast<PanelAttachable*>(overlay)) {
|
||||
if (property.isValid()) {
|
||||
unsigned int attachedPanelId = property.toVariant().toUInt();
|
||||
FloatingUIPanel* panel = nullptr;
|
||||
if (_panels.contains(attachedPanelId)) {
|
||||
panel = _panels[attachedPanelId].get();
|
||||
panel->children.append(overlayId);
|
||||
attachable->setAttachedPanel(panel);
|
||||
} else {
|
||||
attachable->getAttachedPanel()->children.removeAll(overlayId);
|
||||
attachable->setAttachedPanel(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
|
||||
unsigned int thisID = 0;
|
||||
Overlay* thisOverlay = NULL;
|
||||
|
||||
bool created = true;
|
||||
|
||||
if (type == "image") {
|
||||
thisOverlay = new ImageOverlay();
|
||||
} else if (type == "text") {
|
||||
|
@ -153,16 +179,15 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
thisOverlay = new ModelOverlay();
|
||||
} else if (type == "billboard") {
|
||||
thisOverlay = new BillboardOverlay();
|
||||
} else {
|
||||
created = false;
|
||||
}
|
||||
|
||||
if (created) {
|
||||
if (thisOverlay) {
|
||||
thisOverlay->setProperties(properties);
|
||||
thisID = addOverlay(thisOverlay);
|
||||
unsigned int overlayId = addOverlay(thisOverlay);
|
||||
setAttachedPanel(thisOverlay, overlayId, properties.property("attachedPanel"));
|
||||
return overlayId;
|
||||
}
|
||||
|
||||
return thisID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(Overlay* overlay) {
|
||||
|
@ -189,17 +214,12 @@ unsigned int Overlays::addOverlay(Overlay* overlay) {
|
|||
} else {
|
||||
_overlaysHUD[thisID] = overlayPointer;
|
||||
}
|
||||
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
unsigned int Overlays::cloneOverlay(unsigned int id) {
|
||||
Overlay::Pointer thisOverlay = NULL;
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
thisOverlay = _overlaysWorld[id];
|
||||
}
|
||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
|
||||
if (thisOverlay) {
|
||||
return addOverlay(thisOverlay->createClone());
|
||||
|
@ -210,14 +230,8 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
|
|||
|
||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||
QWriteLocker lock(&_lock);
|
||||
Overlay::Pointer thisOverlay;
|
||||
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
thisOverlay = _overlaysWorld[id];
|
||||
}
|
||||
|
||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
if (thisOverlay) {
|
||||
if (thisOverlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(thisOverlay);
|
||||
|
@ -239,6 +253,8 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
|||
thisOverlay->setProperties(properties);
|
||||
}
|
||||
|
||||
setAttachedPanel(thisOverlay.get(), id, properties.property("attachedPanel"));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -302,15 +318,18 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
|
||||
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
|
||||
OverlayPropertyResult result;
|
||||
Overlay::Pointer thisOverlay;
|
||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
QReadLocker lock(&_lock);
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
thisOverlay = _overlaysWorld[id];
|
||||
}
|
||||
if (thisOverlay) {
|
||||
result.value = thisOverlay->getProperty(property);
|
||||
if (property == "attachedPanel") {
|
||||
if (FloatingUIPanel* panel = dynamic_cast<FloatingUIPanel*>(thisOverlay.get())) {
|
||||
result.value = _panels.key(FloatingUIPanel::Pointer(panel));
|
||||
} else {
|
||||
result.value = 0;
|
||||
}
|
||||
} else {
|
||||
result.value = thisOverlay->getProperty(property);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -456,12 +475,8 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
|
|||
|
||||
bool Overlays::isLoaded(unsigned int id) {
|
||||
QReadLocker lock(&_lock);
|
||||
Overlay::Pointer thisOverlay = NULL;
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
thisOverlay = _overlaysWorld[id];
|
||||
} else {
|
||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
if (!thisOverlay) {
|
||||
return false; // not found
|
||||
}
|
||||
return thisOverlay->isLoaded();
|
||||
|
@ -483,3 +498,55 @@ QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
|
|||
}
|
||||
return QSizeF(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
unsigned int Overlays::addPanel(FloatingUIPanel* panel) {
|
||||
QWriteLocker lock(&_lock);
|
||||
|
||||
FloatingUIPanel::Pointer panelPointer(panel);
|
||||
unsigned int thisID = _nextOverlayID;
|
||||
_nextOverlayID++;
|
||||
_panels[thisID] = panelPointer;
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
unsigned int Overlays::addPanel(const QScriptValue& properties) {
|
||||
FloatingUIPanel* panel = new FloatingUIPanel();
|
||||
panel->init(_scriptEngine);
|
||||
panel->setProperties(properties);
|
||||
return addPanel(panel);
|
||||
}
|
||||
|
||||
void Overlays::editPanel(unsigned int panelId, const QScriptValue& properties) {
|
||||
if (_panels.contains(panelId)) {
|
||||
_panels[panelId]->setProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
OverlayPropertyResult Overlays::getPanelProperty(unsigned int panelId, const QString& property) {
|
||||
OverlayPropertyResult result;
|
||||
if (_panels.contains(panelId)) {
|
||||
FloatingUIPanel::Pointer thisPanel = _panels[panelId];
|
||||
QReadLocker lock(&_lock);
|
||||
result.value = thisPanel->getProperty(property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Overlays::deletePanel(unsigned int panelId) {
|
||||
FloatingUIPanel::Pointer panelToDelete;
|
||||
|
||||
{
|
||||
QWriteLocker lock(&_lock);
|
||||
if (_panels.contains(panelId)) {
|
||||
panelToDelete = _panels.take(panelId);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (!panelToDelete->children.isEmpty()) {
|
||||
deleteOverlay(panelToDelete->children.takeLast());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#include "Overlay.h"
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
#include "PanelAttachable.h"
|
||||
|
||||
class PickRay;
|
||||
|
||||
class OverlayPropertyResult {
|
||||
|
@ -90,12 +93,33 @@ public slots:
|
|||
/// overlay; in meters if it is a 3D text overlay
|
||||
QSizeF textSize(unsigned int id, const QString& text) const;
|
||||
|
||||
|
||||
/// adds a panel that has already been created
|
||||
unsigned int addPanel(FloatingUIPanel* panel);
|
||||
|
||||
/// creates and adds a panel based on a set of properties
|
||||
unsigned int addPanel(const QScriptValue& properties);
|
||||
|
||||
/// edit the properties of a panel
|
||||
void editPanel(unsigned int panelId, const QScriptValue& properties);
|
||||
|
||||
/// get a property of a panel
|
||||
OverlayPropertyResult getPanelProperty(unsigned int panelId, const QString& property);
|
||||
|
||||
/// deletes a panel and all child overlays
|
||||
void deletePanel(unsigned int panelId);
|
||||
|
||||
private:
|
||||
void cleanupOverlaysToDelete();
|
||||
Overlay::Pointer getOverlay(unsigned int id) const;
|
||||
void setAttachedPanel(Overlay* overlay, unsigned int overlayId, const QScriptValue& property);
|
||||
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
||||
QMap<unsigned int, FloatingUIPanel::Pointer> _panels;
|
||||
QList<Overlay::Pointer> _overlaysToDelete;
|
||||
unsigned int _nextOverlayID;
|
||||
|
||||
QReadWriteLock _lock;
|
||||
QReadWriteLock _deleteLock;
|
||||
QScriptEngine* _scriptEngine;
|
||||
|
|
44
interface/src/ui/overlays/PanelAttachable.h
Normal file
44
interface/src/ui/overlays/PanelAttachable.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// PanelAttachable.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/1/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_PanelAttachable_h
|
||||
#define hifi_PanelAttachable_h
|
||||
|
||||
#include "FloatingUIPanel.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class PanelAttachable {
|
||||
public:
|
||||
glm::vec3 getOffsetPosition() const { return _offsetPosition; }
|
||||
void setOffsetPosition(glm::vec3 position) { _offsetPosition = position; }
|
||||
|
||||
FloatingUIPanel* getAttachedPanel() const { return _attachedPanel; }
|
||||
void setAttachedPanel(FloatingUIPanel* panel) { _attachedPanel = panel; }
|
||||
|
||||
glm::vec3 getTranslatedPosition(glm::vec3 avatarPosition) {
|
||||
if (getAttachedPanel()) {
|
||||
glm::vec3 totalOffsetPosition =
|
||||
getAttachedPanel()->getFacingRotation() * getOffsetPosition() +
|
||||
getAttachedPanel()->getOffsetPosition();
|
||||
|
||||
return getAttachedPanel()->getOffsetRotation() * totalOffsetPosition +
|
||||
avatarPosition;
|
||||
}
|
||||
return glm::vec3();
|
||||
}
|
||||
|
||||
private:
|
||||
FloatingUIPanel* _attachedPanel = nullptr;
|
||||
glm::vec3 _offsetPosition = glm::vec3(0, 0, 0);
|
||||
};
|
||||
|
||||
#endif // hifi_PanelAttachable_h
|
Loading…
Reference in a new issue