From 718439014ad8a2b1784de15d05a8a668f9c537cd Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Feb 2014 17:28:11 -0800 Subject: [PATCH 01/31] Compute the mesh extents for geometry and use them to set the spanner bounds. --- interface/src/MetavoxelSystem.cpp | 10 +++ interface/src/renderer/FBXReader.cpp | 11 ++++ interface/src/renderer/FBXReader.h | 1 + interface/src/ui/MetavoxelEditor.cpp | 30 ++++++--- libraries/metavoxels/src/MetavoxelUtil.cpp | 74 ++++++++++++++++++++++ libraries/metavoxels/src/MetavoxelUtil.h | 2 + 6 files changed, 118 insertions(+), 10 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 59a714ece5..b7d9ea9e03 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -274,6 +276,14 @@ void StaticModelRenderer::init(Spanner* spanner) { } void StaticModelRenderer::simulate(float deltaTime) { + // update the bounds + Box bounds; + if (_model->isActive()) { + const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents; + bounds = Box(extents.minimum, extents.maximum); + } + static_cast(parent())->setBounds(glm::translate(_model->getTranslation()) * + glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds); _model->simulate(deltaTime); } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8b881940ca..57a9768f7c 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1276,6 +1276,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.bindExtents.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); geometry.staticExtents.minimum = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX); geometry.staticExtents.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + geometry.meshExtents.minimum = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX); + geometry.meshExtents.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); QVariantHash springs = mapping.value("spring").toHash(); QVariant defaultSpring = springs.value("default"); @@ -1287,6 +1289,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat(); glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID); + // compute the mesh extents from the transformed vertices + foreach (const glm::vec3& vertex, extracted.mesh.vertices) { + glm::vec3 transformedVertex = glm::vec3(modelTransform * glm::vec4(vertex, 1.0f)); + geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex); + geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex); + } + // look for textures, material properties int materialIndex = 0; int textureIndex = 0; @@ -1704,5 +1713,7 @@ FBXGeometry readSVO(const QByteArray& model) { geometry.meshes.append(mesh); + geometry.meshExtents.maximum = glm::vec3(1.0f, 1.0f, 1.0f); + return geometry; } diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index b89d0954b4..a26ef40646 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -163,6 +163,7 @@ public: Extents bindExtents; Extents staticExtents; + Extents meshExtents; QVector attachments; }; diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 832c6b5d39..c30dc15b65 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -269,6 +269,12 @@ const float GRID_BRIGHTNESS = 0.5f; void MetavoxelEditor::render() { glDisable(GL_LIGHTING); + + MetavoxelTool* tool = getActiveTool(); + if (tool) { + tool->render(); + } + glDepthMask(GL_FALSE); glPushMatrix(); @@ -277,11 +283,6 @@ void MetavoxelEditor::render() { glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - MetavoxelTool* tool = getActiveTool(); - if (tool) { - tool->render(); - } - glLineWidth(1.0f); // center the grid around the camera position on the plane @@ -375,7 +376,14 @@ void BoxSetTool::render() { resetState(); return; } + glDepthMask(GL_FALSE); + + glPushMatrix(); + glm::quat rotation = _editor->getGridRotation(); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glm::quat inverseRotation = glm::inverse(rotation); glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin(); glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection(); @@ -439,6 +447,8 @@ void BoxSetTool::render() { glPopMatrix(); } + + glPopMatrix(); } bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) { @@ -524,11 +534,6 @@ InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : } void InsertSpannerTool::simulate(float deltaTime) { - SharedObjectPointer spanner = _editor->getValue().value(); - static_cast(spanner.data())->getRenderer()->simulate(deltaTime); -} - -void InsertSpannerTool::render() { _editor->detachValue(); Spanner* spanner = static_cast(_editor->getValue().value().data()); Transformable* transformable = qobject_cast(spanner); @@ -543,6 +548,11 @@ void InsertSpannerTool::render() { transformable->setTranslation(rotation * glm::vec3(glm::vec2(rayOrigin + rayDirection * distance), position)); } + spanner->getRenderer()->simulate(deltaTime); +} + +void InsertSpannerTool::render() { + Spanner* spanner = static_cast(_editor->getValue().value().data()); const float SPANNER_ALPHA = 0.25f; spanner->getRenderer()->render(SPANNER_ALPHA); } diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 2e93fb1804..e1c92f3e8a 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -162,6 +162,80 @@ bool Box::intersects(const Box& other) const { other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; } +Box operator*(const glm::mat4& matrix, const Box& box) { + // start with the constant component + Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2])); + + // for each element, we choose the minimum or maximum based on the matrix sign + if (matrix[0][0] >= 0.0f) { + newBox.minimum.x += matrix[0][0] * box.minimum.x; + newBox.maximum.x += matrix[0][0] * box.maximum.x; + } else { + newBox.minimum.x += matrix[0][0] * box.maximum.x; + newBox.maximum.x += matrix[0][0] * box.minimum.x; + } + if (matrix[1][0] >= 0.0f) { + newBox.minimum.x += matrix[1][0] * box.minimum.y; + newBox.maximum.x += matrix[1][0] * box.maximum.y; + } else { + newBox.minimum.x += matrix[1][0] * box.maximum.y; + newBox.maximum.x += matrix[1][0] * box.minimum.y; + } + if (matrix[2][0] >= 0.0f) { + newBox.minimum.x += matrix[2][0] * box.minimum.z; + newBox.maximum.x += matrix[2][0] * box.maximum.z; + } else { + newBox.minimum.x += matrix[2][0] * box.maximum.z; + newBox.maximum.x += matrix[2][0] * box.minimum.z; + } + + if (matrix[0][1] >= 0.0f) { + newBox.minimum.y += matrix[0][1] * box.minimum.x; + newBox.maximum.y += matrix[0][1] * box.maximum.x; + } else { + newBox.minimum.y += matrix[0][1] * box.maximum.x; + newBox.maximum.y += matrix[0][1] * box.minimum.x; + } + if (matrix[1][1] >= 0.0f) { + newBox.minimum.y += matrix[1][1] * box.minimum.y; + newBox.maximum.y += matrix[1][1] * box.maximum.y; + } else { + newBox.minimum.y += matrix[1][1] * box.maximum.y; + newBox.maximum.y += matrix[1][1] * box.minimum.y; + } + if (matrix[2][1] >= 0.0f) { + newBox.minimum.y += matrix[2][1] * box.minimum.z; + newBox.maximum.y += matrix[2][1] * box.maximum.z; + } else { + newBox.minimum.y += matrix[2][1] * box.maximum.z; + newBox.maximum.y += matrix[2][1] * box.minimum.z; + } + + if (matrix[0][2] >= 0.0f) { + newBox.minimum.z += matrix[0][2] * box.minimum.x; + newBox.maximum.z += matrix[0][2] * box.maximum.x; + } else { + newBox.minimum.z += matrix[0][2] * box.maximum.x; + newBox.maximum.z += matrix[0][2] * box.minimum.x; + } + if (matrix[1][2] >= 0.0f) { + newBox.minimum.z += matrix[1][2] * box.minimum.y; + newBox.maximum.z += matrix[1][2] * box.maximum.y; + } else { + newBox.minimum.z += matrix[1][2] * box.maximum.y; + newBox.maximum.z += matrix[1][2] * box.minimum.y; + } + if (matrix[2][2] >= 0.0f) { + newBox.minimum.z += matrix[2][2] * box.minimum.z; + newBox.maximum.z += matrix[2][2] * box.maximum.z; + } else { + newBox.minimum.z += matrix[2][2] * box.maximum.z; + newBox.maximum.z += matrix[2][2] * box.minimum.z; + } + + return newBox; +} + QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(QMargins()); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 4b3fb43523..adb106b652 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -48,6 +48,8 @@ public: DECLARE_STREAMABLE_METATYPE(Box) +Box operator*(const glm::mat4& matrix, const Box& box); + /// Editor for meta-object values. class QMetaObjectEditor : public QWidget { Q_OBJECT From 5d7eadcca373edfda075feaa958ca312d4569685 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 25 Feb 2014 13:48:46 -0800 Subject: [PATCH 02/31] Working on better streaming for spanners. --- .../metavoxels/src/AttributeRegistry.cpp | 39 ++++++++++++++++++- libraries/metavoxels/src/AttributeRegistry.h | 23 +++++++++++ libraries/metavoxels/src/MetavoxelData.cpp | 12 +++--- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index bd83987666..bc9d9b030a 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -14,6 +14,7 @@ REGISTER_META_OBJECT(QRgbAttribute) REGISTER_META_OBJECT(SharedObjectAttribute) REGISTER_META_OBJECT(SharedObjectSetAttribute) +REGISTER_META_OBJECT(SpannerSetAttribute) AttributeRegistry* AttributeRegistry::getInstance() { static AttributeRegistry registry; @@ -23,7 +24,7 @@ AttributeRegistry* AttributeRegistry::getInstance() { AttributeRegistry::AttributeRegistry() : _guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject, SharedObjectPointer(new DefaultMetavoxelGuide())))), - _spannersAttribute(registerAttribute(new SharedObjectSetAttribute("spanners", &Spanner::staticMetaObject))), + _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { } @@ -145,6 +146,22 @@ Attribute::Attribute(const QString& name) { Attribute::~Attribute() { } +void Attribute::read(MetavoxelNode& root, Bitstream& in) { + root.read(this, in); +} + +void Attribute::write(const MetavoxelNode& root, Bitstream& out) { + root.write(this, out); +} + +void Attribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { + root.readDelta(this, reference, in); +} + +void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { + root.writeDelta(this, reference, out); +} + QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : InlineAttribute(name, defaultValue) { } @@ -255,3 +272,23 @@ bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const { QWidget* SharedObjectSetAttribute::createEditor(QWidget* parent) const { return new SharedObjectEditor(_metaObject, parent); } + +SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* metaObject) : + SharedObjectSetAttribute(name, metaObject) { +} + +void SpannerSetAttribute::read(MetavoxelNode& root, Bitstream& in) { + root.read(this, in); +} + +void SpannerSetAttribute::write(const MetavoxelNode& root, Bitstream& out) { + root.write(this, out); +} + +void SpannerSetAttribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { + root.readDelta(this, reference, in); +} + +void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { + root.writeDelta(this, reference, out); +} diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 2e029f8201..000e18ca6b 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -23,6 +23,7 @@ class QScriptEngine; class QScriptValue; class Attribute; +class MetavoxelNode; typedef SharedObjectPointerTemplate AttributePointer; @@ -170,6 +171,12 @@ public: virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); } virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); } + virtual void read(MetavoxelNode& root, Bitstream& in); + virtual void write(const MetavoxelNode& root, Bitstream& out); + + virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); + virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); + virtual bool equal(void* first, void* second) const = 0; /// Merges the value of a parent and its children. @@ -309,4 +316,20 @@ private: const QMetaObject* _metaObject; }; +/// An attribute that takes the form of a set of spanners. +class SpannerSetAttribute : public SharedObjectSetAttribute { + Q_OBJECT + +public: + + Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(), + const QMetaObject* metaObject = &SharedObject::staticMetaObject); + + virtual void read(MetavoxelNode& root, Bitstream& in); + virtual void write(const MetavoxelNode& root, Bitstream& out); + + virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); + virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); +}; + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5665e70f91..38b073a0b9 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -240,7 +240,7 @@ void MetavoxelData::read(Bitstream& in) { in >> attribute; MetavoxelNode*& root = _roots[attribute]; root = new MetavoxelNode(attribute); - root->read(attribute, in); + attribute->read(*root, in); } } @@ -249,7 +249,7 @@ void MetavoxelData::write(Bitstream& out) const { out << _roots.size(); for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { out << it.key(); - it.value()->write(it.key(), out); + it.key()->write(*it.value(), out); } } @@ -282,12 +282,12 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { if (root) { MetavoxelNode* oldRoot = root; root = new MetavoxelNode(attribute); - root->readDelta(attribute, *oldRoot, in); + attribute->readDelta(*root, *oldRoot, in); oldRoot->decrementReferenceCount(attribute); } else { root = new MetavoxelNode(attribute); - root->read(attribute, in); + attribute->read(*root, in); } } @@ -337,9 +337,9 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c if (it.value() != referenceRoot) { out << it.key(); if (referenceRoot) { - it.value()->writeDelta(it.key(), *referenceRoot, out); + it.key()->writeDelta(*it.value(), *referenceRoot, out); } else { - it.value()->write(it.key(), out); + it.key()->write(*it.value(), out); } } } From 4130d0f28bd07ba5758bce17cb04c5239e4cad48 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 26 Feb 2014 15:01:01 -0800 Subject: [PATCH 03/31] Added spheres as simpler spanners for testing. --- interface/src/MetavoxelSystem.cpp | 21 ++++++++++++++++ interface/src/MetavoxelSystem.h | 11 ++++++++ libraries/metavoxels/src/MetavoxelData.cpp | 24 ++++++++++++++++++ libraries/metavoxels/src/MetavoxelData.h | 29 ++++++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b7d9ea9e03..c5176a65a2 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -20,6 +20,7 @@ #include "MetavoxelSystem.h" #include "renderer/Model.h" +REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) ProgramObject MetavoxelSystem::_program; @@ -256,6 +257,26 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } } +SphereRenderer::SphereRenderer() { +} + +void SphereRenderer::render(float alpha) { + Sphere* sphere = static_cast(parent()); + const QColor& color = sphere->getColor(); + glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha); + + glPushMatrix(); + const glm::vec3& translation = sphere->getTranslation(); + glTranslatef(translation.x, translation.y, translation.z); + glm::quat rotation = glm::quat(glm::radians(sphere->getRotation())); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + + glutSolidSphere(sphere->getScale(), 10, 10); + + glPopMatrix(); +} + StaticModelRenderer::StaticModelRenderer() : _model(new Model(this)) { } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 4364192009..6b6aa70a87 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -124,6 +124,17 @@ private: QList _receiveRecords; }; +/// Renders spheres. +class SphereRenderer : public SpannerRenderer { + Q_OBJECT + +public: + + Q_INVOKABLE SphereRenderer(); + + virtual void render(float alpha); +}; + /// Renders static models. class StaticModelRenderer : public SpannerRenderer { Q_OBJECT diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 38b073a0b9..228b5833f4 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -19,6 +19,7 @@ REGISTER_META_OBJECT(DefaultMetavoxelGuide) REGISTER_META_OBJECT(ScriptedMetavoxelGuide) REGISTER_META_OBJECT(ThrobbingMetavoxelGuide) REGISTER_META_OBJECT(Spanner) +REGISTER_META_OBJECT(Sphere) REGISTER_META_OBJECT(StaticModel) MetavoxelData::MetavoxelData() : _size(1.0f) { @@ -882,6 +883,29 @@ void Transformable::setScale(float scale) { } } +Sphere::Sphere() : + _color(Qt::gray) { + + connect(this, SIGNAL(translationChanged(const glm::vec3&)), SLOT(updateBounds())); + connect(this, SIGNAL(scaleChanged(float)), SLOT(updateBounds())); + updateBounds(); +} + +void Sphere::setColor(const QColor& color) { + if (_color != color) { + emit colorChanged(_color = color); + } +} + +QByteArray Sphere::getRendererClassName() const { + return "SphereRenderer"; +} + +void Sphere::updateBounds() { + glm::vec3 extent(getScale(), getScale(), getScale()); + setBounds(Box(getTranslation() - extent, getTranslation() + extent)); +} + StaticModel::StaticModel() { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 85bdd54938..ce89ca9b91 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -367,6 +367,35 @@ private: float _scale; }; +/// A sphere. +class Sphere : public Transformable { + Q_OBJECT + Q_PROPERTY(QColor color MEMBER _color WRITE setColor NOTIFY colorChanged) + +public: + + Q_INVOKABLE Sphere(); + + void setColor(const QColor& color); + const QColor& getColor() const { return _color; } + +signals: + + void colorChanged(const QColor& color); + +protected: + + virtual QByteArray getRendererClassName() const; + +private slots: + + void updateBounds(); + +private: + + QColor _color; +}; + /// A static 3D model loaded from the network. class StaticModel : public Transformable { Q_OBJECT From 1dfb72173de35d996641ec04cd3cff14155d400a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 26 Feb 2014 16:44:00 -0800 Subject: [PATCH 04/31] Hide metavoxel editing bits when mouse is hidden. --- interface/src/ui/MetavoxelEditor.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index c30dc15b65..61f7b55968 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -371,6 +371,10 @@ BoxSetTool::BoxSetTool(MetavoxelEditor* editor) : } void BoxSetTool::render() { + if (Application::getInstance()->isMouseHidden()) { + resetState(); + return; + } QString selected = _editor->getSelectedAttribute(); if (selected.isNull()) { resetState(); @@ -534,6 +538,9 @@ InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : } void InsertSpannerTool::simulate(float deltaTime) { + if (Application::getInstance()->isMouseHidden()) { + return; + } _editor->detachValue(); Spanner* spanner = static_cast(_editor->getValue().value().data()); Transformable* transformable = qobject_cast(spanner); @@ -552,13 +559,16 @@ void InsertSpannerTool::simulate(float deltaTime) { } void InsertSpannerTool::render() { + if (Application::getInstance()->isMouseHidden()) { + return; + } Spanner* spanner = static_cast(_editor->getValue().value().data()); const float SPANNER_ALPHA = 0.25f; spanner->getRenderer()->render(SPANNER_ALPHA); } bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { - return attribute->inherits("SharedObjectSetAttribute"); + return attribute->inherits("SpannerSetAttribute"); } bool InsertSpannerTool::eventFilter(QObject* watched, QEvent* event) { @@ -584,7 +594,7 @@ RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : } bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const { - return attribute->inherits("SharedObjectSetAttribute"); + return attribute->inherits("SpannerSetAttribute"); } bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) { @@ -604,7 +614,7 @@ ClearSpannersTool::ClearSpannersTool(MetavoxelEditor* editor) : } bool ClearSpannersTool::appliesTo(const AttributePointer& attribute) const { - return attribute->inherits("SharedObjectSetAttribute"); + return attribute->inherits("SpannerSetAttribute"); } void ClearSpannersTool::clear() { From f910c4471bb02cec6e3545c55ee0e6af69748553 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 2 Mar 2014 17:40:58 -0800 Subject: [PATCH 05/31] Distinguish between "hard" and "soft" references to shared objects. Sending bitstreams use soft references and remove their mappings when only soft references remain. --- libraries/metavoxels/src/Bitstream.cpp | 23 +++-- libraries/metavoxels/src/Bitstream.h | 56 ++++++----- libraries/metavoxels/src/SharedObject.cpp | 27 +++-- libraries/metavoxels/src/SharedObject.h | 115 +++++++++++++--------- 4 files changed, 134 insertions(+), 87 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 919bc4cbc8..61e8371652 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -167,11 +167,18 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { _scriptStringStreamer.persistTransientOffsets(mappings.scriptStringOffsets); _sharedObjectStreamer.persistTransientOffsets(mappings.sharedObjectOffsets); - // find out when shared objects' reference counts drop to one in order to clear their mappings - for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); + // find out when shared objects are deleted in order to clear their mappings + for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); it != mappings.sharedObjectOffsets.constEnd(); it++) { if (it.key()) { - connect(it.key().data(), SIGNAL(referenceCountDroppedToOne()), SLOT(clearSharedObject())); + if (it.key()->getHardReferenceCount() > 0) { + connect(it.key().data(), SIGNAL(allHardReferencesCleared(QObject*)), + SLOT(clearSharedObject(QObject*))); + } else { + // invoke on a queued connection so as to run after any other mappings are persisted + QMetaObject::invokeMethod(this, "clearSharedObject", Qt::QueuedConnection, + Q_ARG(QObject*, it.key().data())); + } } } } @@ -465,7 +472,7 @@ Bitstream& Bitstream::operator>(QScriptString& string) { return *this; } -Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { +Bitstream& Bitstream::operator<(const SoftSharedObjectPointer& object) { if (!object) { return *this << (int)0; } @@ -497,10 +504,12 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { return *this; } -void Bitstream::clearSharedObject() { - SharedObjectPointer object(static_cast(sender())); +void Bitstream::clearSharedObject(QObject* object) { object->disconnect(this); - emit sharedObjectCleared(_sharedObjectStreamer.takePersistentID(object)); + int id = _sharedObjectStreamer.takePersistentID(static_cast(object)); + if (id != 0) { + emit sharedObjectCleared(id); + } } void Bitstream::readProperties(QObject* object) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index c06c4c3b5f..fa6975adc1 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -55,26 +55,26 @@ private: /// Provides a means to stream repeated values efficiently. The value is first streamed along with a unique ID. When /// subsequently streamed, only the ID is sent. -template class RepeatedValueStreamer { +template class RepeatedValueStreamer { public: RepeatedValueStreamer(Bitstream& stream) : _stream(stream), _idStreamer(stream), _lastPersistentID(0), _lastTransientOffset(0) { } - QHash getAndResetTransientOffsets(); + QHash getAndResetTransientOffsets(); - void persistTransientOffsets(const QHash& transientOffsets); + void persistTransientOffsets(const QHash& transientOffsets); - QHash getAndResetTransientValues(); + QHash getAndResetTransientValues(); - void persistTransientValues(const QHash& transientValues); + void persistTransientValues(const QHash& transientValues); - int takePersistentID(T value) { return _persistentIDs.take(value); } + int takePersistentID(K value) { return _persistentIDs.take(value); } void removePersistentValue(int id) { _persistentValues.remove(id); } - RepeatedValueStreamer& operator<<(T value); - RepeatedValueStreamer& operator>>(T& value); + RepeatedValueStreamer& operator<<(K value); + RepeatedValueStreamer& operator>>(V& value); private: @@ -82,23 +82,24 @@ private: IDStreamer _idStreamer; int _lastPersistentID; int _lastTransientOffset; - QHash _persistentIDs; - QHash _transientOffsets; - QHash _persistentValues; - QHash _transientValues; + QHash _persistentIDs; + QHash _transientOffsets; + QHash _persistentValues; + QHash _transientValues; }; -template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { - QHash transientOffsets; +template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { + QHash transientOffsets; _transientOffsets.swap(transientOffsets); _lastTransientOffset = 0; _idStreamer.setBitsFromValue(_lastPersistentID); return transientOffsets; } -template inline void RepeatedValueStreamer::persistTransientOffsets(const QHash& transientOffsets) { +template inline void RepeatedValueStreamer::persistTransientOffsets( + const QHash& transientOffsets) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { + for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { int& id = _persistentIDs[it.key()]; if (id == 0) { id = oldLastPersistentID + it.value(); @@ -108,16 +109,17 @@ template inline void RepeatedValueStreamer::persistTransientOffsets( _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { - QHash transientValues; +template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { + QHash transientValues; _transientValues.swap(transientValues); _idStreamer.setBitsFromValue(_lastPersistentID); return transientValues; } -template inline void RepeatedValueStreamer::persistTransientValues(const QHash& transientValues) { +template inline void RepeatedValueStreamer::persistTransientValues( + const QHash& transientValues) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { + for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { int& id = _persistentIDs[it.value()]; if (id == 0) { id = oldLastPersistentID + it.key(); @@ -128,7 +130,7 @@ template inline void RepeatedValueStreamer::persistTransientValues(c _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(T value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(K value) { int id = _persistentIDs.value(value); if (id == 0) { int& offset = _transientOffsets[value]; @@ -145,7 +147,7 @@ template inline RepeatedValueStreamer& RepeatedValueStreamer::ope return *this; } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(T& value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(V& value) { int id; _idStreamer >> id; if (id <= _lastPersistentID) { @@ -153,7 +155,7 @@ template inline RepeatedValueStreamer& RepeatedValueStreamer::ope } else { int offset = id - _lastPersistentID; - typename QHash::iterator it = _transientValues.find(offset); + typename QHash::iterator it = _transientValues.find(offset); if (it == _transientValues.end()) { _stream > value; _transientValues.insert(offset, value); @@ -177,7 +179,7 @@ public: QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; - QHash sharedObjectOffsets; + QHash sharedObjectOffsets; }; class ReadMappings { @@ -306,7 +308,7 @@ public: Bitstream& operator<(const QScriptString& string); Bitstream& operator>(QScriptString& string); - Bitstream& operator<(const SharedObjectPointer& object); + Bitstream& operator<(const SoftSharedObjectPointer& object); Bitstream& operator>(SharedObjectPointer& object); signals: @@ -315,7 +317,7 @@ signals: private slots: - void clearSharedObject(); + void clearSharedObject(QObject* object); private: @@ -329,7 +331,7 @@ private: RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; - RepeatedValueStreamer _sharedObjectStreamer; + RepeatedValueStreamer _sharedObjectStreamer; QHash > _transientSharedObjects; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 7e10068afe..c3a224103d 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,19 +18,30 @@ REGISTER_META_OBJECT(SharedObject) -SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { +static int sharedObjectPointerMetaTypeId = qRegisterMetaType(); +static int softSharedObjectPointerMetaTypeId = qRegisterMetaType(); + +SharedObject::SharedObject() : + _id(++_lastID), + _hardReferenceCount(0), + _softReferenceCount(0) { } -void SharedObject::incrementReferenceCount() { - _referenceCount++; +void SharedObject::decrementHardReferenceCount() { + _hardReferenceCount--; + if (_hardReferenceCount == 0) { + if (_softReferenceCount == 0) { + delete this; + } else { + emit allHardReferencesCleared(this); + } + } } -void SharedObject::decrementReferenceCount() { - if (--_referenceCount == 0) { +void SharedObject::decrementSoftReferenceCount() { + _softReferenceCount--; + if (_hardReferenceCount == 0 && _softReferenceCount == 0) { delete this; - - } else if (_referenceCount == 1) { - emit referenceCountDroppedToOne(); } } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 9895073e44..44bfb73a22 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -27,10 +27,14 @@ public: int getID() { return _id; } - int getReferenceCount() const { return _referenceCount; } - void incrementReferenceCount(); - void decrementReferenceCount(); + int getHardReferenceCount() const { return _hardReferenceCount; } + + void incrementHardReferenceCount() { _hardReferenceCount++; } + void decrementHardReferenceCount(); + void incrementSoftReferenceCount() { _softReferenceCount++; } + void decrementSoftReferenceCount(); + /// Creates a new clone of this object. virtual SharedObject* clone() const; @@ -42,23 +46,29 @@ public: signals: - /// Emitted when the reference count drops to one. - void referenceCountDroppedToOne(); + /// Emitted when only soft reference counts remain. + void allHardReferencesCleared(QObject* object); private: int _id; - int _referenceCount; + int _hardReferenceCount; + int _softReferenceCount; static int _lastID; }; +typedef void (SharedObject::*SharedObjectFn)(); + /// A pointer to a shared object. -template class SharedObjectPointerTemplate { +template class SharedObjectPointerTemplate { public: SharedObjectPointerTemplate(T* data = NULL); - SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); + SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); + template SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other); ~SharedObjectPointerTemplate(); T* data() const { return _data; } @@ -66,7 +76,7 @@ public: /// "Detaches" this object, making a new copy if its reference count is greater than one. bool detach(); - void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } + void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } void reset(); @@ -75,81 +85,91 @@ public: T& operator*() const { return *_data; } T* operator->() const { return _data; } - template SharedObjectPointerTemplate staticCast() const; + template SharedObjectPointerTemplate staticCast() const; - SharedObjectPointerTemplate& operator=(T* data); - SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other); + SharedObjectPointerTemplate& operator=(T* data); + SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other) { + return *this = other.data(); } + template SharedObjectPointerTemplate& operator=( + const SharedObjectPointerTemplate& other) { return *this = other.data(); } - bool operator==(const SharedObjectPointerTemplate& other) const { return _data == other._data; } - bool operator!=(const SharedObjectPointerTemplate& other) const { return _data != other._data; } + bool operator==(T* data) const { return _data == data; } + bool operator!=(T* data) const { return _data != data; } + template bool operator==( + const SharedObjectPointerTemplate& other) const { return _data == other.data(); } + template bool operator!=( + const SharedObjectPointerTemplate& other) const { return _data != other.data(); } + private: T* _data; }; -template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { +template inline + SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { if (_data) { - _data->incrementReferenceCount(); + (_data->*Inc)(); } } -template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other) : - _data(other._data) { - +template inline + SharedObjectPointerTemplate::SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other) : _data(other.data()) { if (_data) { - _data->incrementReferenceCount(); + (_data->*Inc)(); } } -template inline SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { +template template inline + SharedObjectPointerTemplate::SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other) : _data(other.data()) { if (_data) { - _data->decrementReferenceCount(); + (_data->*Inc)(); } } -template inline bool SharedObjectPointerTemplate::detach() { - if (_data && _data->getReferenceCount() > 1) { - _data->decrementReferenceCount(); - (_data = _data->clone())->incrementReferenceCount(); +template inline + SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { + if (_data) { + (_data->*Dec)(); + } +} + +template inline bool SharedObjectPointerTemplate::detach() { + if (_data && _data->getHardReferenceCount() > 1) { + (_data->*Dec)(); + ((_data = _data->clone())->*Inc)(); return true; } return false; } -template inline void SharedObjectPointerTemplate::reset() { +template inline void SharedObjectPointerTemplate::reset() { if (_data) { - _data->decrementReferenceCount(); + (_data->*Dec)(); } _data = NULL; } -template template inline SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { - return SharedObjectPointerTemplate(static_cast(_data)); +template template inline + SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { + return SharedObjectPointerTemplate(static_cast(_data)); } -template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { +template inline + SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { if (_data) { - _data->decrementReferenceCount(); + (_data->*Dec)(); } if ((_data = data)) { - _data->incrementReferenceCount(); + (_data->*Inc)(); } return *this; } -template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=( - const SharedObjectPointerTemplate& other) { - if (_data) { - _data->decrementReferenceCount(); - } - if ((_data = other._data)) { - _data->incrementReferenceCount(); - } - return *this; -} - -template uint qHash(const SharedObjectPointerTemplate& pointer, uint seed = 0) { +template uint qHash( + const SharedObjectPointerTemplate& pointer, uint seed = 0) { return qHash(pointer.data(), seed); } @@ -161,6 +181,11 @@ typedef QSet SharedObjectSet; Q_DECLARE_METATYPE(SharedObjectSet) +typedef SharedObjectPointerTemplate SoftSharedObjectPointer; + +Q_DECLARE_METATYPE(SoftSharedObjectPointer) + /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { Q_OBJECT From 55dca45feb45cb3c283e186d816b430e5d87b5b8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Mar 2014 10:20:50 -0800 Subject: [PATCH 06/31] Working on tests for shared objects. --- libraries/metavoxels/src/SharedObject.cpp | 6 +++ libraries/metavoxels/src/SharedObject.h | 5 +++ tests/metavoxels/src/MetavoxelTests.cpp | 47 ++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 33 ++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index c3a224103d..b542299d00 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -63,6 +63,12 @@ SharedObject* SharedObject::clone() const { bool SharedObject::equals(const SharedObject* other) const { // default behavior is to compare the properties + if (!other) { + return false; + } + if (other == this) { + return true; + } const QMetaObject* metaObject = this->metaObject(); if (metaObject != other->metaObject()) { return false; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 44bfb73a22..f83079b0fa 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -173,6 +173,11 @@ template uint qHash( return qHash(pointer.data(), seed); } +template bool equals( + const SharedObjectPointerTemplate& first, const SharedObjectPointerTemplate& second) { + return first ? first->equals(second) : !second; +} + typedef SharedObjectPointerTemplate SharedObjectPointer; Q_DECLARE_METATYPE(SharedObjectPointer) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 530f7e3108..f06658da68 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -12,6 +12,9 @@ #include "MetavoxelTests.h" +REGISTER_META_OBJECT(TestSharedObjectA) +REGISTER_META_OBJECT(TestSharedObjectB) + MetavoxelTests::MetavoxelTests(int& argc, char** argv) : QCoreApplication(argc, argv) { } @@ -26,6 +29,8 @@ static int reliableMessagesSent = 0; static int reliableMessagesReceived = 0; static int streamedBytesSent = 0; static int streamedBytesReceived = 0; +static int sharedObjectsCreated = 0; +static int sharedObjectsDestroyed = 0; bool MetavoxelTests::run() { @@ -54,6 +59,7 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; + qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "All tests passed!"; @@ -74,6 +80,15 @@ static QByteArray createRandomBytes() { return createRandomBytes(MIN_BYTES, MAX_BYTES); } +static SharedObjectPointer createRandomSharedObject() { + switch (randIntInRange(0, 2)) { + case 0: return new TestSharedObjectA(randFloat()); + case 1: return new TestSharedObjectB(); + case 2: + default: return SharedObjectPointer(); + } +} + Endpoint::Endpoint(const QByteArray& datagramHeader) : _sequencer(new DatagramSequencer(datagramHeader, this)), _highPriorityMessagesToSend(0.0f), @@ -110,7 +125,7 @@ static QVariant createRandomMessage() { return QVariant::fromValue(message); } case 1: { - TestMessageB message = { createRandomBytes() }; + TestMessageB message = { createRandomBytes(), createRandomSharedObject() }; return QVariant::fromValue(message); } case 2: @@ -132,10 +147,15 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe } if (type == TestMessageA::Type) { return firstMessage.value() == secondMessage.value(); + } else if (type == TestMessageB::Type) { - return firstMessage.value() == secondMessage.value(); + TestMessageB first = firstMessage.value(); + TestMessageB second = secondMessage.value(); + return first.foo == second.foo && equals(first.bar, second.bar); + } else if (type == TestMessageC::Type) { return firstMessage.value() == secondMessage.value(); + } else { return firstMessage == secondMessage; } @@ -277,3 +297,26 @@ void Endpoint::readReliableChannel() { } streamedBytesReceived += bytes.size(); } + +TestSharedObjectA::TestSharedObjectA(float foo) : + _foo(foo) { + sharedObjectsCreated++; +} + +TestSharedObjectA::~TestSharedObjectA() { + sharedObjectsDestroyed++; +} + +void TestSharedObjectA::setFoo(float foo) { + if (_foo != foo) { + emit fooChanged(_foo = foo); + } +} + +TestSharedObjectB::TestSharedObjectB() { + sharedObjectsCreated++; +} + +TestSharedObjectB::~TestSharedObjectB() { + sharedObjectsDestroyed++; +} diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index f19870ac15..3b69c28f79 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -64,6 +64,38 @@ private: CircularBuffer _dataStreamed; }; +/// A simple shared object. +class TestSharedObjectA : public SharedObject { + Q_OBJECT + Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged) + +public: + + Q_INVOKABLE TestSharedObjectA(float foo = 0.0f); + virtual ~TestSharedObjectA(); + + void setFoo(float foo); + float getFoo() const { return _foo; } + +signals: + + void fooChanged(float foo); + +private: + + float _foo; +}; + +/// Another simple shared object. +class TestSharedObjectB : public SharedObject { + Q_OBJECT + +public: + + Q_INVOKABLE TestSharedObjectB(); + virtual ~TestSharedObjectB(); +}; + /// A simple test message. class TestMessageA { STREAMABLE @@ -84,6 +116,7 @@ class TestMessageB { public: STREAM QByteArray foo; + STREAM SharedObjectPointer bar; }; DECLARE_STREAMABLE_METATYPE(TestMessageB) From 949e40a10ecadee5ba27681b7da1678f26fba1ec Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Mar 2014 11:44:45 -0800 Subject: [PATCH 07/31] Revert complicated system of "soft" pointers, instead use hard references in write mappings and listen for object destruction. --- libraries/metavoxels/src/Bitstream.cpp | 22 ++-- libraries/metavoxels/src/Bitstream.h | 64 +++++----- .../metavoxels/src/DatagramSequencer.cpp | 2 + libraries/metavoxels/src/SharedObject.cpp | 26 +--- libraries/metavoxels/src/SharedObject.h | 120 +++++++----------- tests/metavoxels/src/MetavoxelTests.cpp | 9 ++ 6 files changed, 108 insertions(+), 135 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 61e8371652..11deb95b14 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -168,21 +168,18 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { _sharedObjectStreamer.persistTransientOffsets(mappings.sharedObjectOffsets); // find out when shared objects are deleted in order to clear their mappings - for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); + for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); it != mappings.sharedObjectOffsets.constEnd(); it++) { if (it.key()) { - if (it.key()->getHardReferenceCount() > 0) { - connect(it.key().data(), SIGNAL(allHardReferencesCleared(QObject*)), - SLOT(clearSharedObject(QObject*))); - } else { - // invoke on a queued connection so as to run after any other mappings are persisted - QMetaObject::invokeMethod(this, "clearSharedObject", Qt::QueuedConnection, - Q_ARG(QObject*, it.key().data())); - } + connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); } } } +void Bitstream::persistAndResetWriteMappings() { + persistWriteMappings(getAndResetWriteMappings()); +} + Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { ReadMappings mappings = { _metaObjectStreamer.getAndResetTransientValues(), _typeStreamerStreamer.getAndResetTransientValues(), @@ -200,6 +197,10 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { _sharedObjectStreamer.persistTransientValues(mappings.sharedObjectValues); } +void Bitstream::persistAndResetReadMappings() { + persistReadMappings(getAndResetReadMappings()); +} + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); @@ -472,7 +473,7 @@ Bitstream& Bitstream::operator>(QScriptString& string) { return *this; } -Bitstream& Bitstream::operator<(const SoftSharedObjectPointer& object) { +Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { if (!object) { return *this << (int)0; } @@ -505,7 +506,6 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { } void Bitstream::clearSharedObject(QObject* object) { - object->disconnect(this); int id = _sharedObjectStreamer.takePersistentID(static_cast(object)); if (id != 0) { emit sharedObjectCleared(id); diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index fa6975adc1..9c42828a66 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -55,26 +55,26 @@ private: /// Provides a means to stream repeated values efficiently. The value is first streamed along with a unique ID. When /// subsequently streamed, only the ID is sent. -template class RepeatedValueStreamer { +template class RepeatedValueStreamer { public: RepeatedValueStreamer(Bitstream& stream) : _stream(stream), _idStreamer(stream), _lastPersistentID(0), _lastTransientOffset(0) { } - QHash getAndResetTransientOffsets(); + QHash getAndResetTransientOffsets(); - void persistTransientOffsets(const QHash& transientOffsets); + void persistTransientOffsets(const QHash& transientOffsets); - QHash getAndResetTransientValues(); + QHash getAndResetTransientValues(); - void persistTransientValues(const QHash& transientValues); + void persistTransientValues(const QHash& transientValues); - int takePersistentID(K value) { return _persistentIDs.take(value); } + int takePersistentID(P value) { return _persistentIDs.take(value); } - void removePersistentValue(int id) { _persistentValues.remove(id); } + void removePersistentValue(int id) { _persistentIDs.remove(_persistentValues.take(id)); } - RepeatedValueStreamer& operator<<(K value); - RepeatedValueStreamer& operator>>(V& value); + RepeatedValueStreamer& operator<<(T value); + RepeatedValueStreamer& operator>>(T& value); private: @@ -82,24 +82,24 @@ private: IDStreamer _idStreamer; int _lastPersistentID; int _lastTransientOffset; - QHash _persistentIDs; - QHash _transientOffsets; - QHash _persistentValues; - QHash _transientValues; + QHash _persistentIDs; + QHash _transientOffsets; + QHash _persistentValues; + QHash _transientValues; }; -template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { - QHash transientOffsets; +template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { + QHash transientOffsets; _transientOffsets.swap(transientOffsets); _lastTransientOffset = 0; _idStreamer.setBitsFromValue(_lastPersistentID); return transientOffsets; } -template inline void RepeatedValueStreamer::persistTransientOffsets( - const QHash& transientOffsets) { +template inline void RepeatedValueStreamer::persistTransientOffsets( + const QHash& transientOffsets) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { + for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { int& id = _persistentIDs[it.key()]; if (id == 0) { id = oldLastPersistentID + it.value(); @@ -109,17 +109,17 @@ template inline void RepeatedValueStreamer::persistTrans _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { - QHash transientValues; +template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { + QHash transientValues; _transientValues.swap(transientValues); _idStreamer.setBitsFromValue(_lastPersistentID); return transientValues; } -template inline void RepeatedValueStreamer::persistTransientValues( - const QHash& transientValues) { +template inline void RepeatedValueStreamer::persistTransientValues( + const QHash& transientValues) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { + for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { int& id = _persistentIDs[it.value()]; if (id == 0) { id = oldLastPersistentID + it.key(); @@ -130,7 +130,7 @@ template inline void RepeatedValueStreamer::persistTrans _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(K value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(T value) { int id = _persistentIDs.value(value); if (id == 0) { int& offset = _transientOffsets[value]; @@ -147,7 +147,7 @@ template inline RepeatedValueStreamer& RepeatedValueStre return *this; } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(V& value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(T& value) { int id; _idStreamer >> id; if (id <= _lastPersistentID) { @@ -155,7 +155,7 @@ template inline RepeatedValueStreamer& RepeatedValueStre } else { int offset = id - _lastPersistentID; - typename QHash::iterator it = _transientValues.find(offset); + typename QHash::iterator it = _transientValues.find(offset); if (it == _transientValues.end()) { _stream > value; _transientValues.insert(offset, value); @@ -179,7 +179,7 @@ public: QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; - QHash sharedObjectOffsets; + QHash sharedObjectOffsets; }; class ReadMappings { @@ -230,12 +230,18 @@ public: /// Persists a set of write mappings recorded earlier. void persistWriteMappings(const WriteMappings& mappings); + /// Immediately persists and resets the write mappings. + void persistAndResetWriteMappings(); + /// Returns the set of transient mappings gathered during reading and resets them. ReadMappings getAndResetReadMappings(); /// Persists a set of read mappings recorded earlier. void persistReadMappings(const ReadMappings& mappings); + /// Immediately persists and resets the read mappings. + void persistAndResetReadMappings(); + /// Removes a shared object from the read mappings. void clearSharedObject(int id) { _sharedObjectStreamer.removePersistentValue(id); } @@ -308,7 +314,7 @@ public: Bitstream& operator<(const QScriptString& string); Bitstream& operator>(QScriptString& string); - Bitstream& operator<(const SoftSharedObjectPointer& object); + Bitstream& operator<(const SharedObjectPointer& object); Bitstream& operator>(SharedObjectPointer& object); signals: @@ -331,7 +337,7 @@ private: RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; - RepeatedValueStreamer _sharedObjectStreamer; + RepeatedValueStreamer _sharedObjectStreamer; QHash > _transientSharedObjects; diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 0c7b8ce8ab..052f480fcf 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -587,6 +587,7 @@ void ReliableChannel::sendMessage(const QVariant& message) { _dataStream << (quint32)0; _bitstream << message; _bitstream.flush(); + _bitstream.persistAndResetWriteMappings(); quint32 length = _buffer.pos() - placeholder; _buffer.writeBytes(placeholder, sizeof(quint32), (const char*)&length); @@ -745,6 +746,7 @@ void ReliableChannel::readData(QDataStream& in) { QVariant message; _bitstream >> message; _bitstream.reset(); + _bitstream.persistAndResetReadMappings(); emit receivedMessage(message); continue; } diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index b542299d00..b67354828a 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,29 +18,15 @@ REGISTER_META_OBJECT(SharedObject) -static int sharedObjectPointerMetaTypeId = qRegisterMetaType(); -static int softSharedObjectPointerMetaTypeId = qRegisterMetaType(); - -SharedObject::SharedObject() : - _id(++_lastID), - _hardReferenceCount(0), - _softReferenceCount(0) { +SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { } -void SharedObject::decrementHardReferenceCount() { - _hardReferenceCount--; - if (_hardReferenceCount == 0) { - if (_softReferenceCount == 0) { - delete this; - } else { - emit allHardReferencesCleared(this); - } - } +void SharedObject::incrementReferenceCount() { + _referenceCount++; } -void SharedObject::decrementSoftReferenceCount() { - _softReferenceCount--; - if (_hardReferenceCount == 0 && _softReferenceCount == 0) { +void SharedObject::decrementReferenceCount() { + if (--_referenceCount == 0) { delete this; } } @@ -62,13 +48,13 @@ SharedObject* SharedObject::clone() const { } bool SharedObject::equals(const SharedObject* other) const { - // default behavior is to compare the properties if (!other) { return false; } if (other == this) { return true; } + // default behavior is to compare the properties const QMetaObject* metaObject = this->metaObject(); if (metaObject != other->metaObject()) { return false; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index f83079b0fa..344a77cc94 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -27,14 +27,10 @@ public: int getID() { return _id; } - int getHardReferenceCount() const { return _hardReferenceCount; } - - void incrementHardReferenceCount() { _hardReferenceCount++; } - void decrementHardReferenceCount(); + int getReferenceCount() const { return _referenceCount; } + void incrementReferenceCount(); + void decrementReferenceCount(); - void incrementSoftReferenceCount() { _softReferenceCount++; } - void decrementSoftReferenceCount(); - /// Creates a new clone of this object. virtual SharedObject* clone() const; @@ -44,31 +40,20 @@ public: // Dumps the contents of this object to the debug output. virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; -signals: - - /// Emitted when only soft reference counts remain. - void allHardReferencesCleared(QObject* object); - private: int _id; - int _hardReferenceCount; - int _softReferenceCount; + int _referenceCount; static int _lastID; }; -typedef void (SharedObject::*SharedObjectFn)(); - /// A pointer to a shared object. -template class SharedObjectPointerTemplate { +template class SharedObjectPointerTemplate { public: SharedObjectPointerTemplate(T* data = NULL); - SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); - template SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other); + SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); ~SharedObjectPointerTemplate(); T* data() const { return _data; } @@ -76,7 +61,7 @@ public: /// "Detaches" this object, making a new copy if its reference count is greater than one. bool detach(); - void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } + void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } void reset(); @@ -85,96 +70,86 @@ public: T& operator*() const { return *_data; } T* operator->() const { return _data; } - template SharedObjectPointerTemplate staticCast() const; + template SharedObjectPointerTemplate staticCast() const; - SharedObjectPointerTemplate& operator=(T* data); - SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other) { - return *this = other.data(); } - template SharedObjectPointerTemplate& operator=( - const SharedObjectPointerTemplate& other) { return *this = other.data(); } + SharedObjectPointerTemplate& operator=(T* data); + SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other); - bool operator==(T* data) const { return _data == data; } - bool operator!=(T* data) const { return _data != data; } + bool operator==(const SharedObjectPointerTemplate& other) const { return _data == other._data; } + bool operator!=(const SharedObjectPointerTemplate& other) const { return _data != other._data; } - template bool operator==( - const SharedObjectPointerTemplate& other) const { return _data == other.data(); } - template bool operator!=( - const SharedObjectPointerTemplate& other) const { return _data != other.data(); } - private: T* _data; }; -template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { if (_data) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } } -template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other) : _data(other.data()) { +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other) : + _data(other._data) { + if (_data) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } } -template template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other) : _data(other.data()) { +template inline SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { if (_data) { - (_data->*Inc)(); + _data->decrementReferenceCount(); } } -template inline - SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { - if (_data) { - (_data->*Dec)(); - } -} - -template inline bool SharedObjectPointerTemplate::detach() { - if (_data && _data->getHardReferenceCount() > 1) { - (_data->*Dec)(); - ((_data = _data->clone())->*Inc)(); +template inline bool SharedObjectPointerTemplate::detach() { + if (_data && _data->getReferenceCount() > 1) { + _data->decrementReferenceCount(); + (_data = _data->clone())->incrementReferenceCount(); return true; } return false; } -template inline void SharedObjectPointerTemplate::reset() { +template inline void SharedObjectPointerTemplate::reset() { if (_data) { - (_data->*Dec)(); + _data->decrementReferenceCount(); } _data = NULL; } -template template inline - SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { - return SharedObjectPointerTemplate(static_cast(_data)); +template template inline SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { + return SharedObjectPointerTemplate(static_cast(_data)); } -template inline - SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { if (_data) { - (_data->*Dec)(); + _data->decrementReferenceCount(); } if ((_data = data)) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } return *this; } -template uint qHash( - const SharedObjectPointerTemplate& pointer, uint seed = 0) { +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=( + const SharedObjectPointerTemplate& other) { + if (_data) { + _data->decrementReferenceCount(); + } + if ((_data = other._data)) { + _data->incrementReferenceCount(); + } + return *this; +} + +template uint qHash(const SharedObjectPointerTemplate& pointer, uint seed = 0) { return qHash(pointer.data(), seed); } -template bool equals( - const SharedObjectPointerTemplate& first, const SharedObjectPointerTemplate& second) { +template bool equals(const SharedObjectPointerTemplate& first, + const SharedObjectPointerTemplate& second) { return first ? first->equals(second) : !second; } @@ -186,11 +161,6 @@ typedef QSet SharedObjectSet; Q_DECLARE_METATYPE(SharedObjectSet) -typedef SharedObjectPointerTemplate SoftSharedObjectPointer; - -Q_DECLARE_METATYPE(SoftSharedObjectPointer) - /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { Q_OBJECT diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index f06658da68..b1f3315bc0 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -10,6 +10,8 @@ #include +#include + #include "MetavoxelTests.h" REGISTER_META_OBJECT(TestSharedObjectA) @@ -245,6 +247,9 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { } void Endpoint::handleHighPriorityMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type) { + return; + } if (_other->_highPriorityMessagesSent.isEmpty()) { throw QString("Received unsent/already sent high priority message."); } @@ -274,6 +279,10 @@ void Endpoint::readMessage(Bitstream& in) { } void Endpoint::handleReliableMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type || + message.userType() == ClearMainChannelSharedObjectMessage::Type) { + return; + } if (_other->_reliableMessagesSent.isEmpty()) { throw QString("Received unsent/already sent reliable message."); } From 47fe928995d0ea360687e04cc508ee91101fda86 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Mar 2014 11:18:31 -0800 Subject: [PATCH 08/31] Workin on LOD support in streaming. --- libraries/metavoxels/src/MetavoxelData.cpp | 5 +++++ libraries/metavoxels/src/MetavoxelData.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 2189176858..5c418eccda 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -22,6 +22,11 @@ REGISTER_META_OBJECT(Spanner) REGISTER_META_OBJECT(Sphere) REGISTER_META_OBJECT(StaticModel) +MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) : + position(position), + threshold(threshold) { +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index ce89ca9b91..2133ad68d8 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -31,6 +31,15 @@ class NetworkValue; class Spanner; class SpannerRenderer; +/// Determines whether to subdivide each node when traversing. +class MetavoxelLOD { +public: + glm::vec3 position; + float threshold; + + MetavoxelLOD(const glm::vec3& position = glm::vec3(), float threshold = 0.0f); +}; + /// The base metavoxel representation shared between server and client. class MetavoxelData { public: From 13b712592f281a90a1c156669e0e3a0575c9b779 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Mar 2014 11:21:59 -0800 Subject: [PATCH 09/31] Use different unused variable warning suppressor for GCC. --- libraries/metavoxels/src/Bitstream.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 9c42828a66..ac77d2317a 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -458,6 +458,13 @@ public: bool operator==(const X& first, const X& second); \ bool operator!=(const X& first, const X& second); \ static const int* _TypePtr##X = &X::Type; +#elif __GNUC__ +#define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ + Bitstream& operator<<(Bitstream& out, const X& obj); \ + Bitstream& operator>>(Bitstream& in, X& obj); \ + bool operator==(const X& first, const X& second); \ + bool operator!=(const X& first, const X& second); \ + __attribute__((unused)) static const int* _TypePtr##X = &X::Type; #else #define STRINGIFY(x) #x #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ From 63b4a2453b00327ca12962b48fa5212d9a3d4f35 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Mar 2014 21:27:13 -0800 Subject: [PATCH 10/31] Lots of work on metavoxel LODs and spanners. --- .../src/metavoxels/MetavoxelServer.cpp | 10 +- .../src/metavoxels/MetavoxelServer.h | 3 +- interface/src/MetavoxelSystem.cpp | 24 +- interface/src/MetavoxelSystem.h | 10 + .../metavoxels/src/AttributeRegistry.cpp | 53 ++- libraries/metavoxels/src/AttributeRegistry.h | 18 +- libraries/metavoxels/src/MetavoxelData.cpp | 340 +++++++++++------- libraries/metavoxels/src/MetavoxelData.h | 57 ++- .../metavoxels/src/MetavoxelMessages.cpp | 4 +- libraries/metavoxels/src/MetavoxelMessages.h | 7 +- 10 files changed, 355 insertions(+), 171 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index fa60d3a88c..ed48340a93 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -111,13 +111,17 @@ int MetavoxelSession::parseData(const QByteArray& packet) { } void MetavoxelSession::sendDelta() { + // wait until we have a valid lod + if (!_lod.isValid()) { + return; + } Bitstream& out = _sequencer.startPacket(); out << QVariant::fromValue(MetavoxelDeltaMessage()); - _server->getData().writeDelta(_sendRecords.first().data, out); + _server->getData().writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod); _sequencer.endPacket(); // record the send - SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData() }; + SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData(), _lod }; _sendRecords.append(record); } @@ -139,7 +143,7 @@ void MetavoxelSession::handleMessage(const QVariant& message) { int userType = message.userType(); if (userType == ClientStateMessage::Type) { ClientStateMessage state = message.value(); - _position = state.position; + _lod = state.lod; } else if (userType == MetavoxelEditMessage::Type) { _server->applyEdit(message.value()); diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index a7939ee115..bd7a280c43 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -78,6 +78,7 @@ private: public: int packetNumber; MetavoxelData data; + MetavoxelLOD lod; }; MetavoxelServer* _server; @@ -86,7 +87,7 @@ private: SharedNodePointer _node; - glm::vec3 _position; + MetavoxelLOD _lod; QList _sendRecords; }; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index abe8988a25..4c1b40dc23 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -182,11 +182,16 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); + connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int))); connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int))); + // insert the baseline send record + SendRecord sendRecord = { 0 }; + _sendRecords.append(sendRecord); + // insert the baseline receive record - ReceiveRecord record = { 0, _data }; - _receiveRecords.append(record); + ReceiveRecord receiveRecord = { 0, _data }; + _receiveRecords.append(receiveRecord); } MetavoxelClient::~MetavoxelClient() { @@ -206,9 +211,14 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { void MetavoxelClient::simulate(float deltaTime) { Bitstream& out = _sequencer.startPacket(); - ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() }; + const float FIXED_LOD_THRESHOLD = 0.0001f; + ClientStateMessage state = { MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD) }; out << QVariant::fromValue(state); _sequencer.endPacket(); + + // record the send + SendRecord record = { _sequencer.getOutgoingPacketNumber(), state.lod }; + _sendRecords.append(record); } int MetavoxelClient::parseData(const QByteArray& packet) { @@ -227,7 +237,7 @@ void MetavoxelClient::readPacket(Bitstream& in) { handleMessage(message, in); // record the receipt - ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data }; + ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data, _sendRecords.first().lod }; _receiveRecords.append(record); // reapply local edits @@ -238,6 +248,10 @@ void MetavoxelClient::readPacket(Bitstream& in) { } } +void MetavoxelClient::clearSendRecordsBefore(int index) { + _sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1); +} + void MetavoxelClient::clearReceiveRecordsBefore(int index) { _receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1); } @@ -245,7 +259,7 @@ void MetavoxelClient::clearReceiveRecordsBefore(int index) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - _data.readDelta(_receiveRecords.first().data, in); + _data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod); } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 6b6aa70a87..155f99ffbd 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -103,16 +103,25 @@ private slots: void readPacket(Bitstream& in); + void clearSendRecordsBefore(int index); + void clearReceiveRecordsBefore(int index); private: void handleMessage(const QVariant& message, Bitstream& in); + class SendRecord { + public: + int packetNumber; + MetavoxelLOD lod; + }; + class ReceiveRecord { public: int packetNumber; MetavoxelData data; + MetavoxelLOD lod; }; SharedNodePointer _node; @@ -121,6 +130,7 @@ private: MetavoxelData _data; + QList _sendRecords; QList _receiveRecords; }; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index bc9d9b030a..4b643ba847 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -49,6 +49,9 @@ void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) { } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { + if (!attribute) { + return attribute; + } AttributePointer& pointer = _attributes[attribute->getName()]; if (!pointer) { pointer = attribute; @@ -146,20 +149,20 @@ Attribute::Attribute(const QString& name) { Attribute::~Attribute() { } -void Attribute::read(MetavoxelNode& root, Bitstream& in) { - root.read(this, in); +void Attribute::read(MetavoxelData& data, MetavoxelStreamState& state) { + data.createRoot(state.attribute)->read(state); } -void Attribute::write(const MetavoxelNode& root, Bitstream& out) { - root.write(this, out); +void Attribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) { + root.write(state); } -void Attribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { - root.readDelta(this, reference, in); +void Attribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { + data.createRoot(state.attribute)->readDelta(reference, state); } -void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { - root.writeDelta(this, reference, out); +void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { + root.writeDelta(reference, state); } QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : @@ -277,18 +280,36 @@ SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* SharedObjectSetAttribute(name, metaObject) { } -void SpannerSetAttribute::read(MetavoxelNode& root, Bitstream& in) { - root.read(this, in); +void SpannerSetAttribute::read(MetavoxelData& data, MetavoxelStreamState& state) { + forever { + SharedObjectPointer object; + state.stream >> object; + if (!object) { + break; + } + data.insert(state.attribute, object); + } } -void SpannerSetAttribute::write(const MetavoxelNode& root, Bitstream& out) { - root.write(this, out); +void SpannerSetAttribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) { + Spanner::incrementVisit(); + root.writeSpanners(state); + state.stream << SharedObjectPointer(); } -void SpannerSetAttribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { - root.readDelta(this, reference, in); +void SpannerSetAttribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { + forever { + SharedObjectPointer object; + state.stream >> object; + if (!object) { + break; + } + data.toggle(state.attribute, object); + } } -void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { - root.writeDelta(this, reference, out); +void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { + Spanner::incrementVisit(); + root.writeSpannerDelta(reference, state); + state.stream << SharedObjectPointer(); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 000e18ca6b..dae0e87f37 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -23,7 +23,9 @@ class QScriptEngine; class QScriptValue; class Attribute; +class MetavoxelData; class MetavoxelNode; +class MetavoxelStreamState; typedef SharedObjectPointerTemplate AttributePointer; @@ -171,11 +173,11 @@ public: virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); } virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); } - virtual void read(MetavoxelNode& root, Bitstream& in); - virtual void write(const MetavoxelNode& root, Bitstream& out); + virtual void read(MetavoxelData& data, MetavoxelStreamState& state); + virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state); - virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); - virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); + virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); virtual bool equal(void* first, void* second) const = 0; @@ -325,11 +327,11 @@ public: Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(), const QMetaObject* metaObject = &SharedObject::staticMetaObject); - virtual void read(MetavoxelNode& root, Bitstream& in); - virtual void write(const MetavoxelNode& root, Bitstream& out); + virtual void read(MetavoxelData& data, MetavoxelStreamState& state); + virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state); - virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); - virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); + virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); + virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); }; #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5c418eccda..970b2a7d87 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -27,6 +27,10 @@ MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) : threshold(threshold) { } +bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const { + return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold; +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -62,7 +66,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { const QVector& inputs = visitor.getInputs(); const QVector& outputs = visitor.getOutputs(); MetavoxelVisitation firstVisitation = { NULL, visitor, QVector(inputs.size() + 1), - QVector(outputs.size()), { glm::vec3(_size, _size, _size) * -0.5f, _size, + QVector(outputs.size()), { getMinimum(), _size, QVector(inputs.size() + 1), QVector(outputs.size()) } }; for (int i = 0; i < inputs.size(); i++) { MetavoxelNode* node = _roots.value(inputs.at(i)); @@ -98,10 +102,27 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { } } -class InsertVisitor : public MetavoxelVisitor { +typedef void (*SpannerUpdateFunction)(SharedObjectSet& set, const SharedObjectPointer& object); + +void insertSpanner(SharedObjectSet& set, const SharedObjectPointer& object) { + set.insert(object); +} + +void removeSpanner(SharedObjectSet& set, const SharedObjectPointer& object) { + set.remove(object); +} + +void toggleSpanner(SharedObjectSet& set, const SharedObjectPointer& object) { + if (!set.remove(object)) { + set.insert(object); + } +} + +template class SpannerUpdateVisitor : public MetavoxelVisitor { public: - InsertVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); + SpannerUpdateVisitor(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object); virtual bool visit(MetavoxelInfo& info); @@ -113,8 +134,8 @@ private: const SharedObjectPointer& _object; }; -InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds, - float granularity, const SharedObjectPointer& object) : +template SpannerUpdateVisitor::SpannerUpdateVisitor(const AttributePointer& attribute, + const Box& bounds, float granularity, const SharedObjectPointer& object) : MetavoxelVisitor(QVector() << attribute, QVector() << attribute), _attribute(attribute), _bounds(bounds), @@ -122,7 +143,7 @@ InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bound _object(object) { } -bool InsertVisitor::visit(MetavoxelInfo& info) { +template bool SpannerUpdateVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_bounds)) { return false; } @@ -130,61 +151,45 @@ bool InsertVisitor::visit(MetavoxelInfo& info) { return true; } SharedObjectSet set = info.inputValues.at(0).getInlineValue(); - set.insert(_object); + F(set, _object); info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); return false; } +void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) { + Spanner* spanner = static_cast(object.data()); + insert(attribute, spanner->getBounds(), spanner->getGranularity(), object); +} + void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object) { // expand to fit the entire bounds while (!getBounds().contains(bounds)) { expand(); } - InsertVisitor visitor(attribute, bounds, granularity, object); + SpannerUpdateVisitor visitor(attribute, bounds, granularity, object); guide(visitor); } -class RemoveVisitor : public MetavoxelVisitor { -public: - - RemoveVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); - - virtual bool visit(MetavoxelInfo& info); - -private: - - const AttributePointer& _attribute; - const Box& _bounds; - float _longestSide; - const SharedObjectPointer& _object; -}; - -RemoveVisitor::RemoveVisitor(const AttributePointer& attribute, const Box& bounds, - float granularity, const SharedObjectPointer& object) : - MetavoxelVisitor(QVector() << attribute, QVector() << attribute), - _attribute(attribute), - _bounds(bounds), - _longestSide(qMax(bounds.getLongestSide(), granularity)), - _object(object) { -} - -bool RemoveVisitor::visit(MetavoxelInfo& info) { - if (!info.getBounds().intersects(_bounds)) { - return false; - } - if (info.size > _longestSide) { - return true; - } - SharedObjectSet set = info.inputValues.at(0).getInlineValue(); - set.remove(_object); - info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); - return false; +void MetavoxelData::remove(const AttributePointer& attribute, const SharedObjectPointer& object) { + Spanner* spanner = static_cast(object.data()); + remove(attribute, spanner->getBounds(), spanner->getGranularity(), object); } void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object) { - RemoveVisitor visitor(attribute, bounds, granularity, object); + SpannerUpdateVisitor visitor(attribute, bounds, granularity, object); + guide(visitor); +} + +void MetavoxelData::toggle(const AttributePointer& attribute, const SharedObjectPointer& object) { + Spanner* spanner = static_cast(object.data()); + toggle(attribute, spanner->getBounds(), spanner->getGranularity(), object); +} + +void MetavoxelData::toggle(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object) { + SpannerUpdateVisitor visitor(attribute, bounds, granularity, object); guide(visitor); } @@ -231,7 +236,7 @@ void MetavoxelData::expand() { _size *= 2.0f; } -void MetavoxelData::read(Bitstream& in) { +void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) { // clear out any existing roots decrementRootReferenceCounts(); _roots.clear(); @@ -239,27 +244,29 @@ void MetavoxelData::read(Bitstream& in) { in >> _size; // read in the new roots - int rootCount; - in >> rootCount; - for (int i = 0; i < rootCount; i++) { + forever { AttributePointer attribute; in >> attribute; - MetavoxelNode*& root = _roots[attribute]; - root = new MetavoxelNode(attribute); - attribute->read(*root, in); + if (!attribute) { + break; + } + MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, lod }; + attribute->read(*this, state); } } -void MetavoxelData::write(Bitstream& out) const { +void MetavoxelData::write(Bitstream& out, const MetavoxelLOD& lod) const { out << _size; - out << _roots.size(); for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { out << it.key(); - it.key()->write(*it.value(), out); + MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, lod }; + it.key()->write(*it.value(), state); } + out << AttributePointer(); } -void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { +void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, + Bitstream& in, const MetavoxelLOD& lod) { // shallow copy the reference *this = reference; @@ -279,34 +286,36 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { } } - int changedCount; - in >> changedCount; - for (int i = 0; i < changedCount; i++) { + forever { AttributePointer attribute; in >> attribute; - MetavoxelNode*& root = _roots[attribute]; - if (root) { - MetavoxelNode* oldRoot = root; - root = new MetavoxelNode(attribute); - attribute->readDelta(*root, *oldRoot, in); + if (!attribute) { + break; + } + MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD }; + MetavoxelNode* oldRoot = _roots.value(attribute); + if (oldRoot) { + oldRoot->incrementReferenceCount(); + attribute->readDelta(*this, *oldRoot, state); oldRoot->decrementReferenceCount(attribute); } else { - root = new MetavoxelNode(attribute); - attribute->read(*root, in); + attribute->read(*this, state); } } - int removedCount; - in >> removedCount; - for (int i = 0; i < removedCount; i++) { + forever { AttributePointer attribute; in >> attribute; + if (!attribute) { + break; + } _roots.take(attribute)->decrementReferenceCount(attribute); } } -void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) const { +void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, + Bitstream& out, const MetavoxelLOD& lod) const { // first things first: there might be no change whatsoever if (_size == reference._size && _roots == reference._roots) { out << false; @@ -329,42 +338,29 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c expandedReference = expanded; } - // count the number of roots added/changed, then write - int changedCount = 0; - for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { - MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); - if (it.value() != referenceRoot) { - changedCount++; - } - } - out << changedCount; + // write the added/changed roots for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); if (it.value() != referenceRoot) { out << it.key(); + MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, referenceLOD }; if (referenceRoot) { - it.key()->writeDelta(*it.value(), *referenceRoot, out); + it.key()->writeDelta(*it.value(), *referenceRoot, state); } else { - it.key()->write(*it.value(), out); + it.key()->write(*it.value(), state); } } } + out << AttributePointer(); // same with nodes removed - int removedCount = 0; - for (QHash::const_iterator it = expandedReference->_roots.constBegin(); - it != expandedReference->_roots.constEnd(); it++) { - if (!_roots.contains(it.key())) { - removedCount++; - } - } - out << removedCount; for (QHash::const_iterator it = expandedReference->_roots.constBegin(); it != expandedReference->_roots.constEnd(); it++) { if (!_roots.contains(it.key())) { out << it.key(); } } + out << AttributePointer(); // delete the expanded reference if we had to expand if (expandedReference != &reference) { @@ -372,6 +368,14 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c } } +MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) { + MetavoxelNode*& root = _roots[attribute]; + if (root) { + root->decrementReferenceCount(attribute); + } + return root = new MetavoxelNode(attribute); +} + void MetavoxelData::incrementRootReferenceCounts() { for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { it.value()->incrementReferenceCount(); @@ -384,6 +388,17 @@ void MetavoxelData::decrementRootReferenceCounts() { } } +static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int index) { + return minimum + glm::vec3( + (index & X_MAXIMUM_FLAG) ? nextSize : 0.0f, + (index & Y_MAXIMUM_FLAG) ? nextSize : 0.0f, + (index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f); +} + +void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { + minimum = getNextMinimum(lastMinimum, size, index); +} + MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) { _attributeValue = attributeValue.copy(); for (int i = 0; i < CHILD_COUNT; i++) { @@ -431,50 +446,72 @@ bool MetavoxelNode::isLeaf() const { return true; } -void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) { - clearChildren(attribute); +void MetavoxelNode::read(MetavoxelStreamState& state) { + clearChildren(state.attribute); + if (!state.shouldSubdivide()) { + state.attribute->read(state.stream, _attributeValue, true); + return; + } bool leaf; - in >> leaf; - attribute->read(in, _attributeValue, leaf); + state.stream >> leaf; + state.attribute->read(state.stream, _attributeValue, leaf); if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; for (int i = 0; i < CHILD_COUNT; i++) { - _children[i] = new MetavoxelNode(attribute); - _children[i]->read(attribute, in); + nextState.setMinimum(state.minimum, i); + _children[i] = new MetavoxelNode(state.attribute); + _children[i]->read(nextState); } } } -void MetavoxelNode::write(const AttributePointer& attribute, Bitstream& out) const { +void MetavoxelNode::write(MetavoxelStreamState& state) const { + if (!state.shouldSubdivide()) { + state.attribute->write(state.stream, _attributeValue, true); + return; + } bool leaf = isLeaf(); - out << leaf; - attribute->write(out, _attributeValue, leaf); + state.stream << leaf; + state.attribute->write(state.stream, _attributeValue, leaf); if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; for (int i = 0; i < CHILD_COUNT; i++) { - _children[i]->write(attribute, out); + nextState.setMinimum(state.minimum, i); + _children[i]->write(nextState); } } } -void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) { - clearChildren(attribute); +void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) { + clearChildren(state.attribute); + if (!state.shouldSubdivide()) { + state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, true); + return; + } bool leaf; - in >> leaf; - attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf); + state.stream >> leaf; + state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, leaf); if (!leaf) { - if (reference.isLeaf()) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (reference.isLeaf() || !state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { - _children[i] = new MetavoxelNode(attribute); - _children[i]->read(attribute, in); + nextState.setMinimum(state.minimum, i); + _children[i] = new MetavoxelNode(state.attribute); + _children[i]->read(nextState); } } else { for (int i = 0; i < CHILD_COUNT; i++) { bool changed; - in >> changed; + state.stream >> changed; if (changed) { - _children[i] = new MetavoxelNode(attribute); - _children[i]->readDelta(attribute, *reference._children[i], in); + nextState.setMinimum(state.minimum, i); + _children[i] = new MetavoxelNode(state.attribute); + _children[i]->readDelta(*reference._children[i], nextState); } else { _children[i] = reference._children[i]; _children[i]->incrementReferenceCount(); @@ -484,28 +521,94 @@ void MetavoxelNode::readDelta(const AttributePointer& attribute, const Metavoxel } } -void MetavoxelNode::writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const { +void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const { + if (!state.shouldSubdivide()) { + state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true); + return; + } bool leaf = isLeaf(); - out << leaf; - attribute->writeDelta(out, _attributeValue, reference._attributeValue, leaf); + state.stream << leaf; + state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf); if (!leaf) { - if (reference.isLeaf()) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (reference.isLeaf() || !state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { - _children[i]->write(attribute, out); + nextState.setMinimum(state.minimum, i); + _children[i]->write(nextState); } } else { for (int i = 0; i < CHILD_COUNT; i++) { if (_children[i] == reference._children[i]) { - out << false; + state.stream << false; } else { - out << true; - _children[i]->writeDelta(attribute, *reference._children[i], out); + nextState.setMinimum(state.minimum, i); + state.stream << true; + _children[i]->writeDelta(*reference._children[i], nextState); } } } } } +void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { + foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { + if (static_cast(object.data())->testAndSetVisited()) { + state.stream << object; + } + } + if (!state.shouldSubdivide() || isLeaf()) { + return; + } + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->writeSpanners(nextState); + } +} + +void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const { + SharedObjectSet oldSet = decodeInline(reference.getAttributeValue()); + SharedObjectSet newSet = decodeInline(_attributeValue); + foreach (const SharedObjectPointer& object, oldSet) { + if (static_cast(object.data())->testAndSetVisited() && !newSet.contains(object)) { + state.stream << object; + } + } + foreach (const SharedObjectPointer& object, newSet) { + if (static_cast(object.data())->testAndSetVisited() && !oldSet.contains(object)) { + state.stream << object; + } + } + if (isLeaf() || !state.shouldSubdivide()) { + if (!reference.isLeaf() && state.shouldSubdivideReference()) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + reference._children[i]->writeSpanners(nextState); + } + } + return; + } + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (reference.isLeaf() || !state.shouldSubdivideReference()) { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->writeSpanners(nextState); + } + return; + } + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i] != reference._children[i]) { + nextState.setMinimum(state.minimum, i); + _children[i]->writeSpannerDelta(*reference._children[i], nextState); + } + } +} + void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) { if (--_referenceCount == 0) { destroy(attribute); @@ -604,10 +707,7 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { MetavoxelNode* child = node ? node->getChild(i) : NULL; nextVisitation.outputNodes[j] = child; } - nextVisitation.info.minimum = visitation.info.minimum + glm::vec3( - (i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, - (i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f, - (i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f); + nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, i); static_cast(nextVisitation.info.inputValues.last().getInlineValue< SharedObjectPointer>().data())->guide(nextVisitation); for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 2133ad68d8..aa2615e574 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -33,13 +33,21 @@ class SpannerRenderer; /// Determines whether to subdivide each node when traversing. class MetavoxelLOD { + STREAMABLE + public: - glm::vec3 position; - float threshold; + STREAM glm::vec3 position; + STREAM float threshold; MetavoxelLOD(const glm::vec3& position = glm::vec3(), float threshold = 0.0f); + + bool isValid() const { return threshold > 0.0f; } + + bool shouldSubdivide(const glm::vec3& minimum, float size) const; }; +DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) + /// The base metavoxel representation shared between server and client. class MetavoxelData { public: @@ -52,25 +60,35 @@ public: float getSize() const { return _size; } + glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; } + Box getBounds() const; /// Applies the specified visitor to the contained voxels. void guide(MetavoxelVisitor& visitor); + void insert(const AttributePointer& attribute, const SharedObjectPointer& object); void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); + void remove(const AttributePointer& attribute, const SharedObjectPointer& object); void remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); + void toggle(const AttributePointer& attribute, const SharedObjectPointer& object); + void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); + void clear(const AttributePointer& attribute); /// Expands the tree, increasing its capacity in all dimensions. void expand(); - void read(Bitstream& in); - void write(Bitstream& out) const; + void read(Bitstream& in, const MetavoxelLOD& lod = MetavoxelLOD()); + void write(Bitstream& out, const MetavoxelLOD& lod = MetavoxelLOD()) const; - void readDelta(const MetavoxelData& reference, Bitstream& in); - void writeDelta(const MetavoxelData& reference, Bitstream& out) const; + void readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& in, const MetavoxelLOD& lod); + void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, + Bitstream& out, const MetavoxelLOD& lod) const; + + MetavoxelNode* createRoot(const AttributePointer& attribute); private: @@ -83,6 +101,22 @@ private: QHash _roots; }; +/// Holds the state used in streaming metavoxel data. +class MetavoxelStreamState { +public: + glm::vec3 minimum; + float size; + const AttributePointer& attribute; + Bitstream& stream; + const MetavoxelLOD& lod; + const MetavoxelLOD& referenceLOD; + + bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); } + bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); } + + void setMinimum(const glm::vec3& lastMinimum, int index); +}; + /// A single node within a metavoxel layer. class MetavoxelNode { public: @@ -104,11 +138,14 @@ public: bool isLeaf() const; - void read(const AttributePointer& attribute, Bitstream& in); - void write(const AttributePointer& attribute, Bitstream& out) const; + void read(MetavoxelStreamState& state); + void write(MetavoxelStreamState& state) const; - void readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in); - void writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const; + void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state); + void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; + + void writeSpanners(MetavoxelStreamState& state) const; + void writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; /// Increments the node's reference count. void incrementReferenceCount() { _referenceCount++; } diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index c66ce61ee9..7ee5482179 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -6,7 +6,6 @@ // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // -#include "MetavoxelData.h" #include "MetavoxelMessages.h" void MetavoxelEditMessage::apply(MetavoxelData& data) const { @@ -106,8 +105,7 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh } void InsertSpannerEdit::apply(MetavoxelData& data) const { - Spanner* spanner = static_cast(this->spanner.data()); - data.insert(attribute, spanner->getBounds(), spanner->getGranularity(), this->spanner); + data.insert(attribute, spanner); } RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index d6f07c2966..980d198872 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -9,10 +9,7 @@ #ifndef __interface__MetavoxelMessages__ #define __interface__MetavoxelMessages__ -#include "AttributeRegistry.h" -#include "MetavoxelUtil.h" - -class MetavoxelData; +#include "MetavoxelData.h" /// Requests to close the session. class CloseSessionMessage { @@ -49,7 +46,7 @@ class ClientStateMessage { public: - STREAM glm::vec3 position; + STREAM MetavoxelLOD lod; }; DECLARE_STREAMABLE_METATYPE(ClientStateMessage) From c4f29005a0b4afce8a43b2214d86e18faed038ec Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 5 Mar 2014 14:13:20 -0800 Subject: [PATCH 11/31] Working on subdivision. --- .../metavoxels/src/AttributeRegistry.cpp | 26 ++++ libraries/metavoxels/src/AttributeRegistry.h | 6 + libraries/metavoxels/src/MetavoxelData.cpp | 133 ++++++++++++++++-- libraries/metavoxels/src/MetavoxelData.h | 9 ++ 4 files changed, 159 insertions(+), 15 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 4b643ba847..b90aa668f5 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -165,6 +165,14 @@ void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& refer root.writeDelta(reference, state); } +void Attribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { + data.getRoot(state.attribute)->readSubdivision(state); +} + +void Attribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { + root.writeSubdivision(state); +} + QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : InlineAttribute(name, defaultValue) { } @@ -313,3 +321,21 @@ void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelN root.writeSpannerDelta(reference, state); state.stream << SharedObjectPointer(); } + +void SpannerSetAttribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { + forever { + SharedObjectPointer object; + state.stream >> object; + if (!object) { + break; + } + data.insert(state.attribute, object); + } +} + +void SpannerSetAttribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { + Spanner::incrementVisit(); + root.writeSpannerSubdivision(state); + state.stream << SharedObjectPointer(); +} + diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index dae0e87f37..8678e62b41 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -178,6 +178,9 @@ public: virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + + virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); virtual bool equal(void* first, void* second) const = 0; @@ -332,6 +335,9 @@ public: virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + + virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); }; #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 970b2a7d87..f3cce11e75 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -31,6 +31,10 @@ bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const { return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold; } +bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const { + return shouldSubdivide(minimum, size) && !reference.shouldSubdivide(minimum, size); +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -295,10 +299,15 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD }; MetavoxelNode* oldRoot = _roots.value(attribute); if (oldRoot) { - oldRoot->incrementReferenceCount(); - attribute->readDelta(*this, *oldRoot, state); - oldRoot->decrementReferenceCount(attribute); - + bool changed; + in >> changed; + if (changed) { + oldRoot->incrementReferenceCount(); + attribute->readDelta(*this, *oldRoot, state); + oldRoot->decrementReferenceCount(attribute); + } else { + attribute->readSubdivision(*this, state); + } } else { attribute->read(*this, state); } @@ -317,7 +326,9 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& out, const MetavoxelLOD& lod) const { // first things first: there might be no change whatsoever - if (_size == reference._size && _roots == reference._roots) { + glm::vec3 minimum = getMinimum(); + bool becameSubdivided = lod.becameSubdivided(minimum, _size, referenceLOD); + if (_size == reference._size && _roots == reference._roots && !becameSubdivided) { out << false; return; } @@ -338,14 +349,20 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO expandedReference = expanded; } - // write the added/changed roots + // write the added/changed/subdivided roots for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); - if (it.value() != referenceRoot) { - out << it.key(); - MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, referenceLOD }; + MetavoxelStreamState state = { minimum, _size, it.key(), out, lod, referenceLOD }; + if (it.value() != referenceRoot || becameSubdivided) { + out << it.key(); if (referenceRoot) { - it.key()->writeDelta(*it.value(), *referenceRoot, state); + if (it.value() == referenceRoot) { + out << false; + it.key()->writeSubdivision(*it.value(), state); + } else { + out << true; + it.key()->writeDelta(*it.value(), *referenceRoot, state); + } } else { it.key()->write(*it.value(), state); } @@ -506,15 +523,18 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta } } else { for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); bool changed; state.stream >> changed; - if (changed) { - nextState.setMinimum(state.minimum, i); + if (changed) { _children[i] = new MetavoxelNode(state.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { _children[i] = reference._children[i]; _children[i]->incrementReferenceCount(); + if (nextState.becameSubdivided()) { + _children[i]->readSubdivision(nextState); + } } } } @@ -539,10 +559,13 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } } else { for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); if (_children[i] == reference._children[i]) { state.stream << false; - } else { - nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSubdivision(nextState); + } + } else { state.stream << true; _children[i]->writeDelta(*reference._children[i], nextState); } @@ -551,6 +574,63 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } } +void MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { + bool leaf; + bool subdivideReference = state.shouldSubdivideReference(); + if (!subdivideReference) { + state.stream >> leaf; + } else { + leaf = isLeaf(); + } + if (leaf) { + clearChildren(state.attribute); + + } else { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!subdivideReference) { + clearChildren(state.attribute); + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i] = new MetavoxelNode(state.attribute); + _children[i]->read(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->readSubdivision(nextState); + } + } + } + } +} + +void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { + bool leaf = isLeaf(); + bool subdivideReference = state.shouldSubdivideReference(); + if (!subdivideReference) { + state.stream << leaf; + } + if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!subdivideReference) { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->write(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSubdivision(nextState); + } + } + } + } +} + void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { if (static_cast(object.data())->testAndSetVisited()) { @@ -602,9 +682,32 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS return; } for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); if (_children[i] != reference._children[i]) { - nextState.setMinimum(state.minimum, i); _children[i]->writeSpannerDelta(*reference._children[i], nextState); + + } else if (nextState.becameSubdivided()) { + _children[i]->writeSpannerSubdivision(nextState); + } + } +} + +void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const { + if (!isLeaf()) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!state.shouldSubdivideReference()) { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->writeSpanners(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSpannerSubdivision(nextState); + } + } } } } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index aa2615e574..0c11055b0f 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -44,6 +44,9 @@ public: bool isValid() const { return threshold > 0.0f; } bool shouldSubdivide(const glm::vec3& minimum, float size) const; + + /// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference. + bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) @@ -88,6 +91,7 @@ public: void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& out, const MetavoxelLOD& lod) const; + MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } MetavoxelNode* createRoot(const AttributePointer& attribute); private: @@ -113,6 +117,7 @@ public: bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); } bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); } + bool becameSubdivided() const { return lod.becameSubdivided(minimum, size, referenceLOD); } void setMinimum(const glm::vec3& lastMinimum, int index); }; @@ -144,8 +149,12 @@ public: void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state); void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; + void readSubdivision(MetavoxelStreamState& state); + void writeSubdivision(MetavoxelStreamState& state) const; + void writeSpanners(MetavoxelStreamState& state) const; void writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; + void writeSpannerSubdivision(MetavoxelStreamState& state) const; /// Increments the node's reference count. void incrementReferenceCount() { _referenceCount++; } From 60b0281095b0172d60c22da6ec25076f49e70714 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 5 Mar 2014 17:12:02 -0800 Subject: [PATCH 12/31] Ordered visitation bits. --- interface/src/MetavoxelSystem.cpp | 33 +++-- interface/src/MetavoxelSystem.h | 10 +- libraries/metavoxels/src/MetavoxelData.cpp | 119 +++++++++++++----- libraries/metavoxels/src/MetavoxelData.h | 45 +++++-- .../metavoxels/src/MetavoxelMessages.cpp | 18 +-- 5 files changed, 162 insertions(+), 63 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 4c1b40dc23..b6b4c2b668 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -61,13 +61,14 @@ void MetavoxelSystem::simulate(float deltaTime) { // simulate the clients _points.clear(); _simulateVisitor.setDeltaTime(deltaTime); + _simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection()); foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { client->simulate(deltaTime); - client->getData().guide(_simulateVisitor); + client->guide(_simulateVisitor); } } } @@ -109,7 +110,7 @@ void MetavoxelSystem::render() { glEnableClientState(GL_NORMAL_ARRAY); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - + glDrawArrays(GL_POINTS, 0, _points.size()); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); @@ -127,7 +128,7 @@ void MetavoxelSystem::render() { QMutexLocker locker(&node->getMutex()); MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { - client->getData().guide(_renderVisitor); + client->guide(_renderVisitor); } } } @@ -147,15 +148,16 @@ MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector& points) : _points(points) { } -void MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) { +bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) { spanner->getRenderer()->simulate(_deltaTime); + return true; } -bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { +int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { SpannerVisitor::visit(info); if (!info.isLeaf) { - return true; + return _order; } QRgb color = info.inputValues.at(0).getInlineValue(); QRgb normal = info.inputValues.at(1).getInlineValue(); @@ -165,15 +167,16 @@ bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { { qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } }; _points.append(point); } - return false; + return STOP_RECURSION; } MetavoxelSystem::RenderVisitor::RenderVisitor() : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute()) { } -void MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { +bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { spanner->getRenderer()->render(1.0f); + return true; } MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : @@ -201,6 +204,16 @@ MetavoxelClient::~MetavoxelClient() { _sequencer.endPacket(); } +static MetavoxelLOD getLOD() { + const float FIXED_LOD_THRESHOLD = 0.01f; + return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD); +} + +void MetavoxelClient::guide(MetavoxelVisitor& visitor) { + visitor.setLOD(getLOD()); + _data.guide(visitor); +} + void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { // apply immediately to local tree edit.apply(_data); @@ -211,8 +224,8 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { void MetavoxelClient::simulate(float deltaTime) { Bitstream& out = _sequencer.startPacket(); - const float FIXED_LOD_THRESHOLD = 0.0001f; - ClientStateMessage state = { MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD) }; + + ClientStateMessage state = { getLOD() }; out << QVariant::fromValue(state); _sequencer.endPacket(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 155f99ffbd..c1833832a7 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -57,18 +57,20 @@ private: public: SimulateVisitor(QVector& points); void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; } - virtual void visit(Spanner* spanner); - virtual bool visit(MetavoxelInfo& info); + void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); } + virtual bool visit(Spanner* spanner); + virtual int visit(MetavoxelInfo& info); private: QVector& _points; float _deltaTime; + int _order; }; class RenderVisitor : public SpannerVisitor { public: RenderVisitor(); - virtual void visit(Spanner* spanner); + virtual bool visit(Spanner* spanner); }; static ProgramObject _program; @@ -89,7 +91,7 @@ public: MetavoxelClient(const SharedNodePointer& node); virtual ~MetavoxelClient(); - MetavoxelData& getData() { return _data; } + void guide(MetavoxelVisitor& visitor); void applyEdit(const MetavoxelEditMessage& edit); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index f3cce11e75..18a290d6e2 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -32,7 +32,19 @@ bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const { } bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const { - return shouldSubdivide(minimum, size) && !reference.shouldSubdivide(minimum, size); + if (position == reference.position && threshold >= reference.threshold) { + return false; // first off, nothing becomes subdivided if it doesn't change + } + if (!shouldSubdivide(minimum, size)) { + return false; // this one must be subdivided + } + // the general check is whether we've gotten closer (as multiplied by the threshold) to any point in the volume, + // which we approximate as a sphere for simplicity + float halfSize = size * 0.5f; + glm::vec3 center = minimum + glm::vec3(halfSize, halfSize, halfSize); + float radius = sqrtf(3 * halfSize * halfSize); + return qMax(0.0f, glm::distance(position, center) - radius) * threshold <= + qMax(0.0f, glm::distance(reference.position, center) - radius) * reference.threshold; } MetavoxelData::MetavoxelData() : _size(1.0f) { @@ -128,7 +140,7 @@ public: SpannerUpdateVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); - virtual bool visit(MetavoxelInfo& info); + virtual int visit(MetavoxelInfo& info); private: @@ -147,17 +159,17 @@ template SpannerUpdateVisitor::SpannerUpdateVisitor( _object(object) { } -template bool SpannerUpdateVisitor::visit(MetavoxelInfo& info) { +template int SpannerUpdateVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_bounds)) { - return false; + return STOP_RECURSION; } if (info.size > _longestSide) { - return true; + return DEFAULT_ORDER; } SharedObjectSet set = info.inputValues.at(0).getInlineValue(); F(set, _object); info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); - return false; + return STOP_RECURSION; } void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) { @@ -737,9 +749,43 @@ void MetavoxelNode::clearChildren(const AttributePointer& attribute) { } } -MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, const QVector& outputs) : +int MetavoxelVisitor::encodeOrder(int first, int second, int third, int fourth, + int fifth, int sixth, int seventh, int eighth) { + return first | (second << 3) | (third << 6) | (fourth << 9) | + (fifth << 12) | (sixth << 15) | (seventh << 18) | (eighth << 21); +} + +class IndexDistance { +public: + int index; + float distance; +}; + +bool operator<(const IndexDistance& first, const IndexDistance& second) { + return first.distance < second.distance; +} + +int MetavoxelVisitor::encodeOrder(const glm::vec3& direction) { + QList indexDistances; + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + IndexDistance indexDistance = { i, glm::dot(direction, getNextMinimum(glm::vec3(), 1.0f, i)) }; + indexDistances.append(indexDistance); + } + qStableSort(indexDistances); + return encodeOrder(indexDistances.at(0).index, indexDistances.at(1).index, indexDistances.at(2).index, + indexDistances.at(3).index, indexDistances.at(4).index, indexDistances.at(5).index, + indexDistances.at(6).index, indexDistances.at(7).index); +} + +const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7); +const int MetavoxelVisitor::STOP_RECURSION = 0; +const int MetavoxelVisitor::SHORT_CIRCUIT = -1; + +MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, + const QVector& outputs, const MetavoxelLOD& lod) : _inputs(inputs), - _outputs(outputs) { + _outputs(outputs), + _lod(lod) { } MetavoxelVisitor::~MetavoxelVisitor() { @@ -750,8 +796,8 @@ void MetavoxelVisitor::prepare() { } SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, const QVector& inputs, - const QVector& outputs) : - MetavoxelVisitor(inputs + spannerInputs, outputs), + const QVector& outputs, const MetavoxelLOD& lod) : + MetavoxelVisitor(inputs + spannerInputs, outputs, lod), _spannerInputCount(spannerInputs.size()) { } @@ -759,24 +805,30 @@ void SpannerVisitor::prepare() { Spanner::incrementVisit(); } -bool SpannerVisitor::visit(MetavoxelInfo& info) { +int SpannerVisitor::visit(MetavoxelInfo& info) { for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { Spanner* spanner = static_cast(object.data()); if (spanner->testAndSetVisited()) { - visit(spanner); + if (!visit(spanner)) { + return SHORT_CIRCUIT; + } } } } - return !info.isLeaf; + return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; } DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } -void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - visitation.info.isLeaf = visitation.allInputNodesLeaves(); - bool keepGoing = visitation.visitor.visit(visitation.info); +bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + bool shouldSubdivide = visitation.visitor.getLOD().shouldSubdivide(visitation.info.minimum, visitation.info.size); + visitation.info.isLeaf = !shouldSubdivide || visitation.allInputNodesLeaves(); + int encodedOrder = visitation.visitor.visit(visitation.info); + if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { + return false; + } for (int i = 0; i < visitation.outputNodes.size(); i++) { OwnedAttributeValue& value = visitation.info.outputValues[i]; if (!value.getAttribute()) { @@ -790,29 +842,35 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { node = new MetavoxelNode(value); } } - if (!keepGoing) { - return; + if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { + return true; } MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor, QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()), { glm::vec3(), visitation.info.size * 0.5f, QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()) } }; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + const int ORDER_ELEMENT_BITS = 3; + const int ORDER_ELEMENT_MASK = (1 << ORDER_ELEMENT_BITS) - 1; + int index = encodedOrder & ORDER_ELEMENT_MASK; + encodedOrder >>= ORDER_ELEMENT_BITS; for (int j = 0; j < visitation.inputNodes.size(); j++) { MetavoxelNode* node = visitation.inputNodes.at(j); - MetavoxelNode* child = node ? node->getChild(i) : NULL; + MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL; nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ? child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) : visitation.info.inputValues[j]; } for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); - MetavoxelNode* child = node ? node->getChild(i) : NULL; + MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL; nextVisitation.outputNodes[j] = child; } - nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, i); - static_cast(nextVisitation.info.inputValues.last().getInlineValue< - SharedObjectPointer>().data())->guide(nextVisitation); + nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index); + if (!static_cast(nextVisitation.info.inputValues.last().getInlineValue< + SharedObjectPointer>().data())->guide(nextVisitation)) { + return false; + } for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { OwnedAttributeValue& value = nextVisitation.info.outputValues[j]; if (!value.getAttribute()) { @@ -839,10 +897,10 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { // it's a leaf; we need to split it up AttributeValue nodeValue = node->getAttributeValue(value.getAttribute()); for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) { - node->setChild((i + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue)); + node->setChild((index + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue)); } } - node->setChild(i, nextVisitation.outputNodes.at(j)); + node->setChild(index, nextVisitation.outputNodes.at(j)); value = AttributeValue(); } } @@ -854,12 +912,13 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { value = node->getAttributeValue(value.getAttribute()); } } + return true; } ThrobbingMetavoxelGuide::ThrobbingMetavoxelGuide() : _rate(10.0) { } -void ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) { +bool ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) { AttributePointer colorAttribute = AttributeRegistry::getInstance()->getColorAttribute(); for (int i = 0; i < visitation.info.inputValues.size(); i++) { AttributeValue& attributeValue = visitation.info.inputValues[i]; @@ -872,7 +931,7 @@ void ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } } - DefaultMetavoxelGuide::guide(visitation); + return DefaultMetavoxelGuide::guide(visitation); } static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* guide, @@ -933,7 +992,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin ScriptedMetavoxelGuide::ScriptedMetavoxelGuide() { } -void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { +bool ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { QScriptValue guideFunction; if (_guideFunction) { guideFunction = _guideFunction->getValue(); @@ -944,8 +1003,7 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } if (!guideFunction.isValid()) { // before we load, just use the default behavior - DefaultMetavoxelGuide::guide(visitation); - return; + return DefaultMetavoxelGuide::guide(visitation); } QScriptEngine* engine = guideFunction.engine(); if (!_minimumHandle.isValid()) { @@ -983,6 +1041,7 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { if (engine->hasUncaughtException()) { qDebug() << "Script error: " << engine->uncaughtException().toString(); } + return true; } void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 0c11055b0f..48246bb633 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -194,8 +194,24 @@ public: class MetavoxelVisitor { public: + /// Encodes a visitation order sequence for the children of a metavoxel. + static int encodeOrder(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eighth); + + /// Encodes a visitation order sequence that visits each child as sorted along the specified direction. + static int encodeOrder(const glm::vec3& direction); + + /// The default visitation order. + static const int DEFAULT_ORDER; + + /// A special "order" that instructs the guide to stop recursion. + static const int STOP_RECURSION; + + /// A special "order" that short-circuits the tour. + static const int SHORT_CIRCUIT; + MetavoxelVisitor(const QVector& inputs, - const QVector& outputs = QVector()); + const QVector& outputs = QVector(), + const MetavoxelLOD& lod = MetavoxelLOD()); virtual ~MetavoxelVisitor(); /// Returns a reference to the list of input attributes desired. @@ -204,18 +220,24 @@ public: /// Returns a reference to the list of output attributes provided. const QVector& getOutputs() const { return _outputs; } + /// Returns a reference to the level of detail that will determine subdivision levels. + const MetavoxelLOD& getLOD() const { return _lod; } + + void setLOD(const MetavoxelLOD& lod) { _lod = lod; } + /// Prepares for a new tour of the metavoxel data. virtual void prepare(); /// Visits a metavoxel. /// \param info the metavoxel data - /// \return if true, continue descending; if false, stop - virtual bool visit(MetavoxelInfo& info) = 0; + /// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour + virtual int visit(MetavoxelInfo& info) = 0; protected: QVector _inputs; QVector _outputs; + MetavoxelLOD _lod; }; typedef QSharedPointer MetavoxelVisitorPointer; @@ -226,13 +248,15 @@ public: SpannerVisitor(const QVector& spannerInputs, const QVector& inputs = QVector(), - const QVector& outputs = QVector()); + const QVector& outputs = QVector(), + const MetavoxelLOD& lod = MetavoxelLOD()); /// Visits a spanner. - virtual void visit(Spanner* spanner) = 0; + /// \return true to continue, false to short-circuit the tour + virtual bool visit(Spanner* spanner) = 0; virtual void prepare(); - virtual bool visit(MetavoxelInfo& info); + virtual int visit(MetavoxelInfo& info); protected: @@ -246,7 +270,8 @@ class MetavoxelGuide : public SharedObject { public: /// Guides the specified visitor to the contained voxels. - virtual void guide(MetavoxelVisitation& visitation) = 0; + /// \return true to keep going, false to short circuit the tour + virtual bool guide(MetavoxelVisitation& visitation) = 0; }; /// Guides visitors through the explicit content of the system. @@ -257,7 +282,7 @@ public: Q_INVOKABLE DefaultMetavoxelGuide(); - virtual void guide(MetavoxelVisitation& visitation); + virtual bool guide(MetavoxelVisitation& visitation); }; /// A temporary test guide that just makes the existing voxels throb with delight. @@ -269,7 +294,7 @@ public: Q_INVOKABLE ThrobbingMetavoxelGuide(); - virtual void guide(MetavoxelVisitation& visitation); + virtual bool guide(MetavoxelVisitation& visitation); private: @@ -285,7 +310,7 @@ public: Q_INVOKABLE ScriptedMetavoxelGuide(); - virtual void guide(MetavoxelVisitation& visitation); + virtual bool guide(MetavoxelVisitation& visitation); public slots: diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 7ee5482179..bcb59dad77 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -24,7 +24,7 @@ public: BoxSetEditVisitor(const BoxSetEdit& edit); - virtual bool visit(MetavoxelInfo& info); + virtual int visit(MetavoxelInfo& info); private: @@ -36,26 +36,26 @@ BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) : _edit(edit) { } -bool BoxSetEditVisitor::visit(MetavoxelInfo& info) { +int BoxSetEditVisitor::visit(MetavoxelInfo& info) { // find the intersection between volume and voxel glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum); glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum); glm::vec3 size = maximum - minimum; if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) { - return false; // disjoint + return STOP_RECURSION; // disjoint } float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size); if (volume >= 1.0f) { info.outputValues[0] = _edit.value; - return false; // entirely contained + return STOP_RECURSION; // entirely contained } if (info.size <= _edit.granularity) { if (volume >= 0.5f) { info.outputValues[0] = _edit.value; } - return false; // reached granularity limit; take best guess + return STOP_RECURSION; // reached granularity limit; take best guess } - return true; // subdivide + return DEFAULT_ORDER; // subdivide } void BoxSetEdit::apply(MetavoxelData& data) const { @@ -77,7 +77,7 @@ public: GlobalSetEditVisitor(const GlobalSetEdit& edit); - virtual bool visit(MetavoxelInfo& info); + virtual int visit(MetavoxelInfo& info); private: @@ -89,9 +89,9 @@ GlobalSetEditVisitor::GlobalSetEditVisitor(const GlobalSetEdit& edit) : _edit(edit) { } -bool GlobalSetEditVisitor::visit(MetavoxelInfo& info) { +int GlobalSetEditVisitor::visit(MetavoxelInfo& info) { info.outputValues[0] = _edit.value; - return false; // entirely contained + return STOP_RECURSION; // entirely contained } void GlobalSetEdit::apply(MetavoxelData& data) const { From 23556f0cf7ce8ac55c6c4326685ca3383d21e06e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 6 Mar 2014 12:38:11 -0800 Subject: [PATCH 13/31] Fix for merging after streaming, added ability to "set" a spanner's attributes in the actual metavoxel data. --- interface/src/ui/MetavoxelEditor.cpp | 44 +++++++++--- interface/src/ui/MetavoxelEditor.h | 40 +++++++++-- libraries/metavoxels/src/MetavoxelData.cpp | 68 ++++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 13 ++++ .../metavoxels/src/MetavoxelMessages.cpp | 37 ++++++++++ libraries/metavoxels/src/MetavoxelMessages.h | 15 ++++ libraries/metavoxels/src/MetavoxelUtil.cpp | 11 +++ libraries/metavoxels/src/MetavoxelUtil.h | 6 ++ 8 files changed, 218 insertions(+), 16 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 61f7b55968..1259be3083 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -100,6 +100,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new InsertSpannerTool(this)); addTool(new RemoveSpannerTool(this)); addTool(new ClearSpannersTool(this)); + addTool(new SetSpannerTool(this)); updateAttributes(); @@ -529,15 +530,15 @@ void GlobalSetTool::apply() { Application::getInstance()->getMetavoxels()->applyEdit(message); } -InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : - MetavoxelTool(editor, "Insert Spanner") { +PlaceSpannerTool::PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText) : + MetavoxelTool(editor, name) { - QPushButton* button = new QPushButton("Insert"); + QPushButton* button = new QPushButton(placeText); layout()->addWidget(button); - connect(button, SIGNAL(clicked()), SLOT(insert())); + connect(button, SIGNAL(clicked()), SLOT(place())); } -void InsertSpannerTool::simulate(float deltaTime) { +void PlaceSpannerTool::simulate(float deltaTime) { if (Application::getInstance()->isMouseHidden()) { return; } @@ -558,7 +559,7 @@ void InsertSpannerTool::simulate(float deltaTime) { spanner->getRenderer()->simulate(deltaTime); } -void InsertSpannerTool::render() { +void PlaceSpannerTool::render() { if (Application::getInstance()->isMouseHidden()) { return; } @@ -567,28 +568,36 @@ void InsertSpannerTool::render() { spanner->getRenderer()->render(SPANNER_ALPHA); } -bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { +bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute->inherits("SpannerSetAttribute"); } -bool InsertSpannerTool::eventFilter(QObject* watched, QEvent* event) { +bool PlaceSpannerTool::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::MouseButtonPress) { - insert(); + place(); return true; } return false; } -void InsertSpannerTool::insert() { +void PlaceSpannerTool::place() { AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); if (!attribute) { return; } SharedObjectPointer spanner = _editor->getValue().value(); - MetavoxelEditMessage message = { QVariant::fromValue(InsertSpannerEdit(attribute, spanner)) }; + MetavoxelEditMessage message = { createEdit(attribute, spanner) }; Application::getInstance()->getMetavoxels()->applyEdit(message); } +InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : + PlaceSpannerTool(editor, "Insert Spanner", "Insert") { +} + +QVariant InsertSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { + return QVariant::fromValue(InsertSpannerEdit(attribute, spanner)); +} + RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : MetavoxelTool(editor, "Remove Spanner", false) { } @@ -625,3 +634,16 @@ void ClearSpannersTool::clear() { MetavoxelEditMessage message = { QVariant::fromValue(ClearSpannersEdit(attribute)) }; Application::getInstance()->getMetavoxels()->applyEdit(message); } + +SetSpannerTool::SetSpannerTool(MetavoxelEditor* editor) : + PlaceSpannerTool(editor, "Set Spanner", "Set") { +} + +bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const { + return attribute == AttributeRegistry::getInstance()->getSpannersAttribute(); +} + +QVariant SetSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { + static_cast(spanner.data())->setGranularity(_editor->getGridSpacing()); + return QVariant::fromValue(SetSpannerEdit(spanner)); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 5b580129a9..76ef8baf6f 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -139,13 +139,13 @@ private slots: void apply(); }; -/// Allows inserting a spanner into the scene. -class InsertSpannerTool : public MetavoxelTool { +/// Base class for insert/set spanner tools. +class PlaceSpannerTool : public MetavoxelTool { Q_OBJECT public: - InsertSpannerTool(MetavoxelEditor* editor); + PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText); virtual void simulate(float deltaTime); @@ -155,9 +155,26 @@ public: virtual bool eventFilter(QObject* watched, QEvent* event); +protected: + + virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0; + private slots: - void insert(); + void place(); +}; + +/// Allows inserting a spanner into the scene. +class InsertSpannerTool : public PlaceSpannerTool { + Q_OBJECT + +public: + + InsertSpannerTool(MetavoxelEditor* editor); + +protected: + + virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); }; /// Allows removing a spanner from the scene. @@ -188,4 +205,19 @@ private slots: void clear(); }; +/// Allows setting the value by placing a spanner. +class SetSpannerTool : public PlaceSpannerTool { + Q_OBJECT + +public: + + SetSpannerTool(MetavoxelEditor* editor); + + virtual bool appliesTo(const AttributePointer& attribute) const; + +protected: + + virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); +}; + #endif /* defined(__interface__MetavoxelEditor__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 18a290d6e2..f1c0b928c9 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -493,6 +493,7 @@ void MetavoxelNode::read(MetavoxelStreamState& state) { _children[i] = new MetavoxelNode(state.attribute); _children[i]->read(nextState); } + mergeChildren(state.attribute); } } @@ -549,7 +550,8 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta } } } - } + } + mergeChildren(state.attribute); } } @@ -1085,6 +1087,15 @@ void Spanner::setBounds(const Box& bounds) { emit boundsChanged(_bounds = bounds); } +const QVector& Spanner::getAttributes() const { + static QVector emptyVector; + return emptyVector; +} + +bool Spanner::getAttributeValues(MetavoxelInfo& info) const { + return false; +} + bool Spanner::testAndSetVisited() { if (_lastVisit == _visit) { return false; @@ -1164,6 +1175,43 @@ void Sphere::setColor(const QColor& color) { } } +const QVector& Sphere::getAttributes() const { + static QVector attributes = QVector() << + AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute(); + return attributes; +} + +bool Sphere::getAttributeValues(MetavoxelInfo& info) const { + // bounds check + Box bounds = info.getBounds(); + if (!getBounds().intersects(bounds)) { + return false; + } + // count the points inside the sphere + int pointsWithin = 0; + for (int i = 0; i < Box::VERTEX_COUNT; i++) { + if (glm::distance(bounds.getVertex(i), getTranslation()) <= getScale()) { + pointsWithin++; + } + } + if (pointsWithin == Box::VERTEX_COUNT) { + // entirely contained + info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline(_color.rgba())); + getNormal(info); + return false; + } + if (info.size <= getGranularity()) { + // best guess + if (pointsWithin > 0) { + info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline(qRgba( + _color.red(), _color.green(), _color.blue(), _color.alpha() * pointsWithin / Box::VERTEX_COUNT))); + getNormal(info); + } + return false; + } + return true; +} + QByteArray Sphere::getRendererClassName() const { return "SphereRenderer"; } @@ -1173,6 +1221,24 @@ void Sphere::updateBounds() { setBounds(Box(getTranslation() - extent, getTranslation() + extent)); } +void Sphere::getNormal(MetavoxelInfo& info) const { + glm::vec3 normal = info.getCenter() - getTranslation(); + float length = glm::length(normal); + QRgb color; + if (length > EPSILON) { + const float NORMAL_SCALE = 127.0f; + float scale = NORMAL_SCALE / length; + const int BYTE_MASK = 0xFF; + color = qRgb((int)(normal.x * scale) & BYTE_MASK, (int)(normal.y * scale) & BYTE_MASK, + (int)(normal.z * scale) & BYTE_MASK); + + } else { + const QRgb DEFAULT_NORMAL = 0x007F00; + color = DEFAULT_NORMAL; + } + info.outputValues[1] = AttributeValue(getAttributes().at(1), encodeInline(color)); +} + StaticModel::StaticModel() { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 48246bb633..5b149c071f 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -188,6 +188,7 @@ public: bool isLeaf; Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); } + glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; } }; /// Interface for visitors to metavoxels. @@ -374,6 +375,13 @@ public: void setGranularity(float granularity) { _granularity = granularity; } float getGranularity() const { return _granularity; } + /// Returns a reference to the list of attributes associated with this spanner. + virtual const QVector& getAttributes() const; + + /// Sets the attribute values associated with this spanner in the supplied info. + /// \return true to recurse, false to stop + virtual bool getAttributeValues(MetavoxelInfo& info) const; + /// Checks whether we've visited this object on the current traversal. If we have, returns false. /// If we haven't, sets the last visit identifier and returns true. bool testAndSetVisited(); @@ -459,6 +467,9 @@ public: void setColor(const QColor& color); const QColor& getColor() const { return _color; } + virtual const QVector& getAttributes() const; + virtual bool getAttributeValues(MetavoxelInfo& info) const; + signals: void colorChanged(const QColor& color); @@ -473,6 +484,8 @@ private slots: private: + void getNormal(MetavoxelInfo& info) const; + QColor _color; }; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index bcb59dad77..1c36f7df46 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -123,3 +123,40 @@ ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) : void ClearSpannersEdit::apply(MetavoxelData& data) const { data.clear(attribute); } + +class SetSpannerEditVisitor : public MetavoxelVisitor { +public: + + SetSpannerEditVisitor(Spanner* spanner); + + virtual int visit(MetavoxelInfo& info); + +private: + + Spanner* _spanner; +}; + +SetSpannerEditVisitor::SetSpannerEditVisitor(Spanner* spanner) : + MetavoxelVisitor(QVector(), spanner->getAttributes()), + _spanner(spanner) { +} + +int SetSpannerEditVisitor::visit(MetavoxelInfo& info) { + return _spanner->getAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION; +} + +SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) : + spanner(spanner) { +} + +void SetSpannerEdit::apply(MetavoxelData& data) const { + Spanner* spanner = static_cast(this->spanner.data()); + + // expand to fit the entire spanner + while (!data.getBounds().contains(spanner->getBounds())) { + data.expand(); + } + + SetSpannerEditVisitor visitor(spanner); + data.guide(visitor); +} diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 980d198872..fe229cc727 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -161,4 +161,19 @@ public: DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit) +/// An edit that sets a spanner's attributes in the voxel tree. +class SetSpannerEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM SharedObjectPointer spanner; + + SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer()); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(SetSpannerEdit) + #endif /* defined(__interface__MetavoxelMessages__) */ diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 86cbe87fd8..9e96b43d3f 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -162,6 +162,17 @@ bool Box::intersects(const Box& other) const { other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; } +const int X_MAXIMUM_FLAG = 1; +const int Y_MAXIMUM_FLAG = 2; +const int Z_MAXIMUM_FLAG = 4; + +glm::vec3 Box::getVertex(int index) const { + return glm::vec3( + (index & X_MAXIMUM_FLAG) ? maximum.x : minimum.x, + (index & Y_MAXIMUM_FLAG) ? maximum.y : minimum.y, + (index & Z_MAXIMUM_FLAG) ? maximum.z : minimum.z); +} + Box operator*(const glm::mat4& matrix, const Box& box) { // start with the constant component Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2])); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index adb106b652..45a9476e4d 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -34,6 +34,8 @@ class Box { public: + static const int VERTEX_COUNT = 8; + STREAM glm::vec3 minimum; STREAM glm::vec3 maximum; @@ -44,6 +46,10 @@ public: bool intersects(const Box& other) const; float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); } + + glm::vec3 getVertex(int index) const; + + glm::vec3 getCenter() const { return (minimum + maximum) * 0.5f; } }; DECLARE_STREAMABLE_METATYPE(Box) From 7fc55e5596fab96961674e41f425450dba7d801f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Mar 2014 13:00:58 -0700 Subject: [PATCH 14/31] Better merging for normals. --- .../metavoxels/src/AttributeRegistry.cpp | 36 ++++++++++++++++++- libraries/metavoxels/src/AttributeRegistry.h | 17 +++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index b90aa668f5..8a444467de 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -12,6 +12,7 @@ #include "MetavoxelData.h" REGISTER_META_OBJECT(QRgbAttribute) +REGISTER_META_OBJECT(PackedNormalAttribute) REGISTER_META_OBJECT(SharedObjectAttribute) REGISTER_META_OBJECT(SharedObjectSetAttribute) REGISTER_META_OBJECT(SpannerSetAttribute) @@ -26,7 +27,7 @@ AttributeRegistry::AttributeRegistry() : SharedObjectPointer(new DefaultMetavoxelGuide())))), _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), - _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { + _normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))) { } static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) { @@ -217,6 +218,39 @@ QWidget* QRgbAttribute::createEditor(QWidget* parent) const { return editor; } +PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultValue) : + QRgbAttribute(name, defaultValue) { +} + +bool PackedNormalAttribute::merge(void*& parent, void* children[]) const { + QRgb firstValue = decodeInline(children[0]); + int totalRed = (char)qRed(firstValue); + int totalGreen = (char)qGreen(firstValue); + int totalBlue = (char)qBlue(firstValue); + bool allChildrenEqual = true; + for (int i = 1; i < Attribute::MERGE_COUNT; i++) { + QRgb value = decodeInline(children[i]); + totalRed += (char)qRed(value); + totalGreen += (char)qGreen(value); + totalBlue += (char)qBlue(value); + allChildrenEqual &= (firstValue == value); + } + parent = encodeInline(packNormal(glm::normalize(glm::vec3(totalRed, totalGreen, totalBlue)))); + return allChildrenEqual; +} + +const float CHAR_SCALE = 127.0f; +const float INVERSE_CHAR_SCALE = 1.0f / CHAR_SCALE; + +QRgb packNormal(const glm::vec3& normal) { + return qRgb((char)(normal.x * CHAR_SCALE), (char)(normal.y * CHAR_SCALE), (char)(normal.z * CHAR_SCALE)); +} + +glm::vec3 unpackNormal(QRgb value) { + return glm::vec3((char)qRed(value) * INVERSE_CHAR_SCALE, (char)qGreen(value) * INVERSE_CHAR_SCALE, + (char)qBlue(value) * INVERSE_CHAR_SCALE); +} + SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject, const SharedObjectPointer& defaultValue) : InlineAttribute(name, defaultValue), diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 8678e62b41..3dc6aa7484 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -272,6 +272,23 @@ public: virtual QWidget* createEditor(QWidget* parent = NULL) const; }; +/// Provides appropriate averaging for packed normals. +class PackedNormalAttribute : public QRgbAttribute { + Q_OBJECT + +public: + + Q_INVOKABLE PackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb()); + + virtual bool merge(void*& parent, void* children[]) const; +}; + +/// Packs a normal into an RGB value. +QRgb packNormal(const glm::vec3& normal); + +/// Unpacks a normal from an RGB value. +glm::vec3 unpackNormal(QRgb value); + /// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject). class SharedObjectAttribute : public InlineAttribute { Q_OBJECT From 802cc3eeedecce625c5fd09ca79d379fb2a8cb6d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Mar 2014 14:58:31 -0700 Subject: [PATCH 15/31] Some untested ray intersection bits. --- libraries/metavoxels/src/MetavoxelData.cpp | 69 ++++++++++++++++++++++ libraries/metavoxels/src/MetavoxelData.h | 55 +++++++++++++++-- libraries/metavoxels/src/MetavoxelUtil.cpp | 52 ++++++++++++++++ libraries/metavoxels/src/MetavoxelUtil.h | 4 ++ 4 files changed, 175 insertions(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index f1c0b928c9..0afb334aca 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "MetavoxelData.h" #include "MetavoxelUtil.h" #include "ScriptCache.h" @@ -821,6 +823,65 @@ int SpannerVisitor::visit(MetavoxelInfo& info) { return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; } +RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, + const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : + MetavoxelVisitor(inputs, outputs, lod), + _origin(origin), + _direction(direction), + _order(encodeOrder(direction)) { +} + +int RayIntersectionVisitor::visit(MetavoxelInfo& info) { + float distance; + if (!info.getBounds().findRayIntersection(_origin, _direction, distance)) { + return STOP_RECURSION; + } + return visit(info, distance); +} + +RayIntersectionSpannerVisitor::RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction, + const QVector& spannerInputs, const QVector& inputs, + const QVector& outputs, const MetavoxelLOD& lod) : + RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod), + _spannerInputCount(spannerInputs.size()) { +} + +void RayIntersectionSpannerVisitor::prepare() { + Spanner::incrementVisit(); +} + +class SpannerDistance { +public: + Spanner* spanner; + float distance; +}; + +bool operator<(const SpannerDistance& first, const SpannerDistance& second) { + return first.distance < second.distance; +} + +int RayIntersectionSpannerVisitor::visit(MetavoxelInfo& info, float distance) { + QVarLengthArray spannerDistances; + for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { + foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { + Spanner* spanner = static_cast(object.data()); + if (spanner->testAndSetVisited()) { + SpannerDistance spannerDistance = { spanner }; + if (spanner->findRayIntersection(_origin, _direction, spannerDistance.distance)) { + spannerDistances.append(spannerDistance); + } + } + } + qStableSort(spannerDistances); + foreach (const SpannerDistance& spannerDistance, spannerDistances) { + if (!visit(spannerDistance.spanner, spannerDistance.distance)) { + return SHORT_CIRCUIT; + } + } + } + return info.isLeaf ? STOP_RECURSION : _order; +} + DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } @@ -1119,6 +1180,10 @@ SpannerRenderer* Spanner::getRenderer() { return _renderer; } +bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + return _bounds.findRayIntersection(origin, direction, distance); +} + QByteArray Spanner::getRendererClassName() const { return "SpannerRendererer"; } @@ -1212,6 +1277,10 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const { return true; } +bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance); +} + QByteArray Sphere::getRendererClassName() const { return "SphereRenderer"; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 5b149c071f..921dccff13 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -191,7 +191,7 @@ public: glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; } }; -/// Interface for visitors to metavoxels. +/// Base class for visitors to metavoxels. class MetavoxelVisitor { public: @@ -241,9 +241,7 @@ protected: MetavoxelLOD _lod; }; -typedef QSharedPointer MetavoxelVisitorPointer; - -/// Interface for visitors to spanners. +/// Base class for visitors to spanners. class SpannerVisitor : public MetavoxelVisitor { public: @@ -264,6 +262,49 @@ protected: int _spannerInputCount; }; +/// Base class for ray intersection visitors. +class RayIntersectionVisitor : public MetavoxelVisitor { +public: + + RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, + const QVector& inputs, + const QVector& outputs = QVector(), + const MetavoxelLOD& lod = MetavoxelLOD()); + + /// Visits a metavoxel that the ray intersects. + virtual int visit(MetavoxelInfo& info, float distance) = 0; + + virtual int visit(MetavoxelInfo& info); + +protected: + + glm::vec3 _origin; + glm::vec3 _direction; + int _order; +}; + +/// Base class for ray intersection spanner visitors. +class RayIntersectionSpannerVisitor : public RayIntersectionVisitor { +public: + + RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction, + const QVector& spannerInputs, + const QVector& inputs = QVector(), + const QVector& outputs = QVector(), + const MetavoxelLOD& lod = MetavoxelLOD()); + + /// Visits a spanner that the ray intersects. + /// \return true to continue, false to short-circuit the tour + virtual bool visit(Spanner* spanner, float distance) = 0; + + virtual void prepare(); + virtual int visit(MetavoxelInfo& info, float distance); + +protected: + + int _spannerInputCount; +}; + /// Interface for objects that guide metavoxel visitors. class MetavoxelGuide : public SharedObject { Q_OBJECT @@ -389,6 +430,9 @@ public: /// Returns a pointer to the renderer, creating it if necessary. SpannerRenderer* getRenderer(); + /// Finds the intersection between the described ray and this spanner. + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; + signals: void boundsWillChange(); @@ -469,7 +513,8 @@ public: virtual const QVector& getAttributes() const; virtual bool getAttributeValues(MetavoxelInfo& info) const; - + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; + signals: void colorChanged(const QColor& color); diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 9e96b43d3f..7993b3bcb6 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -150,6 +150,12 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) : minimum(minimum), maximum(maximum) { } +bool Box::contains(const glm::vec3& point) const { + return point.x >= minimum.x && point.x <= maximum.x && + point.y >= minimum.y && point.y <= maximum.y && + point.z >= minimum.z && point.z <= maximum.z; +} + bool Box::contains(const Box& other) const { return other.minimum.x >= minimum.x && other.maximum.x <= maximum.x && other.minimum.y >= minimum.y && other.maximum.y <= maximum.y && @@ -173,6 +179,52 @@ glm::vec3 Box::getVertex(int index) const { (index & Z_MAXIMUM_FLAG) ? maximum.z : minimum.z); } +// finds the intersection between a ray and the facing plane on one axis +static bool findIntersection(float origin, float direction, float minimum, float maximum, float& distance) { + if (direction > EPSILON) { + distance = (minimum - origin) / direction; + return true; + } else if (direction < -EPSILON) { + distance = (maximum - origin) / direction; + return true; + } + return false; +} + +// determines whether a value is within the extents +static bool isWithin(float value, float minimum, float maximum) { + return value >= minimum && value <= maximum; +} + +bool Box::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + // handle the trivial case where the box contains the origin + if (contains(origin)) { + distance = 0.0f; + return true; + } + // check each axis + float axisDistance; + if ((findIntersection(origin.x, direction.x, minimum.x, maximum.x, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) && + isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) { + distance = axisDistance; + return true; + } + if ((findIntersection(origin.y, direction.y, minimum.y, maximum.y, axisDistance) && axisDistance >= 0 && + isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x) && + isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) { + distance = axisDistance; + return true; + } + if ((findIntersection(origin.z, direction.z, minimum.z, maximum.z, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) && + isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x))) { + distance = axisDistance; + return true; + } + return false; +} + Box operator*(const glm::mat4& matrix, const Box& box) { // start with the constant component Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2])); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 45a9476e4d..3f450212b1 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -41,6 +41,8 @@ public: Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); + bool contains(const glm::vec3& point) const; + bool contains(const Box& other) const; bool intersects(const Box& other) const; @@ -50,6 +52,8 @@ public: glm::vec3 getVertex(int index) const; glm::vec3 getCenter() const { return (minimum + maximum) * 0.5f; } + + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; }; DECLARE_STREAMABLE_METATYPE(Box) From 9e5aae4a39ada274342626bbeedc6171080b32ca Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Mar 2014 17:01:27 -0700 Subject: [PATCH 16/31] Remove spanner bits. --- .../src/metavoxels/MetavoxelServer.cpp | 2 +- interface/src/MetavoxelSystem.cpp | 29 ++++++++++- interface/src/MetavoxelSystem.h | 5 ++ interface/src/ui/MetavoxelEditor.cpp | 13 ++++- libraries/metavoxels/src/Bitstream.cpp | 10 +++- libraries/metavoxels/src/Bitstream.h | 9 ++-- libraries/metavoxels/src/DatagramSequencer.h | 3 ++ libraries/metavoxels/src/MetavoxelData.cpp | 48 +++++++++++++++++-- libraries/metavoxels/src/MetavoxelData.h | 8 +++- .../metavoxels/src/MetavoxelMessages.cpp | 22 +++++---- libraries/metavoxels/src/MetavoxelMessages.h | 16 +++---- libraries/metavoxels/src/SharedObject.cpp | 19 +++++++- libraries/metavoxels/src/SharedObject.h | 22 ++++++++- 13 files changed, 175 insertions(+), 31 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index ed48340a93..98c91d44e7 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -25,7 +25,7 @@ MetavoxelServer::MetavoxelServer(const QByteArray& packet) : } void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) { - edit.apply(_data); + edit.apply(_data, SharedObject::getWeakHash()); } const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server"; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 047422d3dd..da73bfb371 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -44,6 +44,31 @@ void MetavoxelSystem::init() { connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&))); } +SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection( + const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance) { + SharedObjectPointer closestSpanner; + float closestDistance = FLT_MAX; + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::MetavoxelServer) { + QMutexLocker locker(&node->getMutex()); + MetavoxelClient* client = static_cast(node->getLinkedData()); + if (client) { + float clientDistance; + SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection( + origin, direction, attribute, clientDistance); + if (clientSpanner && clientDistance < closestDistance) { + closestSpanner = clientSpanner; + closestDistance = clientDistance; + } + } + } + } + if (closestSpanner) { + distance = closestDistance; + } + return closestSpanner; +} + void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) { foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { @@ -215,7 +240,7 @@ void MetavoxelClient::guide(MetavoxelVisitor& visitor) { void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { // apply immediately to local tree - edit.apply(_data); + edit.apply(_data, _sequencer.getWeakSharedObjectHash()); // start sending it out _sequencer.sendHighPriorityMessage(QVariant::fromValue(edit)); @@ -255,7 +280,7 @@ void MetavoxelClient::readPacket(Bitstream& in) { // reapply local edits foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) { if (message.data.userType() == MetavoxelEditMessage::Type) { - message.data.value().apply(_data); + message.data.value().apply(_data, _sequencer.getWeakSharedObjectHash()); } } } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index c1833832a7..c605205244 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -35,6 +35,9 @@ public: void init(); + SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, + const AttributePointer& attribute, float& distance); + void applyEdit(const MetavoxelEditMessage& edit); void simulate(float deltaTime); @@ -91,6 +94,8 @@ public: MetavoxelClient(const SharedNodePointer& node); virtual ~MetavoxelClient(); + MetavoxelData& getData() { return _data; } + void guide(MetavoxelVisitor& visitor); void applyEdit(const MetavoxelEditMessage& edit); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index cf3f726c70..9d88a571b8 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -607,8 +607,19 @@ bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const { } bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) { + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); + if (!attribute) { + return false; + } if (event->type() == QEvent::MouseButtonPress) { - + float distance; + SharedObjectPointer spanner = Application::getInstance()->getMetavoxels()->findFirstRaySpannerIntersection( + Application::getInstance()->getMouseRayOrigin(), Application::getInstance()->getMouseRayDirection(), + attribute, distance); + if (spanner) { + MetavoxelEditMessage message = { QVariant::fromValue(RemoveSpannerEdit(attribute, spanner->getRemoteID())) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); + } return true; } return false; diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 03a34b100e..0af44eaae6 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -201,6 +201,13 @@ void Bitstream::persistAndResetReadMappings() { persistReadMappings(getAndResetReadMappings()); } +void Bitstream::clearSharedObject(int id) { + SharedObjectPointer object = _sharedObjectStreamer.takePersistentValue(id); + if (object) { + _weakSharedObjectHash.remove(object->getRemoteID()); + } +} + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); @@ -487,7 +494,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { object = SharedObjectPointer(); return *this; } - QPointer& pointer = _transientSharedObjects[id]; + QPointer& pointer = _weakSharedObjectHash[id]; if (pointer) { const QMetaObject* metaObject; _metaObjectStreamer >> metaObject; @@ -500,6 +507,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { QObject* rawObject; *this >> rawObject; pointer = static_cast(rawObject); + pointer->setRemoteID(id); } object = static_cast(pointer.data()); return *this; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index ac77d2317a..297d265d97 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -71,7 +71,7 @@ public: int takePersistentID(P value) { return _persistentIDs.take(value); } - void removePersistentValue(int id) { _persistentIDs.remove(_persistentValues.take(id)); } + T takePersistentValue(int id) { T value = _persistentValues.take(id); _persistentIDs.remove(value); return value; } RepeatedValueStreamer& operator<<(T value); RepeatedValueStreamer& operator>>(T& value); @@ -242,8 +242,11 @@ public: /// Immediately persists and resets the read mappings. void persistAndResetReadMappings(); + /// Returns a reference to the weak hash storing shared objects for this stream. + const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _weakSharedObjectHash; } + /// Removes a shared object from the read mappings. - void clearSharedObject(int id) { _sharedObjectStreamer.removePersistentValue(id); } + void clearSharedObject(int id); Bitstream& operator<<(bool value); Bitstream& operator>>(bool& value); @@ -339,7 +342,7 @@ private: RepeatedValueStreamer _scriptStringStreamer; RepeatedValueStreamer _sharedObjectStreamer; - QHash > _transientSharedObjects; + WeakSharedObjectHash _weakSharedObjectHash; static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 13bdf4c7bf..30a131390d 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -34,6 +34,9 @@ public: DatagramSequencer(const QByteArray& datagramHeader = QByteArray(), QObject* parent = NULL); + /// Returns a reference to the weak hash mapping remote ids to shared objects. + const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _inputStream.getWeakSharedObjectHash(); } + /// Returns the packet number of the last packet sent. int getOutgoingPacketNumber() const { return _outgoingPacketNumber; } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 0afb334aca..047faf5e71 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -218,6 +218,48 @@ void MetavoxelData::clear(const AttributePointer& attribute) { } } +class FirstRaySpannerIntersectionVisitor : public RaySpannerIntersectionVisitor { +public: + + FirstRaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, + const AttributePointer& attribute, const MetavoxelLOD& lod); + + Spanner* getSpanner() const { return _spanner; } + float getDistance() const { return _distance; } + + virtual bool visit(Spanner* spanner, float distance); + +private: + + Spanner* _spanner; + float _distance; +}; + +FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor( + const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) : + RaySpannerIntersectionVisitor(origin, direction, QVector() << attribute, + QVector(), QVector(), lod), + _spanner(NULL) { +} + +bool FirstRaySpannerIntersectionVisitor::visit(Spanner* spanner, float distance) { + _spanner = spanner; + _distance = distance; + return false; +} + +SharedObjectPointer MetavoxelData::findFirstRaySpannerIntersection( + const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, + float& distance, const MetavoxelLOD& lod) { + FirstRaySpannerIntersectionVisitor visitor(origin, direction, attribute, lod); + guide(visitor); + if (!visitor.getSpanner()) { + return SharedObjectPointer(); + } + distance = visitor.getDistance(); + return SharedObjectPointer(visitor.getSpanner()); +} + const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; @@ -839,14 +881,14 @@ int RayIntersectionVisitor::visit(MetavoxelInfo& info) { return visit(info, distance); } -RayIntersectionSpannerVisitor::RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction, +RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const QVector& spannerInputs, const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod), _spannerInputCount(spannerInputs.size()) { } -void RayIntersectionSpannerVisitor::prepare() { +void RaySpannerIntersectionVisitor::prepare() { Spanner::incrementVisit(); } @@ -860,7 +902,7 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) { return first.distance < second.distance; } -int RayIntersectionSpannerVisitor::visit(MetavoxelInfo& info, float distance) { +int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { QVarLengthArray spannerDistances; for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 921dccff13..80ff431172 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -81,6 +81,10 @@ public: void clear(const AttributePointer& attribute); + /// Convenience function that finds the first spanner intersecting the provided ray. + SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, + const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD()); + /// Expands the tree, increasing its capacity in all dimensions. void expand(); @@ -284,10 +288,10 @@ protected: }; /// Base class for ray intersection spanner visitors. -class RayIntersectionSpannerVisitor : public RayIntersectionVisitor { +class RaySpannerIntersectionVisitor : public RayIntersectionVisitor { public: - RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction, + RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const QVector& spannerInputs, const QVector& inputs = QVector(), const QVector& outputs = QVector(), diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 1c36f7df46..ca37746780 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -8,8 +8,8 @@ #include "MetavoxelMessages.h" -void MetavoxelEditMessage::apply(MetavoxelData& data) const { - static_cast(edit.data())->apply(data); +void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + static_cast(edit.data())->apply(data, objects); } MetavoxelEdit::~MetavoxelEdit() { @@ -58,7 +58,7 @@ int BoxSetEditVisitor::visit(MetavoxelInfo& info) { return DEFAULT_ORDER; // subdivide } -void BoxSetEdit::apply(MetavoxelData& data) const { +void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { // expand to fit the entire edit while (!data.getBounds().contains(region)) { data.expand(); @@ -94,7 +94,7 @@ int GlobalSetEditVisitor::visit(MetavoxelInfo& info) { return STOP_RECURSION; // entirely contained } -void GlobalSetEdit::apply(MetavoxelData& data) const { +void GlobalSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { GlobalSetEditVisitor visitor(*this); data.guide(visitor); } @@ -104,7 +104,7 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh spanner(spanner) { } -void InsertSpannerEdit::apply(MetavoxelData& data) const { +void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { data.insert(attribute, spanner); } @@ -113,14 +113,20 @@ RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) id(id) { } -void RemoveSpannerEdit::apply(MetavoxelData& data) const { +void RemoveSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + SharedObject* object = objects.value(id); + if (!object) { + qDebug() << "Missing object to remove" << id; + return; + } + data.remove(attribute, object); } ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) : attribute(attribute) { } -void ClearSpannersEdit::apply(MetavoxelData& data) const { +void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { data.clear(attribute); } @@ -149,7 +155,7 @@ SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) : spanner(spanner) { } -void SetSpannerEdit::apply(MetavoxelData& data) const { +void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { Spanner* spanner = static_cast(this->spanner.data()); // expand to fit the entire spanner diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index fe229cc727..25db8e5464 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -66,7 +66,7 @@ public: STREAM QVariant edit; - void apply(MetavoxelData& data) const; + void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage) @@ -77,7 +77,7 @@ public: virtual ~MetavoxelEdit(); - virtual void apply(MetavoxelData& data) const = 0; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const = 0; }; /// An edit that sets the region within a box to a value. @@ -93,7 +93,7 @@ public: BoxSetEdit(const Box& region = Box(), float granularity = 0.0f, const OwnedAttributeValue& value = OwnedAttributeValue()); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(BoxSetEdit) @@ -108,7 +108,7 @@ public: GlobalSetEdit(const OwnedAttributeValue& value = OwnedAttributeValue()); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(GlobalSetEdit) @@ -125,7 +125,7 @@ public: InsertSpannerEdit(const AttributePointer& attribute = AttributePointer(), const SharedObjectPointer& spanner = SharedObjectPointer()); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(InsertSpannerEdit) @@ -141,7 +141,7 @@ public: RemoveSpannerEdit(const AttributePointer& attribute = AttributePointer(), int id = 0); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(RemoveSpannerEdit) @@ -156,7 +156,7 @@ public: ClearSpannersEdit(const AttributePointer& attribute = AttributePointer()); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit) @@ -171,7 +171,7 @@ public: SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer()); - virtual void apply(MetavoxelData& data) const; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; DECLARE_STREAMABLE_METATYPE(SetSpannerEdit) diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index b4c83231ab..e95958ac76 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,7 +18,12 @@ REGISTER_META_OBJECT(SharedObject) -SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { +SharedObject::SharedObject() : + _id(++_lastID), + _remoteID(0), + _referenceCount(0) { + + _weakHash.insert(_id, this); } void SharedObject::incrementReferenceCount() { @@ -27,6 +32,7 @@ void SharedObject::incrementReferenceCount() { void SharedObject::decrementReferenceCount() { if (--_referenceCount == 0) { + _weakHash.remove(_id); delete this; } } @@ -86,6 +92,17 @@ void SharedObject::dump(QDebug debug) const { } int SharedObject::_lastID = 0; +WeakSharedObjectHash SharedObject::_weakHash; + +void pruneWeakSharedObjectHash(WeakSharedObjectHash& hash) { + for (WeakSharedObjectHash::iterator it = hash.begin(); it != hash.end(); ) { + if (!it.value()) { + it = hash.erase(it); + } else { + it++; + } + } +} SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nullable, QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 344a77cc94..66e6474972 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -9,23 +9,38 @@ #ifndef __interface__SharedObject__ #define __interface__SharedObject__ +#include #include #include +#include #include #include #include class QComboBox; +class SharedObject; + +typedef QHash > WeakSharedObjectHash; + /// A QObject that may be shared over the network. class SharedObject : public QObject { Q_OBJECT public: + /// Returns the weak hash under which all local shared objects are registered. + static const WeakSharedObjectHash& getWeakHash() { return _weakHash; } + Q_INVOKABLE SharedObject(); - int getID() { return _id; } + /// Returns the unique local ID for this object. + int getID() const { return _id; } + + /// Returns the unique remote ID for this object, or zero if this is a local object. + int getRemoteID() const { return _remoteID; } + + void setRemoteID(int remoteID) { _remoteID = remoteID; } int getReferenceCount() const { return _referenceCount; } void incrementReferenceCount(); @@ -43,11 +58,16 @@ public: private: int _id; + int _remoteID; int _referenceCount; static int _lastID; + static WeakSharedObjectHash _weakHash; }; +/// Removes the null references from the supplied hash. +void pruneWeakSharedObjectHash(WeakSharedObjectHash& hash); + /// A pointer to a shared object. template class SharedObjectPointerTemplate { public: From ae6a59ef78481dbb89db4fbb324fd4703f0614f6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Mar 2014 17:53:20 -0700 Subject: [PATCH 17/31] Ray intersections for models, don't load resources if there's no network manager installed. --- interface/src/MetavoxelSystem.cpp | 4 ++++ interface/src/MetavoxelSystem.h | 1 + libraries/metavoxels/src/MetavoxelData.cpp | 14 ++++++++++++-- libraries/metavoxels/src/MetavoxelData.h | 6 +++++- libraries/shared/src/ResourceCache.cpp | 2 +- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index da73bfb371..54cc3b4cdb 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -360,6 +360,10 @@ void StaticModelRenderer::render(float alpha) { _model->render(alpha); } +bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + return _model->findRayIntersection(origin, direction, distance); +} + void StaticModelRenderer::applyTranslation(const glm::vec3& translation) { _model->setTranslation(translation); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index c605205244..2af3262d15 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -163,6 +163,7 @@ public: virtual void init(Spanner* spanner); virtual void simulate(float deltaTime); virtual void render(float alpha); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; private slots: diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 047faf5e71..d64cbc7d94 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1177,9 +1177,9 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { const float DEFAULT_GRANULARITY = 0.01f; Spanner::Spanner() : + _renderer(NULL), _granularity(DEFAULT_GRANULARITY), - _lastVisit(0), - _renderer(NULL) { + _lastVisit(0) { } void Spanner::setBounds(const Box& bounds) { @@ -1247,6 +1247,10 @@ void SpannerRenderer::render(float alpha) { // nothing by default } +bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + return false; +} + Transformable::Transformable() : _scale(1.0f) { } @@ -1359,6 +1363,12 @@ void StaticModel::setURL(const QUrl& url) { } } +bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { + // delegate to renderer, if we have one + return _renderer ? _renderer->findRayIntersection(origin, direction, distance) : + Spanner::findRayIntersection(origin, direction, distance); +} + QByteArray StaticModel::getRendererClassName() const { return "StaticModelRenderer"; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 80ff431172..c5ac570876 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -444,6 +444,8 @@ signals: protected: + SpannerRenderer* _renderer; + /// Returns the name of the class to instantiate in order to render this spanner. virtual QByteArray getRendererClassName() const; @@ -452,7 +454,6 @@ private: Box _bounds; float _granularity; int _lastVisit; ///< the identifier of the last visit - SpannerRenderer* _renderer; static int _visit; ///< the global visit counter }; @@ -468,6 +469,7 @@ public: virtual void init(Spanner* spanner); virtual void simulate(float deltaTime); virtual void render(float alpha); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; }; /// An object with a 3D transform. @@ -550,6 +552,8 @@ public: void setURL(const QUrl& url); const QUrl& getURL() const { return _url; } + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; + signals: void urlChanged(const QUrl& url); diff --git a/libraries/shared/src/ResourceCache.cpp b/libraries/shared/src/ResourceCache.cpp index a7c0302a9c..9d7aa35c31 100644 --- a/libraries/shared/src/ResourceCache.cpp +++ b/libraries/shared/src/ResourceCache.cpp @@ -81,7 +81,7 @@ Resource::Resource(const QUrl& url, bool delayLoad) : _reply(NULL), _attempts(0) { - if (!url.isValid()) { + if (!(url.isValid() && ResourceCache::getNetworkAccessManager())) { _startedLoading = _failedToLoad = true; return; } From 66e322ec55c5d6e23c8f9fa7f24781f03ee287b5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Mar 2014 12:21:58 -0700 Subject: [PATCH 18/31] Added per-attribute LOD threshold multiplier; things like spanners need different LOD thresholds than, say, voxels. --- .../metavoxels/src/AttributeRegistry.cpp | 7 ++- libraries/metavoxels/src/AttributeRegistry.h | 8 +++ libraries/metavoxels/src/MetavoxelData.cpp | 50 +++++++++++++++---- libraries/metavoxels/src/MetavoxelData.h | 13 +++-- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 8a444467de..9ec37acd80 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -28,6 +28,10 @@ AttributeRegistry::AttributeRegistry() : _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))) { + + // our baseline LOD threshold is for voxels; spanners are a different story + const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 4.0f; + _spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER); } static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) { @@ -143,7 +147,8 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const OwnedAttributeValue& o return *this; } -Attribute::Attribute(const QString& name) { +Attribute::Attribute(const QString& name) : + _lodThresholdMultiplier(1.0f) { setObjectName(name); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 3dc6aa7484..3405f90315 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -153,6 +153,7 @@ public: /// Represents a registered attribute. class Attribute : public SharedObject { Q_OBJECT + Q_PROPERTY(float lodThresholdMultiplier MEMBER _lodThresholdMultiplier) public: @@ -163,6 +164,9 @@ public: Q_INVOKABLE QString getName() const { return objectName(); } + float getLODThresholdMultiplier() const { return _lodThresholdMultiplier; } + void setLODThresholdMultiplier(float multiplier) { _lodThresholdMultiplier = multiplier; } + void* create() const { return create(getDefaultValue()); } virtual void* create(void* copy) const = 0; virtual void destroy(void* value) const = 0; @@ -197,6 +201,10 @@ public: /// Creates a widget to use to edit values of this attribute, or returns NULL if the attribute isn't editable. /// The widget should have a single "user" property that will be used to get/set the value. virtual QWidget* createEditor(QWidget* parent = NULL) const { return NULL; } + +private: + + float _lodThresholdMultiplier; }; /// A simple attribute class that stores its values inline. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index d64cbc7d94..8a6b0bc16a 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -29,15 +29,16 @@ MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) : threshold(threshold) { } -bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const { - return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold; +bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size, float multiplier) const { + return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold * multiplier; } -bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const { +bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, + const MetavoxelLOD& reference, float multiplier) const { if (position == reference.position && threshold >= reference.threshold) { return false; // first off, nothing becomes subdivided if it doesn't change } - if (!shouldSubdivide(minimum, size)) { + if (!shouldSubdivide(minimum, size, multiplier)) { return false; // this one must be subdivided } // the general check is whether we've gotten closer (as multiplied by the threshold) to any point in the volume, @@ -468,6 +469,18 @@ static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int in (index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f); } +bool MetavoxelStreamState::shouldSubdivide() const { + return lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier()); +} + +bool MetavoxelStreamState::shouldSubdivideReference() const { + return referenceLOD.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier()); +} + +bool MetavoxelStreamState::becameSubdivided() const { + return lod.becameSubdivided(minimum, size, referenceLOD, attribute->getLODThresholdMultiplier()); +} + void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } @@ -831,7 +844,16 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : _inputs(inputs), _outputs(outputs), - _lod(lod) { + _lod(lod), + _minimumLODThresholdMultiplier(FLT_MAX) { + + // find the minimum LOD threshold multiplier over all attributes + foreach (const AttributePointer& attribute, _inputs) { + _minimumLODThresholdMultiplier = qMin(attribute->getLODThresholdMultiplier(), _minimumLODThresholdMultiplier); + } + foreach (const AttributePointer& attribute, _outputs) { + _minimumLODThresholdMultiplier = qMin(attribute->getLODThresholdMultiplier(), _minimumLODThresholdMultiplier); + } } MetavoxelVisitor::~MetavoxelVisitor() { @@ -928,8 +950,11 @@ DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - bool shouldSubdivide = visitation.visitor.getLOD().shouldSubdivide(visitation.info.minimum, visitation.info.size); - visitation.info.isLeaf = !shouldSubdivide || visitation.allInputNodesLeaves(); + // save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute + float lodBase = glm::distance(visitation.visitor.getLOD().position, visitation.info.getCenter()) * + visitation.visitor.getLOD().threshold; + visitation.info.isLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier()) || + visitation.allInputNodesLeaves(); int encodedOrder = visitation.visitor.visit(visitation.info); if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { return false; @@ -955,20 +980,23 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { { glm::vec3(), visitation.info.size * 0.5f, QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()) } }; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + // the encoded order tells us the child indices for each iteration const int ORDER_ELEMENT_BITS = 3; const int ORDER_ELEMENT_MASK = (1 << ORDER_ELEMENT_BITS) - 1; int index = encodedOrder & ORDER_ELEMENT_MASK; encodedOrder >>= ORDER_ELEMENT_BITS; for (int j = 0; j < visitation.inputNodes.size(); j++) { MetavoxelNode* node = visitation.inputNodes.at(j); - MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL; + const AttributeValue& parentValue = visitation.info.inputValues.at(j); + MetavoxelNode* child = (node && (visitation.info.size >= lodBase * + parentValue.getAttribute()->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ? - child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) : - visitation.info.inputValues[j]; + child->getAttributeValue(parentValue.getAttribute()) : parentValue; } for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); - MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL; + MetavoxelNode* child = (node && (visitation.info.size >= lodBase * + visitation.visitor.getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; nextVisitation.outputNodes[j] = child; } nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index c5ac570876..7e0a863a3b 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -43,10 +43,10 @@ public: bool isValid() const { return threshold > 0.0f; } - bool shouldSubdivide(const glm::vec3& minimum, float size) const; + bool shouldSubdivide(const glm::vec3& minimum, float size, float multiplier = 1.0f) const; /// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference. - bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const; + bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference, float multiplier = 1.0f) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) @@ -119,9 +119,9 @@ public: const MetavoxelLOD& lod; const MetavoxelLOD& referenceLOD; - bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); } - bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); } - bool becameSubdivided() const { return lod.becameSubdivided(minimum, size, referenceLOD); } + bool shouldSubdivide() const; + bool shouldSubdivideReference() const; + bool becameSubdivided() const; void setMinimum(const glm::vec3& lastMinimum, int index); }; @@ -230,6 +230,8 @@ public: void setLOD(const MetavoxelLOD& lod) { _lod = lod; } + float getMinimumLODThresholdMultiplier() const { return _minimumLODThresholdMultiplier; } + /// Prepares for a new tour of the metavoxel data. virtual void prepare(); @@ -243,6 +245,7 @@ protected: QVector _inputs; QVector _outputs; MetavoxelLOD _lod; + float _minimumLODThresholdMultiplier; }; /// Base class for visitors to spanners. From 35d0fa71891c490ac6ad43e37dc4771d39027991 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Mar 2014 13:46:58 -0700 Subject: [PATCH 19/31] Don't render avatars until they've been simulated, init before first simulate. Closes #2262. --- interface/src/avatar/AvatarManager.cpp | 5 ++++- interface/src/avatar/SkeletonModel.cpp | 10 +++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 57e800a401..88ce2b4399 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -54,6 +54,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { ++avatarIterator; continue; } + if (!avatar->isInitialized()) { + avatar->init(); + } if (avatar->getOwningAvatarMixer()) { // this avatar's mixer is still around, go ahead and simulate it avatar->simulate(deltaTime); @@ -80,7 +83,7 @@ void AvatarManager::renderAvatars(bool forShadowMapOrMirror, bool selfAvatarOnly foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) { Avatar* avatar = static_cast(avatarPointer.data()); if (!avatar->isInitialized()) { - avatar->init(); + continue; } if (avatar == static_cast(_myAvatar.data())) { _myAvatar->render(forShadowMapOrMirror); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c57656be58..e1014297e8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -19,18 +19,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : } void SkeletonModel::simulate(float deltaTime, bool delayLoad) { - if (!isActive()) { - Model::simulate(deltaTime, delayLoad); - return; - } setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(180.0f, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); - + Model::simulate(deltaTime, delayLoad); - - if (!_owningAvatar->isMyAvatar()) { + + if (!(isActive() && _owningAvatar->isMyAvatar())) { return; // only simulate for own avatar } From bc3bba924041d1342e3b4bdee990e05df36866f1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Mar 2014 14:01:23 -0700 Subject: [PATCH 20/31] Get rid of unused, expensive "average color" nonsense. --- interface/src/renderer/GeometryCache.cpp | 24 ------------------------ interface/src/renderer/GeometryCache.h | 3 --- interface/src/renderer/Model.cpp | 4 ---- interface/src/renderer/Model.h | 3 --- interface/src/renderer/TextureCache.cpp | 17 ++++------------- interface/src/renderer/TextureCache.h | 6 +----- 6 files changed, 5 insertions(+), 52 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index a7973f4a1b..a13a538b0e 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -378,30 +378,6 @@ QSharedPointer NetworkGeometry::getLODOrFallback(float distance return lod; } -glm::vec4 NetworkGeometry::computeAverageColor() const { - glm::vec4 totalColor; - int totalTriangles = 0; - for (int i = 0; i < _meshes.size(); i++) { - const FBXMesh& mesh = _geometry.meshes.at(i); - if (mesh.isEye) { - continue; // skip eyes - } - const NetworkMesh& networkMesh = _meshes.at(i); - for (int j = 0; j < mesh.parts.size(); j++) { - const FBXMeshPart& part = mesh.parts.at(j); - const NetworkMeshPart& networkPart = networkMesh.parts.at(j); - glm::vec4 color = glm::vec4(part.diffuseColor, 1.0f); - if (networkPart.diffuseTexture) { - color *= networkPart.diffuseTexture->getAverageColor(); - } - int triangles = part.quadIndices.size() * 2 + part.triangleIndices.size(); - totalColor += color * (float) triangles; - totalTriangles += triangles; - } - } - return (totalTriangles == 0) ? glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) : totalColor / (float) totalTriangles; -} - void NetworkGeometry::setLoadPriority(const QPointer& owner, float priority) { Resource::setLoadPriority(owner, priority); diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index da1955039d..cc0775051a 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -79,9 +79,6 @@ public: const FBXGeometry& getFBXGeometry() const { return _geometry; } const QVector& getMeshes() const { return _meshes; } - /// Returns the average color of all meshes in the geometry. - glm::vec4 computeAverageColor() const; - virtual void setLoadPriority(const QPointer& owner, float priority); virtual void setLoadPriorities(const QHash, float>& priorities); virtual void clearLoadPriority(const QPointer& owner); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f6cfb08816..0df6ad721c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -497,10 +497,6 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo } } -glm::vec4 Model::computeAverageColor() const { - return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); -} - bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { const glm::vec3 relativeOrigin = origin - _translation; const FBXGeometry& geometry = _geometry->getFBXGeometry(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 763c30ad39..c7aadee8dc 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -175,9 +175,6 @@ public: /// Returns the extended length from the right hand to its first free ancestor. float getRightArmLength() const; - /// Returns the average color of all meshes in the geometry. - glm::vec4 computeAverageColor() const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; /// \param shapes list of pointers shapes to test against Model diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 80eef66ff5..db019eca95 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -257,7 +257,6 @@ Texture::~Texture() { NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) : Resource(url), - _averageColor(1.0f, 1.0f, 1.0f, 1.0f), _translucent(false) { if (!url.isValid()) { @@ -300,27 +299,20 @@ void ImageReader::run() { image = image.convertToFormat(QImage::Format_ARGB32); } - // sum up the colors for the average and check for translucency - glm::vec4 accumulated; + // check for translucency int translucentPixels = 0; const int EIGHT_BIT_MAXIMUM = 255; + const int RGB_BITS = 24; for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { - QRgb pixel = image.pixel(x, y); - accumulated.r += qRed(pixel); - accumulated.g += qGreen(pixel); - accumulated.b += qBlue(pixel); - - int alpha = qAlpha(pixel); + int alpha = image.pixel(x, y) >> RGB_BITS; if (alpha != 0 && alpha != EIGHT_BIT_MAXIMUM) { translucentPixels++; } - accumulated.a += alpha; } } int imageArea = image.width() * image.height(); QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), - Q_ARG(const glm::vec4&, accumulated / (float) (imageArea * EIGHT_BIT_MAXIMUM)), Q_ARG(bool, translucentPixels >= imageArea / 2)); _reply->deleteLater(); } @@ -330,8 +322,7 @@ void NetworkTexture::downloadFinished(QNetworkReply* reply) { QThreadPool::globalInstance()->start(new ImageReader(_self, reply)); } -void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) { - _averageColor = averageColor; +void NetworkTexture::setImage(const QImage& image, bool translucent) { _translucent = translucent; finishedLoading(true); diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 0111a2826d..d7e61954ce 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -119,9 +119,6 @@ public: NetworkTexture(const QUrl& url, bool normalMap); - /// Returns the average color over the entire texture. - const glm::vec4& getAverageColor() const { return _averageColor; } - /// Checks whether it "looks like" this texture is translucent /// (majority of pixels neither fully opaque or fully transparent). bool isTranslucent() const { return _translucent; } @@ -131,11 +128,10 @@ protected: virtual void downloadFinished(QNetworkReply* reply); virtual void imageLoaded(const QImage& image); - Q_INVOKABLE void setImage(const QImage& image, const glm::vec4& averageColor, bool translucent); + Q_INVOKABLE void setImage(const QImage& image, bool translucent); private: - glm::vec4 _averageColor; bool _translucent; }; From f8e6593bcf7b320cc23cbbc54f7f993019207a41 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Mar 2014 15:24:14 -0700 Subject: [PATCH 21/31] Turn off mipmaps. Performance is actually substantially better without them. --- interface/src/renderer/TextureCache.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index db019eca95..91cf1c8b6e 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -113,8 +113,7 @@ GLuint TextureCache::getFileTextureID(const QString& filename) { glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); _fileTextureIDs.insert(filename, id); @@ -330,8 +329,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent) { glBindTexture(GL_TEXTURE_2D, getID()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } @@ -364,8 +362,7 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio glBindTexture(GL_TEXTURE_2D, texture->getID()); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1, GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits()); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } From bf9929e64d30840e5b013ce0a271ef243cda09af Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Mar 2014 17:16:49 -0700 Subject: [PATCH 22/31] Since the bucky balls are showing up in the hot spots list when profiling, don't simulate them if they're disabled. --- interface/src/Application.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 032e849f0a..bff223e5e3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1241,8 +1241,10 @@ void Application::idle() { _idleLoopStdev.reset(); } - _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData()); - + if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { + _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData()); + } + // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. idleTimer->start(2); } From aa8c2fc8cb0ed10348dd1cfecd95b7dcd1dc2d74 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Mar 2014 17:26:58 -0700 Subject: [PATCH 23/31] use radians instead of degrees (almost) everywhere --- CMakeLists.txt | 1 + animation-server/src/AnimationServer.cpp | 20 +-- assignment-client/src/audio/AudioMixer.cpp | 4 +- interface/src/Application.cpp | 120 +++++++++--------- interface/src/Application.h | 4 +- interface/src/Audio.cpp | 3 +- interface/src/Camera.cpp | 2 +- interface/src/Camera.h | 2 +- interface/src/Environment.cpp | 4 +- interface/src/Menu.cpp | 4 +- interface/src/MetavoxelSystem.h | 2 +- interface/src/Stars.cpp | 3 +- interface/src/Util.cpp | 48 +++---- interface/src/Util.h | 4 +- interface/src/avatar/Avatar.cpp | 30 ++--- interface/src/avatar/FaceModel.cpp | 9 +- interface/src/avatar/Head.cpp | 6 +- interface/src/avatar/MyAvatar.cpp | 79 ++++++------ interface/src/avatar/MyAvatar.h | 10 +- interface/src/avatar/SkeletonModel.cpp | 7 +- interface/src/devices/Faceshift.cpp | 4 +- interface/src/devices/Faceshift.h | 5 +- interface/src/devices/OculusManager.cpp | 9 +- interface/src/devices/OculusManager.h | 3 + interface/src/devices/SixenseManager.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 4 +- interface/src/renderer/FBXReader.cpp | 21 +-- interface/src/renderer/FBXReader.h | 4 +- interface/src/renderer/GeometryCache.cpp | 6 +- interface/src/renderer/Model.cpp | 12 +- interface/src/starfield/Generator.cpp | 3 +- interface/src/starfield/renderer/Renderer.cpp | 2 +- interface/src/ui/MetavoxelEditor.cpp | 6 +- interface/src/world.h | 4 - libraries/audio/src/Sound.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 8 +- libraries/avatars/src/AvatarData.h | 10 +- libraries/avatars/src/HeadData.cpp | 7 +- libraries/avatars/src/HeadData.h | 24 ++-- libraries/metavoxels/src/MetavoxelData.h | 2 +- libraries/octree/src/ViewFrustum.cpp | 6 +- libraries/octree/src/ViewFrustum.h | 2 +- libraries/script-engine/src/EventTypes.cpp | 5 +- libraries/script-engine/src/EventTypes.h | 2 + libraries/script-engine/src/Quat.cpp | 8 +- libraries/script-engine/src/Quat.h | 6 +- libraries/shared/src/SharedUtil.cpp | 46 +++---- libraries/shared/src/SharedUtil.h | 19 +-- tests/physics/src/CollisionInfoTests.cpp | 4 +- tests/physics/src/PhysicsTestUtil.h | 2 - tests/physics/src/ShapeColliderTests.cpp | 8 +- 51 files changed, 302 insertions(+), 306 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33589ddb57..4674df40de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ if (WIN32) endif (WIN32) project(hifi) +add_definitions(-DGLM_FORCE_RADIANS) if (WIN32) add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp index a013eaaf5c..410ce22f33 100644 --- a/animation-server/src/AnimationServer.cpp +++ b/animation-server/src/AnimationServer.cpp @@ -78,9 +78,9 @@ glm::vec3 bugDirection = glm::vec3(0, 0, 1); const int VOXELS_PER_BUG = 18; glm::vec3 bugPathCenter = glm::vec3(0.25f,0.15f,0.25f); // glm::vec3(BUG_VOXEL_SIZE * 150.0, BUG_VOXEL_SIZE * 30.0, BUG_VOXEL_SIZE * 150.0); float bugPathRadius = 0.2f; //BUG_VOXEL_SIZE * 140.0; -float bugPathTheta = 0.0 * PI_OVER_180; -float bugRotation = 0.0 * PI_OVER_180; -float bugAngleDelta = 0.2 * PI_OVER_180; +float bugPathTheta = 0.0f * RADIANS_PER_DEGREE; +float bugRotation = 0.0f * RADIANS_PER_DEGREE; +float bugAngleDelta = 0.2f * RADIANS_PER_DEGREE; bool moveBugInLine = false; class BugPart { @@ -160,11 +160,11 @@ static void renderMovingBug() { bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE); // Check boundaries - if (bugPosition.z > 1.0) { - bugDirection.z = -1; + if (bugPosition.z > 1.0f) { + bugDirection.z = -1.f; } if (bugPosition.z < BUG_VOXEL_SIZE) { - bugDirection.z = 1; + bugDirection.z = 1.f; } } else { @@ -174,9 +174,9 @@ static void renderMovingBug() { bugRotation -= bugAngleDelta; // rotate slightly // If we loop past end of circle, just reset back into normal range - if (bugPathTheta > (360.0f * PI_OVER_180)) { - bugPathTheta = 0; - bugRotation = 0; + if (bugPathTheta > TWO_PI) { + bugPathTheta = 0.f; + bugRotation = 0.f; } float x = bugPathCenter.x + bugPathRadius * cos(bugPathTheta); @@ -225,7 +225,7 @@ static void sendVoxelBlinkMessage() { VoxelDetail detail; detail.s = BEACON_SIZE; - glm::vec3 position = glm::vec3(0, 0, detail.s); + glm::vec3 position = glm::vec3(0.f, 0.f, detail.s); detail.x = detail.s * floor(position.x / detail.s); detail.y = detail.s * floor(position.y / detail.s); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 900de817fa..812acc8d70 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -114,7 +114,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO)); // multiply the current attenuation coefficient by the calculated off axis coefficient attenuationCoefficient *= offAxisCoefficient; @@ -148,7 +148,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf // figure out the number of samples of delay and the ratio of the amplitude // in the weak channel for audio spatialization - float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 28285cd7da..b88dee244e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -507,7 +507,7 @@ void Application::paintGL() { float headHeight = _myAvatar->getHead()->calculateAverageEyePosition().y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale()); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); } // Update camera position @@ -744,7 +744,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (!_myAvatar->getDriveKeys(UP)) { _myAvatar->jump(); } - _myAvatar->setDriveKeys(UP, 1); + _myAvatar->setDriveKeys(UP, 1.f); break; case Qt::Key_Asterisk: @@ -752,11 +752,11 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_C: - _myAvatar->setDriveKeys(DOWN, 1); + _myAvatar->setDriveKeys(DOWN, 1.f); break; case Qt::Key_W: - _myAvatar->setDriveKeys(FWD, 1); + _myAvatar->setDriveKeys(FWD, 1.f); break; case Qt::Key_S: @@ -765,7 +765,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } else if (!isShifted && isMeta) { takeSnapshot(); } else { - _myAvatar->setDriveKeys(BACK, 1); + _myAvatar->setDriveKeys(BACK, 1.f); } break; @@ -783,12 +783,12 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); } else { - _myAvatar->setDriveKeys(ROT_LEFT, 1); + _myAvatar->setDriveKeys(ROT_LEFT, 1.f); } break; case Qt::Key_D: - _myAvatar->setDriveKeys(ROT_RIGHT, 1); + _myAvatar->setDriveKeys(ROT_RIGHT, 1.f); break; case Qt::Key_Return: @@ -800,19 +800,19 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Up: - _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1); + _myAvatar->setDriveKeys(isShifted ? UP : FWD, 1.f); break; case Qt::Key_Down: - _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1); + _myAvatar->setDriveKeys(isShifted ? DOWN : BACK, 1.f); break; case Qt::Key_Left: - _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1); + _myAvatar->setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1.f); break; case Qt::Key_Right: - _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1); + _myAvatar->setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1.f); break; case Qt::Key_I: @@ -946,47 +946,47 @@ void Application::keyReleaseEvent(QKeyEvent* event) { switch (event->key()) { case Qt::Key_E: - _myAvatar->setDriveKeys(UP, 0); + _myAvatar->setDriveKeys(UP, 0.f); break; case Qt::Key_C: - _myAvatar->setDriveKeys(DOWN, 0); + _myAvatar->setDriveKeys(DOWN, 0.f); break; case Qt::Key_W: - _myAvatar->setDriveKeys(FWD, 0); + _myAvatar->setDriveKeys(FWD, 0.f); break; case Qt::Key_S: - _myAvatar->setDriveKeys(BACK, 0); + _myAvatar->setDriveKeys(BACK, 0.f); break; case Qt::Key_A: - _myAvatar->setDriveKeys(ROT_LEFT, 0); + _myAvatar->setDriveKeys(ROT_LEFT, 0.f); break; case Qt::Key_D: - _myAvatar->setDriveKeys(ROT_RIGHT, 0); + _myAvatar->setDriveKeys(ROT_RIGHT, 0.f); break; case Qt::Key_Up: - _myAvatar->setDriveKeys(FWD, 0); - _myAvatar->setDriveKeys(UP, 0); + _myAvatar->setDriveKeys(FWD, 0.f); + _myAvatar->setDriveKeys(UP, 0.f); break; case Qt::Key_Down: - _myAvatar->setDriveKeys(BACK, 0); - _myAvatar->setDriveKeys(DOWN, 0); + _myAvatar->setDriveKeys(BACK, 0.f); + _myAvatar->setDriveKeys(DOWN, 0.f); break; case Qt::Key_Left: - _myAvatar->setDriveKeys(LEFT, 0); - _myAvatar->setDriveKeys(ROT_LEFT, 0); + _myAvatar->setDriveKeys(LEFT, 0.f); + _myAvatar->setDriveKeys(ROT_LEFT, 0.f); break; case Qt::Key_Right: - _myAvatar->setDriveKeys(RIGHT, 0); - _myAvatar->setDriveKeys(ROT_RIGHT, 0); + _myAvatar->setDriveKeys(RIGHT, 0.f); + _myAvatar->setDriveKeys(ROT_RIGHT, 0.f); break; default: @@ -1488,7 +1488,7 @@ void Application::init() { 3.0f * TREE_SCALE / 2.0f)); _sharedVoxelSystemViewFrustum.setNearClip(TREE_SCALE / 2.0f); _sharedVoxelSystemViewFrustum.setFarClip(3.0f * TREE_SCALE / 2.0f); - _sharedVoxelSystemViewFrustum.setFieldOfView(90); + _sharedVoxelSystemViewFrustum.setFieldOfView(90.f); _sharedVoxelSystemViewFrustum.setOrientation(glm::quat()); _sharedVoxelSystemViewFrustum.calculate(); _sharedVoxelSystem.setViewFrustum(&_sharedVoxelSystemViewFrustum); @@ -2120,7 +2120,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // We will use these below, from either the camera or head vectors calculated above glm::vec3 position(camera.getPosition()); - float fov = camera.getFieldOfView(); + float fov = camera.getFieldOfView(); // degrees float nearClip = camera.getNearClip(); float farClip = camera.getFarClip(); float aspectRatio = camera.getAspectRatio(); @@ -2133,7 +2133,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // Also make sure it's got the correct lens details from the camera viewFrustum.setAspectRatio(aspectRatio); - viewFrustum.setFieldOfView(fov); + viewFrustum.setFieldOfView(fov); // degrees viewFrustum.setNearClip(nearClip); viewFrustum.setFarClip(farClip); viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition()); @@ -2195,7 +2195,7 @@ void Application::updateShadowMap() { glPushMatrix(); glLoadIdentity(); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // store view matrix without translation, which we'll use for precision-sensitive objects glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); @@ -2274,7 +2274,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); - glRotatef(-glm::angle(eyeOffsetOrient), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); + glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); // transform view according to whichCamera @@ -2283,7 +2283,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); - glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // store view matrix without translation, which we'll use for precision-sensitive objects glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); @@ -2501,7 +2501,7 @@ void Application::displayOverlay() { (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) ? 80 : 20; - drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0, frameTimer, WHITE_TEXT); + drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT); } _overlays.render2D(); @@ -2556,11 +2556,11 @@ void Application::displayStats() { sprintf(framesPerSecond, "Framerate: %3.0f FPS", _fps); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, serverNodes, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, serverNodes, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarNodes, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, framesPerSecond, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, WHITE_TEXT); if (_statsExpanded) { char packetsPerSecond[30]; @@ -2569,9 +2569,9 @@ void Application::displayStats() { sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, packetsPerSecond, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecond, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, averageMegabitsPerSecond, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, WHITE_TEXT); } verticalOffset = 0; @@ -2614,7 +2614,7 @@ void Application::displayStats() { "Buffer msecs %.1f", (float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) / (float)_audio.getNetworkSampleRate() * 1000.f); - drawText(30, _glWidget->height() - 22, 0.10f, 0, 2, audioJitter, WHITE_TEXT); + drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT); char audioPing[30]; @@ -2627,18 +2627,18 @@ void Application::displayStats() { sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, audioPing, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, audioPing, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarPing, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, voxelAvgPing, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, WHITE_TEXT); if (_statsExpanded) { char voxelMaxPing[30]; sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, voxelMaxPing, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, WHITE_TEXT); } verticalOffset = 0; @@ -2666,11 +2666,11 @@ void Application::displayStats() { char avatarMixerStats[200]; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarPosition, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarVelocity, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, WHITE_TEXT); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarBodyYaw, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, WHITE_TEXT); if (_statsExpanded) { SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer); @@ -2683,7 +2683,7 @@ void Application::displayStats() { } verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, avatarMixerStats, WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT); } verticalOffset = 0; @@ -2698,7 +2698,7 @@ void Application::displayStats() { voxelStats.str(""); voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB"; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); voxelStats.str(""); voxelStats << @@ -2708,14 +2708,14 @@ void Application::displayStats() { voxelStats << " / GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB"; } verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); // Voxel Rendering voxelStats.str(""); voxelStats.precision(4); voxelStats << "Voxel Rendering Slots Max: " << _voxels.getMaxVoxels() / 1000.f << "K"; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); } voxelStats.str(""); @@ -2723,7 +2723,7 @@ void Application::displayStats() { voxelStats << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); // iterate all the current voxel stats, and list their sending modes, and total voxel counts std::stringstream sendingMode(""); @@ -2767,7 +2767,7 @@ void Application::displayStats() { sendingMode << " "; } verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)sendingMode.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), WHITE_TEXT); } // Incoming packets @@ -2779,7 +2779,7 @@ void Application::displayStats() { voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); } if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { @@ -2802,7 +2802,7 @@ void Application::displayStats() { voxelStats.str(""); voxelStats << "Server voxels: " << serversTotalString.toLocal8Bit().constData(); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); if (_statsExpanded) { QString serversInternalString = locale.toString((uint)totalInternal); @@ -2813,7 +2813,7 @@ void Application::displayStats() { "Internal: " << serversInternalString.toLocal8Bit().constData() << " " << "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); } unsigned long localTotal = VoxelTreeElement::getNodeCount(); @@ -2823,7 +2823,7 @@ void Application::displayStats() { voxelStats.str(""); voxelStats << "Local voxels: " << localTotalString.toLocal8Bit().constData(); verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); if (_statsExpanded) { unsigned long localInternal = VoxelTreeElement::getInternalNodeCount(); @@ -2836,7 +2836,7 @@ void Application::displayStats() { "Internal: " << localInternalString.toLocal8Bit().constData() << " " << "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT); + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT); } } @@ -2927,17 +2927,17 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { void Application::renderRearViewMirror(const QRect& region, bool billboard) { bool eyeRelativeCamera = false; if (billboard) { - _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); + _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees _mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale()); _mirrorCamera.setTargetPosition(_myAvatar->getPosition()); } else if (_rearMirrorTools->getZoomLevel() == BODY) { - _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); + _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees _mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale()); _mirrorCamera.setTargetPosition(_myAvatar->getChestPosition()); } else { // HEAD zoom level - _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); + _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees _mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale()); if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) { // as a hack until we have a better way of dealing with coordinate precision issues, reposition the @@ -2951,7 +2951,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { } _mirrorCamera.setAspectRatio((float)region.width() / region.height()); - _mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); + _mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); _mirrorCamera.update(1.0f/_fps); // set the bounds of rear mirror view diff --git a/interface/src/Application.h b/interface/src/Application.h index a93d3d1352..72631666e6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -95,8 +95,8 @@ static const float NODE_KILLED_BLUE = 0.0f; static const QString SNAPSHOT_EXTENSION = ".jpg"; -static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; -static const float BILLBOARD_DISTANCE = 5.0f; +static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees +static const float BILLBOARD_DISTANCE = 5.0f; // meters class Application : public QApplication { Q_OBJECT diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7f6f1bcb05..c666fcd242 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -656,7 +655,7 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { const float MAX_DURATION = 2.f; const float MIN_AUDIBLE_VOLUME = 0.001f; const float NOISE_MAGNITUDE = 0.02f; - float frequency = (_drumSoundFrequency / SAMPLE_RATE) * PI_TIMES_TWO; + float frequency = (_drumSoundFrequency / SAMPLE_RATE) * TWO_PI; if (_drumSoundVolume > 0.f) { for (int i = 0; i < numSamples; i++) { t = (float) _drumSoundSample + (float) i; diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 6cb44f5919..252b3be685 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -81,7 +81,7 @@ void Camera::updateFollowMode(float deltaTime) { _distance = _newDistance; _tightness = _newTightness; } else { - _modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PIE ); + _modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PI ); _upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift; _distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift; _tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift; diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 81632f4424..9973fd246e 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -89,7 +89,7 @@ private: glm::vec3 _position; glm::vec3 _idealPosition; glm::vec3 _targetPosition; - float _fieldOfView; + float _fieldOfView; // degrees float _aspectRatio; float _nearClip; float _farClip; diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index 9efaa274c0..1f9e23bee1 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -237,8 +237,8 @@ void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius()); program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness()); program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness()); - program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PIf); - program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PIf); + program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI); + program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI); program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())); program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f); program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0674826342..caeb8661b8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -699,8 +699,8 @@ void Menu::editPreferences() { form->addRow("Faceshift Eye Deflection:", faceshiftEyeDeflection); QSpinBox* fieldOfView = new QSpinBox(); - fieldOfView->setMaximum(180); - fieldOfView->setMinimum(1); + fieldOfView->setMaximum(180.f); + fieldOfView->setMinimum(1.f); fieldOfView->setValue(_fieldOfView); form->addRow("Vertical Field of View (Degrees):", fieldOfView); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 4364192009..3658c42f5b 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -139,7 +139,7 @@ public: private slots: void applyTranslation(const glm::vec3& translation); - void applyRotation(const glm::vec3& rotation); + void applyRotation(const glm::vec3& eulerAngles); // eulerAngles are in degrees void applyScale(float scale); void applyURL(const QUrl& url); diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 69340b2926..dcfe726fff 100755 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -30,9 +30,8 @@ bool Stars::setResolution(unsigned k) { } void Stars::render(float fovY, float aspect, float nearZ, float alpha) { - // determine length of screen diagonal from quadrant height and aspect ratio - float quadrantHeight = nearZ * tan(angleConvert(fovY) * 0.5f); + float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f); float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); // determine fov angle in respect to the diagonal diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 03b5bed038..45b2c4a616 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -68,19 +68,21 @@ void printVector(glm::vec3 vec) { printf("%4.2f, %4.2f, %4.2f\n", vec.x, vec.y, vec.z); } -// Return the azimuth angle in degrees between two points. +// Return the azimuth angle (in radians) between two points. float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos) { - return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf; + return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z); } -// Return the angle in degrees between the head and an object in the scene. The value is zero if you are looking right at it. The angle is negative if the object is to your right. +// Return the angle (in radians) between the head and an object in the scene. +// The value is zero if you are looking right at it. +// The angle is negative if the object is to your right. float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float head_yaw) { - return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf + render_yaw + head_yaw; + return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) + render_yaw + head_yaw; } -// Helper function returns the positive angle in degrees between two 3D vectors +// Helper function returns the positive angle (in radians) between two 3D vectors float angleBetween(const glm::vec3& v1, const glm::vec3& v2) { - return acos((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))) * 180.f / PIf; + return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))); } // Helper function return the rotation from the first vector onto the second @@ -90,7 +92,7 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { return glm::quat(); } glm::vec3 axis; - if (angle > 179.99f) { // 180 degree rotation; must use another axis + if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); float axisLength = glm::length(axis); if (axisLength < EPSILON) { // parallel to x; y will work @@ -314,7 +316,7 @@ float widthChar(float scale, int mono, char ch) { return textRenderer(mono)->computeWidth(ch) * (scale / 0.10); } -void drawText(int x, int y, float scale, float rotate, int mono, +void drawText(int x, int y, float scale, float radians, int mono, char const* string, const float* color) { // // Draws text on screen as stroked so it can be resized @@ -322,16 +324,16 @@ void drawText(int x, int y, float scale, float rotate, int mono, glPushMatrix(); glTranslatef(static_cast(x), static_cast(y), 0.0f); glColor3fv(color); - glRotated(rotate,0,0,1); - glScalef(scale / 0.10, scale / 0.10, 1.0); + glRotated(double(radians * DEGREES_PER_RADIAN), 0.0, 0.0, 1.0); + glScalef(scale / 0.1f, scale / 0.1f, 1.f); textRenderer(mono)->draw(0, 0, string); glPopMatrix(); } -void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec, float r, float g, float b) { +void drawvec3(int x, int y, float scale, float radians, float thick, int mono, glm::vec3 vec, float r, float g, float b) { // - // Draws text on screen as stroked so it can be resized + // Draws vec3 on screen as stroked so it can be resized // char vectext[20]; sprintf(vectext,"%3.1f,%3.1f,%3.1f", vec.x, vec.y, vec.z); @@ -339,10 +341,10 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPushMatrix(); glTranslatef(static_cast(x), static_cast(y), 0); glColor3f(r,g,b); - glRotated(180+rotate,0,0,1); - glRotated(180,0,1,0); + glRotated(180.0 + double(radians * DEGREES_PER_RADIAN), 0.0, 0.0, 1.0); + glRotated(180.0, 0.0, 1.0, 0.0); glLineWidth(thick); - glScalef(scale, scale, 1.0); + glScalef(scale, scale, 1.f); len = (int) strlen(vectext); for (i = 0; i < len; i++) { if (!mono) glutStrokeCharacter(GLUT_STROKE_ROMAN, int(vectext[i])); @@ -371,9 +373,9 @@ void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::ve glBegin(GL_LINE_STRIP); for (int i=0; igetCamera()->getRotation(); glm::vec3 chatAxis = glm::axis(chatRotation); - glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z); + glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z); - glColor3f(0, 0.8f, 0); - glRotatef(180, 0, 1, 0); - glRotatef(180, 0, 0, 1); + glColor3f(0.f, 0.8f, 0.f); + glRotatef(180.f, 0.f, 1.f, 0.f); + glRotatef(180.f, 0.f, 0.f, 1.f); glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f); glDisable(GL_LIGHTING); @@ -288,7 +288,7 @@ void Avatar::render(bool forShadowMap) { _chatMessage[lastIndex] = '\0'; textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str()); _chatMessage[lastIndex] = lastChar; - glColor3f(0, 1, 0); + glColor3f(0.f, 1.f, 0.f); textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex); } glEnable(GL_LIGHTING); @@ -301,12 +301,12 @@ void Avatar::render(bool forShadowMap) { glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { glm::quat orientation = getOrientation(); glm::vec3 currentUp = orientation * IDENTITY_UP; - float angle = glm::degrees(acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f))); + float angle = acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f)); if (angle < EPSILON) { return glm::quat(); } glm::vec3 axis; - if (angle > 179.99f) { // 180 degree rotation; must use another axis + if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis axis = orientation * IDENTITY_RIGHT; } else { axis = glm::normalize(glm::cross(currentUp, _worldUpDirection)); @@ -356,9 +356,9 @@ void Avatar::renderBillboard() { // rotate about vertical to face the camera glm::quat rotation = getOrientation(); glm::vec3 cameraVector = glm::inverse(rotation) * (Application::getInstance()->getCamera()->getPosition() - _position); - rotation = rotation * glm::angleAxis(glm::degrees(atan2f(-cameraVector.x, -cameraVector.z)), glm::vec3(0.0f, 1.0f, 0.0f)); + rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // compute the size from the billboard camera parameters and scale float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); @@ -404,7 +404,7 @@ void Avatar::renderDisplayName() { // we need "always facing camera": we must remove the camera rotation from the stack glm::quat rotation = Application::getInstance()->getCamera()->getRotation(); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates // We project a unit vector and check the difference in screen coordinates, to check which is the @@ -662,15 +662,15 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin)); perpSin = glm::cross(perpCos, axis); - float anglea = 0.0; - float angleb = 0.0; + float anglea = 0.f; + float angleb = 0.f; for (int i = 0; i < NUM_BODY_CONE_SIDES; i ++) { // the rectangles that comprise the sides of the cone section are // referenced by "a" and "b" in one dimension, and "1", and "2" in the other dimension. anglea = angleb; - angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * PIf * 2.0f; + angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * TWO_PI; float sa = sinf(anglea); float sb = sinf(angleb); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 04f1388015..eba8f7bf1a 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -56,9 +56,10 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation))); - state.rotation = glm::angleAxis(-_owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) * - glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) * - glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation; + state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) + * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) + * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) + * joint.rotation; } void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { @@ -69,7 +70,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() + _owningHead->getSaccade() - _translation, 1.0f)); glm::quat between = rotationBetween(front, lookAt); - const float MAX_ANGLE = 30.0f; + const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; state.rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * joint.rotation; } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 74bf983eb1..6c2bad865f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -183,13 +183,13 @@ void Head::setScale (float scale) { } glm::quat Head::getTweakedOrientation() const { - return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() ))); + return _owningAvatar->getOrientation() * glm::quat(glm::radians( + glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() ))); } glm::quat Head::getCameraOrientation () const { Avatar* owningAvatar = static_cast(_owningAvatar); - return owningAvatar->getWorldAlignedOrientation() - * glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f))); + return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f))); } glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7108e0d0cc..92552e0a35 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -34,8 +34,8 @@ using namespace std; const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f); -const float YAW_MAG = 500.0f; -const float PITCH_MAG = 100.0f; +const float YAW_SPEED = 500.0f; // degrees/sec +const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_BODY_FORCE = 30.0f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; @@ -118,12 +118,13 @@ void MyAvatar::update(float deltaTime) { Head* head = getHead(); if (OculusManager::isConnected()) { - float yaw, pitch, roll; + float yaw, pitch, roll; // these angles will be in radians OculusManager::getEulerAngles(yaw, pitch, roll); - head->setYaw(yaw); - head->setPitch(pitch); - head->setRoll(roll); + // but these euler angles are stored in degrees + head->setYaw(yaw * DEGREES_PER_RADIAN); + head->setPitch(pitch * DEGREES_PER_RADIAN); + head->setRoll(roll * DEGREES_PER_RADIAN); } // Get audio loudness data from audio input device @@ -186,7 +187,7 @@ void MyAvatar::simulate(float deltaTime) { float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE; if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) { - radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f)); + radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cosf(0.5f * RADIANS_PER_DEGREE * myCamera->getFieldOfView())); radius *= COLLISION_RADIUS_SCALAR; } @@ -206,11 +207,11 @@ void MyAvatar::simulate(float deltaTime) { // update body yaw by body yaw delta orientation = orientation * glm::quat(glm::radians( - glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); + glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); // decay body rotation momentum const float BODY_SPIN_FRICTION = 7.5f; - float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime; + float bodySpinMomentum = 1.f - BODY_SPIN_FRICTION * deltaTime; if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; } _bodyPitchDelta *= bodySpinMomentum; _bodyYawDelta *= bodySpinMomentum; @@ -340,12 +341,12 @@ void MyAvatar::updateFromGyros(float deltaTime) { bool trackerActive = false; if (faceshift->isActive()) { estimatedPosition = faceshift->getHeadTranslation(); - estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); + estimatedRotation = DEGREES_PER_RADIAN * safeEulerAngles(faceshift->getHeadRotation()); trackerActive = true; } else if (visage->isActive()) { estimatedPosition = visage->getHeadTranslation(); - estimatedRotation = safeEulerAngles(visage->getHeadRotation()); + estimatedRotation = DEGREES_PER_RADIAN * safeEulerAngles(visage->getHeadRotation()); trackerActive = true; } @@ -492,12 +493,11 @@ void MyAvatar::render(bool forShadowMapOrMirror) { glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::vec3 chatAxis = glm::axis(chatRotation); - glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z); + glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z); - - glColor3f(0, 0.8f, 0); - glRotatef(180, 0, 1, 0); - glRotatef(180, 0, 0, 1); + glColor3f(0.f, 0.8f, 0.f); + glRotatef(180.f, 0.f, 1.f, 0.f); + glRotatef(180.f, 0.f, 0.f, 1.f); glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f); glDisable(GL_LIGHTING); @@ -513,7 +513,7 @@ void MyAvatar::render(bool forShadowMapOrMirror) { _chatMessage[lastIndex] = '\0'; textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str()); _chatMessage[lastIndex] = lastChar; - glColor3f(0, 1, 0); + glColor3f(0.f, 1.f, 0.f); textRenderer()->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex); } glEnable(GL_LIGHTING); @@ -527,7 +527,7 @@ void MyAvatar::renderHeadMouse() const { // TODO? resurrect headMouse stuff? /* // Display small target box at center or head mouse target that can also be used to measure LOD - glColor3f(1.0, 1.0, 1.0); + glColor3f(1.f, 1.f, 1.f); glDisable(GL_LINE_SMOOTH); const int PIXEL_BOX = 16; glBegin(GL_LINES); @@ -549,7 +549,7 @@ void MyAvatar::renderHeadMouse() const { int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE; int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE; - glColor3f(0.0, 1.0, 1.0); + glColor3f(0.f, 1.f, 1.f); glDisable(GL_LINE_SMOOTH); glBegin(GL_LINES); glVertex2f(eyeTargetX - PIXEL_BOX/2, eyeTargetY); @@ -624,15 +624,15 @@ void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) { // first orbit horizontally glm::quat orientation = getOrientation(); const float ANGULAR_SCALE = 0.5f; - glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, orientation * IDENTITY_UP); + glm::quat rotation = glm::angleAxis(glm::radians(- deltaX * ANGULAR_SCALE), orientation * IDENTITY_UP); setPosition(position + rotation * (getPosition() - position)); orientation = rotation * orientation; setOrientation(orientation); // then vertically float oldPitch = getHead()->getPitch(); - getHead()->setPitch(oldPitch + deltaY * -ANGULAR_SCALE); - rotation = glm::angleAxis(getHead()->getPitch() - oldPitch, orientation * IDENTITY_RIGHT); + getHead()->setPitch(oldPitch - deltaY * ANGULAR_SCALE); + rotation = glm::angleAxis(glm::radians((getHead()->getPitch() - oldPitch)), orientation * IDENTITY_RIGHT); setPosition(position + rotation * (getPosition() - position)); } @@ -737,9 +737,9 @@ void MyAvatar::updateThrust(float deltaTime) { _thrust -= _driveKeys[LEFT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right; _thrust += _driveKeys[UP] * _scale * THRUST_MAG_UP * _thrustMultiplier * deltaTime * up; _thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up; - _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_MAG * deltaTime; - _bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_MAG * deltaTime; - getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_MAG * deltaTime); + _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime; + _bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime; + getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime); // If thrust keys are being held down, slowly increase thrust to allow reaching great speeds if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) { @@ -1037,7 +1037,7 @@ void MyAvatar::updateChatCircle(float deltaTime) { const float CIRCLE_INFLUENCE_SCALE = 2.0f; const float MIN_RADIUS = 0.3f; for (int i = sortedAvatars.size() - 1; i >= 0; i--) { - float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO); + float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / TWO_PI); if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) { sortedAvatars.remove(i); } else { @@ -1048,7 +1048,7 @@ void MyAvatar::updateChatCircle(float deltaTime) { return; } center = sortedAvatars.last().accumulatedCenter; - float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO); + float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / TWO_PI); // compute the average up vector glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; @@ -1069,18 +1069,18 @@ void MyAvatar::updateChatCircle(float deltaTime) { glm::vec3 delta = _position - center; glm::vec3 projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; - float leftDistance = PI_TIMES_TWO; - float rightDistance = PI_TIMES_TWO; + float leftDistance = TWO_PI; + float rightDistance = TWO_PI; foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { delta = sortedAvatar.avatar->getPosition() - center; projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; if (angle < myAngle) { leftDistance = min(myAngle - angle, leftDistance); - rightDistance = min(PI_TIMES_TWO - (myAngle - angle), rightDistance); + rightDistance = min(TWO_PI - (myAngle - angle), rightDistance); } else { - leftDistance = min(PI_TIMES_TWO - (angle - myAngle), leftDistance); + leftDistance = min(TWO_PI - (angle - myAngle), leftDistance); rightDistance = min(angle - myAngle, rightDistance); } } @@ -1126,13 +1126,6 @@ void MyAvatar::setGravity(glm::vec3 gravity) { } } -void MyAvatar::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = safeEulerAngles(orientation); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; -} - void MyAvatar::goHome() { qDebug("Going Home!"); setPosition(START_LOCATION); @@ -1169,7 +1162,7 @@ void MyAvatar::updateLocationInDataServer() { if (accountManager.isLoggedIn()) { QString positionString(createByteArray(_position)); - QString orientationString(createByteArray(safeEulerAngles(getOrientation()))); + QString orientationString(createByteArray(glm::radians(safeEulerAngles(getOrientation())))); // construct the json to put the user's location QString locationPutJson = QString() + "{\"address\":{\"position\":\"" @@ -1202,10 +1195,10 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { NodeList::getInstance()->getDomainInfo().setHostname(domainHostnameString); // orient the user to face the target - glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(), - orientationItems[1].toFloat(), - orientationItems[2].toFloat()))) - * glm::angleAxis(180.0f, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::quat newOrientation = glm::quat(glm::vec3(orientationItems[0].toFloat(), + orientationItems[1].toFloat(), + orientationItems[2].toFloat())) + * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setOrientation(newOrientation); // move the user a couple units away diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f1448edb97..dfc114d952 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -44,10 +44,8 @@ public: void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } void setLeanScale(float scale) { _leanScale = scale; } void setGravity(glm::vec3 gravity); - void setOrientation(const glm::quat& orientation); void setMoveTarget(const glm::vec3 moveTarget); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } - // getters float getSpeed() const { return _speed; } @@ -55,7 +53,7 @@ public: float getLeanScale() const { return _leanScale; } float getElapsedTimeStopped() const { return _elapsedTimeStopped; } float getElapsedTimeMoving() const { return _elapsedTimeMoving; } - float getAbsoluteHeadYaw() const; + float getAbsoluteHeadYaw() const; // degrees const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } glm::vec3 getGravity() const { return _gravity; } @@ -68,7 +66,7 @@ public: // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; - bool getDriveKeys(int key) { return _driveKeys[key]; }; + bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; }; void jump() { _shouldJump = true; }; bool isMyAvatar() { return true; } @@ -101,8 +99,8 @@ public slots: private: bool _mousePressed; - float _bodyPitchDelta; - float _bodyRollDelta; + float _bodyPitchDelta; // degrees + float _bodyRollDelta; // degrees bool _shouldJump; float _driveKeys[MAX_DRIVE_KEYS]; glm::vec3 _gravity; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c57656be58..231e2b4ae0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -24,7 +24,7 @@ void SkeletonModel::simulate(float deltaTime, bool delayLoad) { return; } setTranslation(_owningAvatar->getPosition()); - setRotation(_owningAvatar->getOrientation() * glm::angleAxis(180.0f, glm::vec3(0.0f, 1.0f, 0.0f))); + setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); @@ -199,8 +199,9 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); - state.rotation = glm::angleAxis(-_owningAvatar->getHead()->getLeanSideways(), glm::normalize(inverse * axes[2])) * - glm::angleAxis(-_owningAvatar->getHead()->getLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation; + state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanSideways(), + glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanForward(), + glm::normalize(inverse * axes[0])) * joint.rotation; } void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) { diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 60839c362d..4fe89ff98b 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -65,8 +65,8 @@ void Faceshift::update() { return; } // get the euler angles relative to the window - glm::vec3 eulers = safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3( - (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))); + glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3( + (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f))))); // compute and subtract the long term average const float LONG_TERM_AVERAGE_SMOOTHING = 0.999f; diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index d3981fc182..908354ae9d 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -33,6 +33,7 @@ public: const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; } const glm::vec3& getHeadTranslation() const { return _headTranslation; } + // these pitch/yaw angles are in degrees float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; } float getEyeGazeLeftYaw() const { return _eyeGazeLeftYaw; } @@ -96,9 +97,9 @@ private: glm::vec3 _headAngularVelocity; glm::vec3 _headTranslation; + // degrees float _eyeGazeLeftPitch; float _eyeGazeLeftYaw; - float _eyeGazeRightPitch; float _eyeGazeRightYaw; @@ -121,10 +122,12 @@ private: int _jawOpenIndex; + // degrees float _longTermAverageEyePitch; float _longTermAverageEyeYaw; bool _longTermAverageInitialized; + // degrees float _estimatedEyePitch; float _estimatedEyeYaw; }; diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 0f937995b9..c5377ce428 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -27,7 +27,7 @@ int OculusManager::_scaleLocation; int OculusManager::_scaleInLocation; int OculusManager::_hmdWarpParamLocation; bool OculusManager::_isConnected = false; -float OculusManager::_yawOffset = 0; +float OculusManager::_yawOffset = 0.0f; // radians #ifdef HAVE_LIBOVR using namespace OVR; @@ -198,12 +198,7 @@ void OculusManager::updateYawOffset() { void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #ifdef HAVE_LIBOVR _sensorFusion->GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); - - // convert each angle to degrees - // remove the yaw offset from the returned yaw - yaw = glm::degrees(yaw - _yawOffset); - pitch = glm::degrees(pitch); - roll = glm::degrees(roll); + yaw = yaw - _yawOffset; #endif } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 3eb22110f5..b3cd400ac8 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -32,6 +32,9 @@ public: static void reset(); + /// param \yaw[out] yaw in radians + /// param \pitch[out] pitch in radians + /// param \roll[out] roll in radians static void getEulerAngles(float& yaw, float& pitch, float& roll); static void updateYawOffset(); diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 5d7e631966..287aa4e5f6 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -89,7 +89,7 @@ void SixenseManager::update(float deltaTime) { // Rotation of Palm glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); - rotation = glm::angleAxis(180.0f, glm::vec3(0.f, 1.f, 0.f)) * rotation; + rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); glm::vec3 newNormal = rotation * PALM_VECTOR; palm->setRawNormal(newNormal); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 9325efd77b..07aeea92b4 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -52,7 +52,7 @@ void TV3DManager::setFrustum(Camera& whichCamera) { double nearZ = whichCamera.getNearClip(); // near clipping plane double screenZ = Application::getInstance()->getViewFrustum()->getFocalLength(); // screen projection plane - double top = nearZ * tan(DTR * fovy / 2); //sets top of frustum based on fovy and near clipping plane + double top = nearZ * tan(DTR * fovy / 2.0); //sets top of frustum based on fovy and near clipping plane double right = _aspect * top; // sets right of frustum based on aspect ratio double frustumshift = (IOD / 2) * nearZ / screenZ; @@ -136,4 +136,4 @@ void TV3DManager::display(Camera& whichCamera) { // reset the viewport to how we started glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); -} \ No newline at end of file +} diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index c13cc7deab..6e6c9275d9 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -533,8 +533,8 @@ public: glm::quat postRotation; glm::mat4 postTransform; - glm::vec3 rotationMin; - glm::vec3 rotationMax; + glm::vec3 rotationMin; // radians + glm::vec3 rotationMax; // radians }; glm::mat4 getGlobalTransform(const QMultiHash& parentMap, @@ -806,7 +806,7 @@ void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) { } glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); mesh.tangents[firstIndex] += glm::cross(glm::angleAxis( - -glm::degrees(atan2f(-texCoordDelta.t, texCoordDelta.s)), normal) * glm::normalize(bitangent), normal); + - atan2f(-texCoordDelta.t, texCoordDelta.s), normal) * glm::normalize(bitangent), normal); } QVector getIndices(const QVector ids, QVector modelIDs) { @@ -1000,6 +1000,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) jointRightFingertipIDs[index] = getID(object.properties); } glm::vec3 translation; + // NOTE: the euler angles as supplied by the FBX file are in degrees glm::vec3 rotationOffset; glm::vec3 preRotation, rotation, postRotation; glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); @@ -1054,7 +1055,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } else if (property.properties.at(0) == "RotationMin") { rotationMin = getVec3(property.properties, index); - } else if (property.properties.at(0) == "RotationMax") { + } + // NOTE: these rotation limits are stored in degrees (NOT radians) + else if (property.properties.at(0) == "RotationMax") { rotationMax = getVec3(property.properties, index); } else if (property.properties.at(0) == "RotationMinX") { @@ -1104,10 +1107,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) model.postRotation = glm::quat(glm::radians(postRotation)); model.postTransform = glm::translate(-rotationPivot) * glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot); - model.rotationMin = glm::vec3(rotationMinX ? rotationMin.x : -180.0f, - rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f); - model.rotationMax = glm::vec3(rotationMaxX ? rotationMax.x : 180.0f, - rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f); + // NOTE: anbgles from the FBX file are in degrees + // so we convert them to radians for the FBXModel class + model.rotationMin = glm::radians(glm::vec3(rotationMinX ? rotationMin.x : -180.0f, + rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f)); + model.rotationMax = glm::radians(glm::vec3(rotationMaxX ? rotationMax.x : 180.0f, + rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f)); models.insert(getID(object.properties), model); } else if (object.name == "Texture") { diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 3bc80bbf2f..ac4e4bfa14 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -76,8 +76,8 @@ public: glm::quat postRotation; glm::mat4 postTransform; glm::mat4 transform; - glm::vec3 rotationMin; - glm::vec3 rotationMax; + glm::vec3 rotationMin; // radians + glm::vec3 rotationMax; // radians glm::quat inverseDefaultRotation; glm::quat inverseBindRotation; glm::mat4 bindTransform; diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 222edcf46a..0dce47fcfd 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -30,11 +30,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) { GLfloat* vertexData = new GLfloat[vertices * 3]; GLfloat* vertex = vertexData; for (int i = 0; i < stacks - 1; i++) { - float phi = PIf * 0.5f * i / (stacks - 1); + float phi = PI_OVER_TWO * float(i) / float(stacks - 1); float z = sinf(phi), radius = cosf(phi); for (int j = 0; j < slices; j++) { - float theta = PIf * 2.0f * j / slices; + float theta = TWO_PI * float(j) / float(slices); *(vertex++) = sinf(theta) * radius; *(vertex++) = cosf(theta) * radius; @@ -180,7 +180,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) { float y = (float)i / (stacks - 1); for (int j = 0; j <= slices; j++) { - float theta = 3 * PIf / 2 + PIf * j / slices; + float theta = 3.f * PI_OVER_TWO + PI * float(j) / float(slices); //normals *(vertex++) = sinf(theta); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f6cfb08816..4354509037 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -760,15 +760,15 @@ float Model::getLimbLength(int jointIndex) const { void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { JointState& state = _jointStates[jointIndex]; const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; - if (!constrain || (joint.rotationMin == glm::vec3(-180.0f, -180.0f, -180.0f) && - joint.rotationMax == glm::vec3(180.0f, 180.0f, 180.0f))) { + if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && + joint.rotationMax == glm::vec3(PI, PI, PI))) { // no constraints state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation; state.combinedRotation = delta * state.combinedRotation; return; } - glm::quat newRotation = glm::quat(glm::radians(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax))); + glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation * + glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; } @@ -789,7 +789,7 @@ void Model::renderCollisionProxies(float alpha) { glTranslatef(position.x, position.y, position.z); const glm::quat& rotation = shape->getRotation(); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // draw a grey sphere at shape position glColor4f(0.75f, 0.75f, 0.75f, alpha); @@ -864,7 +864,7 @@ void Model::applyCollision(CollisionInfo& collision) { axis = glm::normalize(axis); glm::vec3 end; getJointPosition(jointIndex, end); - glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start); + glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start); // try to move it setJointPosition(jointIndex, newEnd, -1, true); } diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp index 72f5e6c859..6065140505 100644 --- a/interface/src/starfield/Generator.cpp +++ b/interface/src/starfield/Generator.cpp @@ -16,6 +16,7 @@ using namespace starfield; const float Generator::STAR_COLORIZATION = 0.1f; +const float PI_OVER_180 = 3.14159265358979f / 180.f; void Generator::computeStarPositions(InputVertices& destination, unsigned limit, unsigned seed) { InputVertices* vertices = & destination; @@ -89,4 +90,4 @@ unsigned Generator::computeStarColor(float colorization) { red = green = blue = 2 + (rand() % 128); } return red | (green << 8) | (blue << 16); -} \ No newline at end of file +} diff --git a/interface/src/starfield/renderer/Renderer.cpp b/interface/src/starfield/renderer/Renderer.cpp index d1a8cbab8d..0be9850338 100755 --- a/interface/src/starfield/renderer/Renderer.cpp +++ b/interface/src/starfield/renderer/Renderer.cpp @@ -308,4 +308,4 @@ bool Renderer::TileSelection::deferred(Renderer::TileSelection::Cursor& cursor) return true; } return false; -} \ No newline at end of file +} diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 0c6c12d868..f2e43588ff 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -138,11 +138,11 @@ glm::quat MetavoxelEditor::getGridRotation() const { return glm::quat(); case GRID_PLANE_XZ: - return glm::angleAxis(-90.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + return glm::angleAxis(-PI_OVER_TWO, glm::vec3(1.0f, 0.0f, 0.0f)); case GRID_PLANE_YZ: default: - return glm::angleAxis(90.0f, glm::vec3(0.0f, 1.0f, 0.0f)); + return glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 1.0f, 0.0f)); } } @@ -275,7 +275,7 @@ void MetavoxelEditor::render() { glm::quat rotation = getGridRotation(); glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); MetavoxelTool* tool = getActiveTool(); if (tool) { diff --git a/interface/src/world.h b/interface/src/world.h index 8d3bd7322e..bc8dab9106 100644 --- a/interface/src/world.h +++ b/interface/src/world.h @@ -9,10 +9,6 @@ #ifndef __interface__world__ #define __interface__world__ -#ifndef PIf -#define PIf 3.14159265f -#endif - const float GRAVITY_EARTH = 9.80665f; const float EDGE_SIZE_GROUND_PLANE = 20.f; diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 83b4d8a79c..91a47b7d2c 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -41,7 +41,7 @@ Sound::Sound(float volume, float frequency, float duration, float decay, QObject int numSamples = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // we add sounds in chunks of this many samples int chunkStartingSample = 0; - float waveFrequency = (frequency / SAMPLE_RATE) * PI_TIMES_TWO; + float waveFrequency = (frequency / SAMPLE_RATE) * TWO_PI; while (volume > 0.f) { for (int i = 0; i < numSamples; i++) { t = (float)chunkStartingSample + (float)i; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 2483e0514b..ea2c2ab590 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -33,9 +33,9 @@ QNetworkAccessManager* AvatarData::networkAccessManager = NULL; AvatarData::AvatarData() : NodeData(), _handPosition(0,0,0), - _bodyYaw(-90.0), - _bodyPitch(0.0), - _bodyRoll(0.0), + _bodyYaw(-90.f), + _bodyPitch(0.0f), + _bodyRoll(0.0f), _targetScale(1.0f), _handState(0), _keyState(NO_KEY_DOWN), @@ -510,7 +510,7 @@ void AvatarData::setClampedTargetScale(float targetScale) { } void AvatarData::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = safeEulerAngles(orientation); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); _bodyPitch = eulerAngles.x; _bodyYaw = eulerAngles.y; _bodyRoll = eulerAngles.z; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 925540f899..067fadd8b1 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -108,7 +108,7 @@ public: QByteArray toByteArray(); int parseData(const QByteArray& packet); - // Body Rotation + // Body Rotation (degrees) float getBodyYaw() const { return _bodyYaw; } void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; } float getBodyPitch() const { return _bodyPitch; } @@ -122,7 +122,7 @@ public: glm::quat getHeadOrientation() const { return _headData->getOrientation(); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } - // access to Head().set/getMousePitch + // access to Head().set/getMousePitch (degrees) float getHeadPitch() const { return _headData->getPitch(); } void setHeadPitch(float value) { _headData->setPitch(value); }; @@ -217,9 +217,9 @@ protected: glm::vec3 _handPosition; // Body rotation - float _bodyYaw; - float _bodyPitch; - float _bodyRoll; + float _bodyYaw; // degrees + float _bodyPitch; // degrees + float _bodyRoll; // degrees // Body scale float _targetScale; diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index dac4941d97..a94096d73a 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -17,9 +17,9 @@ HeadData::HeadData(AvatarData* owningAvatar) : _yaw(0.0f), _pitch(0.0f), _roll(0.0f), - _lookAtPosition(0.0f, 0.0f, 0.0f), _leanSideways(0.0f), _leanForward(0.0f), + _lookAtPosition(0.0f, 0.0f, 0.0f), _audioLoudness(0.0f), _isFaceshiftConnected(false), _leftEyeBlink(0.0f), @@ -39,12 +39,11 @@ void HeadData::setOrientation(const glm::quat& orientation) { // rotate body about vertical axis glm::quat bodyOrientation = _owningAvatar->getOrientation(); glm::vec3 newFront = glm::inverse(bodyOrientation) * (orientation * IDENTITY_FRONT); - bodyOrientation = bodyOrientation * glm::angleAxis(glm::degrees(atan2f(-newFront.x, -newFront.z)), - glm::vec3(0.0f, 1.0f, 0.0f)); + bodyOrientation = bodyOrientation * glm::angleAxis(atan2f(-newFront.x, -newFront.z), glm::vec3(0.0f, 1.0f, 0.0f)); _owningAvatar->setOrientation(bodyOrientation); // the rest goes to the head - glm::vec3 eulers = safeEulerAngles(glm::inverse(bodyOrientation) * orientation); + glm::vec3 eulers = DEGREES_PER_RADIAN * safeEulerAngles(glm::inverse(bodyOrientation) * orientation); _pitch = eulers.x; _yaw = eulers.y; _roll = eulers.z; diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index dfecbd0320..56dc5630d0 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -15,12 +15,13 @@ #include #include -const float MIN_HEAD_YAW = -110; -const float MAX_HEAD_YAW = 110; -const float MIN_HEAD_PITCH = -60; -const float MAX_HEAD_PITCH = 60; -const float MIN_HEAD_ROLL = -50; -const float MAX_HEAD_ROLL = 50; +// degrees +const float MIN_HEAD_YAW = -110.f; +const float MAX_HEAD_YAW = 110.f; +const float MIN_HEAD_PITCH = -60.f; +const float MAX_HEAD_PITCH = 60.f; +const float MIN_HEAD_ROLL = -50.f; +const float MAX_HEAD_ROLL = 50.f; class AvatarData; @@ -29,21 +30,17 @@ public: HeadData(AvatarData* owningAvatar); virtual ~HeadData() { }; + // degrees float getLeanSideways() const { return _leanSideways; } void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } - float getLeanForward() const { return _leanForward; } void setLeanForward(float leanForward) { _leanForward = leanForward; } - float getYaw() const { return _yaw; } void setYaw(float yaw) { _yaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } - float getPitch() const { return _pitch; } void setPitch(float pitch) { _pitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } - float getRoll() const { return _roll; } void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } - virtual float getTweakedYaw() const { return _yaw; } virtual float getTweakedPitch() const { return _pitch; } virtual float getTweakedRoll() const { return _roll; } @@ -62,6 +59,7 @@ public: float getPupilDilation() const { return _pupilDilation; } void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } + // degrees void addYaw(float yaw); void addPitch(float pitch); void addRoll(float roll); @@ -73,12 +71,14 @@ public: friend class AvatarData; protected: + // degrees float _yaw; float _pitch; float _roll; - glm::vec3 _lookAtPosition; float _leanSideways; float _leanForward; + + glm::vec3 _lookAtPosition; float _audioLoudness; bool _isFaceshiftConnected; float _leftEyeBlink; diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 85bdd54938..d3946c2677 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -363,7 +363,7 @@ signals: private: glm::vec3 _translation; - glm::vec3 _rotation; + glm::vec3 _rotation; // Euler Angles in degrees float _scale; }; diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index da353a713e..aeffcc4968 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -384,14 +384,14 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const // Compute the angular distance between the two orientations const float ORIENTATION_SIMILAR_ENOUGH = 10.0f; // 10 degrees in any direction glm::quat dQOrientation = _orientation * glm::inverse(compareTo._orientation); - float angleOrientation = compareTo._orientation == _orientation ? 0.0f : glm::angle(dQOrientation); + float angleOrientation = compareTo._orientation == _orientation ? 0.0f : glm::degrees(glm::angle(dQOrientation)); if (isNaN(angleOrientation)) { angleOrientation = 0.0f; } glm::quat dQEyeOffsetOrientation = _eyeOffsetOrientation * glm::inverse(compareTo._eyeOffsetOrientation); float angleEyeOffsetOrientation = compareTo._eyeOffsetOrientation == _eyeOffsetOrientation - ? 0.0f : glm::angle(dQEyeOffsetOrientation); + ? 0.0f : glm::degrees(glm::angle(dQEyeOffsetOrientation)); if (isNaN(angleEyeOffsetOrientation)) { angleOrientation = 0.0f; } @@ -463,7 +463,7 @@ void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearValue, float& farValue, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { // compute our dimensions the usual way - float hheight = _nearClip * tanf(_fieldOfView * 0.5f * PI_OVER_180); + float hheight = _nearClip * tanf(_fieldOfView * 0.5f * RADIANS_PER_DEGREE); float hwidth = _aspectRatio * hheight; // get our frustum corners in view space diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 36d3346cdb..da4a6997f1 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -120,7 +120,7 @@ private: glm::vec3 _right; // Lens attributes - float _fieldOfView; + float _fieldOfView; // degrees float _aspectRatio; float _nearClip; float _farClip; diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index d016dc6fc4..9885b8d9dc 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -387,11 +387,10 @@ TouchEvent::TouchEvent(const QTouchEvent& event, const TouchEvent& other) { calculateMetaAttributes(other); } -// returns the degrees between two points (note: 0 degrees is 'east') +// returns the angle (in degrees) between two points (note: 0 degrees is 'east') float angleBetweenPoints(const glm::vec2& a, const glm::vec2& b ) { glm::vec2 length = b - a; - float radian = std::atan2(length.y, length.x); - float angle = radian * 180.0f / PIE; + float angle = DEGREES_PER_RADIAN * std::atan2(length.y, length.x); if (angle < 0) { angle += 360.0f; }; diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 5cd31f190c..f5a4fa5c9b 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -74,6 +74,8 @@ public: float radius; bool isPinching; bool isPinchOpening; + + // angles are in degrees QVector angles; // angle from center to each point float angle; // the average of the angles float deltaAngle; // the change in average angle from last event diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 78ea73987b..14025f0c67 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -22,8 +22,8 @@ glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { return q1 * q2; } -glm::quat Quat::fromVec3(const glm::vec3& vec3) { - return glm::quat(vec3); +glm::quat Quat::fromVec3(const glm::vec3& eulerAngles) { + return glm::quat(glm::radians(eulerAngles)); } glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { @@ -47,11 +47,11 @@ glm::vec3 Quat::getUp(const glm::quat& orientation) { } glm::vec3 Quat::safeEulerAngles(const glm::quat& orientation) { - return ::safeEulerAngles(orientation); + return glm::degrees(::safeEulerAngles(orientation)); } glm::quat Quat::angleAxis(float angle, const glm::vec3& v) { - return glm::angleAxis(angle, v); + return glm::angleAxis(glm::radians(angle), v); } glm::quat Quat::mix(const glm::quat& q1, const glm::quat& q2, float alpha) { diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index f006374347..3e5f46682c 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -24,13 +24,13 @@ class Quat : public QObject { public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); glm::quat fromVec3(const glm::vec3& vec3); - glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); + glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); // degrees glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); glm::vec3 getUp(const glm::quat& orientation); - glm::vec3 safeEulerAngles(const glm::quat& orientation); - glm::quat angleAxis(float angle, const glm::vec3& v); + glm::vec3 safeEulerAngles(const glm::quat& orientation); // degrees + glm::quat angleAxis(float angle, const glm::vec3& v); // degrees glm::quat mix(const glm::quat& q1, const glm::quat& q2, float alpha); void print(const QString& lable, const glm::quat& q); }; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f80c56fd0c..70fac3efe4 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -501,27 +501,27 @@ int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm } -int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { - const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); +int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { + const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.f); - uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO); + uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO); memcpy(buffer, &angleHolder, sizeof(uint16_t)); return sizeof(uint16_t); } int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { - *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0 - 180; + *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.f - 180.f; return sizeof(uint16_t); } int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { - const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.0); + const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.f); uint16_t quatParts[4]; - quatParts[0] = floorf((quatInput.x + 1.0) * QUAT_PART_CONVERSION_RATIO); - quatParts[1] = floorf((quatInput.y + 1.0) * QUAT_PART_CONVERSION_RATIO); - quatParts[2] = floorf((quatInput.z + 1.0) * QUAT_PART_CONVERSION_RATIO); - quatParts[3] = floorf((quatInput.w + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO); + quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO); memcpy(buffer, &quatParts, sizeof(quatParts)); return sizeof(quatParts); @@ -531,16 +531,16 @@ int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatO uint16_t quatParts[4]; memcpy(&quatParts, buffer, sizeof(quatParts)); - quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.0) - 1.0; - quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.0) - 1.0; - quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.0) - 1.0; - quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.f) - 1.f; + quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.f) - 1.f; return sizeof(quatParts); } -float SMALL_LIMIT = 10.0; -float LARGE_LIMIT = 1000.0; +float SMALL_LIMIT = 10.f; +float LARGE_LIMIT = 1000.f; int packFloatRatioToTwoByte(unsigned char* buffer, float ratio) { // if the ratio is less than 10, then encode it as a positive number scaled from 0 to int16::max() @@ -642,24 +642,24 @@ glm::vec3 safeEulerAngles(const glm::quat& q) { float sy = 2.0f * (q.y * q.w - q.x * q.z); if (sy < 1.0f - EPSILON) { if (sy > -1.0f + EPSILON) { - return glm::degrees(glm::vec3( + return glm::vec3( atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), asinf(sy), - atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)))); + atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); } else { // not a unique solution; x + z = atan2(-m21, m11) - return glm::degrees(glm::vec3( + return glm::vec3( 0.0f, - PIf * -0.5f, - atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)))); + - PI_OVER_TWO, + atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } } else { // not a unique solution; x - z = atan2(-m21, m11) - return glm::degrees(glm::vec3( + return glm::vec3( 0.0f, - PIf * 0.5f, - -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)))); + PI_OVER_TWO, + -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index b08e0413a6..1695b3b253 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -47,9 +47,13 @@ static const float ZERO = 0.0f; static const float ONE = 1.0f; static const float ONE_HALF = 0.5f; static const float ONE_THIRD = 0.333333f; -static const float PIE = 3.141592f; -static const float PI_TIMES_TWO = 3.141592f * 2.0f; -static const float PI_OVER_180 = 3.141592f / 180.0f; + +static const float PI = 3.14159265358979f; +static const float TWO_PI = 2.f * PI; +static const float PI_OVER_TWO = ONE_HALF * PI; +static const float RADIANS_PER_DEGREE = PI / 180.0f; +static const float DEGREES_PER_RADIAN = 180.0f / PI; + static const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations static const float SQUARE_ROOT_OF_2 = (float)sqrt(2.f); static const float SQUARE_ROOT_OF_3 = (float)sqrt(3.f); @@ -133,8 +137,8 @@ bool isBetween(int64_t value, int64_t max, int64_t min); // These pack/unpack functions are designed to start specific known types in as efficient a manner // as possible. Taking advantage of the known characteristics of the semantic types. -// Angles are known to be between 0 and 360deg, this allows us to encode in 16bits with great accuracy -int packFloatAngleToTwoByte(unsigned char* buffer, float angle); +// Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy +int packFloatAngleToTwoByte(unsigned char* buffer, float degrees); int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer); // Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 @@ -164,10 +168,7 @@ int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, flo int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); -#ifndef PIf -#define PIf 3.14159265f -#endif - +/// \return vec3 with euler angles in radians glm::vec3 safeEulerAngles(const glm::quat& q); #endif /* defined(__hifi__SharedUtil__) */ diff --git a/tests/physics/src/CollisionInfoTests.cpp b/tests/physics/src/CollisionInfoTests.cpp index 813100944b..43601978ae 100644 --- a/tests/physics/src/CollisionInfoTests.cpp +++ b/tests/physics/src/CollisionInfoTests.cpp @@ -25,7 +25,7 @@ void CollisionInfoTests::rotateThenTranslate() { collision._contactPoint = yAxis; collision._addedVelocity = xAxis + yAxis + zAxis; - glm::quat rotation = glm::angleAxis(rightAngle, zAxis); + glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); float distance = 3.f; glm::vec3 translation = distance * yAxis; @@ -64,7 +64,7 @@ void CollisionInfoTests::translateThenRotate() { collision._contactPoint = yAxis; collision._addedVelocity = xAxis + yAxis + zAxis; - glm::quat rotation = glm::angleAxis( -rightAngle, zAxis); + glm::quat rotation = glm::angleAxis( -PI_OVER_TWO, zAxis); float distance = 3.f; glm::vec3 translation = distance * yAxis; diff --git a/tests/physics/src/PhysicsTestUtil.h b/tests/physics/src/PhysicsTestUtil.h index dcbeaed346..c4c7962466 100644 --- a/tests/physics/src/PhysicsTestUtil.h +++ b/tests/physics/src/PhysicsTestUtil.h @@ -18,8 +18,6 @@ const glm::vec3 xAxis(1.f, 0.f, 0.f); const glm::vec3 yAxis(0.f, 1.f, 0.f); const glm::vec3 zAxis(0.f, 0.f, 1.f); -const float rightAngle = 90.f; // degrees - std::ostream& operator<<(std::ostream& s, const glm::vec3& v); std::ostream& operator<<(std::ostream& s, const glm::quat& q); std::ostream& operator<<(std::ostream& s, const glm::mat4& m); diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 314498b1d6..79de9f9175 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -485,7 +485,7 @@ void ShapeColliderTests::capsuleMissesCapsule() { } // rotate B and move it to the side - glm::quat rotation = glm::angleAxis(rightAngle, zAxis); + glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setPosition((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions)) @@ -566,7 +566,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { } { // rotate B and move it to the side - glm::quat rotation = glm::angleAxis(rightAngle, zAxis); + glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setPosition((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); @@ -590,7 +590,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { { // again, but this time check collision details float overlap = 0.1f; - glm::quat rotation = glm::angleAxis(rightAngle, zAxis); + glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); glm::vec3 positionB = ((totalRadius + capsuleB.getHalfHeight()) - overlap) * xAxis; capsuleB.setPosition(positionB); @@ -657,7 +657,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { { // collide cylinder wall against cylinder wall float overlap = 0.137f; float shift = 0.317f * halfHeightA; - glm::quat rotation = glm::angleAxis(rightAngle, zAxis); + glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); glm::vec3 positionB = (totalRadius - overlap) * zAxis + shift * yAxis; capsuleB.setPosition(positionB); From f5cdb98efb0d67d8a63a8e2da7ad4d207cacc2c4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Mar 2014 20:32:02 -0700 Subject: [PATCH 24/31] switch ReceivedPacketProcessor to using QWaitCondition --- libraries/shared/src/GenericThread.cpp | 2 ++ libraries/shared/src/GenericThread.h | 2 ++ libraries/shared/src/ReceivedPacketProcessor.cpp | 13 ++++++++++--- libraries/shared/src/ReceivedPacketProcessor.h | 6 ++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index ff371e0f32..59f2426bdb 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -44,6 +44,8 @@ void GenericThread::initialize(bool isThreaded) { void GenericThread::terminate() { if (_isThreaded) { _stopThread = true; + + terminating(); if (_thread) { _thread->wait(); diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index 76ceed83cb..1b5b05db5d 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -33,6 +33,8 @@ public: /// Override this function to do whatever your class actually does, return false to exit thread early. virtual bool process() = 0; + virtual void terminating() { }; // lets your subclass know we're terminating, and it should respond appropriately + bool isThreaded() const { return _isThreaded; } public slots: diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index b966109903..419e79881f 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -16,6 +16,10 @@ ReceivedPacketProcessor::ReceivedPacketProcessor() { _dontSleep = false; } +void ReceivedPacketProcessor::terminating() { + _hasPackets.wakeAll(); +} + void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& destinationNode, const QByteArray& packet) { // Make sure our Node and NodeList knows we've heard from this node. destinationNode->setLastHeardMicrostamp(usecTimestampNow()); @@ -24,6 +28,9 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& desti lock(); _packets.push_back(networkPacket); unlock(); + + // Make sure to wake our actual processing thread because we now have packets for it to process. + _hasPackets.wakeAll(); } bool ReceivedPacketProcessor::process() { @@ -31,11 +38,11 @@ bool ReceivedPacketProcessor::process() { // If a derived class handles process sleeping, like the JurisdiciontListener, then it can set // this _dontSleep member and we will honor that request. if (_packets.size() == 0 && !_dontSleep) { - const quint64 RECEIVED_THREAD_SLEEP_INTERVAL = (1000 * 1000)/60; // check at 60fps - usleep(RECEIVED_THREAD_SLEEP_INTERVAL); + _waitingOnPacketsMutex.lock(); + _hasPackets.wait(&_waitingOnPacketsMutex); + _waitingOnPacketsMutex.unlock(); } while (_packets.size() > 0) { - lock(); // lock to make sure nothing changes on us NetworkPacket& packet = _packets.front(); // get the oldest packet NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index 043dd6c6c4..4088422561 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -11,6 +11,8 @@ #ifndef __shared__ReceivedPacketProcessor__ #define __shared__ReceivedPacketProcessor__ +#include + #include "GenericThread.h" #include "NetworkPacket.h" @@ -43,11 +45,15 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process(); + virtual void terminating(); + bool _dontSleep; private: std::vector _packets; + QWaitCondition _hasPackets; + QMutex _waitingOnPacketsMutex; }; #endif // __shared__PacketReceiver__ From 8befefb0542feda2f76bcb7301390b35ea8fe548 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Mar 2014 20:45:46 -0700 Subject: [PATCH 25/31] first cut at making PacketSender use QWaitCondition --- libraries/shared/src/PacketSender.cpp | 17 ++++++++++++++++- libraries/shared/src/PacketSender.h | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 9d819b96d7..52f8759c8b 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -54,6 +54,10 @@ void PacketSender::queuePacketForSending(const SharedNodePointer& destinationNod unlock(); _totalPacketsQueued++; _totalBytesQueued += packet.size(); + + // Make sure to wake our actual processing thread because we now have packets for it to process. + qDebug() << "PacketSender::queuePacketForSending()... wake up, we need to send packets!."; + _hasPackets.wakeAll(); } void PacketSender::setPacketsPerSecond(int packetsPerSecond) { @@ -68,6 +72,10 @@ bool PacketSender::process() { return nonThreadedProcess(); } +void PacketSender::terminating() { + qDebug() << "PacketSender::terminating()... wake up, we need to die."; + _hasPackets.wakeAll(); +} bool PacketSender::threadedProcess() { bool hasSlept = false; @@ -113,7 +121,14 @@ bool PacketSender::threadedProcess() { // we don't want to sleep too long because how ever much we sleep will delay any future unsent // packets that arrive while we're sleeping. So we sleep 1/2 of our target fps interval if (!hasSlept) { - usleep(MINIMAL_SLEEP_INTERVAL); + //usleep(MINIMAL_SLEEP_INTERVAL); + + // wait till we have packets + _waitingOnPacketsMutex.lock(); + qDebug() << "PacketSender::threadedProcess()... waiting on packets to send..."; + _hasPackets.wait(&_waitingOnPacketsMutex); + qDebug() << "PacketSender::threadedProcess()... YIPEEE we're awake..."; + _waitingOnPacketsMutex.unlock(); } return isStillRunning(); diff --git a/libraries/shared/src/PacketSender.h b/libraries/shared/src/PacketSender.h index 7d00e622b9..bd8de9a1b1 100644 --- a/libraries/shared/src/PacketSender.h +++ b/libraries/shared/src/PacketSender.h @@ -11,6 +11,8 @@ #ifndef __shared__PacketSender__ #define __shared__PacketSender__ +#include + #include "GenericThread.h" #include "NetworkPacket.h" #include "NodeList.h" @@ -44,6 +46,7 @@ public: int getPacketsPerSecond() const { return _packetsPerSecond; } virtual bool process(); + virtual void terminating(); /// are there packets waiting in the send queue to be sent bool hasPacketsToSend() const { return _packets.size() > 0; } @@ -113,6 +116,9 @@ private: quint64 _totalPacketsQueued; quint64 _totalBytesQueued; + + QWaitCondition _hasPackets; + QMutex _waitingOnPacketsMutex; }; #endif // __shared__PacketSender__ From 025da315c6293bc41919995397e5c8cc41825164 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Mar 2014 21:11:47 -0700 Subject: [PATCH 26/31] removed dontSleep from JurisdictionListener --- libraries/octree/src/JurisdictionListener.cpp | 2 -- libraries/shared/src/PacketSender.cpp | 4 ---- libraries/shared/src/ReceivedPacketProcessor.cpp | 8 +------- libraries/shared/src/ReceivedPacketProcessor.h | 4 +--- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 49cdfac741..c280b48c99 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -19,8 +19,6 @@ JurisdictionListener::JurisdictionListener(NodeType_t type) : _nodeType(type), _packetSender(JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) { - ReceivedPacketProcessor::_dontSleep = true; // we handle sleeping so this class doesn't need to - connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); // tell our NodeList we want to hear about nodes with our node type diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 52f8759c8b..062976cc37 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -56,7 +56,6 @@ void PacketSender::queuePacketForSending(const SharedNodePointer& destinationNod _totalBytesQueued += packet.size(); // Make sure to wake our actual processing thread because we now have packets for it to process. - qDebug() << "PacketSender::queuePacketForSending()... wake up, we need to send packets!."; _hasPackets.wakeAll(); } @@ -73,7 +72,6 @@ bool PacketSender::process() { } void PacketSender::terminating() { - qDebug() << "PacketSender::terminating()... wake up, we need to die."; _hasPackets.wakeAll(); } @@ -125,9 +123,7 @@ bool PacketSender::threadedProcess() { // wait till we have packets _waitingOnPacketsMutex.lock(); - qDebug() << "PacketSender::threadedProcess()... waiting on packets to send..."; _hasPackets.wait(&_waitingOnPacketsMutex); - qDebug() << "PacketSender::threadedProcess()... YIPEEE we're awake..."; _waitingOnPacketsMutex.unlock(); } diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index 419e79881f..df7bfad165 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -12,10 +12,6 @@ #include "ReceivedPacketProcessor.h" #include "SharedUtil.h" -ReceivedPacketProcessor::ReceivedPacketProcessor() { - _dontSleep = false; -} - void ReceivedPacketProcessor::terminating() { _hasPackets.wakeAll(); } @@ -35,9 +31,7 @@ void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& desti bool ReceivedPacketProcessor::process() { - // If a derived class handles process sleeping, like the JurisdiciontListener, then it can set - // this _dontSleep member and we will honor that request. - if (_packets.size() == 0 && !_dontSleep) { + if (_packets.size() == 0) { _waitingOnPacketsMutex.lock(); _hasPackets.wait(&_waitingOnPacketsMutex); _waitingOnPacketsMutex.unlock(); diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index 4088422561..7c99218753 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -19,7 +19,7 @@ /// Generalized threaded processor for handling received inbound packets. class ReceivedPacketProcessor : public GenericThread { public: - ReceivedPacketProcessor(); + ReceivedPacketProcessor() { } /// Add packet from network receive thread to the processing queue. /// \param sockaddr& senderAddress the address of the sender @@ -47,8 +47,6 @@ protected: virtual void terminating(); - bool _dontSleep; - private: std::vector _packets; From e72d3127bf85b701ed641e348ce9cc4d5f09decf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Mar 2014 21:25:30 -0700 Subject: [PATCH 27/31] fix comment and remove dead code --- libraries/shared/src/PacketSender.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 062976cc37..9fac115a39 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -115,12 +115,8 @@ bool PacketSender::threadedProcess() { } } - // if threaded and we haven't slept? We want to sleep a little so we don't hog the CPU, but - // we don't want to sleep too long because how ever much we sleep will delay any future unsent - // packets that arrive while we're sleeping. So we sleep 1/2 of our target fps interval + // if threaded and we haven't slept? We want to wait for our consumer to signal us with new packets if (!hasSlept) { - //usleep(MINIMAL_SLEEP_INTERVAL); - // wait till we have packets _waitingOnPacketsMutex.lock(); _hasPackets.wait(&_waitingOnPacketsMutex); From 4c26f025ac89fce9bfc526131caec6bf06a16003 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 12 Mar 2014 19:58:08 +0200 Subject: [PATCH 28/31] Enabled 'Enter' to open the chat. Deleted the now obsolete ChatEntry. --- interface/interface_en.ts | 16 +++--- interface/src/Application.cpp | 31 +--------- interface/src/Application.h | 4 -- interface/src/Menu.cpp | 6 +- interface/src/ui/ChatEntry.cpp | 102 --------------------------------- interface/src/ui/ChatEntry.h | 35 ----------- 6 files changed, 14 insertions(+), 180 deletions(-) delete mode 100644 interface/src/ui/ChatEntry.cpp delete mode 100644 interface/src/ui/ChatEntry.h diff --git a/interface/interface_en.ts b/interface/interface_en.ts index a8f78cd36e..685c6e3f67 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 032e849f0a..13e3d36fad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -153,7 +153,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _touchAvgY(0.0f), _isTouchPressed(false), _mousePressed(false), - _chatEntryOn(false), _audio(&_audioScope, STARTUP_JITTER_SAMPLES), _enableProcessVoxelsThread(true), _voxelProcessor(), @@ -698,21 +697,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } if (activeWindow() == _window) { - if (_chatEntryOn) { - if (_chatEntry.keyPressEvent(event)) { - _myAvatar->setKeyState(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete ? - DELETE_KEY_DOWN : INSERT_KEY_DOWN); - _myAvatar->setChatMessage(string(_chatEntry.getContents().size(), SOLID_BLOCK_CHAR)); - - } else { - _myAvatar->setChatMessage(_chatEntry.getContents()); - _chatEntry.clear(); - _chatEntryOn = false; - setMenuShortcutsEnabled(true); - } - return; - } - bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); switch (event->key()) { @@ -793,10 +777,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Return: case Qt::Key_Enter: - _chatEntryOn = true; - _myAvatar->setKeyState(NO_KEY_DOWN); - _myAvatar->setChatMessage(string()); - setMenuShortcutsEnabled(false); + Menu::getInstance()->triggerOption(MenuOption::Chat); break; case Qt::Key_Up: @@ -939,11 +920,6 @@ void Application::keyReleaseEvent(QKeyEvent* event) { if (activeWindow() == _window) { - if (_chatEntryOn) { - _myAvatar->setKeyState(NO_KEY_DOWN); - return; - } - switch (event->key()) { case Qt::Key_E: _myAvatar->setDriveKeys(UP, 0); @@ -2483,11 +2459,6 @@ void Application::displayOverlay() { } } - // Show chat entry field - if (_chatEntryOn) { - _chatEntry.render(_glWidget->width(), _glWidget->height()); - } - // Show on-screen msec timer if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { char frameTimer[10]; diff --git a/interface/src/Application.h b/interface/src/Application.h index 234f264447..70b7347654 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -64,7 +64,6 @@ #include "renderer/TextureCache.h" #include "renderer/VoxelShader.h" #include "ui/BandwidthDialog.h" -#include "ui/ChatEntry.h" #include "ui/OctreeStatsDialog.h" #include "ui/RearMirrorTools.h" #include "ui/LodToolsDialog.h" @@ -426,9 +425,6 @@ private: bool _mousePressed; // true if mouse has been pressed (clear when finished) - ChatEntry _chatEntry; // chat entry field - bool _chatEntryOn; // Whether to show the chat entry - GeometryCache _geometryCache; TextureCache _textureCache; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5f6c541bc5..f0d4d8c133 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -163,7 +163,11 @@ Menu::Menu() : addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST())); - _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, this, SLOT(showChat())); + _chatAction = addActionToQMenuAndActionHash(toolsMenu, + MenuOption::Chat, + Qt::Key_Return, + this, + SLOT(showChat())); #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); toggleChat(); diff --git a/interface/src/ui/ChatEntry.cpp b/interface/src/ui/ChatEntry.cpp deleted file mode 100644 index 470b62542b..0000000000 --- a/interface/src/ui/ChatEntry.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// -// ChatEntry.cpp -// interface -// -// Created by Andrzej Kapolka on 4/24/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. - -#include - -#include "ChatEntry.h" -#include "InterfaceConfig.h" -#include "Util.h" - -using namespace std; - -const int MAX_CONTENT_LENGTH = 80; - -ChatEntry::ChatEntry() : _cursorPos(0) { -} - -void ChatEntry::clear() { - _contents.clear(); - _cursorPos = 0; -} - -bool ChatEntry::keyPressEvent(QKeyEvent* event) { - event->accept(); - switch (event->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - return false; - - case Qt::Key_Escape: - clear(); - return false; - - case Qt::Key_Backspace: - if (_cursorPos != 0) { - _contents.erase(_cursorPos - 1, 1); - _cursorPos--; - } - return true; - - case Qt::Key_Delete: - if (_cursorPos < (int)_contents.size()) { - _contents.erase(_cursorPos, 1); - } - return true; - - case Qt::Key_Left: - if (_cursorPos != 0) { - _cursorPos--; - } - return true; - - case Qt::Key_Right: - if (_cursorPos != _contents.size()) { - _cursorPos++; - } - return true; - - default: - QString text = event->text(); - if (text.isEmpty()) { - event->ignore(); - return true; - } - if (_contents.size() < MAX_CONTENT_LENGTH) { - _contents.insert(_cursorPos, 1, text.at(0).toLatin1()); - _cursorPos++; - } - return true; - } -} - -const float ALL_WHITE[] = { 1.0f, 1.0f, 1.0f }; - -void ChatEntry::render(int screenWidth, int screenHeight) { - // draw a gray background so that we can actually see what we're typing - int bottom = screenHeight - 150, top = screenHeight - 165; - int left = 20, right = left + 600; - - glColor3f(0.2f, 0.2f, 0.2f); - glBegin(GL_QUADS); - glVertex2f(left - 5, bottom + 7); - glVertex2f(right + 5, bottom + 7); - glVertex2f(right + 5, top - 3); - glVertex2f(left - 5, top - 3); - glEnd(); - - drawText(left, bottom, 0.10f, 0, 2, _contents.c_str(), ALL_WHITE); - - float width = 0; - for (string::iterator it = _contents.begin(), end = it + _cursorPos; it != end; it++) { - width += widthChar(0.10f, 0, *it); - } - glDisable(GL_LINE_SMOOTH); - glBegin(GL_LINE_STRIP); - glVertex2f(left + width, top + 2); - glVertex2f(left + width, bottom + 2); - glEnd(); -} diff --git a/interface/src/ui/ChatEntry.h b/interface/src/ui/ChatEntry.h deleted file mode 100644 index 478641325d..0000000000 --- a/interface/src/ui/ChatEntry.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// ChatEntry.h -// interface -// -// Created by Andrzej Kapolka on 4/24/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__ChatEntry__ -#define __interface__ChatEntry__ - -#include - -class QKeyEvent; - -class ChatEntry { -public: - - ChatEntry(); - - const std::string& getContents() const { return _contents; } - - void clear(); - - bool keyPressEvent(QKeyEvent* event); - - void render(int screenWidth, int screenHeight); - -private: - - std::string _contents; - int _cursorPos; -}; - -#endif /* defined(__interface__ChatEntry__) */ From c3e8d51694d386fab583823bda165643a5325c3b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 12 Mar 2014 12:06:59 -0700 Subject: [PATCH 29/31] orientation stored in dataserver is in degrees --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d2c3c4357a..8136e06085 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1155,7 +1155,7 @@ void MyAvatar::updateLocationInDataServer() { if (accountManager.isLoggedIn()) { QString positionString(createByteArray(_position)); - QString orientationString(createByteArray(glm::radians(safeEulerAngles(getOrientation())))); + QString orientationString(createByteArray(glm::degrees(safeEulerAngles(getOrientation())))); // construct the json to put the user's location QString locationPutJson = QString() + "{\"address\":{\"position\":\"" From e68241d2a9a67a1364d82ca19da95bcc262f2d85 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 12 Mar 2014 12:08:27 -0700 Subject: [PATCH 30/31] using glm::degrees() instead of DEGREES_PER_RADIAN --- interface/src/avatar/MyAvatar.cpp | 4 ++-- libraries/avatars/src/HeadData.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8136e06085..0a2462e656 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -334,12 +334,12 @@ void MyAvatar::updateFromGyros(float deltaTime) { bool trackerActive = false; if (faceshift->isActive()) { estimatedPosition = faceshift->getHeadTranslation(); - estimatedRotation = DEGREES_PER_RADIAN * safeEulerAngles(faceshift->getHeadRotation()); + estimatedRotation = glm::degrees(safeEulerAngles(faceshift->getHeadRotation())); trackerActive = true; } else if (visage->isActive()) { estimatedPosition = visage->getHeadTranslation(); - estimatedRotation = DEGREES_PER_RADIAN * safeEulerAngles(visage->getHeadRotation()); + estimatedRotation = glm::degrees(safeEulerAngles(visage->getHeadRotation())); trackerActive = true; } diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index a94096d73a..cf48aeabfa 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -43,7 +43,7 @@ void HeadData::setOrientation(const glm::quat& orientation) { _owningAvatar->setOrientation(bodyOrientation); // the rest goes to the head - glm::vec3 eulers = DEGREES_PER_RADIAN * safeEulerAngles(glm::inverse(bodyOrientation) * orientation); + glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation)); _pitch = eulers.x; _yaw = eulers.y; _roll = eulers.z; From 6caf6b2c311d2950a8ae764bea3b94055a5e204a Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 12 Mar 2014 21:23:35 +0200 Subject: [PATCH 31/31] Filtered received messages, accepting only group ones. --- interface/src/ui/ChatWindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 7a3f1ab906..2fd3d4f9cb 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -179,6 +179,10 @@ void ChatWindow::participantsChanged() { } void ChatWindow::messageReceived(const QXmppMessage& message) { + if (message.type() != QXmppMessage::GroupChat) { + return; + } + QLabel* userLabel = new QLabel(getParticipantName(message.from())); QFont font = userLabel->font(); font.setBold(true);