diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js new file mode 100644 index 0000000000..d297e2525d --- /dev/null +++ b/examples/overlaysExample.js @@ -0,0 +1,35 @@ +// +// overlaysExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/14/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Overlays class +// +// + + /* + _testOverlayA.init(_glWidget, QString("https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg"), + QRect(100,100,62,40), QRect(0,0,62,40)); + xColor red = { 255, 0, 0 }; + _testOverlayA.setBackgroundColor(red); + _testOverlayB.init(_glWidget, QString("https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg"), + QRect(170,100,62,40), QRect(0,80,62,40)); + */ + +var toolA = Overlays.addOverlay({ + x: 100, + y: 100, + width: 62, + height: 40, + subImage: { x: 0, y: 0, width: 62, height: 40 }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + backgroundColor: { red: 255, green: 0, blue: 255}, + alpha: 1.0 + }); + +function scriptEnding() { + Overlays.deleteOverlay(toolA); +} +Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e95f8b5f7f..4da0a35279 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -289,6 +289,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense)); checkVersion(); + + _overlays.init(_glWidget); // do this before scripts load + // do this as late as possible so that all required subsystems are inialized loadScripts(); @@ -1870,14 +1873,13 @@ void Application::init() { _audio.init(_glWidget); - _testOverlayA.init(_glWidget, QString("./resources/images/hifi-interface-tools.svg"), QRect(100,100,62,40), QRect(0,0,62,40)); - _testOverlayB.init(_glWidget, QString("./resources/images/hifi-interface-tools.svg"), QRect(170,100,62,40), QRect(0,80,62,40)); - _rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings); connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView())); connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); + + } void Application::closeMirrorView() { @@ -2986,8 +2988,7 @@ void Application::displayOverlay() { _pieMenu.render(); } - _testOverlayA.render(); // - _testOverlayB.render(); // + _overlays.render(); glPopMatrix(); } @@ -4066,6 +4067,8 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->registerGlobalObject("Camera", cameraScriptable); connect(scriptEngine, SIGNAL(finished(const QString&)), cameraScriptable, SLOT(deleteLater())); + scriptEngine->registerGlobalObject("Overlays", &_overlays); + QThread* workerThread = new QThread(this); // when the worker thread is started, call our engine's run.. diff --git a/interface/src/Application.h b/interface/src/Application.h index c8541aee29..b2a66d0bf8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,7 +70,7 @@ #include "FileLogger.h" #include "ParticleTreeRenderer.h" #include "ControllerScriptingInterface.h" -#include "ui/ImageOverlay.h" +#include "ui/Overlays.h" class QAction; @@ -490,8 +490,7 @@ private: TouchEvent _lastTouchEvent; - ImageOverlay _testOverlayA; - ImageOverlay _testOverlayB; + Overlays _overlays; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/ui/ImageOverlay.cpp b/interface/src/ui/ImageOverlay.cpp index 33c139089d..b85f05f557 100644 --- a/interface/src/ui/ImageOverlay.cpp +++ b/interface/src/ui/ImageOverlay.cpp @@ -1,3 +1,11 @@ +// +// ImageOverlay.cpp +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + + #include "ImageOverlay.h" #include @@ -7,17 +15,24 @@ ImageOverlay::ImageOverlay() : _parent(NULL), - _textureID(0) + _textureID(0), + _alpha(DEFAULT_ALPHA), + _backgroundColor(DEFAULT_BACKGROUND_COLOR), + _renderImage(false), + _textureBound(false) { -} +} -void ImageOverlay::init(QGLWidget* parent, const QString& filename, const QRect& drawAt, const QRect& fromImage) { +void ImageOverlay::init(QGLWidget* parent) { + qDebug() << "ImageOverlay::init() parent=" << parent; _parent = parent; - qDebug() << "ImageOverlay::init()... filename=" << filename; + + /* + qDebug() << "ImageOverlay::init()... url=" << url; _bounds = drawAt; _fromImage = fromImage; - _textureImage = QImage(filename); - _textureID = _parent->bindTexture(_textureImage); + setImageURL(url); + */ } @@ -28,17 +43,43 @@ ImageOverlay::~ImageOverlay() { } } +void ImageOverlay::setImageURL(const QUrl& url) { + // TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made? + QNetworkAccessManager* manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); + manager->get(QNetworkRequest(url)); +} + +void ImageOverlay::replyFinished(QNetworkReply* reply) { + qDebug() << "ImageOverlay::replyFinished() reply=" << reply; + // replace our byte array with the downloaded data + QByteArray rawData = reply->readAll(); + _textureImage.loadFromData(rawData); + _renderImage = true; + + // TODO: handle setting image multiple times, how do we manage releasing the bound texture + qDebug() << "ImageOverlay::replyFinished() about to call _parent->bindTexture(_textureImage)... _parent" << _parent; + + + qDebug() << "ImageOverlay::replyFinished _textureID=" << _textureID + << "_textureImage.width()=" << _textureImage.width() + << "_textureImage.height()=" << _textureImage.height(); +} void ImageOverlay::render() { -qDebug() << "ImageOverlay::render _textureID=" << _textureID << "_bounds=" << _bounds; + //qDebug() << "ImageOverlay::render _textureID=" << _textureID << "_bounds=" << _bounds; + + if (_renderImage && !_textureBound) { + _textureID = _parent->bindTexture(_textureImage); + _textureBound = true; + } - - bool renderImage = false; - if (renderImage) { + if (_renderImage) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, _textureID); } - glColor4f(1.0f, 0.0f, 0.0f, 0.7f); // ??? + const float MAX_COLOR = 255; + glColor4f((_backgroundColor.red / MAX_COLOR), (_backgroundColor.green / MAX_COLOR), (_backgroundColor.blue / MAX_COLOR), _alpha); float imageWidth = _textureImage.width(); float imageHeight = _textureImage.height(); @@ -47,23 +88,84 @@ qDebug() << "ImageOverlay::render _textureID=" << _textureID << "_bounds=" << _b float w = _fromImage.width() / imageWidth; // ?? is this what we want? not sure float h = _fromImage.height() / imageHeight; - qDebug() << "ImageOverlay::render x=" << x << "y=" << y << "w="< #include +#include +#include +#include #include +#include #include #include #include #include "InterfaceConfig.h" -//#include "Util.h" +const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 }; +const float DEFAULT_ALPHA = 0.7f; class ImageOverlay : QObject { Q_OBJECT @@ -34,9 +38,10 @@ class ImageOverlay : QObject { public: ImageOverlay(); ~ImageOverlay(); - void init(QGLWidget* parent, const QString& filename, const QRect& drawAt, const QRect& fromImage); + void init(QGLWidget* parent); void render(); +public slots: // getters int getX() const { return _bounds.x(); } int getY() const { return _bounds.y(); } @@ -47,19 +52,25 @@ public: const xColor& getBackgroundColor() const { return _backgroundColor; } float getAlpha() const { return _alpha; } const QUrl& getImageURL() const { return _imageURL; } + QScriptValue getProperties(); // setters - void setX(int x) { } - void setY(int y) { } - void setWidth(int width) { } - void setHeight(int height) { } - void setBounds(const QRect& bounds) { } - void setClipFromSource(const QRect& bounds) { } - void setBackgroundColor(const xColor& color) { } - void setAlpha(float) { } - void setImageURL(const QUrl& ) { } + void setX(int x) { _bounds.setX(x); } + void setY(int y) { _bounds.setY(y); } + void setWidth(int width) { _bounds.setWidth(width); } + void setHeight(int height) { _bounds.setHeight(height); } + void setBounds(const QRect& bounds) { _bounds = bounds; } + void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } + void setBackgroundColor(const xColor& color) { _backgroundColor = color; } + void setAlpha(float alpha) { _alpha = alpha; } + void setImageURL(const QUrl& url); + void setProperties(const QScriptValue& properties); + +private slots: + void replyFinished(QNetworkReply* reply); // we actually want to hide this... private: + QUrl _imageURL; QGLWidget* _parent; QImage _textureImage; @@ -68,6 +79,9 @@ private: QRect _fromImage; // where from in the image to sample float _alpha; xColor _backgroundColor; + bool _renderImage; + bool _textureBound; }; + #endif /* defined(__interface__ImageOverlay__) */ diff --git a/interface/src/ui/Overlays.cpp b/interface/src/ui/Overlays.cpp new file mode 100644 index 0000000000..438e94ad60 --- /dev/null +++ b/interface/src/ui/Overlays.cpp @@ -0,0 +1,66 @@ +// +// Overlays.cpp +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + + +#include "Overlays.h" + +unsigned int Overlays::_nextOverlayID = 0; + +Overlays::Overlays() { +} + +Overlays::~Overlays() { +} + +void Overlays::init(QGLWidget* parent) { + qDebug() << "Overlays::init() parent=" << parent; + _parent = parent; +} + +void Overlays::render() { + foreach(ImageOverlay* thisOverlay, _imageOverlays) { + thisOverlay->render(); + } +} + +// TODO: make multi-threaded safe +unsigned int Overlays::addOverlay(const QScriptValue& properties) { + unsigned int thisID = _nextOverlayID; + _nextOverlayID++; + ImageOverlay* thisOverlay = new ImageOverlay(); + thisOverlay->init(_parent); + thisOverlay->setProperties(properties); + _imageOverlays[thisID] = thisOverlay; + return thisID; +} + +QScriptValue Overlays::getOverlayProperties(unsigned int id) { + if (!_imageOverlays.contains(id)) { + return QScriptValue(); + } + ImageOverlay* thisOverlay = _imageOverlays[id]; + return thisOverlay->getProperties(); +} + +// TODO: make multi-threaded safe +bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { + if (!_imageOverlays.contains(id)) { + return false; + } + ImageOverlay* thisOverlay = _imageOverlays[id]; + thisOverlay->setProperties(properties); + return true; +} + +// TODO: make multi-threaded safe +void Overlays::deleteOverlay(unsigned int id) { + if (_imageOverlays.contains(id)) { + _imageOverlays.erase(_imageOverlays.find(id)); + + } +} + diff --git a/interface/src/ui/Overlays.h b/interface/src/ui/Overlays.h new file mode 100644 index 0000000000..8b9f6eb8be --- /dev/null +++ b/interface/src/ui/Overlays.h @@ -0,0 +1,58 @@ +// +// Overlays.h +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Overlays__ +#define __interface__Overlays__ + +/** +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "InterfaceConfig.h" +**/ + +#include + +#include "ImageOverlay.h" + +class Overlays : public QObject { + Q_OBJECT +public: + Overlays(); + ~Overlays(); + void init(QGLWidget* parent); + void render(); + +public slots: + /// adds an overlay with the specific properties + unsigned int addOverlay(const QScriptValue& properties); + + /// gets the current overlay properties for a specific overlay + QScriptValue getOverlayProperties(unsigned int id); + + /// edits an overlay updating only the included properties, will return the identified OverlayID in case of + /// successful edit, if the input id is for an unknown overlay this function will have no effect + bool editOverlay(unsigned int id, const QScriptValue& properties); + + /// deletes a particle + void deleteOverlay(unsigned int id); + +private: + QMap _imageOverlays; + static unsigned int _nextOverlayID; + QGLWidget* _parent; +}; + + +#endif /* defined(__interface__Overlays__) */ diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 89bf5ceb62..1ed82564b6 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -23,7 +23,6 @@ OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packe } OctreeScriptingInterface::~OctreeScriptingInterface() { -qDebug() << "OctreeScriptingInterface::~OctreeScriptingInterface() this=" << this; cleanupManagedObjects(); }