first working version of scriptable Overlays

This commit is contained in:
ZappoMan 2014-02-14 15:37:47 -08:00
parent 8e284a55b1
commit 2eac9c293f
8 changed files with 314 additions and 38 deletions

View file

@ -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);

View file

@ -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..

View file

@ -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__) */

View file

@ -1,3 +1,11 @@
//
// ImageOverlay.cpp
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#include "ImageOverlay.h"
#include <QSvgRenderer>
@ -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="<<w << "h="<<h << "(1.0f - y)=" << (1.0f - y);
//qDebug() << "ImageOverlay::render x=" << x << "y=" << y << "w="<<w << "h="<<h << "(1.0f - y)=" << (1.0f - y);
glBegin(GL_QUADS);
//glTexCoord2f(x, 1.0f - y);
if (_renderImage) {
glTexCoord2f(x, 1.0f - y);
}
glVertex2f(_bounds.left(), _bounds.top());
//glTexCoord2f(x + w, 1.0f - y);
if (_renderImage) {
glTexCoord2f(x + w, 1.0f - y);
}
glVertex2f(_bounds.right(), _bounds.top());
//glTexCoord2f(x + w, 1.0f - (y + h));
if (_renderImage) {
glTexCoord2f(x + w, 1.0f - (y + h));
}
glVertex2f(_bounds.right(), _bounds.bottom());
//glTexCoord2f(x, 1.0f - (y + h));
if (_renderImage) {
glTexCoord2f(x, 1.0f - (y + h));
}
glVertex2f(_bounds.left(), _bounds.bottom());
glEnd();
if (renderImage) {
if (_renderImage) {
glDisable(GL_TEXTURE_2D);
}
}
// TODO: handle only setting the included values...
QScriptValue ImageOverlay::getProperties() {
return QScriptValue();
}
// TODO: handle only setting the included values...
void ImageOverlay::setProperties(const QScriptValue& properties) {
QScriptValue bounds = properties.property("bounds");
if (bounds.isValid()) {
QRect boundsRect;
boundsRect.setX(bounds.property("x").toVariant().toInt());
boundsRect.setY(bounds.property("y").toVariant().toInt());
boundsRect.setWidth(bounds.property("width").toVariant().toInt());
boundsRect.setHeight(bounds.property("height").toVariant().toInt());
setBounds(boundsRect);
} else {
setX(properties.property("x").toVariant().toInt());
setY(properties.property("y").toVariant().toInt());
setWidth(properties.property("width").toVariant().toInt());
setHeight(properties.property("height").toVariant().toInt());
}
QScriptValue subImageBounds = properties.property("subImage");
if (subImageBounds.isValid()) {
QRect subImageRect;
subImageRect.setX(subImageBounds.property("x").toVariant().toInt());
subImageRect.setY(subImageBounds.property("y").toVariant().toInt());
subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt());
subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt());
setClipFromSource(subImageRect);
qDebug() << "set subImage to " << getClipFromSource();
}
QScriptValue imageURL = properties.property("imageURL");
if (imageURL.isValid()) {
setImageURL(imageURL.toVariant().toString());
}
QScriptValue color = properties.property("backgroundColor");
if (color.isValid()) {
QScriptValue red = color.property("red");
QScriptValue green = color.property("green");
QScriptValue blue = color.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_backgroundColor.red = red.toVariant().toInt();
_backgroundColor.green = green.toVariant().toInt();
_backgroundColor.blue = blue.toVariant().toInt();
}
}
setAlpha(properties.property("alpha").toVariant().toFloat());
}

View file

@ -8,17 +8,21 @@
#ifndef __interface__ImageOverlay__
#define __interface__ImageOverlay__
#include <QImage>
#include <QGLWidget>
#include <QImage>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRect>
#include <QScriptValue>
#include <QString>
#include <QUrl>
#include <SharedUtil.h>
#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__) */

View file

@ -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));
}
}

View file

@ -0,0 +1,58 @@
//
// Overlays.h
// interface
//
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__Overlays__
#define __interface__Overlays__
/**
#include <QGLWidget>
#include <QImage>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRect>
#include <QString>
#include <QUrl>
#include <SharedUtil.h>
#include "InterfaceConfig.h"
**/
#include <QScriptValue>
#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<unsigned int, ImageOverlay*> _imageOverlays;
static unsigned int _nextOverlayID;
QGLWidget* _parent;
};
#endif /* defined(__interface__Overlays__) */

View file

@ -23,7 +23,6 @@ OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packe
}
OctreeScriptingInterface::~OctreeScriptingInterface() {
qDebug() << "OctreeScriptingInterface::~OctreeScriptingInterface() this=" << this;
cleanupManagedObjects();
}