mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-22 19:34:20 +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) {
|
void BillboardOverlay::render(RenderArgs* args) {
|
||||||
if (!_texture) {
|
if (!_texture) {
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
|
@ -46,15 +53,17 @@ void BillboardOverlay::render(RenderArgs* args) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 newPos = getTranslatedPosition(Application::getInstance()->getAvatarPosition());
|
||||||
|
if (newPos != glm::vec3()) {
|
||||||
|
setPosition(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
if (_isFacingAvatar) {
|
if (_isFacingAvatar) {
|
||||||
// LOL, quaternions are hard.
|
// LOL, quaternions are hard.
|
||||||
// rotate about vertical to face the camera
|
|
||||||
// glm::vec3 dPos = getPosition() - args->_viewFrustum->getPosition();
|
// glm::vec3 dPos = getPosition() - args->_viewFrustum->getPosition();
|
||||||
// dPos = glm::normalize(dPos);
|
// dPos = glm::normalize(dPos);
|
||||||
// rotation = glm::quat(0, dPos.x, dPos.y, dPos.z);
|
// 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);
|
// float horizontal = glm::sqrt(dPos.x * dPos.x + dPos.y + dPos.y);
|
||||||
// glm::vec3 zAxis = glm::vec3(0, 0, 1);
|
// glm::vec3 zAxis = glm::vec3(0, 0, 1);
|
||||||
// rotation = rotationBetween(zAxis, dPos);
|
// rotation = rotationBetween(zAxis, dPos);
|
||||||
|
@ -70,9 +79,24 @@ void BillboardOverlay::render(RenderArgs* args) {
|
||||||
// rotation = yawQuat * pitchQuat;
|
// rotation = yawQuat * pitchQuat;
|
||||||
// glm::vec3 pitch = glm::vec3(dPos.x, dPos.y, 0);
|
// glm::vec3 pitch = glm::vec3(dPos.x, dPos.y, 0);
|
||||||
// rotation = glm::quat(glm::vec3(pitch, yaw, 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();
|
rotation *= getRotation();
|
||||||
} else {
|
} else {
|
||||||
rotation = getRotation();
|
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();
|
float imageWidth = _texture->getWidth();
|
||||||
|
@ -114,7 +138,7 @@ void BillboardOverlay::render(RenderArgs* args) {
|
||||||
Transform transform = _transform;
|
Transform transform = _transform;
|
||||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||||
transform.setRotation(rotation);
|
transform.setRotation(rotation);
|
||||||
|
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||||
|
|
||||||
|
@ -171,6 +195,21 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||||
if (isFacingAvatarValue.isValid()) {
|
if (isFacingAvatarValue.isValid()) {
|
||||||
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
|
_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) {
|
QScriptValue BillboardOverlay::getProperty(const QString& property) {
|
||||||
|
@ -183,6 +222,9 @@ QScriptValue BillboardOverlay::getProperty(const QString& property) {
|
||||||
if (property == "isFacingAvatar") {
|
if (property == "isFacingAvatar") {
|
||||||
return _isFacingAvatar;
|
return _isFacingAvatar;
|
||||||
}
|
}
|
||||||
|
if (property == "offsetPosition") {
|
||||||
|
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
|
||||||
|
}
|
||||||
|
|
||||||
return Planar3DOverlay::getProperty(property);
|
return Planar3DOverlay::getProperty(property);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,9 @@
|
||||||
#include <TextureCache.h>
|
#include <TextureCache.h>
|
||||||
|
|
||||||
#include "Planar3DOverlay.h"
|
#include "Planar3DOverlay.h"
|
||||||
|
#include "PanelAttachable.h"
|
||||||
|
|
||||||
class BillboardOverlay : public Planar3DOverlay {
|
class BillboardOverlay : public Planar3DOverlay, public PanelAttachable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
BillboardOverlay();
|
BillboardOverlay();
|
||||||
|
@ -24,6 +25,8 @@ public:
|
||||||
|
|
||||||
virtual void render(RenderArgs* args);
|
virtual void render(RenderArgs* args);
|
||||||
|
|
||||||
|
virtual void update(float deltatime);
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setURL(const QString& url);
|
void setURL(const QString& url);
|
||||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
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();
|
_overlaysHUD.clear();
|
||||||
_overlaysWorld.clear();
|
_overlaysWorld.clear();
|
||||||
|
_panels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupOverlaysToDelete();
|
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 Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
|
||||||
unsigned int thisID = 0;
|
|
||||||
Overlay* thisOverlay = NULL;
|
Overlay* thisOverlay = NULL;
|
||||||
|
|
||||||
bool created = true;
|
|
||||||
if (type == "image") {
|
if (type == "image") {
|
||||||
thisOverlay = new ImageOverlay();
|
thisOverlay = new ImageOverlay();
|
||||||
} else if (type == "text") {
|
} else if (type == "text") {
|
||||||
|
@ -153,16 +179,15 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
||||||
thisOverlay = new ModelOverlay();
|
thisOverlay = new ModelOverlay();
|
||||||
} else if (type == "billboard") {
|
} else if (type == "billboard") {
|
||||||
thisOverlay = new BillboardOverlay();
|
thisOverlay = new BillboardOverlay();
|
||||||
} else {
|
|
||||||
created = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (created) {
|
if (thisOverlay) {
|
||||||
thisOverlay->setProperties(properties);
|
thisOverlay->setProperties(properties);
|
||||||
thisID = addOverlay(thisOverlay);
|
unsigned int overlayId = addOverlay(thisOverlay);
|
||||||
|
setAttachedPanel(thisOverlay, overlayId, properties.property("attachedPanel"));
|
||||||
|
return overlayId;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return thisID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Overlays::addOverlay(Overlay* overlay) {
|
unsigned int Overlays::addOverlay(Overlay* overlay) {
|
||||||
|
@ -189,17 +214,12 @@ unsigned int Overlays::addOverlay(Overlay* overlay) {
|
||||||
} else {
|
} else {
|
||||||
_overlaysHUD[thisID] = overlayPointer;
|
_overlaysHUD[thisID] = overlayPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return thisID;
|
return thisID;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Overlays::cloneOverlay(unsigned int id) {
|
unsigned int Overlays::cloneOverlay(unsigned int id) {
|
||||||
Overlay::Pointer thisOverlay = NULL;
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (_overlaysHUD.contains(id)) {
|
|
||||||
thisOverlay = _overlaysHUD[id];
|
|
||||||
} else if (_overlaysWorld.contains(id)) {
|
|
||||||
thisOverlay = _overlaysWorld[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
return addOverlay(thisOverlay->createClone());
|
return addOverlay(thisOverlay->createClone());
|
||||||
|
@ -210,14 +230,8 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
|
||||||
|
|
||||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||||
QWriteLocker lock(&_lock);
|
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) {
|
||||||
if (thisOverlay->is3D()) {
|
if (thisOverlay->is3D()) {
|
||||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(thisOverlay);
|
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(thisOverlay);
|
||||||
|
@ -239,6 +253,8 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||||
thisOverlay->setProperties(properties);
|
thisOverlay->setProperties(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAttachedPanel(thisOverlay.get(), id, properties.property("attachedPanel"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -302,15 +318,18 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||||
|
|
||||||
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
|
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
|
||||||
OverlayPropertyResult result;
|
OverlayPropertyResult result;
|
||||||
Overlay::Pointer thisOverlay;
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
QReadLocker lock(&_lock);
|
QReadLocker lock(&_lock);
|
||||||
if (_overlaysHUD.contains(id)) {
|
|
||||||
thisOverlay = _overlaysHUD[id];
|
|
||||||
} else if (_overlaysWorld.contains(id)) {
|
|
||||||
thisOverlay = _overlaysWorld[id];
|
|
||||||
}
|
|
||||||
if (thisOverlay) {
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -456,12 +475,8 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
|
||||||
|
|
||||||
bool Overlays::isLoaded(unsigned int id) {
|
bool Overlays::isLoaded(unsigned int id) {
|
||||||
QReadLocker lock(&_lock);
|
QReadLocker lock(&_lock);
|
||||||
Overlay::Pointer thisOverlay = NULL;
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (_overlaysHUD.contains(id)) {
|
if (!thisOverlay) {
|
||||||
thisOverlay = _overlaysHUD[id];
|
|
||||||
} else if (_overlaysWorld.contains(id)) {
|
|
||||||
thisOverlay = _overlaysWorld[id];
|
|
||||||
} else {
|
|
||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
return thisOverlay->isLoaded();
|
return thisOverlay->isLoaded();
|
||||||
|
@ -483,3 +498,55 @@ QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
|
||||||
}
|
}
|
||||||
return QSizeF(0.0f, 0.0f);
|
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 "Overlay.h"
|
||||||
|
|
||||||
|
#include "FloatingUIPanel.h"
|
||||||
|
#include "PanelAttachable.h"
|
||||||
|
|
||||||
class PickRay;
|
class PickRay;
|
||||||
|
|
||||||
class OverlayPropertyResult {
|
class OverlayPropertyResult {
|
||||||
|
@ -90,12 +93,33 @@ public slots:
|
||||||
/// overlay; in meters if it is a 3D text overlay
|
/// overlay; in meters if it is a 3D text overlay
|
||||||
QSizeF textSize(unsigned int id, const QString& text) const;
|
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:
|
private:
|
||||||
void cleanupOverlaysToDelete();
|
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> _overlaysHUD;
|
||||||
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
||||||
|
QMap<unsigned int, FloatingUIPanel::Pointer> _panels;
|
||||||
QList<Overlay::Pointer> _overlaysToDelete;
|
QList<Overlay::Pointer> _overlaysToDelete;
|
||||||
unsigned int _nextOverlayID;
|
unsigned int _nextOverlayID;
|
||||||
|
|
||||||
QReadWriteLock _lock;
|
QReadWriteLock _lock;
|
||||||
QReadWriteLock _deleteLock;
|
QReadWriteLock _deleteLock;
|
||||||
QScriptEngine* _scriptEngine;
|
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