From 5abf908874cfcecf08d8c86801fc7b6055475585 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 16 Feb 2014 11:36:06 -0800 Subject: [PATCH] added 3D cube overlay support --- examples/overlaysExample.js | 66 ++++++++++++++------ interface/src/Application.cpp | 5 +- interface/src/ui/Cube3DOverlay.cpp | 98 ++++++++++++++++++++++++++++++ interface/src/ui/Cube3DOverlay.h | 57 +++++++++++++++++ interface/src/ui/ImageOverlay.cpp | 4 +- interface/src/ui/ImageOverlay.h | 3 +- interface/src/ui/Overlay.cpp | 10 +-- interface/src/ui/Overlay.h | 6 +- interface/src/ui/Overlay2D.cpp | 63 +++++++++++++++++++ interface/src/ui/Overlay2D.h | 51 ++++++++++++++++ interface/src/ui/Overlays.cpp | 67 ++++++++++++++------ interface/src/ui/Overlays.h | 6 +- interface/src/ui/TextOverlay.cpp | 4 +- interface/src/ui/TextOverlay.h | 3 +- 14 files changed, 389 insertions(+), 54 deletions(-) create mode 100644 interface/src/ui/Cube3DOverlay.cpp create mode 100644 interface/src/ui/Cube3DOverlay.h create mode 100644 interface/src/ui/Overlay2D.cpp create mode 100644 interface/src/ui/Overlay2D.h diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index 79cd65df68..501f9a248e 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -39,7 +39,7 @@ for (s = 0; s < numberOfSwatches; s++) { height: 54, subImage: { x: imageFromX, y: imageFromY, width: 30, height: 54 }, imageURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/testing-swatches.svg", - backgroundColor: swatchColors[s], + color: swatchColors[s], alpha: 1 }); } @@ -49,11 +49,10 @@ var text = Overlays.addOverlay("text", { y: 100, width: 150, height: 50, - backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 0, green: 0, blue: 0}, textColor: { red: 255, green: 0, blue: 0}, topMargin: 4, leftMargin: 4, - alpha: 0.7, text: "Here is some text.\nAnd a second line." }); @@ -64,8 +63,7 @@ var toolA = Overlays.addOverlay("image", { 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: 255, blue: 255}, - alpha: 0.7, + color: { red: 255, green: 255, blue: 255}, visible: false }); @@ -73,7 +71,7 @@ var slider = Overlays.addOverlay("image", { // alternate form of expressing bounds bounds: { x: 100, y: 300, width: 158, height: 35}, imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/slider.png", - backgroundColor: { red: 255, green: 255, blue: 255}, + color: { red: 255, green: 255, blue: 255}, alpha: 1 }); @@ -86,22 +84,39 @@ var thumb = Overlays.addOverlay("image", { width: 18, height: 17, imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", - backgroundColor: { red: 255, green: 255, blue: 255}, + color: { red: 255, green: 255, blue: 255}, alpha: 1 }); - -// 270x 109 -// 109... 109/2 = 54,1,54 -// 270... 39 to 66 = 28 x 9 swatches with -// unselected: -// 38,0,28,54 -// selected: -// 38,55,28,54 -//http://highfidelity-public.s3-us-west-1.amazonaws.com/images/swatches.svg -// 123456789*123456789*123456789* -// 0123456789*123456789*123456789* +// our 3D cube that moves around... +var cubePosition = { x: 2, y: 0, z: 2 }; +var cubeSize = 5; +var cubeMove = 0.1; +var minCubeX = 1; +var maxCubeX = 20; +var solidCubePosition = { x: 0, y: 5, z: 0 }; +var solidCubeSize = 2; +var minSolidCubeX = 0; +var maxSolidCubeX = 10; +var solidCubeMove = 0.05; + +var cube = Overlays.addOverlay("cube", { + position: cubePosition, + size: cubeSize, + color: { red: 255, green: 0, blue: 0}, + alpha: 1, + solid: false + }); + +var solidCube = Overlays.addOverlay("cube", { + position: solidCubePosition, + size: solidCubeSize, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + solid: true + }); + function scriptEnding() { Overlays.deleteOverlay(toolA); @@ -127,6 +142,21 @@ function update() { } Overlays.editOverlay(toolA, { visible: toolAVisible } ); } + + // move our 3D cube + cubePosition.x += cubeMove; + cubePosition.z += cubeMove; + if (cubePosition.x > maxCubeX || cubePosition.x < minCubeX) { + cubeMove = cubeMove * -1; + } + Overlays.editOverlay(cube, { position: cubePosition } ); + + solidCubePosition.x += solidCubeMove; + solidCubePosition.z += solidCubeMove; + if (solidCubePosition.x > maxSolidCubeX || solidCubePosition.x < minSolidCubeX) { + solidCubeMove = solidCubeMove * -1; + } + Overlays.editOverlay(solidCube, { position: solidCubePosition } ); } Script.willSendVisualDataCallback.connect(update); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4da0a35279..521757abab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2842,6 +2842,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // give external parties a change to hook in emit renderingInWorldInterface(); + + // render JS/scriptable overlays + _overlays.render3D(); } } @@ -2988,7 +2991,7 @@ void Application::displayOverlay() { _pieMenu.render(); } - _overlays.render(); + _overlays.render2D(); glPopMatrix(); } diff --git a/interface/src/ui/Cube3DOverlay.cpp b/interface/src/ui/Cube3DOverlay.cpp new file mode 100644 index 0000000000..dda1f64295 --- /dev/null +++ b/interface/src/ui/Cube3DOverlay.cpp @@ -0,0 +1,98 @@ +// +// Cube3DOverlay.cpp +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include +#include + +#include "Cube3DOverlay.h" +#include "TextRenderer.h" + +const glm::vec3 DEFAULT_POSITION = glm::vec3(0.0f, 0.0f, 0.0f); +const float DEFAULT_SIZE = 1.0f; +const float DEFAULT_LINE_WIDTH = 1.0f; +const bool DEFAULT_isSolid = false; + +Cube3DOverlay::Cube3DOverlay() : + _position(DEFAULT_POSITION), + _size(DEFAULT_SIZE), + _lineWidth(DEFAULT_LINE_WIDTH), + _isSolid(DEFAULT_isSolid) +{ +} + +Cube3DOverlay::~Cube3DOverlay() { +} + +void Cube3DOverlay::render() { + if (!_visible) { + return; // do nothing if we're not visible + } + + const float MAX_COLOR = 255; + glColor4f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, _alpha); + + + glDisable(GL_LIGHTING); + glPushMatrix(); + glTranslatef(_position.x + _size * 0.5f, + _position.y + _size * 0.5f, + _position.z + _size * 0.5f); + glLineWidth(_lineWidth); + if (_isSolid) { + glutSolidCube(_size); + } else { + glutWireCube(_size); + } + glPopMatrix(); + +} + +void Cube3DOverlay::setProperties(const QScriptValue& properties) { + Overlay::setProperties(properties); + + QScriptValue position = properties.property("position"); + if (position.isValid()) { + QScriptValue x = position.property("x"); + QScriptValue y = position.property("y"); + QScriptValue z = position.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(); + setPosition(newPosition); + } + } + + if (properties.property("size").isValid()) { + setSize(properties.property("size").toVariant().toFloat()); + } + + if (properties.property("lineWidth").isValid()) { + setLineWidth(properties.property("lineWidth").toVariant().toFloat()); + } + + if (properties.property("isSolid").isValid()) { + setIsSolid(properties.property("isSolid").toVariant().toBool()); + } + if (properties.property("isWire").isValid()) { + setIsSolid(!properties.property("isWire").toVariant().toBool()); + } + if (properties.property("solid").isValid()) { + setIsSolid(properties.property("solid").toVariant().toBool()); + } + if (properties.property("wire").isValid()) { + setIsSolid(!properties.property("wire").toVariant().toBool()); + } + + +} + + diff --git a/interface/src/ui/Cube3DOverlay.h b/interface/src/ui/Cube3DOverlay.h new file mode 100644 index 0000000000..ad6ba92d02 --- /dev/null +++ b/interface/src/ui/Cube3DOverlay.h @@ -0,0 +1,57 @@ +// +// Cube3DOverlay.h +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Cube3DOverlay__ +#define __interface__Cube3DOverlay__ + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Overlay.h" + +class Cube3DOverlay : public Overlay { + Q_OBJECT + +public: + Cube3DOverlay(); + ~Cube3DOverlay(); + virtual void render(); + + // getters + const glm::vec3& getPosition() const { return _position; } + float getSize() const { return _size; } + float getLineWidth() const { return _lineWidth; } + bool getIsSolid() const { return _isSolid; } + + // setters + void setPosition(const glm::vec3& position) { _position = position; } + void setSize(float size) { _size = size; } + void setLineWidth(float lineWidth) { _lineWidth = lineWidth; } + void setIsSolid(bool isSolid) { _isSolid = isSolid; } + + virtual void setProperties(const QScriptValue& properties); + +private: + glm::vec3 _position; + float _size; + float _lineWidth; + bool _isSolid; +}; + + +#endif /* defined(__interface__Cube3DOverlay__) */ diff --git a/interface/src/ui/ImageOverlay.cpp b/interface/src/ui/ImageOverlay.cpp index d048e7a27e..178383749b 100644 --- a/interface/src/ui/ImageOverlay.cpp +++ b/interface/src/ui/ImageOverlay.cpp @@ -61,7 +61,7 @@ void ImageOverlay::render() { glBindTexture(GL_TEXTURE_2D, _textureID); } const float MAX_COLOR = 255; - glColor4f(_backgroundColor.red / MAX_COLOR, _backgroundColor.green / MAX_COLOR, _backgroundColor.blue / MAX_COLOR, _alpha); + glColor4f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, _alpha); float imageWidth = _textureImage.width(); float imageHeight = _textureImage.height(); @@ -107,7 +107,7 @@ void ImageOverlay::render() { } void ImageOverlay::setProperties(const QScriptValue& properties) { - Overlay::setProperties(properties); + Overlay2D::setProperties(properties); QScriptValue subImageBounds = properties.property("subImage"); if (subImageBounds.isValid()) { diff --git a/interface/src/ui/ImageOverlay.h b/interface/src/ui/ImageOverlay.h index be7d8cf5d8..77cac3b3c6 100644 --- a/interface/src/ui/ImageOverlay.h +++ b/interface/src/ui/ImageOverlay.h @@ -23,8 +23,9 @@ #include #include "Overlay.h" +#include "Overlay2D.h" -class ImageOverlay : public Overlay { +class ImageOverlay : public Overlay2D { Q_OBJECT public: diff --git a/interface/src/ui/Overlay.cpp b/interface/src/ui/Overlay.cpp index 4660fd6ada..c6b3902fd6 100644 --- a/interface/src/ui/Overlay.cpp +++ b/interface/src/ui/Overlay.cpp @@ -19,7 +19,7 @@ Overlay::Overlay() : _parent(NULL), _alpha(DEFAULT_ALPHA), - _backgroundColor(DEFAULT_BACKGROUND_COLOR), + _color(DEFAULT_BACKGROUND_COLOR), _visible(true) { } @@ -69,15 +69,15 @@ void Overlay::setProperties(const QScriptValue& properties) { //qDebug() << "set bounds to " << getBounds(); } - QScriptValue color = properties.property("backgroundColor"); + QScriptValue color = properties.property("color"); 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(); + _color.red = red.toVariant().toInt(); + _color.green = green.toVariant().toInt(); + _color.blue = blue.toVariant().toInt(); } } diff --git a/interface/src/ui/Overlay.h b/interface/src/ui/Overlay.h index ce63fdaba5..4f1cdc9edb 100644 --- a/interface/src/ui/Overlay.h +++ b/interface/src/ui/Overlay.h @@ -37,7 +37,7 @@ public: int getWidth() const { return _bounds.width(); } int getHeight() const { return _bounds.height(); } const QRect& getBounds() const { return _bounds; } - const xColor& getBackgroundColor() const { return _backgroundColor; } + const xColor& getColor() const { return _color; } float getAlpha() const { return _alpha; } // setters @@ -47,7 +47,7 @@ public: void setWidth(int width) { _bounds.setWidth(width); } void setHeight(int height) { _bounds.setHeight(height); } void setBounds(const QRect& bounds) { _bounds = bounds; } - void setBackgroundColor(const xColor& color) { _backgroundColor = color; } + void setColor(const xColor& color) { _color = color; } void setAlpha(float alpha) { _alpha = alpha; } virtual void setProperties(const QScriptValue& properties); @@ -56,7 +56,7 @@ protected: QGLWidget* _parent; QRect _bounds; // where on the screen to draw float _alpha; - xColor _backgroundColor; + xColor _color; bool _visible; // should the overlay be drawn at all }; diff --git a/interface/src/ui/Overlay2D.cpp b/interface/src/ui/Overlay2D.cpp new file mode 100644 index 0000000000..0c459811c4 --- /dev/null +++ b/interface/src/ui/Overlay2D.cpp @@ -0,0 +1,63 @@ +// +// Overlay2D.cpp +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include +#include +#include +#include + +#include "Overlay2D.h" + + +Overlay2D::Overlay2D() { +} + +Overlay2D::~Overlay2D() { +} + +void Overlay2D::setProperties(const QScriptValue& properties) { + Overlay::setProperties(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 { + QRect oldBounds = getBounds(); + QRect newBounds = oldBounds; + + if (properties.property("x").isValid()) { + newBounds.setX(properties.property("x").toVariant().toInt()); + } else { + newBounds.setX(oldBounds.x()); + } + if (properties.property("y").isValid()) { + newBounds.setY(properties.property("y").toVariant().toInt()); + } else { + newBounds.setY(oldBounds.y()); + } + if (properties.property("width").isValid()) { + newBounds.setWidth(properties.property("width").toVariant().toInt()); + } else { + newBounds.setWidth(oldBounds.width()); + } + if (properties.property("height").isValid()) { + newBounds.setHeight(properties.property("height").toVariant().toInt()); + } else { + newBounds.setHeight(oldBounds.height()); + } + setBounds(newBounds); + //qDebug() << "set bounds to " << getBounds(); + } +} diff --git a/interface/src/ui/Overlay2D.h b/interface/src/ui/Overlay2D.h new file mode 100644 index 0000000000..3da8f8bca4 --- /dev/null +++ b/interface/src/ui/Overlay2D.h @@ -0,0 +1,51 @@ +// +// Overlay2D.h +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Overlay2D__ +#define __interface__Overlay2D__ + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include +#include +#include +#include + +#include // for xColor + +#include "Overlay.h" + +class Overlay2D : public Overlay { + Q_OBJECT + +public: + Overlay2D(); + ~Overlay2D(); + + // getters + int getX() const { return _bounds.x(); } + int getY() const { return _bounds.y(); } + int getWidth() const { return _bounds.width(); } + int getHeight() const { return _bounds.height(); } + const QRect& getBounds() const { return _bounds; } + + // setters + 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; } + + virtual void setProperties(const QScriptValue& properties); + +protected: + QRect _bounds; // where on the screen to draw +}; + + +#endif /* defined(__interface__Overlay2D__) */ diff --git a/interface/src/ui/Overlays.cpp b/interface/src/ui/Overlays.cpp index 2f31e7e8c7..b731d46b16 100644 --- a/interface/src/ui/Overlays.cpp +++ b/interface/src/ui/Overlays.cpp @@ -6,8 +6,9 @@ // -#include "Overlays.h" +#include "Cube3DOverlay.h" #include "ImageOverlay.h" +#include "Overlays.h" #include "TextOverlay.h" @@ -23,8 +24,14 @@ void Overlays::init(QGLWidget* parent) { _parent = parent; } -void Overlays::render() { - foreach(Overlay* thisOverlay, _overlays) { +void Overlays::render2D() { + foreach(Overlay* thisOverlay, _overlays2D) { + thisOverlay->render(); + } +} + +void Overlays::render3D() { + foreach(Overlay* thisOverlay, _overlays3D) { thisOverlay->render(); } } @@ -32,21 +39,36 @@ void Overlays::render() { // TODO: make multi-threaded safe unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { unsigned int thisID = 0; + bool created = false; + bool is3D = false; + Overlay* thisOverlay = NULL; if (type == "image") { - thisID = _nextOverlayID; - _nextOverlayID++; - ImageOverlay* thisOverlay = new ImageOverlay(); + thisOverlay = new ImageOverlay(); thisOverlay->init(_parent); thisOverlay->setProperties(properties); - _overlays[thisID] = thisOverlay; + created = true; } else if (type == "text") { - thisID = _nextOverlayID; - _nextOverlayID++; - TextOverlay* thisOverlay = new TextOverlay(); + thisOverlay = new TextOverlay(); thisOverlay->init(_parent); thisOverlay->setProperties(properties); - _overlays[thisID] = thisOverlay; + created = true; + } else if (type == "cube") { + thisOverlay = new Cube3DOverlay(); + thisOverlay->init(_parent); + thisOverlay->setProperties(properties); + created = true; + is3D = true; + } + + if (created) { + thisID = _nextOverlayID; + _nextOverlayID++; + if (is3D) { + _overlays3D[thisID] = thisOverlay; + } else { + _overlays2D[thisID] = thisOverlay; + } } return thisID; @@ -54,23 +76,30 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope // TODO: make multi-threaded safe bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { - if (!_overlays.contains(id)) { - return false; + Overlay* thisOverlay = NULL; + if (_overlays2D.contains(id)) { + thisOverlay = _overlays2D[id]; + } else if (_overlays3D.contains(id)) { + thisOverlay = _overlays3D[id]; } - Overlay* thisOverlay = _overlays[id]; - thisOverlay->setProperties(properties); - return true; + if (thisOverlay) { + thisOverlay->setProperties(properties); + return true; + } + return false; } // TODO: make multi-threaded safe void Overlays::deleteOverlay(unsigned int id) { - if (_overlays.contains(id)) { - _overlays.erase(_overlays.find(id)); + if (_overlays2D.contains(id)) { + _overlays2D.erase(_overlays2D.find(id)); + } else if (_overlays3D.contains(id)) { + _overlays3D.erase(_overlays3D.find(id)); } } unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { - QMapIterator i(_overlays); + QMapIterator i(_overlays2D); i.toBack(); while (i.hasPrevious()) { i.previous(); diff --git a/interface/src/ui/Overlays.h b/interface/src/ui/Overlays.h index e39949d2c9..cfd84fd44b 100644 --- a/interface/src/ui/Overlays.h +++ b/interface/src/ui/Overlays.h @@ -18,7 +18,8 @@ public: Overlays(); ~Overlays(); void init(QGLWidget* parent); - void render(); + void render3D(); + void render2D(); public slots: /// adds an overlay with the specific properties @@ -35,7 +36,8 @@ public slots: unsigned int getOverlayAtPoint(const glm::vec2& point); private: - QMap _overlays; + QMap _overlays2D; + QMap _overlays3D; static unsigned int _nextOverlayID; QGLWidget* _parent; }; diff --git a/interface/src/ui/TextOverlay.cpp b/interface/src/ui/TextOverlay.cpp index 51b57c2f3f..edaec6849a 100644 --- a/interface/src/ui/TextOverlay.cpp +++ b/interface/src/ui/TextOverlay.cpp @@ -29,7 +29,7 @@ void TextOverlay::render() { } const float MAX_COLOR = 255; - glColor4f(_backgroundColor.red / MAX_COLOR, _backgroundColor.green / MAX_COLOR, _backgroundColor.blue / MAX_COLOR, _alpha); + glColor4f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, _alpha); glBegin(GL_QUADS); glVertex2f(_bounds.left(), _bounds.top()); @@ -63,7 +63,7 @@ void TextOverlay::render() { } void TextOverlay::setProperties(const QScriptValue& properties) { - Overlay::setProperties(properties); + Overlay2D::setProperties(properties); QScriptValue text = properties.property("text"); if (text.isValid()) { diff --git a/interface/src/ui/TextOverlay.h b/interface/src/ui/TextOverlay.h index 323116eccf..d565aeb70d 100644 --- a/interface/src/ui/TextOverlay.h +++ b/interface/src/ui/TextOverlay.h @@ -23,10 +23,11 @@ #include #include "Overlay.h" +#include "Overlay2D.h" const int DEFAULT_MARGIN = 10; -class TextOverlay : public Overlay { +class TextOverlay : public Overlay2D { Q_OBJECT public: