Merge pull request #5000 from huffman/scene-overlay

Team Teaching - Move overlay rendering to Scene pipeline
This commit is contained in:
samcake 2015-05-29 15:31:46 -07:00
commit f8a90684ce
10 changed files with 159 additions and 128 deletions

View file

@ -3035,17 +3035,6 @@ void Application::updateShadowMap(RenderArgs* renderArgs) {
_entities.render(renderArgs);
}
// render JS/scriptable overlays
{
PerformanceTimer perfTimer("3dOverlays");
_overlays.renderWorld(renderArgs, false);
}
{
PerformanceTimer perfTimer("3dOverlaysFront");
_overlays.renderWorld(renderArgs, true);
}
glDisable(GL_POLYGON_OFFSET_FILL);
glPopMatrix();
@ -3364,12 +3353,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
DependencyManager::get<DeferredLightingEffect>()->prepare();
if (!selfAvatarOnly) {
// render JS/scriptable overlays
{
PerformanceTimer perfTimer("3dOverlays");
_overlays.renderWorld(renderArgs, false);
}
// render models...
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
@ -3487,13 +3470,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
// Render 3D overlays that should be drawn in front
{
PerformanceTimer perfTimer("3dOverlaysFront");
glClear(GL_DEPTH_BUFFER_BIT);
Glower glower(renderArgs); // Sets alpha to 1.0
_overlays.renderWorld(renderArgs, true);
}
activeRenderingThread = nullptr;
}

View file

@ -637,9 +637,6 @@ private:
TouchEvent _lastTouchEvent;
Overlays _overlays;
ApplicationOverlay _applicationOverlay;
RunningScriptsWidget* _runningScriptsWidget;
QHash<QString, ScriptEngine*> _scriptEnginesHash;
bool _runningScriptsWidgetWasVisible;
@ -679,6 +676,9 @@ private:
render::ScenePointer _main3DScene{ new render::Scene() };
render::EnginePointer _renderEngine{ new render::Engine() };
Overlays _overlays;
ApplicationOverlay _applicationOverlay;
};
#endif // hifi_Application_h

View file

@ -76,7 +76,6 @@ public:
typedef render::Payload<AvatarData> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
typedef Payload::DataPointer Pointer;
void init();
void simulate(float deltaTime);

View file

@ -49,6 +49,11 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
Base3DOverlay::~Base3DOverlay() {
}
// TODO: Implement accurate getBounds() implementations
AABox Base3DOverlay::getBounds() const {
return AABox(_position, glm::vec3(1.0f));
}
void Base3DOverlay::setProperties(const QScriptValue& properties) {
Overlay::setProperties(properties);

View file

@ -49,6 +49,8 @@ public:
void setDrawInFront(bool value) { _drawInFront = value; }
void setDrawOnHUD(bool value) { _drawOnHUD = value; }
virtual AABox getBounds() const;
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);

View file

@ -16,6 +16,7 @@
#include <NumericalConstants.h>
Overlay::Overlay() :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_glowLevel(0.0f),
@ -35,6 +36,7 @@ Overlay::Overlay() :
}
Overlay::Overlay(const Overlay* overlay) :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(overlay->_isLoaded),
_alpha(overlay->_alpha),
_glowLevel(overlay->_glowLevel),
@ -225,3 +227,4 @@ float Overlay::updatePulse() {
return _pulse;
}

View file

@ -21,6 +21,8 @@
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h> // for xColor
#include <RenderArgs.h>
#include <AABox.h>
#include <render/Scene.h>
const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 };
const float DEFAULT_ALPHA = 0.7f;
@ -33,7 +35,12 @@ public:
NO_ANCHOR,
MY_AVATAR
};
typedef std::shared_ptr<Overlay> Pointer;
typedef render::Payload<Overlay> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
Overlay();
Overlay(const Overlay* overlay);
~Overlay();
@ -50,7 +57,6 @@ public:
float getGlowLevel();
Anchor getAnchor() const { return _anchor; }
float getPulseMax() const { return _pulseMax; }
float getPulseMin() const { return _pulseMin; }
float getPulsePeriod() const { return _pulsePeriod; }
@ -81,9 +87,14 @@ public:
virtual Overlay* createClone() const = 0;
virtual QScriptValue getProperty(const QString& property);
render::ItemID getRenderItemID() const { return _renderItemID; }
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
protected:
float updatePulse();
render::ItemID _renderItemID;
bool _isLoaded;
float _alpha;
float _glowLevel;

View file

@ -16,6 +16,7 @@
#include <Application.h>
#include <avatar/AvatarManager.h>
#include <LODManager.h>
#include <render/Scene.h>
#include "BillboardOverlay.h"
#include "Circle3DOverlay.h"
@ -31,6 +32,50 @@
#include "TextOverlay.h"
#include "Text3DOverlay.h"
namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
if (overlay->is3D() && !static_cast<Base3DOverlay*>(overlay.get())->getDrawOnHUD()) {
if (static_cast<Base3DOverlay*>(overlay.get())->getDrawInFront()) {
return ItemKey::Builder().withTypeShape().withNoDepthSort().build();
} else {
return ItemKey::Builder::opaqueShape();
}
} else {
return ItemKey::Builder().withTypeShape().withViewSpace().build();
}
}
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
if (overlay->is3D()) {
return static_cast<Base3DOverlay*>(overlay.get())->getBounds();
} else {
QRect bounds = static_cast<Overlay2D*>(overlay.get())->getBounds();
return AABox(glm::vec3(bounds.x(), bounds.y(), 0.0f), glm::vec3(bounds.width(), bounds.height(), 0.1f));
}
}
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
if (args) {
args->_elementsTouched++;
glPushMatrix();
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::quat myAvatarRotation = avatar->getOrientation();
glm::vec3 myAvatarPosition = avatar->getPosition();
float angle = glm::degrees(glm::angle(myAvatarRotation));
glm::vec3 axis = glm::axis(myAvatarRotation);
float myAvatarScale = avatar->getScale();
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
glRotatef(angle, axis.x, axis.y, axis.z);
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
}
overlay->render(args);
glPopMatrix();
}
}
}
Overlays::Overlays() : _nextOverlayID(1) {
}
@ -38,23 +83,18 @@ Overlays::~Overlays() {
{
QWriteLocker lock(&_lock);
foreach(Overlay* thisOverlay, _overlaysHUD) {
delete thisOverlay;
QWriteLocker deleteLock(&_deleteLock);
foreach(Overlay::Pointer overlay, _overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, _overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
_overlaysHUD.clear();
foreach(Overlay* thisOverlay, _overlaysWorld) {
delete thisOverlay;
}
_overlaysWorld.clear();
}
if (!_overlaysToDelete.isEmpty()) {
QWriteLocker lock(&_deleteLock);
do {
delete _overlaysToDelete.takeLast();
} while (!_overlaysToDelete.isEmpty());
}
cleanupOverlaysToDelete();
}
void Overlays::init() {
@ -65,21 +105,39 @@ void Overlays::update(float deltatime) {
{
QWriteLocker lock(&_lock);
foreach(Overlay* thisOverlay, _overlaysHUD) {
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime);
}
foreach(Overlay* thisOverlay, _overlaysWorld) {
foreach(Overlay::Pointer thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime);
}
}
cleanupOverlaysToDelete();
}
void Overlays::cleanupOverlaysToDelete() {
if (!_overlaysToDelete.isEmpty()) {
QWriteLocker lock(&_deleteLock);
do {
delete _overlaysToDelete.takeLast();
} while (!_overlaysToDelete.isEmpty());
render::PendingChanges pendingChanges;
{
QWriteLocker lock(&_deleteLock);
do {
Overlay::Pointer overlay = _overlaysToDelete.takeLast();
auto itemID = overlay->getRenderItemID();
if (itemID != render::Item::INVALID_ITEM_ID) {
pendingChanges.removeItem(itemID);
}
} while (!_overlaysToDelete.isEmpty());
}
if (pendingChanges._removedItems.size() > 0) {
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
scene->enqueuePendingChanges(pendingChanges);
}
}
}
void Overlays::renderHUD(RenderArgs* renderArgs) {
@ -87,7 +145,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
auto lodManager = DependencyManager::get<LODManager>();
foreach(Overlay* thisOverlay, _overlaysHUD) {
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
if (thisOverlay->is3D()) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
@ -96,57 +154,12 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
} else{
} else {
thisOverlay->render(renderArgs);
}
}
}
void Overlays::renderWorld(RenderArgs* renderArgs, bool drawFront) {
QReadLocker lock(&_lock);
if (_overlaysWorld.size() == 0) {
return;
}
bool myAvatarComputed = false;
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::quat myAvatarRotation;
glm::vec3 myAvatarPosition(0.0f);
float angle = 0.0f;
glm::vec3 axis(0.0f, 1.0f, 0.0f);
float myAvatarScale = 1.0f;
auto lodManager = DependencyManager::get<LODManager>();
foreach(Overlay* thisOverlay, _overlaysWorld) {
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay);
if (overlay3D->getDrawInFront() != drawFront) {
continue;
}
glPushMatrix();
switch (thisOverlay->getAnchor()) {
case Overlay::MY_AVATAR:
if (!myAvatarComputed) {
myAvatarRotation = avatar->getOrientation();
myAvatarPosition = avatar->getPosition();
angle = glm::degrees(glm::angle(myAvatarRotation));
axis = glm::axis(myAvatarRotation);
myAvatarScale = avatar->getScale();
myAvatarComputed = true;
}
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
glRotatef(angle, axis.x, axis.y, axis.z);
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
break;
default:
break;
}
thisOverlay->render(renderArgs);
glPopMatrix();
}
}
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
unsigned int thisID = 0;
Overlay* thisOverlay = NULL;
@ -189,6 +202,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
}
unsigned int Overlays::addOverlay(Overlay* overlay) {
Overlay::Pointer overlayPointer(overlay);
overlay->init(_scriptEngine);
QWriteLocker lock(&_lock);
@ -197,19 +211,30 @@ unsigned int Overlays::addOverlay(Overlay* overlay) {
if (overlay->is3D()) {
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(overlay);
if (overlay3D->getDrawOnHUD()) {
_overlaysHUD[thisID] = overlay;
_overlaysHUD[thisID] = overlayPointer;
} else {
_overlaysWorld[thisID] = overlay;
_overlaysWorld[thisID] = overlayPointer;
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
auto overlayPayload = new Overlay::Payload(overlayPointer);
auto overlayPayloadPointer = Overlay::PayloadPointer(overlayPayload);
render::ItemID itemID = scene->allocateID();
overlay->setRenderItemID(itemID);
render::PendingChanges pendingChanges;
pendingChanges.resetItem(itemID, overlayPayloadPointer);
scene->enqueuePendingChanges(pendingChanges);
}
} else {
_overlaysHUD[thisID] = overlay;
_overlaysHUD[thisID] = overlayPointer;
}
return thisID;
}
unsigned int Overlays::cloneOverlay(unsigned int id) {
Overlay* thisOverlay = NULL;
Overlay::Pointer thisOverlay = NULL;
if (_overlaysHUD.contains(id)) {
thisOverlay = _overlaysHUD[id];
} else if (_overlaysWorld.contains(id)) {
@ -225,7 +250,7 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
QWriteLocker lock(&_lock);
Overlay* thisOverlay = NULL;
Overlay::Pointer thisOverlay;
if (_overlaysHUD.contains(id)) {
thisOverlay = _overlaysHUD[id];
@ -235,7 +260,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
if (thisOverlay) {
if (thisOverlay->is3D()) {
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay);
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay.get());
bool oldDrawOnHUD = overlay3D->getDrawOnHUD();
thisOverlay->setProperties(properties);
@ -260,7 +285,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
}
void Overlays::deleteOverlay(unsigned int id) {
Overlay* overlayToDelete;
Overlay::Pointer overlayToDelete;
{
QWriteLocker lock(&_lock);
@ -284,7 +309,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
}
QReadLocker lock(&_lock);
QMapIterator<unsigned int, Overlay*> i(_overlaysHUD);
QMapIterator<unsigned int, Overlay::Pointer> i(_overlaysHUD);
i.toBack();
const float LARGE_NEGATIVE_FLOAT = -9999999;
@ -297,14 +322,14 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
i.previous();
unsigned int thisID = i.key();
if (i.value()->is3D()) {
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value());
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value().get());
if (!thisOverlay->getIgnoreRayIntersection()) {
if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace)) {
return thisID;
}
}
} else {
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value());
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value().get());
if (thisOverlay->getVisible() && thisOverlay->isLoaded() &&
thisOverlay->getBounds().contains(pointCopy.x, pointCopy.y, false)) {
return thisID;
@ -317,7 +342,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
OverlayPropertyResult result;
Overlay* thisOverlay = NULL;
Overlay::Pointer thisOverlay;
QReadLocker lock(&_lock);
if (_overlaysHUD.contains(id)) {
thisOverlay = _overlaysHUD[id];
@ -364,12 +389,12 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray)
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
RayToOverlayIntersectionResult result;
QMapIterator<unsigned int, Overlay*> i(_overlaysWorld);
QMapIterator<unsigned int, Overlay::Pointer> i(_overlaysWorld);
i.toBack();
while (i.hasPrevious()) {
i.previous();
unsigned int thisID = i.key();
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value());
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value().get());
if (thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) {
float thisDistance;
BoxFace thisFace;
@ -471,7 +496,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
bool Overlays::isLoaded(unsigned int id) {
QReadLocker lock(&_lock);
Overlay* thisOverlay = NULL;
Overlay::Pointer thisOverlay = NULL;
if (_overlaysHUD.contains(id)) {
thisOverlay = _overlaysHUD[id];
} else if (_overlaysWorld.contains(id)) {
@ -483,16 +508,16 @@ bool Overlays::isLoaded(unsigned int id) {
}
QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
Overlay* thisOverlay = _overlaysHUD[id];
Overlay::Pointer thisOverlay = _overlaysHUD[id];
if (thisOverlay) {
if (typeid(*thisOverlay) == typeid(TextOverlay)) {
return static_cast<TextOverlay*>(thisOverlay)->textSize(text);
return static_cast<TextOverlay*>(thisOverlay.get())->textSize(text);
}
} else {
thisOverlay = _overlaysWorld[id];
if (thisOverlay) {
if (typeid(*thisOverlay) == typeid(Text3DOverlay)) {
return static_cast<Text3DOverlay*>(thisOverlay)->textSize(text);
return static_cast<Text3DOverlay*>(thisOverlay.get())->textSize(text);
}
}
}

View file

@ -53,7 +53,6 @@ public:
~Overlays();
void init();
void update(float deltatime);
void renderWorld(RenderArgs* renderArgs, bool drawFront);
void renderHUD(RenderArgs* renderArgs);
public slots:
@ -90,9 +89,10 @@ public slots:
QSizeF textSize(unsigned int id, const QString& text) const;
private:
QMap<unsigned int, Overlay*> _overlaysHUD;
QMap<unsigned int, Overlay*> _overlaysWorld;
QList<Overlay*> _overlaysToDelete;
void cleanupOverlaysToDelete();
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
QList<Overlay::Pointer> _overlaysToDelete;
unsigned int _nextOverlayID;
QReadWriteLock _lock;
QReadWriteLock _deleteLock;

View file

@ -32,15 +32,16 @@ class Context;
class ItemKey {
public:
enum FlagBit {
TYPE_SHAPE = 0, // Item is a Shape
TYPE_LIGHT, // Item is a Light
TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
VIEW_SPACE, // Transformed in view space, and not in world space
DYNAMIC, // Dynamic and bound will change unlike static item
DEFORMED, // Deformed within bound, not solid
INVISIBLE, // Visible or not? could be just here to cast shadow
SHADOW_CASTER, // Item cast shadows
PICKABLE, // Item can be picked/selected
TYPE_SHAPE = 0, // Item is a Shape
TYPE_LIGHT, // Item is a Light
TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
VIEW_SPACE, // Transformed in view space, and not in world space
DYNAMIC, // Dynamic and bound will change unlike static item
DEFORMED, // Deformed within bound, not solid
INVISIBLE, // Visible or not? could be just here to cast shadow
SHADOW_CASTER, // Item cast shadows
PICKABLE, // Item can be picked/selected
NO_DEPTH_SORT, // Item should not be depth sorted
NUM_FLAGS, // Not a valid flag
};
@ -68,6 +69,7 @@ public:
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
Builder& withNoDepthSort() { _flags.set(NO_DEPTH_SORT); return (*this); }
// Convenient standard keys that we will keep on using all over the place
static ItemKey opaqueShape() { return Builder().withTypeShape().build(); }
@ -80,7 +82,7 @@ public:
bool isWorldSpace() const { return !_flags[VIEW_SPACE]; }
bool isViewSpace() const { return _flags[VIEW_SPACE]; }
bool isStatic() const { return !_flags[DYNAMIC]; }
bool isDynamic() const { return _flags[DYNAMIC]; }
@ -88,11 +90,14 @@ public:
bool isDeformed() const { return _flags[DEFORMED]; }
bool isVisible() const { return !_flags[INVISIBLE]; }
bool isUnvisible() const { return _flags[INVISIBLE]; }
bool isInvisible() const { return _flags[INVISIBLE]; }
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
bool isPickable() const { return _flags[PICKABLE]; }
bool isDepthSort() const { return !_flags[NO_DEPTH_SORT]; }
bool isNoDepthSort() const { return _flags[NO_DEPTH_SORT]; }
};
inline QDebug operator<<(QDebug debug, const ItemKey& itemKey) {
@ -142,6 +147,9 @@ public:
Builder& withPickable() { _value.set(ItemKey::PICKABLE); _mask.set(ItemKey::PICKABLE); return (*this); }
Builder& withDepthSort() { _value.reset(ItemKey::NO_DEPTH_SORT); _mask.set(ItemKey::NO_DEPTH_SORT); return (*this); }
Builder& withNotDepthSort() { _value.set(ItemKey::NO_DEPTH_SORT); _mask.set(ItemKey::NO_DEPTH_SORT); return (*this); }
// Convenient standard keys that we will keep on using all over the place
static ItemFilter opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace().build(); }
static ItemFilter transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace().build(); }
@ -174,6 +182,8 @@ public:
typedef std::vector<Item> Vector;
typedef unsigned int ID;
static const ID INVALID_ITEM_ID = 0;
// Bound is the AABBox fully containing this item
typedef AABox Bound;