mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +02:00
Merge pull request #3104 from Atlante45/model_and_billboard_overlays
Model and billboard overlays
This commit is contained in:
commit
d8a5f59511
7 changed files with 354 additions and 3 deletions
|
@ -135,7 +135,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
args->_elementsTouched++;
|
args->_elementsTouched++;
|
||||||
// actually render it here...
|
// actually render it here...
|
||||||
// we need to iterate the actual modelItems of the element
|
// we need to iterate the actual modelItems of the element
|
||||||
ModelTreeElement* modelTreeElement = (ModelTreeElement*)element;
|
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
|
||||||
|
|
||||||
QList<ModelItem>& modelItems = modelTreeElement->getModels();
|
QList<ModelItem>& modelItems = modelTreeElement->getModels();
|
||||||
|
|
||||||
|
|
136
interface/src/ui/overlays/BillboardOverlay.cpp
Normal file
136
interface/src/ui/overlays/BillboardOverlay.cpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
//
|
||||||
|
// BillboardOverlay.cpp
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Clement on 7/1/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "../../Application.h"
|
||||||
|
|
||||||
|
#include "BillboardOverlay.h"
|
||||||
|
|
||||||
|
BillboardOverlay::BillboardOverlay()
|
||||||
|
: _manager(NULL),
|
||||||
|
_scale(1.0f),
|
||||||
|
_isFacingAvatar(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BillboardOverlay::render() {
|
||||||
|
if (_billboard.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_billboardTexture) {
|
||||||
|
QImage image = QImage::fromData(_billboard);
|
||||||
|
if (image.format() != QImage::Format_ARGB32) {
|
||||||
|
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
|
}
|
||||||
|
_size = image.size();
|
||||||
|
_billboardTexture.reset(new Texture());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _size.width(), _size.height(), 0,
|
||||||
|
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glAlphaFunc(GL_GREATER, 0.5f);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
glPushMatrix(); {
|
||||||
|
glTranslatef(_position.x, _position.y, _position.z);
|
||||||
|
if (_isFacingAvatar) {
|
||||||
|
// rotate about vertical to face the camera
|
||||||
|
glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
|
||||||
|
rotation *= glm::angleAxis(glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
glm::vec3 axis = glm::axis(rotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||||
|
} else {
|
||||||
|
glm::vec3 axis = glm::axis(_rotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(_rotation)), axis.x, axis.y, axis.z);
|
||||||
|
}
|
||||||
|
glScalef(_scale, _scale, _scale);
|
||||||
|
|
||||||
|
float maxSize = glm::max(_size.width(), _size.height());
|
||||||
|
float x = _size.width() / (2.0f * maxSize);
|
||||||
|
float y = -_size.height() / (2.0f * maxSize);
|
||||||
|
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
glBegin(GL_QUADS); {
|
||||||
|
glTexCoord2f(0.0f, 0.0f);
|
||||||
|
glVertex2f(-x, -y);
|
||||||
|
glTexCoord2f(1.0f, 0.0f);
|
||||||
|
glVertex2f(x, -y);
|
||||||
|
glTexCoord2f(1.0f, 1.0f);
|
||||||
|
glVertex2f(x, y);
|
||||||
|
glTexCoord2f(0.0f, 1.0f);
|
||||||
|
glVertex2f(-x, y);
|
||||||
|
} glEnd();
|
||||||
|
|
||||||
|
} glPopMatrix();
|
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
||||||
|
Base3DOverlay::setProperties(properties);
|
||||||
|
|
||||||
|
QScriptValue urlValue = properties.property("url");
|
||||||
|
if (urlValue.isValid()) {
|
||||||
|
_url = urlValue.toVariant().toString();
|
||||||
|
|
||||||
|
setBillboardURL(_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue scaleValue = properties.property("scale");
|
||||||
|
if (scaleValue.isValid()) {
|
||||||
|
_scale = scaleValue.toVariant().toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue rotationValue = properties.property("rotation");
|
||||||
|
if (rotationValue.isValid()) {
|
||||||
|
QScriptValue x = rotationValue.property("x");
|
||||||
|
QScriptValue y = rotationValue.property("y");
|
||||||
|
QScriptValue z = rotationValue.property("z");
|
||||||
|
QScriptValue w = rotationValue.property("w");
|
||||||
|
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||||
|
_rotation.x = x.toVariant().toFloat();
|
||||||
|
_rotation.y = y.toVariant().toFloat();
|
||||||
|
_rotation.z = z.toVariant().toFloat();
|
||||||
|
_rotation.w = w.toVariant().toFloat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue isFacingAvatarValue = properties.property("isFacingAvatar");
|
||||||
|
if (isFacingAvatarValue.isValid()) {
|
||||||
|
_isFacingAvatar = isFacingAvatarValue.toVariant().toBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||||
|
void BillboardOverlay::setBillboardURL(const QUrl url) {
|
||||||
|
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
|
||||||
|
_manager->deleteLater();
|
||||||
|
_manager = new QNetworkAccessManager();
|
||||||
|
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
||||||
|
_manager->get(QNetworkRequest(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BillboardOverlay::replyFinished(QNetworkReply* reply) {
|
||||||
|
// replace our byte array with the downloaded data
|
||||||
|
_billboard = reply->readAll();
|
||||||
|
_manager->deleteLater();
|
||||||
|
_manager = NULL;
|
||||||
|
}
|
46
interface/src/ui/overlays/BillboardOverlay.h
Normal file
46
interface/src/ui/overlays/BillboardOverlay.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// BillboardOverlay.h
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Clement on 7/1/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_BillboardOverlay_h
|
||||||
|
#define hifi_BillboardOverlay_h
|
||||||
|
|
||||||
|
#include <QScopedPointer>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "Base3DOverlay.h"
|
||||||
|
#include "../../renderer/TextureCache.h"
|
||||||
|
|
||||||
|
class BillboardOverlay : public Base3DOverlay {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
BillboardOverlay();
|
||||||
|
|
||||||
|
virtual void render();
|
||||||
|
virtual void setProperties(const QScriptValue& properties);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void replyFinished(QNetworkReply* reply);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setBillboardURL(const QUrl url);
|
||||||
|
|
||||||
|
QNetworkAccessManager* _manager;
|
||||||
|
QUrl _url;
|
||||||
|
QByteArray _billboard;
|
||||||
|
QSize _size;
|
||||||
|
QScopedPointer<Texture> _billboardTexture;
|
||||||
|
|
||||||
|
glm::quat _rotation;
|
||||||
|
float _scale;
|
||||||
|
bool _isFacingAvatar;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_BillboardOverlay_h
|
|
@ -19,7 +19,7 @@
|
||||||
#include "ImageOverlay.h"
|
#include "ImageOverlay.h"
|
||||||
|
|
||||||
ImageOverlay::ImageOverlay() :
|
ImageOverlay::ImageOverlay() :
|
||||||
_manager(0),
|
_manager(NULL),
|
||||||
_textureID(0),
|
_textureID(0),
|
||||||
_renderImage(false),
|
_renderImage(false),
|
||||||
_textureBound(false),
|
_textureBound(false),
|
||||||
|
@ -37,6 +37,7 @@ ImageOverlay::~ImageOverlay() {
|
||||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||||
void ImageOverlay::setImageURL(const QUrl& url) {
|
void ImageOverlay::setImageURL(const QUrl& url) {
|
||||||
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
|
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
|
||||||
|
_manager->deleteLater();
|
||||||
_manager = new QNetworkAccessManager();
|
_manager = new QNetworkAccessManager();
|
||||||
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
||||||
_manager->get(QNetworkRequest(url));
|
_manager->get(QNetworkRequest(url));
|
||||||
|
@ -49,6 +50,7 @@ void ImageOverlay::replyFinished(QNetworkReply* reply) {
|
||||||
_textureImage.loadFromData(rawData);
|
_textureImage.loadFromData(rawData);
|
||||||
_renderImage = true;
|
_renderImage = true;
|
||||||
_manager->deleteLater();
|
_manager->deleteLater();
|
||||||
|
_manager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageOverlay::render() {
|
void ImageOverlay::render() {
|
||||||
|
|
115
interface/src/ui/overlays/ModelOverlay.cpp
Normal file
115
interface/src/ui/overlays/ModelOverlay.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
//
|
||||||
|
// ModelOverlay.cpp
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Clement on 6/30/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#include "../../Menu.h"
|
||||||
|
|
||||||
|
#include "ModelOverlay.h"
|
||||||
|
|
||||||
|
ModelOverlay::ModelOverlay()
|
||||||
|
: _model(),
|
||||||
|
_scale(1.0f),
|
||||||
|
_updateModel(false) {
|
||||||
|
_model.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::update(float deltatime) {
|
||||||
|
if (_updateModel) {
|
||||||
|
_updateModel = false;
|
||||||
|
|
||||||
|
_model.setScaleToFit(true, _scale);
|
||||||
|
_model.setSnapModelToCenter(true);
|
||||||
|
_model.setRotation(_rotation);
|
||||||
|
_model.setTranslation(_position);
|
||||||
|
_model.setURL(_url);
|
||||||
|
_model.simulate(deltatime, true);
|
||||||
|
} else {
|
||||||
|
_model.simulate(deltatime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::render() {
|
||||||
|
if (_model.isActive()) {
|
||||||
|
|
||||||
|
if (_model.isRenderable()) {
|
||||||
|
_model.render(_alpha);
|
||||||
|
}
|
||||||
|
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
|
||||||
|
if (displayModelBounds) {
|
||||||
|
glm::vec3 unRotatedMinimum = _model.getUnscaledMeshExtents().minimum;
|
||||||
|
glm::vec3 unRotatedMaximum = _model.getUnscaledMeshExtents().maximum;
|
||||||
|
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||||
|
|
||||||
|
float width = unRotatedExtents.x;
|
||||||
|
float height = unRotatedExtents.y;
|
||||||
|
float depth = unRotatedExtents.z;
|
||||||
|
|
||||||
|
Extents rotatedExtents = _model.getUnscaledMeshExtents();
|
||||||
|
calculateRotatedExtents(rotatedExtents, _rotation);
|
||||||
|
|
||||||
|
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
|
||||||
|
|
||||||
|
const glm::vec3& modelScale = _model.getScale();
|
||||||
|
|
||||||
|
glPushMatrix(); {
|
||||||
|
glTranslatef(_position.x, _position.y, _position.z);
|
||||||
|
|
||||||
|
// draw the rotated bounding cube
|
||||||
|
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
glPushMatrix(); {
|
||||||
|
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
|
||||||
|
glutWireCube(1.0);
|
||||||
|
} glPopMatrix();
|
||||||
|
|
||||||
|
// draw the model relative bounding box
|
||||||
|
glm::vec3 axis = glm::axis(_rotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(_rotation)), axis.x, axis.y, axis.z);
|
||||||
|
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
|
||||||
|
glColor3f(0.0f, 1.0f, 0.0f);
|
||||||
|
glutWireCube(1.0);
|
||||||
|
|
||||||
|
} glPopMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::setProperties(const QScriptValue &properties) {
|
||||||
|
Base3DOverlay::setProperties(properties);
|
||||||
|
|
||||||
|
QScriptValue urlValue = properties.property("url");
|
||||||
|
if (urlValue.isValid()) {
|
||||||
|
_url = urlValue.toVariant().toString();
|
||||||
|
_updateModel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue scaleValue = properties.property("scale");
|
||||||
|
if (scaleValue.isValid()) {
|
||||||
|
_scale = scaleValue.toVariant().toFloat();
|
||||||
|
_updateModel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue rotationValue = properties.property("rotation");
|
||||||
|
if (rotationValue.isValid()) {
|
||||||
|
QScriptValue x = rotationValue.property("x");
|
||||||
|
QScriptValue y = rotationValue.property("y");
|
||||||
|
QScriptValue z = rotationValue.property("z");
|
||||||
|
QScriptValue w = rotationValue.property("w");
|
||||||
|
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
|
||||||
|
_rotation.x = x.toVariant().toFloat();
|
||||||
|
_rotation.y = y.toVariant().toFloat();
|
||||||
|
_rotation.z = z.toVariant().toFloat();
|
||||||
|
_rotation.w = w.toVariant().toFloat();
|
||||||
|
}
|
||||||
|
_updateModel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.property("position").isValid()) {
|
||||||
|
_updateModel = true;
|
||||||
|
}
|
||||||
|
}
|
38
interface/src/ui/overlays/ModelOverlay.h
Normal file
38
interface/src/ui/overlays/ModelOverlay.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// ModelOverlay.h
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Clement on 6/30/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_ModelOverlay_h
|
||||||
|
#define hifi_ModelOverlay_h
|
||||||
|
|
||||||
|
#include "Base3DOverlay.h"
|
||||||
|
|
||||||
|
#include "../../renderer/Model.h"
|
||||||
|
|
||||||
|
class ModelOverlay : public Base3DOverlay {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ModelOverlay();
|
||||||
|
|
||||||
|
virtual void update(float deltatime);
|
||||||
|
virtual void render();
|
||||||
|
virtual void setProperties(const QScriptValue& properties);
|
||||||
|
private:
|
||||||
|
|
||||||
|
Model _model;
|
||||||
|
|
||||||
|
QUrl _url;
|
||||||
|
glm::quat _rotation;
|
||||||
|
float _scale;
|
||||||
|
|
||||||
|
bool _updateModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ModelOverlay_h
|
|
@ -10,13 +10,15 @@
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
|
||||||
|
#include "BillboardOverlay.h"
|
||||||
#include "Cube3DOverlay.h"
|
#include "Cube3DOverlay.h"
|
||||||
#include "ImageOverlay.h"
|
#include "ImageOverlay.h"
|
||||||
#include "Line3DOverlay.h"
|
#include "Line3DOverlay.h"
|
||||||
|
#include "LocalVoxelsOverlay.h"
|
||||||
|
#include "ModelOverlay.h"
|
||||||
#include "Overlays.h"
|
#include "Overlays.h"
|
||||||
#include "Sphere3DOverlay.h"
|
#include "Sphere3DOverlay.h"
|
||||||
#include "TextOverlay.h"
|
#include "TextOverlay.h"
|
||||||
#include "LocalVoxelsOverlay.h"
|
|
||||||
|
|
||||||
Overlays::Overlays() : _nextOverlayID(1) {
|
Overlays::Overlays() : _nextOverlayID(1) {
|
||||||
}
|
}
|
||||||
|
@ -156,6 +158,18 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
||||||
thisOverlay->setProperties(properties);
|
thisOverlay->setProperties(properties);
|
||||||
created = true;
|
created = true;
|
||||||
is3D = true;
|
is3D = true;
|
||||||
|
} else if (type == "model") {
|
||||||
|
thisOverlay = new ModelOverlay();
|
||||||
|
thisOverlay->init(_parent);
|
||||||
|
thisOverlay->setProperties(properties);
|
||||||
|
created = true;
|
||||||
|
is3D = true;
|
||||||
|
} else if (type == "billboard") {
|
||||||
|
thisOverlay = new BillboardOverlay();
|
||||||
|
thisOverlay->init(_parent);
|
||||||
|
thisOverlay->setProperties(properties);
|
||||||
|
created = true;
|
||||||
|
is3D = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (created) {
|
if (created) {
|
||||||
|
|
Loading…
Reference in a new issue