mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 16:33:33 +02:00
Merge pull request #2006 from ZappoMan/overlaysupport
Scriptable Overlay Support
This commit is contained in:
commit
fc3cc52665
27 changed files with 1495 additions and 17 deletions
examples
interface/src
Application.cppApplication.hUtil.h
ui
Base3DOverlay.cppBase3DOverlay.hCube3DOverlay.cppCube3DOverlay.hImageOverlay.cppImageOverlay.hLine3DOverlay.cppLine3DOverlay.hOverlay.cppOverlay.hOverlay2D.cppOverlay2D.hOverlays.cppOverlays.hSphere3DOverlay.cppSphere3DOverlay.hTextOverlay.cppTextOverlay.hTextRenderer.cppTextRenderer.hVolume3DOverlay.cppVolume3DOverlay.h
libraries/octree/src
279
examples/overlaysExample.js
Normal file
279
examples/overlaysExample.js
Normal file
|
@ -0,0 +1,279 @@
|
|||
//
|
||||
// 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
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
// The "Swatches" example of this script will create 9 different image overlays, that use the color feature to
|
||||
// display different colors as color swatches. The overlays can be clicked on, to change the "selectedSwatch" variable
|
||||
// and update the image used for the overlay so that it appears to have a selected indicator.
|
||||
// These are our colors...
|
||||
var swatchColors = new Array();
|
||||
swatchColors[0] = { red: 255, green: 0, blue: 0};
|
||||
swatchColors[1] = { red: 0, green: 255, blue: 0};
|
||||
swatchColors[2] = { red: 0, green: 0, blue: 255};
|
||||
swatchColors[3] = { red: 255, green: 255, blue: 0};
|
||||
swatchColors[4] = { red: 255, green: 0, blue: 255};
|
||||
swatchColors[5] = { red: 0, green: 255, blue: 255};
|
||||
swatchColors[6] = { red: 128, green: 128, blue: 128};
|
||||
swatchColors[7] = { red: 128, green: 0, blue: 0};
|
||||
swatchColors[8] = { red: 0, green: 240, blue: 240};
|
||||
|
||||
// The location of the placement of these overlays
|
||||
var swatchesX = 100;
|
||||
var swatchesY = 200;
|
||||
|
||||
// These will be our "overlay IDs"
|
||||
var swatches = new Array();
|
||||
var numberOfSwatches = 9;
|
||||
var selectedSwatch = 0;
|
||||
|
||||
// create the overlays, position them in a row, set their colors, and for the selected one, use a different source image
|
||||
// location so that it displays the "selected" marker
|
||||
for (s = 0; s < numberOfSwatches; s++) {
|
||||
var imageFromX = 12 + (s * 27);
|
||||
var imageFromY = 0;
|
||||
if (s == selectedSwatch) {
|
||||
imageFromY = 55;
|
||||
}
|
||||
|
||||
swatches[s] = Overlays.addOverlay("image", {
|
||||
x: 100 + (30 * s),
|
||||
y: 200,
|
||||
width: 31,
|
||||
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",
|
||||
color: swatchColors[s],
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
|
||||
// This will create a text overlay that when you click on it, the text will change
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: 200,
|
||||
y: 100,
|
||||
width: 150,
|
||||
height: 50,
|
||||
color: { red: 0, green: 0, blue: 0},
|
||||
textColor: { red: 255, green: 0, blue: 0},
|
||||
topMargin: 4,
|
||||
leftMargin: 4,
|
||||
text: "Here is some text.\nAnd a second line."
|
||||
});
|
||||
|
||||
// This will create an image overlay, which starts out as invisible
|
||||
var toolA = Overlays.addOverlay("image", {
|
||||
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",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
visible: false
|
||||
});
|
||||
|
||||
// This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to
|
||||
// move the slider
|
||||
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",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
// This is the thumb of our slider
|
||||
var minThumbX = 130;
|
||||
var maxThumbX = minThumbX + 65;
|
||||
var thumbX = (minThumbX + maxThumbX) / 2;
|
||||
var thumb = Overlays.addOverlay("image", {
|
||||
x: thumbX,
|
||||
y: 309,
|
||||
width: 18,
|
||||
height: 17,
|
||||
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
|
||||
// We will also demonstrate some 3D overlays. We will create a couple of cubes, spheres, and lines
|
||||
// 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 cube = Overlays.addOverlay("cube", {
|
||||
position: cubePosition,
|
||||
size: cubeSize,
|
||||
color: { red: 255, green: 0, blue: 0},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var solidCubePosition = { x: 0, y: 5, z: 0 };
|
||||
var solidCubeSize = 2;
|
||||
var minSolidCubeX = 0;
|
||||
var maxSolidCubeX = 10;
|
||||
var solidCubeMove = 0.05;
|
||||
var solidCube = Overlays.addOverlay("cube", {
|
||||
position: solidCubePosition,
|
||||
size: solidCubeSize,
|
||||
color: { red: 0, green: 255, blue: 0},
|
||||
alpha: 1,
|
||||
solid: true
|
||||
});
|
||||
|
||||
var spherePosition = { x: 5, y: 5, z: 5 };
|
||||
var sphereSize = 1;
|
||||
var minSphereSize = 0.5;
|
||||
var maxSphereSize = 10;
|
||||
var sphereSizeChange = 0.05;
|
||||
|
||||
var sphere = Overlays.addOverlay("sphere", {
|
||||
position: spherePosition,
|
||||
size: sphereSize,
|
||||
color: { red: 0, green: 0, blue: 255},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var line3d = Overlays.addOverlay("line3d", {
|
||||
position: { x: 0, y: 0, z:0 },
|
||||
end: { x: 10, y: 10, z:10 },
|
||||
color: { red: 0, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
lineWidth: 5
|
||||
});
|
||||
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(toolA);
|
||||
for (s = 0; s < numberOfSwatches; s++) {
|
||||
Overlays.deleteOverlay(swatches[s]);
|
||||
}
|
||||
Overlays.deleteOverlay(thumb);
|
||||
Overlays.deleteOverlay(slider);
|
||||
Overlays.deleteOverlay(text);
|
||||
Overlays.deleteOverlay(cube);
|
||||
Overlays.deleteOverlay(solidCube);
|
||||
Overlays.deleteOverlay(sphere);
|
||||
Overlays.deleteOverlay(line3d);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
||||
var toolAVisible = false;
|
||||
var count = 0;
|
||||
|
||||
// Our update() function is called at approximately 60fps, and we will use it to animate our various overlays
|
||||
function update() {
|
||||
count++;
|
||||
|
||||
// every second or so, toggle the visibility our our blinking tool
|
||||
if (count % 60 == 0) {
|
||||
if (toolAVisible) {
|
||||
toolAVisible = false;
|
||||
} else {
|
||||
toolAVisible = true;
|
||||
}
|
||||
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 } );
|
||||
|
||||
// move our solid 3D cube
|
||||
solidCubePosition.x += solidCubeMove;
|
||||
solidCubePosition.z += solidCubeMove;
|
||||
if (solidCubePosition.x > maxSolidCubeX || solidCubePosition.x < minSolidCubeX) {
|
||||
solidCubeMove = solidCubeMove * -1;
|
||||
}
|
||||
Overlays.editOverlay(solidCube, { position: solidCubePosition } );
|
||||
|
||||
// adjust our 3D sphere
|
||||
sphereSize += sphereSizeChange;
|
||||
if (sphereSize > maxSphereSize || sphereSize < minSphereSize) {
|
||||
sphereSizeChange = sphereSizeChange * -1;
|
||||
}
|
||||
Overlays.editOverlay(sphere, { size: sphereSize, solid: (sphereSizeChange < 0) } );
|
||||
|
||||
|
||||
// update our 3D line to go from origin to our avatar's position
|
||||
Overlays.editOverlay(line3d, { end: MyAvatar.position } );
|
||||
}
|
||||
Script.willSendVisualDataCallback.connect(update);
|
||||
|
||||
|
||||
// The slider is handled in the mouse event callbacks.
|
||||
var movingSlider = false;
|
||||
var thumbClickOffsetX = 0;
|
||||
function mouseMoveEvent(event) {
|
||||
if (movingSlider) {
|
||||
newThumbX = event.x - thumbClickOffsetX;
|
||||
if (newThumbX < minThumbX) {
|
||||
newThumbX = minThumbX;
|
||||
}
|
||||
if (newThumbX > maxThumbX) {
|
||||
newThumbX = maxThumbX;
|
||||
}
|
||||
Overlays.editOverlay(thumb, { x: newThumbX } );
|
||||
}
|
||||
}
|
||||
|
||||
// we also handle click detection in our mousePressEvent()
|
||||
function mousePressEvent(event) {
|
||||
var clickedText = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
|
||||
// If the user clicked on the thumb, handle the slider logic
|
||||
if (clickedOverlay == thumb) {
|
||||
movingSlider = true;
|
||||
thumbClickOffsetX = event.x - thumbX;
|
||||
|
||||
} else if (clickedOverlay == text) { // if the user clicked on the text, update text with where you clicked
|
||||
|
||||
Overlays.editOverlay(text, { text: "you clicked here:\n " + event.x + "," + event.y } );
|
||||
clickedText = true;
|
||||
|
||||
} else { // if the user clicked on one of the color swatches, update the selectedSwatch
|
||||
|
||||
for (s = 0; s < numberOfSwatches; s++) {
|
||||
if (clickedOverlay == swatches[s]) {
|
||||
Overlays.editOverlay(swatches[selectedSwatch], { subImage: { y: 0 } } );
|
||||
Overlays.editOverlay(swatches[s], { subImage: { y: 55 } } );
|
||||
selectedSwatch = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!clickedText) { // if you didn't click on the text, then update the text accordningly
|
||||
Overlays.editOverlay(text, { text: "you didn't click here" } );
|
||||
}
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
if (movingSlider) {
|
||||
movingSlider = false;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
|
@ -291,6 +291,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();
|
||||
|
@ -1909,6 +1912,8 @@ void Application::init() {
|
|||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Application::closeMirrorView() {
|
||||
|
@ -2877,6 +2882,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// give external parties a change to hook in
|
||||
emit renderingInWorldInterface();
|
||||
|
||||
// render JS/scriptable overlays
|
||||
_overlays.render3D();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3023,6 +3031,8 @@ void Application::displayOverlay() {
|
|||
_pieMenu.render();
|
||||
}
|
||||
|
||||
_overlays.render2D();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -4100,6 +4110,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..
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "FileLogger.h"
|
||||
#include "ParticleTreeRenderer.h"
|
||||
#include "ControllerScriptingInterface.h"
|
||||
#include "ui/Overlays.h"
|
||||
|
||||
|
||||
class QAction;
|
||||
|
@ -490,6 +491,8 @@ private:
|
|||
void takeSnapshot();
|
||||
|
||||
TouchEvent _lastTouchEvent;
|
||||
|
||||
Overlays _overlays;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__Application__) */
|
||||
|
|
|
@ -19,15 +19,6 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QSettings>
|
||||
|
||||
// the standard sans serif font family
|
||||
#define SANS_FONT_FAMILY "Helvetica"
|
||||
|
||||
// the standard mono font family
|
||||
#define MONO_FONT_FAMILY "Courier"
|
||||
|
||||
// the Inconsolata font family
|
||||
#define INCONSOLATA_FONT_FAMILY "Inconsolata"
|
||||
|
||||
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up);
|
||||
|
||||
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);
|
||||
|
|
61
interface/src/ui/Base3DOverlay.cpp
Normal file
61
interface/src/ui/Base3DOverlay.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Base3DOverlay.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 <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Base3DOverlay.h"
|
||||
#include "TextRenderer.h"
|
||||
|
||||
const glm::vec3 DEFAULT_POSITION = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
const float DEFAULT_LINE_WIDTH = 1.0f;
|
||||
|
||||
Base3DOverlay::Base3DOverlay() :
|
||||
_position(DEFAULT_POSITION),
|
||||
_lineWidth(DEFAULT_LINE_WIDTH)
|
||||
{
|
||||
}
|
||||
|
||||
Base3DOverlay::~Base3DOverlay() {
|
||||
}
|
||||
|
||||
void Base3DOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay::setProperties(properties);
|
||||
|
||||
QScriptValue position = properties.property("position");
|
||||
|
||||
// if "position" property was not there, check to see if they included aliases: start, point, p1
|
||||
if (!position.isValid()) {
|
||||
position = properties.property("start");
|
||||
if (!position.isValid()) {
|
||||
position = properties.property("p1");
|
||||
if (!position.isValid()) {
|
||||
position = properties.property("point");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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("lineWidth").isValid()) {
|
||||
setLineWidth(properties.property("lineWidth").toVariant().toFloat());
|
||||
}
|
||||
}
|
36
interface/src/ui/Base3DOverlay.h
Normal file
36
interface/src/ui/Base3DOverlay.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// Base3DOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Base3DOverlay__
|
||||
#define __interface__Base3DOverlay__
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
class Base3DOverlay : public Overlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Base3DOverlay();
|
||||
~Base3DOverlay();
|
||||
|
||||
// getters
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
float getLineWidth() const { return _lineWidth; }
|
||||
|
||||
// setters
|
||||
void setPosition(const glm::vec3& position) { _position = position; }
|
||||
void setLineWidth(float lineWidth) { _lineWidth = lineWidth; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
protected:
|
||||
glm::vec3 _position;
|
||||
float _lineWidth;
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Base3DOverlay__) */
|
44
interface/src/ui/Cube3DOverlay.cpp
Normal file
44
interface/src/ui/Cube3DOverlay.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// 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 <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Cube3DOverlay.h"
|
||||
|
||||
Cube3DOverlay::Cube3DOverlay() {
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
}
|
23
interface/src/ui/Cube3DOverlay.h
Normal file
23
interface/src/ui/Cube3DOverlay.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Cube3DOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Cube3DOverlay__
|
||||
#define __interface__Cube3DOverlay__
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
class Cube3DOverlay : public Volume3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Cube3DOverlay();
|
||||
~Cube3DOverlay();
|
||||
virtual void render();
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Cube3DOverlay__) */
|
145
interface/src/ui/ImageOverlay.cpp
Normal file
145
interface/src/ui/ImageOverlay.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// ImageOverlay.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 <QGLWidget>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "ImageOverlay.h"
|
||||
|
||||
ImageOverlay::ImageOverlay() :
|
||||
_textureID(0),
|
||||
_renderImage(false),
|
||||
_textureBound(false),
|
||||
_wantClipFromImage(false)
|
||||
{
|
||||
}
|
||||
|
||||
ImageOverlay::~ImageOverlay() {
|
||||
if (_parent && _textureID) {
|
||||
// do we need to call this?
|
||||
//_parent->deleteTexture(_textureID);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||
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) {
|
||||
|
||||
// replace our byte array with the downloaded data
|
||||
QByteArray rawData = reply->readAll();
|
||||
_textureImage.loadFromData(rawData);
|
||||
_renderImage = true;
|
||||
|
||||
}
|
||||
|
||||
void ImageOverlay::render() {
|
||||
if (!_visible) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
if (_renderImage && !_textureBound) {
|
||||
_textureID = _parent->bindTexture(_textureImage);
|
||||
_textureBound = true;
|
||||
}
|
||||
|
||||
if (_renderImage) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, _textureID);
|
||||
}
|
||||
const float MAX_COLOR = 255;
|
||||
glColor4f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, _alpha);
|
||||
|
||||
float imageWidth = _textureImage.width();
|
||||
float imageHeight = _textureImage.height();
|
||||
|
||||
QRect fromImage;
|
||||
if (_wantClipFromImage) {
|
||||
fromImage = _fromImage;
|
||||
} else {
|
||||
fromImage.setX(0);
|
||||
fromImage.setY(0);
|
||||
fromImage.setWidth(imageWidth);
|
||||
fromImage.setHeight(imageHeight);
|
||||
}
|
||||
float x = fromImage.x() / imageWidth;
|
||||
float y = fromImage.y() / imageHeight;
|
||||
float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure
|
||||
float h = fromImage.height() / imageHeight;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x, 1.0f - y);
|
||||
}
|
||||
glVertex2f(_bounds.left(), _bounds.top());
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x + w, 1.0f - y);
|
||||
}
|
||||
glVertex2f(_bounds.right(), _bounds.top());
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x + w, 1.0f - (y + h));
|
||||
}
|
||||
glVertex2f(_bounds.right(), _bounds.bottom());
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x, 1.0f - (y + h));
|
||||
}
|
||||
glVertex2f(_bounds.left(), _bounds.bottom());
|
||||
glEnd();
|
||||
if (_renderImage) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
|
||||
QScriptValue subImageBounds = properties.property("subImage");
|
||||
if (subImageBounds.isValid()) {
|
||||
QRect oldSubImageRect = _fromImage;
|
||||
QRect subImageRect = _fromImage;
|
||||
if (subImageBounds.property("x").isValid()) {
|
||||
subImageRect.setX(subImageBounds.property("x").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setX(oldSubImageRect.x());
|
||||
}
|
||||
if (subImageBounds.property("y").isValid()) {
|
||||
subImageRect.setY(subImageBounds.property("y").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setY(oldSubImageRect.y());
|
||||
}
|
||||
if (subImageBounds.property("width").isValid()) {
|
||||
subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setWidth(oldSubImageRect.width());
|
||||
}
|
||||
if (subImageBounds.property("height").isValid()) {
|
||||
subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setHeight(oldSubImageRect.height());
|
||||
}
|
||||
setClipFromSource(subImageRect);
|
||||
}
|
||||
|
||||
QScriptValue imageURL = properties.property("imageURL");
|
||||
if (imageURL.isValid()) {
|
||||
setImageURL(imageURL.toVariant().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
60
interface/src/ui/ImageOverlay.h
Normal file
60
interface/src/ui/ImageOverlay.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// ImageOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__ImageOverlay__
|
||||
#define __interface__ImageOverlay__
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
#include "Overlay2D.h"
|
||||
|
||||
class ImageOverlay : public Overlay2D {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageOverlay();
|
||||
~ImageOverlay();
|
||||
virtual void render();
|
||||
|
||||
// getters
|
||||
const QRect& getClipFromSource() const { return _fromImage; }
|
||||
const QUrl& getImageURL() const { return _imageURL; }
|
||||
|
||||
// setters
|
||||
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; }
|
||||
void setImageURL(const QUrl& url);
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply* reply); // we actually want to hide this...
|
||||
|
||||
private:
|
||||
|
||||
QUrl _imageURL;
|
||||
QImage _textureImage;
|
||||
GLuint _textureID;
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
bool _renderImage; // is there an image associated with this overlay, or is it just a colored rectangle
|
||||
bool _textureBound; // has the texture been bound
|
||||
bool _wantClipFromImage;
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__ImageOverlay__) */
|
60
interface/src/ui/Line3DOverlay.cpp
Normal file
60
interface/src/ui/Line3DOverlay.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Line3DOverlay.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 "Line3DOverlay.h"
|
||||
|
||||
|
||||
Line3DOverlay::Line3DOverlay() {
|
||||
}
|
||||
|
||||
Line3DOverlay::~Line3DOverlay() {
|
||||
}
|
||||
|
||||
void Line3DOverlay::render() {
|
||||
if (!_visible) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
const float MAX_COLOR = 255;
|
||||
glDisable(GL_LIGHTING);
|
||||
glLineWidth(_lineWidth);
|
||||
glColor4f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, _alpha);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(_position.x, _position.y, _position.z);
|
||||
glVertex3f(_end.x, _end.y, _end.z);
|
||||
glEnd();
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void Line3DOverlay::setProperties(const QScriptValue& properties) {
|
||||
Base3DOverlay::setProperties(properties);
|
||||
|
||||
QScriptValue end = properties.property("end");
|
||||
// if "end" property was not there, check to see if they included aliases: endPoint, or p2
|
||||
if (!end.isValid()) {
|
||||
end = properties.property("endPoint");
|
||||
if (!end.isValid()) {
|
||||
end = properties.property("p2");
|
||||
}
|
||||
}
|
||||
if (end.isValid()) {
|
||||
QScriptValue x = end.property("x");
|
||||
QScriptValue y = end.property("y");
|
||||
QScriptValue z = end.property("z");
|
||||
if (x.isValid() && y.isValid() && z.isValid()) {
|
||||
glm::vec3 newEnd;
|
||||
newEnd.x = x.toVariant().toFloat();
|
||||
newEnd.y = y.toVariant().toFloat();
|
||||
newEnd.z = z.toVariant().toFloat();
|
||||
setEnd(newEnd);
|
||||
}
|
||||
}
|
||||
}
|
34
interface/src/ui/Line3DOverlay.h
Normal file
34
interface/src/ui/Line3DOverlay.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Line3DOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Line3DOverlay__
|
||||
#define __interface__Line3DOverlay__
|
||||
|
||||
#include "Base3DOverlay.h"
|
||||
|
||||
class Line3DOverlay : public Base3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Line3DOverlay();
|
||||
~Line3DOverlay();
|
||||
virtual void render();
|
||||
|
||||
// getters
|
||||
const glm::vec3& getEnd() const { return _end; }
|
||||
|
||||
// setters
|
||||
void setEnd(const glm::vec3& end) { _end = end; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
protected:
|
||||
glm::vec3 _end;
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Line3DOverlay__) */
|
55
interface/src/ui/Overlay.cpp
Normal file
55
interface/src/ui/Overlay.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// Overlay.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 <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
|
||||
Overlay::Overlay() :
|
||||
_parent(NULL),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_color(DEFAULT_BACKGROUND_COLOR),
|
||||
_visible(true)
|
||||
{
|
||||
}
|
||||
|
||||
void Overlay::init(QGLWidget* parent) {
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
|
||||
Overlay::~Overlay() {
|
||||
}
|
||||
|
||||
void Overlay::setProperties(const QScriptValue& properties) {
|
||||
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()) {
|
||||
_color.red = red.toVariant().toInt();
|
||||
_color.green = green.toVariant().toInt();
|
||||
_color.blue = blue.toVariant().toInt();
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.property("alpha").isValid()) {
|
||||
setAlpha(properties.property("alpha").toVariant().toFloat());
|
||||
}
|
||||
|
||||
if (properties.property("visible").isValid()) {
|
||||
setVisible(properties.property("visible").toVariant().toBool());
|
||||
}
|
||||
}
|
53
interface/src/ui/Overlay.h
Normal file
53
interface/src/ui/Overlay.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Overlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Overlay__
|
||||
#define __interface__Overlay__
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
#include <QString>
|
||||
|
||||
#include <SharedUtil.h> // for xColor
|
||||
|
||||
const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 };
|
||||
const float DEFAULT_ALPHA = 0.7f;
|
||||
|
||||
class Overlay : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Overlay();
|
||||
~Overlay();
|
||||
void init(QGLWidget* parent);
|
||||
virtual void render() = 0;
|
||||
|
||||
// getters
|
||||
bool getVisible() const { return _visible; }
|
||||
const xColor& getColor() const { return _color; }
|
||||
float getAlpha() const { return _alpha; }
|
||||
|
||||
// setters
|
||||
void setVisible(bool visible) { _visible = visible; }
|
||||
void setColor(const xColor& color) { _color = color; }
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
protected:
|
||||
QGLWidget* _parent;
|
||||
float _alpha;
|
||||
xColor _color;
|
||||
bool _visible; // should the overlay be drawn at all
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Overlay__) */
|
63
interface/src/ui/Overlay2D.cpp
Normal file
63
interface/src/ui/Overlay2D.cpp
Normal file
|
@ -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 <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
51
interface/src/ui/Overlay2D.h
Normal file
51
interface/src/ui/Overlay2D.h
Normal file
|
@ -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 <QGLWidget>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
#include <QString>
|
||||
|
||||
#include <SharedUtil.h> // 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__) */
|
129
interface/src/ui/Overlays.cpp
Normal file
129
interface/src/ui/Overlays.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// Overlays.cpp
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#include "Cube3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
#include "Line3DOverlay.h"
|
||||
#include "Overlays.h"
|
||||
#include "Sphere3DOverlay.h"
|
||||
#include "TextOverlay.h"
|
||||
|
||||
|
||||
unsigned int Overlays::_nextOverlayID = 1;
|
||||
|
||||
Overlays::Overlays() {
|
||||
}
|
||||
|
||||
Overlays::~Overlays() {
|
||||
}
|
||||
|
||||
void Overlays::init(QGLWidget* parent) {
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
void Overlays::render2D() {
|
||||
foreach(Overlay* thisOverlay, _overlays2D) {
|
||||
thisOverlay->render();
|
||||
}
|
||||
}
|
||||
|
||||
void Overlays::render3D() {
|
||||
foreach(Overlay* thisOverlay, _overlays3D) {
|
||||
thisOverlay->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") {
|
||||
thisOverlay = new ImageOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
} else if (type == "text") {
|
||||
thisOverlay = new TextOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
} else if (type == "cube") {
|
||||
thisOverlay = new Cube3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "sphere") {
|
||||
thisOverlay = new Sphere3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "line3d") {
|
||||
thisOverlay = new Line3DOverlay();
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: make multi-threaded safe
|
||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||
Overlay* thisOverlay = NULL;
|
||||
if (_overlays2D.contains(id)) {
|
||||
thisOverlay = _overlays2D[id];
|
||||
} else if (_overlays3D.contains(id)) {
|
||||
thisOverlay = _overlays3D[id];
|
||||
}
|
||||
if (thisOverlay) {
|
||||
thisOverlay->setProperties(properties);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: make multi-threaded safe
|
||||
void Overlays::deleteOverlay(unsigned int 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<unsigned int, Overlay*> i(_overlays2D);
|
||||
i.toBack();
|
||||
while (i.hasPrevious()) {
|
||||
i.previous();
|
||||
unsigned int thisID = i.key();
|
||||
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value());
|
||||
if (thisOverlay->getVisible() && thisOverlay->getBounds().contains(point.x, point.y, false)) {
|
||||
return thisID;
|
||||
}
|
||||
}
|
||||
return 0; // not found
|
||||
}
|
||||
|
||||
|
46
interface/src/ui/Overlays.h
Normal file
46
interface/src/ui/Overlays.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Overlays.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Overlays__
|
||||
#define __interface__Overlays__
|
||||
|
||||
#include <QScriptValue>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
class Overlays : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Overlays();
|
||||
~Overlays();
|
||||
void init(QGLWidget* parent);
|
||||
void render3D();
|
||||
void render2D();
|
||||
|
||||
public slots:
|
||||
/// adds an overlay with the specific properties
|
||||
unsigned int addOverlay(const QString& type, const QScriptValue& properties);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// returns the top most overlay at the screen point, or 0 if not overlay at that point
|
||||
unsigned int getOverlayAtPoint(const glm::vec2& point);
|
||||
|
||||
private:
|
||||
QMap<unsigned int, Overlay*> _overlays2D;
|
||||
QMap<unsigned int, Overlay*> _overlays3D;
|
||||
static unsigned int _nextOverlayID;
|
||||
QGLWidget* _parent;
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Overlays__) */
|
45
interface/src/ui/Sphere3DOverlay.cpp
Normal file
45
interface/src/ui/Sphere3DOverlay.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Sphere3DOverlay.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 <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Sphere3DOverlay.h"
|
||||
|
||||
Sphere3DOverlay::Sphere3DOverlay() {
|
||||
}
|
||||
|
||||
Sphere3DOverlay::~Sphere3DOverlay() {
|
||||
}
|
||||
|
||||
void Sphere3DOverlay::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);
|
||||
const int slices = 15;
|
||||
if (_isSolid) {
|
||||
glutSolidSphere(_size, slices, slices);
|
||||
} else {
|
||||
glutWireSphere(_size, slices, slices);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
}
|
23
interface/src/ui/Sphere3DOverlay.h
Normal file
23
interface/src/ui/Sphere3DOverlay.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Sphere3DOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Sphere3DOverlay__
|
||||
#define __interface__Sphere3DOverlay__
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
class Sphere3DOverlay : public Volume3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Sphere3DOverlay();
|
||||
~Sphere3DOverlay();
|
||||
virtual void render();
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Sphere3DOverlay__) */
|
82
interface/src/ui/TextOverlay.cpp
Normal file
82
interface/src/ui/TextOverlay.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// TextOverlay.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 <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "TextOverlay.h"
|
||||
#include "TextRenderer.h"
|
||||
|
||||
TextOverlay::TextOverlay() :
|
||||
_leftMargin(DEFAULT_MARGIN),
|
||||
_topMargin(DEFAULT_MARGIN)
|
||||
{
|
||||
}
|
||||
|
||||
TextOverlay::~TextOverlay() {
|
||||
}
|
||||
|
||||
void TextOverlay::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);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(_bounds.left(), _bounds.top());
|
||||
glVertex2f(_bounds.right(), _bounds.top());
|
||||
glVertex2f(_bounds.right(), _bounds.bottom());
|
||||
glVertex2f(_bounds.left(), _bounds.bottom());
|
||||
glEnd();
|
||||
|
||||
//TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false,
|
||||
// EffectType effect = NO_EFFECT, int effectThickness = 1);
|
||||
|
||||
TextRenderer textRenderer(SANS_FONT_FAMILY, 11, 50);
|
||||
const int leftAdjust = -1; // required to make text render relative to left edge of bounds
|
||||
const int topAdjust = -2; // required to make text render relative to top edge of bounds
|
||||
int x = _bounds.left() + _leftMargin + leftAdjust;
|
||||
int y = _bounds.top() + _topMargin + topAdjust;
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
QStringList lines = _text.split("\n");
|
||||
int lineOffset = 0;
|
||||
foreach(QString thisLine, lines) {
|
||||
if (lineOffset == 0) {
|
||||
lineOffset = textRenderer.calculateHeight(qPrintable(thisLine));
|
||||
}
|
||||
lineOffset += textRenderer.draw(x, y + lineOffset, qPrintable(thisLine));
|
||||
|
||||
const int lineGap = 2;
|
||||
lineOffset += lineGap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TextOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
|
||||
QScriptValue text = properties.property("text");
|
||||
if (text.isValid()) {
|
||||
setText(text.toVariant().toString());
|
||||
}
|
||||
|
||||
if (properties.property("leftMargin").isValid()) {
|
||||
setLeftMargin(properties.property("leftMargin").toVariant().toInt());
|
||||
}
|
||||
|
||||
if (properties.property("topMargin").isValid()) {
|
||||
setTopMargin(properties.property("topMargin").toVariant().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
59
interface/src/ui/TextOverlay.h
Normal file
59
interface/src/ui/TextOverlay.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// TextOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__TextOverlay__
|
||||
#define __interface__TextOverlay__
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
#include "Overlay2D.h"
|
||||
|
||||
const int DEFAULT_MARGIN = 10;
|
||||
|
||||
class TextOverlay : public Overlay2D {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TextOverlay();
|
||||
~TextOverlay();
|
||||
virtual void render();
|
||||
|
||||
// getters
|
||||
const QString& getText() const { return _text; }
|
||||
int getLeftMargin() const { return _leftMargin; }
|
||||
int getTopMargin() const { return _topMargin; }
|
||||
|
||||
// setters
|
||||
void setText(const QString& text) { _text = text; }
|
||||
void setLeftMargin(int margin) { _leftMargin = margin; }
|
||||
void setTopMargin(int margin) { _topMargin = margin; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
private:
|
||||
|
||||
QString _text;
|
||||
int _leftMargin;
|
||||
int _topMargin;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__TextOverlay__) */
|
|
@ -8,6 +8,8 @@
|
|||
#include <QFont>
|
||||
#include <QPaintEngine>
|
||||
#include <QtDebug>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "TextRenderer.h"
|
||||
|
@ -30,10 +32,25 @@ TextRenderer::~TextRenderer() {
|
|||
glDeleteTextures(_allTextureIDs.size(), _allTextureIDs.constData());
|
||||
}
|
||||
|
||||
void TextRenderer::draw(int x, int y, const char* str) {
|
||||
int TextRenderer::calculateHeight(const char* str) {
|
||||
int maxHeight = 0;
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
const Glyph& glyph = getGlyph(*ch);
|
||||
if (glyph.textureID() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glyph.bounds().height() > maxHeight) {
|
||||
maxHeight = glyph.bounds().height();
|
||||
}
|
||||
}
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
int TextRenderer::draw(int x, int y, const char* str) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
int maxHeight = 0;
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
const Glyph& glyph = getGlyph(*ch);
|
||||
if (glyph.textureID() == 0) {
|
||||
|
@ -41,19 +58,23 @@ void TextRenderer::draw(int x, int y, const char* str) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (glyph.bounds().height() > maxHeight) {
|
||||
maxHeight = glyph.bounds().height();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||
|
||||
|
||||
int left = x + glyph.bounds().x();
|
||||
int right = x + glyph.bounds().x() + glyph.bounds().width();
|
||||
int bottom = y + glyph.bounds().y();
|
||||
int top = y + glyph.bounds().y() + glyph.bounds().height();
|
||||
|
||||
|
||||
float scale = 1.0 / IMAGE_SIZE;
|
||||
float ls = glyph.location().x() * scale;
|
||||
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
|
||||
float bt = glyph.location().y() * scale;
|
||||
float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
|
||||
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(ls, bt);
|
||||
glVertex2f(left, bottom);
|
||||
|
@ -64,12 +85,13 @@ void TextRenderer::draw(int x, int y, const char* str) {
|
|||
glTexCoord2f(ls, tt);
|
||||
glVertex2f(left, top);
|
||||
glEnd();
|
||||
|
||||
|
||||
x += glyph.width();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
int TextRenderer::computeWidth(char ch)
|
||||
|
|
|
@ -20,6 +20,16 @@
|
|||
// a special "character" that renders as a solid block
|
||||
const char SOLID_BLOCK_CHAR = 127;
|
||||
|
||||
// the standard sans serif font family
|
||||
#define SANS_FONT_FAMILY "Helvetica"
|
||||
|
||||
// the standard mono font family
|
||||
#define MONO_FONT_FAMILY "Courier"
|
||||
|
||||
// the Inconsolata font family
|
||||
#define INCONSOLATA_FONT_FAMILY "Inconsolata"
|
||||
|
||||
|
||||
class Glyph;
|
||||
|
||||
class TextRenderer {
|
||||
|
@ -33,7 +43,11 @@ public:
|
|||
|
||||
const QFontMetrics& metrics() const { return _metrics; }
|
||||
|
||||
void draw(int x, int y, const char* str);
|
||||
// returns the height of the tallest character
|
||||
int calculateHeight(const char* str);
|
||||
|
||||
// also returns the height of the tallest character
|
||||
int draw(int x, int y, const char* str);
|
||||
|
||||
int computeWidth(char ch);
|
||||
int computeWidth(const char* str);
|
||||
|
|
47
interface/src/ui/Volume3DOverlay.cpp
Normal file
47
interface/src/ui/Volume3DOverlay.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// Volume3DOverlay.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 <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
const float DEFAULT_SIZE = 1.0f;
|
||||
const bool DEFAULT_IS_SOLID = false;
|
||||
|
||||
Volume3DOverlay::Volume3DOverlay() :
|
||||
_size(DEFAULT_SIZE),
|
||||
_isSolid(DEFAULT_IS_SOLID)
|
||||
{
|
||||
}
|
||||
|
||||
Volume3DOverlay::~Volume3DOverlay() {
|
||||
}
|
||||
|
||||
void Volume3DOverlay::setProperties(const QScriptValue& properties) {
|
||||
Base3DOverlay::setProperties(properties);
|
||||
|
||||
if (properties.property("size").isValid()) {
|
||||
setSize(properties.property("size").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());
|
||||
}
|
||||
}
|
42
interface/src/ui/Volume3DOverlay.h
Normal file
42
interface/src/ui/Volume3DOverlay.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Volume3DOverlay.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Volume3DOverlay__
|
||||
#define __interface__Volume3DOverlay__
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QScriptValue>
|
||||
|
||||
#include "Base3DOverlay.h"
|
||||
|
||||
class Volume3DOverlay : public Base3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Volume3DOverlay();
|
||||
~Volume3DOverlay();
|
||||
|
||||
// getters
|
||||
float getSize() const { return _size; }
|
||||
bool getIsSolid() const { return _isSolid; }
|
||||
|
||||
// setters
|
||||
void setSize(float size) { _size = size; }
|
||||
void setIsSolid(bool isSolid) { _isSolid = isSolid; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
protected:
|
||||
float _size;
|
||||
bool _isSolid;
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__Volume3DOverlay__) */
|
|
@ -23,7 +23,6 @@ OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packe
|
|||
}
|
||||
|
||||
OctreeScriptingInterface::~OctreeScriptingInterface() {
|
||||
qDebug() << "OctreeScriptingInterface::~OctreeScriptingInterface() this=" << this;
|
||||
cleanupManagedObjects();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue