diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 39b8892f13..563d90f6b9 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -30,6 +30,7 @@ #include "Grid3DOverlay.h" #include "TextOverlay.h" #include "Text3DOverlay.h" +#include "Web3DOverlay.h" Overlays::Overlays() : _nextOverlayID(1) { @@ -170,6 +171,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope thisOverlay = std::make_shared(Application::getInstance()->getEntityClipboardRenderer()); } else if (type == ModelOverlay::TYPE) { thisOverlay = std::make_shared(); + } else if (type == Web3DOverlay::TYPE) { + thisOverlay = std::make_shared(); } if (thisOverlay) { diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp new file mode 100644 index 0000000000..c173c5927f --- /dev/null +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -0,0 +1,163 @@ +// +// Web3DOverlay.cpp +// +// +// Created by Clement on 7/1/14. +// Modified and renamed by Zander Otavka on 8/4/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 "Web3DOverlay.h" + +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// #include "Application.h" +// #include "GeometryUtil.h" + +static const float DPI = 30.47f; +static const float METERS_TO_INCHES = 39.3701f; +static const float INCHES_TO_METERS = 1.0f / 39.3701f; + +QString const Web3DOverlay::TYPE = "web3d"; + +Web3DOverlay::Web3DOverlay() : _dpi(DPI) { } + +Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) : + Billboard3DOverlay(Web3DOverlay), + _url(Web3DOverlay->_url), + _dpi(Web3DOverlay->_dpi), + _resolution(Web3DOverlay->_resolution) +{ +} + +Web3DOverlay::~Web3DOverlay() { + if (_webSurface) { + _webSurface->pause(); + _webSurface->disconnect(_connection); + // The lifetime of the QML surface MUST be managed by the main thread + // Additionally, we MUST use local variables copied by value, rather than + // member variables, since they would implicitly refer to a this that + // is no longer valid + auto webSurface = _webSurface; + AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] { + webSurface->deleteLater(); + }); + } +} + +void Web3DOverlay::update(float deltatime) { + applyTransformTo(_transform); +} + +void Web3DOverlay::render(RenderArgs* args) { + if (!_visible || !getParentVisible()) { + return; + } + + QOpenGLContext * currentContext = QOpenGLContext::currentContext(); + QSurface * currentSurface = currentContext->surface(); + if (!_webSurface) { + _webSurface = new OffscreenQmlSurface(); + _webSurface->create(currentContext); + _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); + _webSurface->load("WebEntity.qml"); + _webSurface->resume(); + _webSurface->getRootItem()->setProperty("url", _url); + _webSurface->resize(QSize(_resolution.x, _resolution.y)); + _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { + _texture = textureId; + }); + currentContext->makeCurrent(currentSurface); + } + + vec2 size = _resolution / _dpi * INCHES_TO_METERS; + vec2 halfSize = size / 2.0f; + vec4 color(toGlm(getColor()), getAlpha()); + + applyTransformTo(_transform, true); + Transform transform = _transform; + if (glm::length2(getDimensions()) != 1.0f) { + transform.postScale(vec3(getDimensions(), 1.0f)); + } + + Q_ASSERT(args->_batch); + gpu::Batch& batch = *args->_batch; + if (_texture) { + batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); + } else { + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); + } + + batch.setModelTransform(transform); + DependencyManager::get()->bindSimpleProgram(batch, true, false, false, true); + DependencyManager::get()->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); + batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me +} + +void Web3DOverlay::setProperties(const QScriptValue &properties) { + Billboard3DOverlay::setProperties(properties); + + QScriptValue urlValue = properties.property("url"); + if (urlValue.isValid()) { + QString newURL = urlValue.toVariant().toString(); + if (newURL != _url) { + setURL(newURL); + } + } + + QScriptValue resolution = properties.property("resolution"); + if (resolution.isValid()) { + vec2FromScriptValue(resolution, _resolution); + } + + + QScriptValue dpi = properties.property("dpi"); + if (dpi.isValid()) { + _dpi = dpi.toVariant().toFloat(); + } +} + +QScriptValue Web3DOverlay::getProperty(const QString& property) { + if (property == "url") { + return _url; + } + if (property == "dpi") { + return _dpi; + } + return Billboard3DOverlay::getProperty(property); +} + +void Web3DOverlay::setURL(const QString& url) { + _url = url; + _isLoaded = false; +} + +bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) { + //// Make sure position and rotation is updated. + applyTransformTo(_transform, true); + vec2 size = _resolution / _dpi * INCHES_TO_METERS * vec2(getDimensions()); + // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. + return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), size, distance); +} + +Web3DOverlay* Web3DOverlay::createClone() const { + return new Web3DOverlay(this); +} diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h new file mode 100644 index 0000000000..59c8fae0fe --- /dev/null +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -0,0 +1,50 @@ +// +// Created by Bradley Austin Davis on 2015/08/31 +// 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 +// + +#ifndef hifi_Web3DOverlay_h +#define hifi_Web3DOverlay_h + +#include "Billboard3DOverlay.h" + +class OffscreenQmlSurface; + +class Web3DOverlay : public Billboard3DOverlay { + Q_OBJECT + +public: + static QString const TYPE; + virtual QString getType() const { return TYPE; } + + Web3DOverlay(); + Web3DOverlay(const Web3DOverlay* Web3DOverlay); + virtual ~Web3DOverlay(); + + virtual void render(RenderArgs* args); + + virtual void update(float deltatime); + + // setters + void setURL(const QString& url); + + virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); + + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + + virtual Web3DOverlay* createClone() const; + +private: + OffscreenQmlSurface* _webSurface{ nullptr }; + QMetaObject::Connection _connection; + uint32_t _texture{ 0 }; + QString _url; + float _dpi; + vec2 _resolution{ 640, 480 }; +}; + +#endif // hifi_Web3DOverlay_h