From 7355fb61d8e278dbb64274cccbf4e96b7053811d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 16 Jul 2014 14:07:28 -0700 Subject: [PATCH 01/24] Added ability to visit metavoxels changed compared to a reference. --- libraries/metavoxels/src/MetavoxelData.cpp | 227 +++++++++++++++++++-- libraries/metavoxels/src/MetavoxelData.h | 29 +++ 2 files changed, 243 insertions(+), 13 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 41cf2b2a20..208e9cf309 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -85,13 +85,14 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { // start with the root values/defaults (plus the guide attribute) const QVector& inputs = visitor.getInputs(); const QVector& outputs = visitor.getOutputs(); - MetavoxelVisitation firstVisitation = { NULL, visitor, QVector(inputs.size() + 1), - QVector(outputs.size()), { NULL, getMinimum(), _size, - QVector(inputs.size() + 1), QVector(outputs.size()) } }; + MetavoxelVisitation firstVisitation(NULL, visitor, QVector(inputs.size() + 1), + QVector(outputs.size()), MetavoxelInfo(NULL, getMinimum(), _size, + QVector(inputs.size() + 1), QVector(outputs.size()))); for (int i = 0; i < inputs.size(); i++) { - MetavoxelNode* node = _roots.value(inputs.at(i)); + const AttributePointer& input = inputs.at(i); + MetavoxelNode* node = _roots.value(input); firstVisitation.inputNodes[i] = node; - firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(inputs[i]) : inputs[i]; + firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(input) : input; } AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute(); MetavoxelNode* node = _roots.value(guideAttribute); @@ -122,6 +123,62 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { } } +void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { + // let the visitor know we're about to begin a tour + visitor.prepare(); + + // start with the root values/defaults (plus the guide attribute) + const QVector& inputs = visitor.getInputs(); + const QVector& outputs = visitor.getOutputs(); + DifferentMetavoxelVisitation firstVisitation(NULL, visitor, QVector(inputs.size() + 1), + QVector(outputs.size()), MetavoxelInfo(NULL, getMinimum(), _size, + QVector(inputs.size() + 1), QVector(outputs.size())), + QVector(inputs.size() + 1)); + bool allNodesSame = true; + for (int i = 0; i < inputs.size(); i++) { + const AttributePointer& input = inputs.at(i); + MetavoxelNode* node = _roots.value(input); + firstVisitation.inputNodes[i] = node; + firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(input) : input; + MetavoxelNode* compareNode = other._roots.value(input); + firstVisitation.compareNodes[i] = compareNode; + allNodesSame &= (node == compareNode); + } + AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute(); + MetavoxelNode* node = _roots.value(guideAttribute); + firstVisitation.inputNodes.last() = node; + firstVisitation.info.inputValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute; + MetavoxelNode* compareNode = other._roots.value(guideAttribute); + firstVisitation.compareNodes.last() = compareNode; + allNodesSame &= (node == compareNode); + if (allNodesSame) { + return; + } + for (int i = 0; i < outputs.size(); i++) { + MetavoxelNode* node = _roots.value(outputs.at(i)); + firstVisitation.outputNodes[i] = node; + } + static_cast(firstVisitation.info.inputValues.last().getInlineValue< + SharedObjectPointer>().data())->guideToDifferent(firstVisitation); + for (int i = 0; i < outputs.size(); i++) { + OwnedAttributeValue& value = firstVisitation.info.outputValues[i]; + if (!value.getAttribute()) { + continue; + } + // replace the old node with the new + MetavoxelNode*& node = _roots[value.getAttribute()]; + if (node) { + node->decrementReferenceCount(value.getAttribute()); + } + node = firstVisitation.outputNodes.at(i); + if (node->isLeaf() && value.isDefault()) { + // immediately remove the new node if redundant + node->decrementReferenceCount(value.getAttribute()); + _roots.remove(value.getAttribute()); + } + } +} + typedef void (*SpannerUpdateFunction)(SharedObjectSet& set, const SharedObjectPointer& object); void insertSpanner(SharedObjectSet& set, const SharedObjectPointer& object) { @@ -1119,6 +1176,18 @@ void MetavoxelNode::countNodes(const AttributePointer& attribute, const glm::vec } } +MetavoxelInfo::MetavoxelInfo(MetavoxelInfo* parentInfo, const glm::vec3& minimum, float size, + const QVector& inputValues, const QVector& outputValues, + bool isLODLeaf, bool isLeaf) : + parentInfo(parentInfo), + minimum(minimum), + size(size), + inputValues(inputValues), + outputValues(outputValues), + isLODLeaf(isLODLeaf), + isLeaf(isLeaf) { +} + 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) | @@ -1169,6 +1238,7 @@ int MetavoxelVisitor::encodeRandomOrder() { 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; +const int MetavoxelVisitor::ALL_NODES = 1 << 24; MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : @@ -1324,10 +1394,112 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { return STOP_RECURSION; } +bool MetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visitation) { + return guide(visitation); +} + DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } +static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) { + MetavoxelVisitation nextVisitation(&visitation, visitation.visitor, QVector(visitation.inputNodes.size()), + QVector(visitation.outputNodes.size()), MetavoxelInfo(&visitation.info, 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 + 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); + 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(parentValue.getAttribute()) : parentValue.getAttribute()->inherit(parentValue); + } + for (int j = 0; j < visitation.outputNodes.size(); j++) { + MetavoxelNode* node = visitation.outputNodes.at(j); + 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); + 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()) { + continue; + } + // replace the child + OwnedAttributeValue& parentValue = visitation.info.outputValues[j]; + if (!parentValue.getAttribute()) { + // shallow-copy the parent node on first change + parentValue = value; + MetavoxelNode*& node = visitation.outputNodes[j]; + if (node) { + node = new MetavoxelNode(value.getAttribute(), node); + } else { + // create leaf with inherited value + node = new MetavoxelNode(value.getAttribute()->inherit(visitation.getInheritedOutputValue(j))); + } + } + MetavoxelNode* node = visitation.outputNodes.at(j); + MetavoxelNode* child = node->getChild(index); + if (child) { + child->decrementReferenceCount(value.getAttribute()); + } else { + // it's a leaf; we need to split it up + AttributeValue nodeValue = value.getAttribute()->inherit(node->getAttributeValue(value.getAttribute())); + for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) { + node->setChild((index + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue)); + } + } + node->setChild(index, nextVisitation.outputNodes.at(j)); + value = AttributeValue(); + } + } + for (int i = 0; i < visitation.outputNodes.size(); i++) { + OwnedAttributeValue& value = visitation.info.outputValues[i]; + if (value.getAttribute()) { + MetavoxelNode* node = visitation.outputNodes.at(i); + node->mergeChildren(value.getAttribute()); + value = node->getAttributeValue(value.getAttribute()); + } + } + return true; +} + bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier()); + visitation.info.isLeaf = visitation.info.isLODLeaf || 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()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { + // "set" to same value; disregard + value = AttributeValue(); + } else { + node = value.getAttribute()->createMetavoxelNode(value, node); + } + } + return (encodedOrder == MetavoxelVisitor::STOP_RECURSION) || defaultGuideToChildren(visitation, lodBase, encodedOrder); +} + +bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visitation) { // 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; @@ -1353,21 +1525,34 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { return true; } - MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor, + if (encodedOrder & MetavoxelVisitor::ALL_NODES) { + return defaultGuideToChildren(visitation, lodBase, encodedOrder); + } + DifferentMetavoxelVisitation nextVisitation(&visitation, visitation.visitor, QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()), - { &visitation.info, glm::vec3(), visitation.info.size * 0.5f, QVector(visitation.inputNodes.size()), - QVector(visitation.outputNodes.size()) } }; + MetavoxelInfo(&visitation.info, glm::vec3(), visitation.info.size * 0.5f, + QVector(visitation.inputNodes.size()), + QVector(visitation.outputNodes.size())), + QVector(visitation.inputNodes.size())); for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { // the encoded order tells us the child indices for each iteration int index = encodedOrder & ORDER_ELEMENT_MASK; encodedOrder >>= ORDER_ELEMENT_BITS; + bool allNodesSame = true; for (int j = 0; j < visitation.inputNodes.size(); j++) { MetavoxelNode* node = visitation.inputNodes.at(j); const AttributeValue& parentValue = visitation.info.inputValues.at(j); - MetavoxelNode* child = (node && (visitation.info.size >= lodBase * - parentValue.getAttribute()->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; + bool expand = (visitation.info.size >= lodBase * parentValue.getAttribute()->getLODThresholdMultiplier()); + MetavoxelNode* child = (node && expand) ? node->getChild(index) : NULL; nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ? child->getAttributeValue(parentValue.getAttribute()) : parentValue.getAttribute()->inherit(parentValue); + MetavoxelNode* compareNode = visitation.compareNodes.at(j); + MetavoxelNode* compareChild = (compareNode && expand) ? compareNode->getChild(index) : NULL; + nextVisitation.compareNodes[j] = compareChild; + allNodesSame &= (child == compareChild); + } + if (allNodesSame) { + continue; } for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); @@ -1377,7 +1562,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index); if (!static_cast(nextVisitation.info.inputValues.last().getInlineValue< - SharedObjectPointer>().data())->guide(nextVisitation)) { + SharedObjectPointer>().data())->guideToDifferent(nextVisitation)) { return false; } for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { @@ -1470,10 +1655,10 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin // start with the basics, including inherited attribute values QScriptValue infoValue = context->argument(0); QScriptValue minimum = infoValue.property(guide->_minimumHandle); - MetavoxelInfo info = { + MetavoxelInfo info( NULL, glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()), (float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues, - guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() }; + guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool()); // extract and convert the values provided by the script QScriptValue inputValues = infoValue.property(guide->_inputValuesHandle); @@ -1559,6 +1744,15 @@ void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) { _minimumHandle = QScriptString(); } +MetavoxelVisitation::MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, + const QVector& inputNodes, const QVector& outputNodes, const MetavoxelInfo& info) : + previous(previous), + visitor(visitor), + inputNodes(inputNodes), + outputNodes(outputNodes), + info(info) { +} + bool MetavoxelVisitation::allInputNodesLeaves() const { foreach (MetavoxelNode* node, inputNodes) { if (node && !node->isLeaf()) { @@ -1578,6 +1772,13 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor.getOutputs().at(index)); } +DifferentMetavoxelVisitation::DifferentMetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, + const QVector& inputNodes, const QVector& outputNodes, + const MetavoxelInfo& info, const QVector& compareNodes) : + MetavoxelVisitation(previous, visitor, inputNodes, outputNodes, info), + compareNodes(compareNodes) { +} + const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f; const float DEFAULT_VOXELIZATION_GRANULARITY = powf(2.0f, -3.0f); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index eeab5bd0f4..3afd4c27bc 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -27,6 +27,7 @@ class QScriptContext; +class DifferentMetavoxelVisitation; class MetavoxelNode; class MetavoxelVisitation; class MetavoxelVisitor; @@ -80,6 +81,9 @@ public: /// Applies the specified visitor to the contained voxels. void guide(MetavoxelVisitor& visitor); + /// Guides the specified visitor to the voxels that differ from those of the specified other. + void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor); + /// Inserts a spanner into the specified attribute layer. void insert(const AttributePointer& attribute, const SharedObjectPointer& object); void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); @@ -252,6 +256,9 @@ public: bool isLODLeaf; bool isLeaf; + MetavoxelInfo(MetavoxelInfo* parentInfo, const glm::vec3& minimum, float size, const QVector& inputValues, + const QVector& outputValues, bool isLODLeaf = false, bool isLeaf = false); + 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; } }; @@ -278,6 +285,9 @@ public: /// A special "order" that short-circuits the tour. static const int SHORT_CIRCUIT; + /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones). + static const int ALL_NODES; + MetavoxelVisitor(const QVector& inputs, const QVector& outputs = QVector(), const MetavoxelLOD& lod = MetavoxelLOD()); @@ -390,6 +400,10 @@ public: /// Guides the specified visitor to the contained voxels. /// \return true to keep going, false to short circuit the tour virtual bool guide(MetavoxelVisitation& visitation) = 0; + + /// Guides the specified visitor to the voxels that differ from a reference. + /// \return true to keep going, false to short circuit the tour + virtual bool guideToDifferent(DifferentMetavoxelVisitation& visitation); }; /// Guides visitors through the explicit content of the system. @@ -401,6 +415,7 @@ public: Q_INVOKABLE DefaultMetavoxelGuide(); virtual bool guide(MetavoxelVisitation& visitation); + virtual bool guideToDifferent(DifferentMetavoxelVisitation& visitation); }; /// A temporary test guide that just makes the existing voxels throb with delight. @@ -469,10 +484,24 @@ public: QVector outputNodes; MetavoxelInfo info; + MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, const QVector& inputNodes, + const QVector& outputNodes, const MetavoxelInfo& info); + bool allInputNodesLeaves() const; AttributeValue getInheritedOutputValue(int index) const; }; +/// Extends the basic visitation to include state required to visit different metavoxels. +class DifferentMetavoxelVisitation : public MetavoxelVisitation { +public: + + QVector compareNodes; + + DifferentMetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, + const QVector& inputNodes, const QVector& outputNodes, + const MetavoxelInfo& info, const QVector& compareNodes); +}; + /// An object that spans multiple octree cells. class Spanner : public SharedObject { Q_OBJECT From 64c3a623f4e7e02565a2c34db090b79dcc439ed5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 16 Jul 2014 17:56:22 -0700 Subject: [PATCH 02/24] Working on point buffer building. --- interface/src/MetavoxelSystem.cpp | 56 +++++++++++++++++++ interface/src/MetavoxelSystem.h | 36 ++++++++++++ libraries/metavoxels/src/AttributeRegistry.h | 23 ++++++++ .../metavoxels/src/MetavoxelClientManager.cpp | 9 +++ .../metavoxels/src/MetavoxelClientManager.h | 4 +- 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 66933643ae..4c8df2f624 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -45,6 +45,7 @@ void MetavoxelSystem::init() { } _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); _buffer.create(); + _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute()); } MetavoxelLOD MetavoxelSystem::getLOD() const { @@ -209,11 +210,66 @@ int MetavoxelSystemClient::parseData(const QByteArray& packet) { return packet.size(); } +class BufferBuilder : public MetavoxelVisitor { +public: + + BufferBuilder(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +BufferBuilder::BufferBuilder(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << + AttributeRegistry::getInstance()->getNormalAttribute(), QVector(), lod) { +} + +int BufferBuilder::visit(MetavoxelInfo& info) { + if (info.isLeaf) { + + return STOP_RECURSION; + } + return DEFAULT_ORDER; +} + +void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { + BufferBuilder builder(_remoteDataLOD); + _data.guideToDifferent(oldData, builder); +} + void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { NodeList::getInstance()->writeDatagram(data, _node); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } +PointBuffer::PointBuffer(const QOpenGLBuffer& buffer, const QVector& offsets, int lastLeafCount) : + _buffer(buffer), + _offsets(offsets), + _lastLeafCount(lastLeafCount) { +} + +void PointBuffer::render(int level) { + _buffer.bind(); + + BufferPoint* point = 0; + glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex); + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); + glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); + + int nextLevel = level + 1; + if (nextLevel >= _offsets.size()) { + glDrawArrays(GL_POINTS, _offsets.last() - _lastLeafCount, _lastLeafCount); + + } else { + int first = _offsets.at(level); + glDrawArrays(GL_POINTS, first, _offsets.at(nextLevel) - first); + } + _buffer.release(); +} + +PointBufferAttribute::PointBufferAttribute() : + SharedPointerAttribute("pointBuffer") { +} + static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; glClipPlane(plane, coefficients); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index f3a4fd4412..6d14bd0f56 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -80,6 +80,7 @@ private: SimulateVisitor _simulateVisitor; RenderVisitor _renderVisitor; QOpenGLBuffer _buffer; + AttributePointer _pointBufferAttribute; }; /// A client session associated with a single server. @@ -94,9 +95,44 @@ public: protected: + virtual void dataChanged(const MetavoxelData& oldData); virtual void sendDatagram(const QByteArray& data); }; +/// Describes contents of a point in a point buffer. +class BufferPoint { +public: + glm::vec4 vertex; + quint8 color[3]; + quint8 normal[3]; +}; + +/// Contains the information necessary to render a group of points at variable detail levels. +class PointBuffer { +public: + + PointBuffer(const QOpenGLBuffer& buffer, const QVector& offsets, int lastLeafCount); + + void render(int level); + +private: + + QOpenGLBuffer _buffer; + QVector _offsets; + int _lastLeafCount; +}; + +typedef QSharedPointer PointBufferPointer; + +/// A client-side attribute that stores point buffers. +class PointBufferAttribute : public SharedPointerAttribute { + Q_OBJECT + +public: + + Q_INVOKABLE PointBufferAttribute(); +}; + /// Base class for spanner renderers; provides clipping. class ClippedRenderer : public SpannerRenderer { Q_OBJECT diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 23e3c1fa97..1e3420e69e 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -404,6 +404,29 @@ public: virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; +/// Template for attributes that take the form of shared pointers. +template class SharedPointerAttribute : public InlineAttribute > { +public: + + SharedPointerAttribute(const QString& name, const QSharedPointer& defaultValue = QSharedPointer()) : + InlineAttribute >(name, defaultValue) { } + + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; +}; + +template inline bool SharedPointerAttribute::merge( + void*& parent, void* children[], bool postRead) const { + QSharedPointer firstChild = decodeInline >(children[0]); + for (int i = 1; i < Attribute::MERGE_COUNT; i++) { + if (firstChild != decodeInline >(children[i])) { + *(QSharedPointer*)&parent = InlineAttribute >::_defaultValue; + return false; + } + } + *(QSharedPointer*)&parent = firstChild; + return true; +} + /// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject). class SharedObjectAttribute : public InlineAttribute { Q_OBJECT diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 0b9e3f3d8c..25f8c70d61 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -124,13 +124,19 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) } else { // apply immediately to local tree + MetavoxelData oldData = _data; edit.apply(_data, _sequencer.getWeakSharedObjectHash()); + dataChanged(oldData); // start sending it out _sequencer.sendHighPriorityMessage(QVariant::fromValue(edit)); } } +void MetavoxelClient::dataChanged(const MetavoxelData& oldData) { + // nothing by default +} + void MetavoxelClient::writeUpdateMessage(Bitstream& out) { ClientStateMessage state = { _manager->getLOD() }; out << QVariant::fromValue(state); @@ -152,12 +158,15 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { in.reset(); } // copy to local and reapply local edits + MetavoxelData oldData = _data; _data = _remoteData; foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) { if (message.data.userType() == MetavoxelEditMessage::Type) { message.data.value().apply(_data, _sequencer.getWeakSharedObjectHash()); } } + dataChanged(oldData); + } else if (userType == MetavoxelDeltaPendingMessage::Type) { // check the id to make sure this is not a delta we've already processed int id = message.value().id; diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 191af794f7..fe1a4c09bb 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -63,14 +63,14 @@ public: protected: + virtual void dataChanged(const MetavoxelData& oldData); + virtual void writeUpdateMessage(Bitstream& out); virtual void handleMessage(const QVariant& message, Bitstream& in); virtual PacketRecord* maybeCreateSendRecord() const; virtual PacketRecord* maybeCreateReceiveRecord() const; -private: - MetavoxelClientManager* _manager; MetavoxelData _data; MetavoxelData _remoteData; From 28dbb60e7e83281d5adbdcec157033ec426b1c3a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 16 Jul 2014 19:14:38 -0700 Subject: [PATCH 03/24] Working on post-visit callback. --- interface/src/MetavoxelSystem.cpp | 17 +++++++++++++++ interface/src/MetavoxelSystem.h | 4 ++++ libraries/metavoxels/src/MetavoxelData.cpp | 24 ++++++++++++++++++++++ libraries/metavoxels/src/MetavoxelData.h | 8 +++++++- 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 4c8df2f624..701b3b768c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -270,6 +270,23 @@ PointBufferAttribute::PointBufferAttribute() : SharedPointerAttribute("pointBuffer") { } +MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const { + return new MetavoxelNode(value, original); +} + +bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const { + for (int i = 0; i < MERGE_COUNT; i++) { + if (!decodeInline(children[i]).isNull()) { + return false; + } + } + return true; +} + +AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) const { + return AttributeValue(parentValue.getAttribute()); +} + static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; glClipPlane(plane, coefficients); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 6d14bd0f56..fa14a64601 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -131,6 +131,10 @@ class PointBufferAttribute : public SharedPointerAttribute { public: Q_INVOKABLE PointBufferAttribute(); + + virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const; + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; + virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; /// Base class for spanner renderers; provides clipping. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 208e9cf309..0ddde0afb0 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1263,6 +1263,10 @@ void MetavoxelVisitor::prepare() { // nothing by default } +bool MetavoxelVisitor::postVisit(MetavoxelInfo& info) { + return false; +} + SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, const QVector& spannerMasks, const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod), @@ -1470,6 +1474,16 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas value = node->getAttributeValue(value.getAttribute()); } } + if (visitation.visitor.postVisit(visitation.info)) { + for (int i = 0; i < visitation.outputNodes.size(); i++) { + OwnedAttributeValue& value = visitation.info.outputValues[i]; + if (!value.getAttribute()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + + } + } return true; } @@ -1606,6 +1620,16 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit value = node->getAttributeValue(value.getAttribute()); } } + if (visitation.visitor.postVisit(visitation.info)) { + for (int i = 0; i < visitation.outputNodes.size(); i++) { + OwnedAttributeValue& value = visitation.info.outputValues[i]; + if (!value.getAttribute()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + + } + } return true; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 3afd4c27bc..edff9da312 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -311,9 +311,15 @@ public: /// Visits a metavoxel. /// \param info the metavoxel data - /// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour + /// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour. + /// If child traversal is requested, postVisit will be called after we return from traversing the children and have merged + /// their values virtual int visit(MetavoxelInfo& info) = 0; + /// Called after we have visited all of a metavoxel's children. + /// \return whether or not any outputs were set in the info + virtual bool postVisit(MetavoxelInfo& info); + protected: QVector _inputs; From 06be03521992eb40552467a20cee0d50d43db45a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 17 Jul 2014 12:47:30 -0700 Subject: [PATCH 04/24] Allow post-visits to set output values. --- libraries/metavoxels/src/MetavoxelData.cpp | 36 +++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 0ddde0afb0..440cb93546 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1474,14 +1474,24 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas value = node->getAttributeValue(value.getAttribute()); } } - if (visitation.visitor.postVisit(visitation.info)) { + visitation.info.outputValues.swap(nextVisitation.info.outputValues); + bool changed = visitation.visitor.postVisit(visitation.info); + visitation.info.outputValues.swap(nextVisitation.info.outputValues); + if (changed) { for (int i = 0; i < visitation.outputNodes.size(); i++) { - OwnedAttributeValue& value = visitation.info.outputValues[i]; - if (!value.getAttribute()) { + const OwnedAttributeValue& newValue = nextVisitation.info.outputValues.at(i); + if (!newValue.getAttribute()) { continue; } + OwnedAttributeValue& value = visitation.info.outputValues[i]; MetavoxelNode*& node = visitation.outputNodes[i]; - + if (value.getAttribute()) { + node->setAttributeValue(value = newValue); + + } else if (!(node && node->isLeaf() && newValue.getAttribute()->equal( + newValue.getValue(), node->getAttributeValue()))) { + node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node); + } } } return true; @@ -1620,14 +1630,24 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit value = node->getAttributeValue(value.getAttribute()); } } - if (visitation.visitor.postVisit(visitation.info)) { + visitation.info.outputValues.swap(nextVisitation.info.outputValues); + bool changed = visitation.visitor.postVisit(visitation.info); + visitation.info.outputValues.swap(nextVisitation.info.outputValues); + if (changed) { for (int i = 0; i < visitation.outputNodes.size(); i++) { - OwnedAttributeValue& value = visitation.info.outputValues[i]; - if (!value.getAttribute()) { + const OwnedAttributeValue& newValue = nextVisitation.info.outputValues.at(i); + if (!newValue.getAttribute()) { continue; } + OwnedAttributeValue& value = visitation.info.outputValues[i]; MetavoxelNode*& node = visitation.outputNodes[i]; - + if (value.getAttribute()) { + node->setAttributeValue(value = newValue); + + } else if (!(node && node->isLeaf() && newValue.getAttribute()->equal( + newValue.getValue(), node->getAttributeValue()))) { + node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node); + } } } return true; From bc2441ac44dc083986bf60d4588e1a8037e0e03c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 17 Jul 2014 15:22:06 -0700 Subject: [PATCH 05/24] Let the visitor maintain a list of reusable visitations, rather than always allocating new ones on the stack. --- libraries/metavoxels/src/MetavoxelData.cpp | 140 +++++++++++---------- libraries/metavoxels/src/MetavoxelData.h | 35 +++--- 2 files changed, 91 insertions(+), 84 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 440cb93546..3792f5ec95 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -85,9 +85,9 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { // start with the root values/defaults (plus the guide attribute) const QVector& inputs = visitor.getInputs(); const QVector& outputs = visitor.getOutputs(); - MetavoxelVisitation firstVisitation(NULL, visitor, QVector(inputs.size() + 1), - QVector(outputs.size()), MetavoxelInfo(NULL, getMinimum(), _size, - QVector(inputs.size() + 1), QVector(outputs.size()))); + MetavoxelVisitation& firstVisitation = visitor.acquireVisitation(); + firstVisitation.info.minimum = getMinimum(); + firstVisitation.info.size = _size; for (int i = 0; i < inputs.size(); i++) { const AttributePointer& input = inputs.at(i); MetavoxelNode* node = _roots.value(input); @@ -120,7 +120,9 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { node->decrementReferenceCount(value.getAttribute()); _roots.remove(value.getAttribute()); } + value = AttributeValue(); } + visitor.releaseVisitation(); } void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { @@ -130,10 +132,10 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito // start with the root values/defaults (plus the guide attribute) const QVector& inputs = visitor.getInputs(); const QVector& outputs = visitor.getOutputs(); - DifferentMetavoxelVisitation firstVisitation(NULL, visitor, QVector(inputs.size() + 1), - QVector(outputs.size()), MetavoxelInfo(NULL, getMinimum(), _size, - QVector(inputs.size() + 1), QVector(outputs.size())), - QVector(inputs.size() + 1)); + MetavoxelVisitation& firstVisitation = visitor.acquireVisitation(); + firstVisitation.compareNodes.resize(inputs.size() + 1); + firstVisitation.info.minimum = getMinimum(); + firstVisitation.info.size = _size; bool allNodesSame = true; for (int i = 0; i < inputs.size(); i++) { const AttributePointer& input = inputs.at(i); @@ -152,6 +154,7 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito firstVisitation.compareNodes.last() = compareNode; allNodesSame &= (node == compareNode); if (allNodesSame) { + visitor.releaseVisitation(); return; } for (int i = 0; i < outputs.size(); i++) { @@ -176,7 +179,9 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito node->decrementReferenceCount(value.getAttribute()); _roots.remove(value.getAttribute()); } + value = AttributeValue(); } + visitor.releaseVisitation(); } typedef void (*SpannerUpdateFunction)(SharedObjectSet& set, const SharedObjectPointer& object); @@ -1176,16 +1181,13 @@ void MetavoxelNode::countNodes(const AttributePointer& attribute, const glm::vec } } -MetavoxelInfo::MetavoxelInfo(MetavoxelInfo* parentInfo, const glm::vec3& minimum, float size, - const QVector& inputValues, const QVector& outputValues, - bool isLODLeaf, bool isLeaf) : +MetavoxelInfo::MetavoxelInfo(MetavoxelInfo* parentInfo, int inputValuesSize, int outputValuesSize) : parentInfo(parentInfo), - minimum(minimum), - size(size), - inputValues(inputValues), - outputValues(outputValues), - isLODLeaf(isLODLeaf), - isLeaf(isLeaf) { + inputValues(inputValuesSize), + outputValues(outputValuesSize) { +} + +MetavoxelInfo::MetavoxelInfo() { } int MetavoxelVisitor::encodeOrder(int first, int second, int third, int fourth, @@ -1245,7 +1247,8 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, _inputs(inputs), _outputs(outputs), _lod(lod), - _minimumLODThresholdMultiplier(FLT_MAX) { + _minimumLODThresholdMultiplier(FLT_MAX), + _depth(-1) { // find the minimum LOD threshold multiplier over all attributes foreach (const AttributePointer& attribute, _inputs) { @@ -1267,6 +1270,14 @@ bool MetavoxelVisitor::postVisit(MetavoxelInfo& info) { return false; } +MetavoxelVisitation& MetavoxelVisitor::acquireVisitation() { + if (++_depth >= _visitations.size()) { + _visitations.append(MetavoxelVisitation(_depth == 0 ? NULL : &_visitations[_depth - 1], + this, _inputs.size() + 1, _outputs.size())); + } + return _visitations[_depth]; +} + SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, const QVector& spannerMasks, const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod), @@ -1398,7 +1409,7 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { return STOP_RECURSION; } -bool MetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visitation) { +bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { return guide(visitation); } @@ -1406,10 +1417,8 @@ DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) { - MetavoxelVisitation nextVisitation(&visitation, visitation.visitor, QVector(visitation.inputNodes.size()), - QVector(visitation.outputNodes.size()), MetavoxelInfo(&visitation.info, glm::vec3(), - visitation.info.size * 0.5f, QVector(visitation.inputNodes.size()), - QVector(visitation.outputNodes.size()))); + MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); + nextVisitation.info.size = visitation.info.size * 0.5f; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { // the encoded order tells us the child indices for each iteration int index = encodedOrder & ORDER_ELEMENT_MASK; @@ -1425,12 +1434,13 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); MetavoxelNode* child = (node && (visitation.info.size >= lodBase * - visitation.visitor.getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; + 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); if (!static_cast(nextVisitation.info.inputValues.last().getInlineValue< SharedObjectPointer>().data())->guide(nextVisitation)) { + visitation.visitor->releaseVisitation(); return false; } for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { @@ -1474,12 +1484,13 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas value = node->getAttributeValue(value.getAttribute()); } } + visitation.visitor->releaseVisitation(); visitation.info.outputValues.swap(nextVisitation.info.outputValues); - bool changed = visitation.visitor.postVisit(visitation.info); + bool changed = visitation.visitor->postVisit(visitation.info); visitation.info.outputValues.swap(nextVisitation.info.outputValues); if (changed) { for (int i = 0; i < visitation.outputNodes.size(); i++) { - const OwnedAttributeValue& newValue = nextVisitation.info.outputValues.at(i); + OwnedAttributeValue& newValue = nextVisitation.info.outputValues[i]; if (!newValue.getAttribute()) { continue; } @@ -1492,6 +1503,7 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas newValue.getValue(), node->getAttributeValue()))) { node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node); } + newValue = AttributeValue(); } } return true; @@ -1499,11 +1511,11 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier()); + float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) * + visitation.visitor->getLOD().threshold; + visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves(); - int encodedOrder = visitation.visitor.visit(visitation.info); + int encodedOrder = visitation.visitor->visit(visitation.info); if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { return false; } @@ -1523,13 +1535,13 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { return (encodedOrder == MetavoxelVisitor::STOP_RECURSION) || defaultGuideToChildren(visitation, lodBase, encodedOrder); } -bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visitation) { +bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier()); + float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) * + visitation.visitor->getLOD().threshold; + visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves(); - int encodedOrder = visitation.visitor.visit(visitation.info); + int encodedOrder = visitation.visitor->visit(visitation.info); if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { return false; } @@ -1552,12 +1564,9 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit if (encodedOrder & MetavoxelVisitor::ALL_NODES) { return defaultGuideToChildren(visitation, lodBase, encodedOrder); } - DifferentMetavoxelVisitation nextVisitation(&visitation, visitation.visitor, - QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()), - MetavoxelInfo(&visitation.info, glm::vec3(), visitation.info.size * 0.5f, - QVector(visitation.inputNodes.size()), - QVector(visitation.outputNodes.size())), - QVector(visitation.inputNodes.size())); + MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); + nextVisitation.compareNodes.resize(visitation.compareNodes.size()); + nextVisitation.info.size = visitation.info.size * 0.5f; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { // the encoded order tells us the child indices for each iteration int index = encodedOrder & ORDER_ELEMENT_MASK; @@ -1581,12 +1590,13 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); MetavoxelNode* child = (node && (visitation.info.size >= lodBase * - visitation.visitor.getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; + 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); if (!static_cast(nextVisitation.info.inputValues.last().getInlineValue< SharedObjectPointer>().data())->guideToDifferent(nextVisitation)) { + visitation.visitor->releaseVisitation(); return false; } for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { @@ -1630,12 +1640,13 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit value = node->getAttributeValue(value.getAttribute()); } } + visitation.visitor->releaseVisitation(); visitation.info.outputValues.swap(nextVisitation.info.outputValues); - bool changed = visitation.visitor.postVisit(visitation.info); + bool changed = visitation.visitor->postVisit(visitation.info); visitation.info.outputValues.swap(nextVisitation.info.outputValues); if (changed) { for (int i = 0; i < visitation.outputNodes.size(); i++) { - const OwnedAttributeValue& newValue = nextVisitation.info.outputValues.at(i); + OwnedAttributeValue& newValue = nextVisitation.info.outputValues[i]; if (!newValue.getAttribute()) { continue; } @@ -1648,6 +1659,7 @@ bool DefaultMetavoxelGuide::guideToDifferent(DifferentMetavoxelVisitation& visit newValue.getValue(), node->getAttributeValue()))) { node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node); } + newValue = AttributeValue(); } } return true; @@ -1685,12 +1697,12 @@ static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* QScriptValue ScriptedMetavoxelGuide::getInputs(QScriptContext* context, QScriptEngine* engine) { ScriptedMetavoxelGuide* guide = static_cast(context->callee().data().toVariant().value()); - return getAttributes(engine, guide, guide->_visitation->visitor.getInputs()); + return getAttributes(engine, guide, guide->_visitation->visitor->getInputs()); } QScriptValue ScriptedMetavoxelGuide::getOutputs(QScriptContext* context, QScriptEngine* engine) { ScriptedMetavoxelGuide* guide = static_cast(context->callee().data().toVariant().value()); - return getAttributes(engine, guide, guide->_visitation->visitor.getOutputs()); + return getAttributes(engine, guide, guide->_visitation->visitor->getOutputs()); } QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) { @@ -1699,14 +1711,16 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin // start with the basics, including inherited attribute values QScriptValue infoValue = context->argument(0); QScriptValue minimum = infoValue.property(guide->_minimumHandle); - MetavoxelInfo info( - NULL, glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()), - (float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues, - guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool()); + MetavoxelInfo info(NULL, 0, 0); + info.inputValues = guide->_visitation->info.inputValues; + info.outputValues = guide->_visitation->info.outputValues; + info.minimum = glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()); + info.size = (float)infoValue.property(guide->_sizeHandle).toNumber(); + info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool(); // extract and convert the values provided by the script QScriptValue inputValues = infoValue.property(guide->_inputValuesHandle); - const QVector& inputs = guide->_visitation->visitor.getInputs(); + const QVector& inputs = guide->_visitation->visitor->getInputs(); for (int i = 0; i < inputs.size(); i++) { QScriptValue attributeValue = inputValues.property(i); if (attributeValue.isValid()) { @@ -1715,7 +1729,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin } } - QScriptValue result = guide->_visitation->visitor.visit(info); + QScriptValue result = guide->_visitation->visitor->visit(info); // destroy any created values for (int i = 0; i < inputs.size(); i++) { @@ -1788,13 +1802,16 @@ void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) { _minimumHandle = QScriptString(); } -MetavoxelVisitation::MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, - const QVector& inputNodes, const QVector& outputNodes, const MetavoxelInfo& info) : +MetavoxelVisitation::MetavoxelVisitation(MetavoxelVisitation* previous, + MetavoxelVisitor* visitor, int inputNodesSize, int outputNodesSize) : previous(previous), visitor(visitor), - inputNodes(inputNodes), - outputNodes(outputNodes), - info(info) { + inputNodes(inputNodesSize), + outputNodes(outputNodesSize), + info(previous ? &previous->info : NULL, inputNodesSize, outputNodesSize) { +} + +MetavoxelVisitation::MetavoxelVisitation() { } bool MetavoxelVisitation::allInputNodesLeaves() const { @@ -1810,17 +1827,10 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { for (const MetavoxelVisitation* visitation = previous; visitation; visitation = visitation->previous) { MetavoxelNode* node = visitation->outputNodes.at(index); if (node) { - return node->getAttributeValue(visitor.getOutputs().at(index)); + return node->getAttributeValue(visitor->getOutputs().at(index)); } } - return AttributeValue(visitor.getOutputs().at(index)); -} - -DifferentMetavoxelVisitation::DifferentMetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, - const QVector& inputNodes, const QVector& outputNodes, - const MetavoxelInfo& info, const QVector& compareNodes) : - MetavoxelVisitation(previous, visitor, inputNodes, outputNodes, info), - compareNodes(compareNodes) { + return AttributeValue(visitor->getOutputs().at(index)); } const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f; diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index edff9da312..17bbd6ce82 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -27,7 +27,6 @@ class QScriptContext; -class DifferentMetavoxelVisitation; class MetavoxelNode; class MetavoxelVisitation; class MetavoxelVisitor; @@ -256,8 +255,8 @@ public: bool isLODLeaf; bool isLeaf; - MetavoxelInfo(MetavoxelInfo* parentInfo, const glm::vec3& minimum, float size, const QVector& inputValues, - const QVector& outputValues, bool isLODLeaf = false, bool isLeaf = false); + MetavoxelInfo(MetavoxelInfo* parentInfo, int inputValuesSize, int outputValuesSize); + MetavoxelInfo(); 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; } @@ -320,12 +319,20 @@ public: /// \return whether or not any outputs were set in the info virtual bool postVisit(MetavoxelInfo& info); + /// Acquires the next visitation, incrementing the depth. + MetavoxelVisitation& acquireVisitation(); + + /// Releases the current visitation, decrementing the depth. + void releaseVisitation() { _depth--; } + protected: QVector _inputs; QVector _outputs; MetavoxelLOD _lod; float _minimumLODThresholdMultiplier; + QList _visitations; + int _depth; }; /// Base class for visitors to spanners. @@ -409,7 +416,7 @@ public: /// Guides the specified visitor to the voxels that differ from a reference. /// \return true to keep going, false to short circuit the tour - virtual bool guideToDifferent(DifferentMetavoxelVisitation& visitation); + virtual bool guideToDifferent(MetavoxelVisitation& visitation); }; /// Guides visitors through the explicit content of the system. @@ -421,7 +428,7 @@ public: Q_INVOKABLE DefaultMetavoxelGuide(); virtual bool guide(MetavoxelVisitation& visitation); - virtual bool guideToDifferent(DifferentMetavoxelVisitation& visitation); + virtual bool guideToDifferent(MetavoxelVisitation& visitation); }; /// A temporary test guide that just makes the existing voxels throb with delight. @@ -485,29 +492,19 @@ class MetavoxelVisitation { public: MetavoxelVisitation* previous; - MetavoxelVisitor& visitor; + MetavoxelVisitor* visitor; QVector inputNodes; QVector outputNodes; + QVector compareNodes; MetavoxelInfo info; - MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, const QVector& inputNodes, - const QVector& outputNodes, const MetavoxelInfo& info); + MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor* visitor, int inputNodesSize, int outputNodesSize); + MetavoxelVisitation(); bool allInputNodesLeaves() const; AttributeValue getInheritedOutputValue(int index) const; }; -/// Extends the basic visitation to include state required to visit different metavoxels. -class DifferentMetavoxelVisitation : public MetavoxelVisitation { -public: - - QVector compareNodes; - - DifferentMetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor& visitor, - const QVector& inputNodes, const QVector& outputNodes, - const MetavoxelInfo& info, const QVector& compareNodes); -}; - /// An object that spans multiple octree cells. class Spanner : public SharedObject { Q_OBJECT From cda1a7f32a287ed302ccd9031b285f9196876d42 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Jul 2014 12:27:51 -0700 Subject: [PATCH 06/24] Working on optimized point rendering. --- interface/src/MetavoxelSystem.cpp | 31 +++++++++++++++++++++++++++++-- interface/src/MetavoxelSystem.h | 5 +++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 701b3b768c..ed6be89033 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -216,21 +216,48 @@ public: BufferBuilder(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); + virtual bool postVisit(MetavoxelInfo& info); + +private: + + QVector _depthPoints; }; BufferBuilder::BufferBuilder(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute(), QVector(), lod) { + AttributeRegistry::getInstance()->getNormalAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { } +const int ALPHA_RENDER_THRESHOLD = 0; + int BufferBuilder::visit(MetavoxelInfo& info) { + if (_depth >= _depthPoints.size()) { + _depthPoints.resize(_depth + 1); + } + QRgb color = info.inputValues.at(0).getInlineValue(); + quint8 alpha = qAlpha(color); + if (alpha <= ALPHA_RENDER_THRESHOLD) { + return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; + } + QRgb normal = info.inputValues.at(1).getInlineValue(); + BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; if (info.isLeaf) { - + _depthPoints[_depth].first.append(point); return STOP_RECURSION; } + _depthPoints[_depth].second.append(point); return DEFAULT_ORDER; } +const int BUFFER_LEAF_THRESHOLD = 1024; + +bool BufferBuilder::postVisit(MetavoxelInfo& info) { + return false; +} + void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { BufferBuilder builder(_remoteDataLOD); _data.guideToDifferent(oldData, builder); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index fa14a64601..0cf9b83e8a 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -32,6 +32,8 @@ public: MetavoxelSystem(); + const AttributePointer& getPointBufferAttribute() const { return _pointBufferAttribute; } + virtual void init(); virtual MetavoxelLOD getLOD() const; @@ -107,6 +109,9 @@ public: quint8 normal[3]; }; +typedef QVector BufferPointVector; +typedef QPair BufferPointVectorPair; + /// Contains the information necessary to render a group of points at variable detail levels. class PointBuffer { public: From 38f3f8039881da8be6667c9753f813e34c9f1c83 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Jul 2014 18:51:01 -0700 Subject: [PATCH 07/24] More work on point rendering. --- interface/src/MetavoxelSystem.cpp | 57 +++++++++++++++++--- interface/src/MetavoxelSystem.h | 6 +-- libraries/metavoxels/src/AttributeRegistry.h | 23 -------- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index ed6be89033..8b3564944b 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -225,13 +225,17 @@ private: BufferBuilder::BufferBuilder(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute(), QVector() << - Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { + AttributeRegistry::getInstance()->getNormalAttribute() << + Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { } const int ALPHA_RENDER_THRESHOLD = 0; int BufferBuilder::visit(MetavoxelInfo& info) { + if (info.inputValues.at(2).getInlineValue()) { + info.outputValues[0] = AttributeValue(_outputs.at(0)); + } if (_depth >= _depthPoints.size()) { _depthPoints.resize(_depth + 1); } @@ -252,10 +256,51 @@ int BufferBuilder::visit(MetavoxelInfo& info) { return DEFAULT_ORDER; } -const int BUFFER_LEAF_THRESHOLD = 1024; +const int BUFFER_LEVELS = 5; bool BufferBuilder::postVisit(MetavoxelInfo& info) { - return false; + if (_depth % BUFFER_LEVELS != 0) { + return false; + } + QVector offsets; + offsets.append(0); + int leafCount = 0; + int totalPoints = 0; + int lastDepth = qMin(_depth + BUFFER_LEVELS, _depthPoints.size()); + for (int i = _depth; i < lastDepth; i++) { + const BufferPointVectorPair& pair = _depthPoints.at(i); + offsets.append(totalPoints += ((leafCount += pair.first.size()) + pair.second.size())); + } + QOpenGLBuffer buffer; + buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + buffer.create(); + buffer.bind(); + buffer.allocate(totalPoints * sizeof(BufferPoint)); + int offset = 0; + for (int i = _depth; i < lastDepth; i++) { + // write the internal nodes from the current level + BufferPointVector& internal = _depthPoints[i].second; + int length = internal.size() * sizeof(BufferPoint); + buffer.write(offset, internal.constData(), length); + offset += length; + internal.clear(); + + // and the leaves from the top down + for (int j = _depth; j <= i; j++) { + const BufferPointVector& leaves = _depthPoints.at(j).first; + length = leaves.size() * sizeof(BufferPoint); + buffer.write(offset, leaves.constData(), length); + offset += length; + } + } + // clear the leaves now that we're done with them + for (int i = _depth; i < lastDepth; i++) { + _depthPoints[i].first.clear(); + } + buffer.release(); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + new PointBuffer(buffer, offsets, leafCount)))); + return true; } void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { @@ -294,7 +339,7 @@ void PointBuffer::render(int level) { } PointBufferAttribute::PointBufferAttribute() : - SharedPointerAttribute("pointBuffer") { + InlineAttribute("pointBuffer") { } MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const { @@ -303,7 +348,7 @@ MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& v bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const { for (int i = 0; i < MERGE_COUNT; i++) { - if (!decodeInline(children[i]).isNull()) { + if (decodeInline(children[i])) { return false; } } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 0cf9b83e8a..f882235fa2 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -113,7 +113,7 @@ typedef QVector BufferPointVector; typedef QPair BufferPointVectorPair; /// Contains the information necessary to render a group of points at variable detail levels. -class PointBuffer { +class PointBuffer : public QSharedData { public: PointBuffer(const QOpenGLBuffer& buffer, const QVector& offsets, int lastLeafCount); @@ -127,10 +127,10 @@ private: int _lastLeafCount; }; -typedef QSharedPointer PointBufferPointer; +typedef QExplicitlySharedDataPointer PointBufferPointer; /// A client-side attribute that stores point buffers. -class PointBufferAttribute : public SharedPointerAttribute { +class PointBufferAttribute : public InlineAttribute { Q_OBJECT public: diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 1e3420e69e..23e3c1fa97 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -404,29 +404,6 @@ public: virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; -/// Template for attributes that take the form of shared pointers. -template class SharedPointerAttribute : public InlineAttribute > { -public: - - SharedPointerAttribute(const QString& name, const QSharedPointer& defaultValue = QSharedPointer()) : - InlineAttribute >(name, defaultValue) { } - - virtual bool merge(void*& parent, void* children[], bool postRead = false) const; -}; - -template inline bool SharedPointerAttribute::merge( - void*& parent, void* children[], bool postRead) const { - QSharedPointer firstChild = decodeInline >(children[0]); - for (int i = 1; i < Attribute::MERGE_COUNT; i++) { - if (firstChild != decodeInline >(children[i])) { - *(QSharedPointer*)&parent = InlineAttribute >::_defaultValue; - return false; - } - } - *(QSharedPointer*)&parent = firstChild; - return true; -} - /// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject). class SharedObjectAttribute : public InlineAttribute { Q_OBJECT From dd7f3703e1e6dd7f89a82c249ac0e9eb93a30a2b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 21 Jul 2014 14:48:54 -0700 Subject: [PATCH 08/24] More work on point rendering. --- interface/src/MetavoxelSystem.cpp | 226 +++++++++--------- interface/src/MetavoxelSystem.h | 33 --- .../metavoxels/src/MetavoxelClientManager.cpp | 12 + .../metavoxels/src/MetavoxelClientManager.h | 2 + libraries/metavoxels/src/MetavoxelData.cpp | 134 ++++++----- libraries/metavoxels/src/MetavoxelData.h | 4 +- 6 files changed, 200 insertions(+), 211 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8b3564944b..c30976d83e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -29,11 +29,6 @@ REGISTER_META_OBJECT(StaticModelRenderer) ProgramObject MetavoxelSystem::_program; int MetavoxelSystem::_pointScaleLocation; -MetavoxelSystem::MetavoxelSystem() : - _simulateVisitor(_points), - _buffer(QOpenGLBuffer::VertexBuffer) { -} - void MetavoxelSystem::init() { MetavoxelClientManager::init(); @@ -41,10 +36,10 @@ void MetavoxelSystem::init() { _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); _program.link(); + _program.bind(); _pointScaleLocation = _program.uniformLocation("pointScale"); + _program.release(); } - _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); - _buffer.create(); _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute()); } @@ -55,21 +50,85 @@ MetavoxelLOD MetavoxelSystem::getLOD() const { BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); } +class SpannerSimulateVisitor : public SpannerVisitor { +public: + + SpannerSimulateVisitor(float deltaTime); + + virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); + +private: + + float _deltaTime; +}; + +SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime) : + SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), + QVector(), QVector(), QVector(), + Application::getInstance()->getMetavoxels()->getLOD()), + _deltaTime(deltaTime) { +} + +bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { + spanner->getRenderer()->simulate(_deltaTime); + return true; +} + void MetavoxelSystem::simulate(float deltaTime) { // update the clients - _points.clear(); - _simulateVisitor.setDeltaTime(deltaTime); - _simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection()); update(); - _buffer.bind(); - int bytes = _points.size() * sizeof(Point); - if (_buffer.size() < bytes) { - _buffer.allocate(_points.constData(), bytes); - } else { - _buffer.write(0, _points.constData(), bytes); + SpannerSimulateVisitor spannerSimulateVisitor(deltaTime); + guide(spannerSimulateVisitor); +} + +class PointBufferRenderVisitor : public MetavoxelVisitor { +public: + + PointBufferRenderVisitor(); + + virtual int visit(MetavoxelInfo& info); + +private: + + int _order; +}; + +PointBufferRenderVisitor::PointBufferRenderVisitor() : + MetavoxelVisitor(QVector() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), + QVector(), Application::getInstance()->getMetavoxels()->getLOD()), + _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { +} + +int PointBufferRenderVisitor::visit(MetavoxelInfo& info) { + PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); + if (buffer) { + buffer->render(1000); } - _buffer.release(); + if (info.isLeaf) { + return STOP_RECURSION; + } + return _order; +} + +class SpannerRenderVisitor : public SpannerVisitor { +public: + + SpannerRenderVisitor(); + + virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); +}; + +SpannerRenderVisitor::SpannerRenderVisitor() : + SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), + QVector() << AttributeRegistry::getInstance()->getSpannerMaskAttribute(), + QVector(), QVector(), Application::getInstance()->getMetavoxels()->getLOD(), + encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { +} + +bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { + spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize); + return true; } void MetavoxelSystem::render() { @@ -87,20 +146,14 @@ void MetavoxelSystem::render() { _program.setUniformValue(_pointScaleLocation, viewportDiagonal * Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); - _buffer.bind(); - - Point* pt = 0; - glVertexPointer(4, GL_FLOAT, sizeof(Point), &pt->vertex); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Point), &pt->color); - glNormalPointer(GL_BYTE, sizeof(Point), &pt->normal); - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - glDrawArrays(GL_POINTS, 0, _points.size()); + PointBufferRenderVisitor pointBufferRenderVisitor; + guide(pointBufferRenderVisitor); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); @@ -108,19 +161,10 @@ void MetavoxelSystem::render() { glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - _buffer.release(); - _program.release(); - foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - if (node->getType() == NodeType::MetavoxelServer) { - QMutexLocker locker(&node->getMutex()); - MetavoxelSystemClient* client = static_cast(node->getLinkedData()); - if (client) { - client->guide(_renderVisitor); - } - } - } + SpannerRenderVisitor spannerRenderVisitor; + guide(spannerRenderVisitor); } MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { @@ -129,74 +173,6 @@ MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { void MetavoxelSystem::updateClient(MetavoxelClient* client) { MetavoxelClientManager::updateClient(client); - client->guide(_simulateVisitor); -} - -MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector& points) : - SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector(), QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute() << - AttributeRegistry::getInstance()->getSpannerColorAttribute() << - AttributeRegistry::getInstance()->getSpannerNormalAttribute()), - _points(points) { -} - -bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { - spanner->getRenderer()->simulate(_deltaTime); - return true; -} - -int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { - SpannerVisitor::visit(info); - - if (!info.isLeaf) { - return _order; - } - QRgb color = info.inputValues.at(0).getInlineValue(); - QRgb normal = info.inputValues.at(1).getInlineValue(); - quint8 alpha = qAlpha(color); - if (!info.isLODLeaf) { - if (alpha > 0) { - Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - _points.append(point); - } - } else { - QRgb spannerColor = info.inputValues.at(2).getInlineValue(); - QRgb spannerNormal = info.inputValues.at(3).getInlineValue(); - quint8 spannerAlpha = qAlpha(spannerColor); - if (spannerAlpha > 0) { - if (alpha > 0) { - Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha }, - { quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } }; - _points.append(point); - - } else { - Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha }, - { quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } }; - _points.append(point); - } - } else if (alpha > 0) { - Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - _points.append(point); - } - } - return STOP_RECURSION; -} - -MetavoxelSystem::RenderVisitor::RenderVisitor() : - SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector() << AttributeRegistry::getInstance()->getSpannerMaskAttribute()) { -} - -bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { - spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize); - return true; } MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) : @@ -232,6 +208,9 @@ BufferBuilder::BufferBuilder(const MetavoxelLOD& lod) : const int ALPHA_RENDER_THRESHOLD = 0; +const int BUFFER_LEVELS = 5; +const int LAST_BUFFER_LEVEL = BUFFER_LEVELS - 1; + int BufferBuilder::visit(MetavoxelInfo& info) { if (info.inputValues.at(2).getInlineValue()) { info.outputValues[0] = AttributeValue(_outputs.at(0)); @@ -253,11 +232,9 @@ int BufferBuilder::visit(MetavoxelInfo& info) { return STOP_RECURSION; } _depthPoints[_depth].second.append(point); - return DEFAULT_ORDER; + return DEFAULT_ORDER | ((_depth % BUFFER_LEVELS) == LAST_BUFFER_LEVEL ? 0 : ALL_NODES); } -const int BUFFER_LEVELS = 5; - bool BufferBuilder::postVisit(MetavoxelInfo& info) { if (_depth % BUFFER_LEVELS != 0) { return false; @@ -305,7 +282,17 @@ bool BufferBuilder::postVisit(MetavoxelInfo& info) { void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { BufferBuilder builder(_remoteDataLOD); - _data.guideToDifferent(oldData, builder); + const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); + MetavoxelNode* oldRoot = oldData.getRoot(pointBufferAttribute); + if (oldRoot && oldData.getSize() == _data.getSize()) { + oldRoot->incrementReferenceCount(); + _data.setRoot(pointBufferAttribute, oldRoot); + _data.guideToDifferent(oldData, builder); + + } else { + _data.clear(pointBufferAttribute); + _data.guide(builder); + } } void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { @@ -320,6 +307,19 @@ PointBuffer::PointBuffer(const QOpenGLBuffer& buffer, const QVector& offset } void PointBuffer::render(int level) { + int first, count; + int nextLevel = level + 1; + if (nextLevel >= _offsets.size()) { + first = _offsets.last() - _lastLeafCount; + count = _lastLeafCount; + + } else { + first = _offsets.at(level); + count = _offsets.at(nextLevel) - first; + } + if (count == 0) { + return; + } _buffer.bind(); BufferPoint* point = 0; @@ -327,14 +327,8 @@ void PointBuffer::render(int level) { glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); - int nextLevel = level + 1; - if (nextLevel >= _offsets.size()) { - glDrawArrays(GL_POINTS, _offsets.last() - _lastLeafCount, _lastLeafCount); - - } else { - int first = _offsets.at(level); - glDrawArrays(GL_POINTS, first, _offsets.at(nextLevel) - first); - } + glDrawArrays(GL_POINTS, first, count); + _buffer.release(); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index f882235fa2..6557dc5018 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -30,8 +30,6 @@ class MetavoxelSystem : public MetavoxelClientManager { public: - MetavoxelSystem(); - const AttributePointer& getPointBufferAttribute() const { return _pointBufferAttribute; } virtual void init(); @@ -48,40 +46,9 @@ protected: private: - class Point { - public: - glm::vec4 vertex; - quint8 color[4]; - quint8 normal[3]; - }; - - class SimulateVisitor : public SpannerVisitor { - public: - SimulateVisitor(QVector& points); - void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; } - void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); } - virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); - virtual int visit(MetavoxelInfo& info); - - private: - QVector& _points; - float _deltaTime; - int _order; - }; - - class RenderVisitor : public SpannerVisitor { - public: - RenderVisitor(); - virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); - }; - static ProgramObject _program; static int _pointScaleLocation; - QVector _points; - SimulateVisitor _simulateVisitor; - RenderVisitor _renderVisitor; - QOpenGLBuffer _buffer; AttributePointer _pointBufferAttribute; }; diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 25f8c70d61..d1ea3021a6 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -103,6 +103,18 @@ void MetavoxelClientManager::updateClient(MetavoxelClient* client) { client->update(); } +void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) { + 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->guide(visitor); + } + } + } +} + MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) : Endpoint(node, new PacketRecord(), new PacketRecord()), _manager(manager), diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index fe1a4c09bb..fcc8b31a1f 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -45,6 +45,8 @@ protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); virtual void updateClient(MetavoxelClient* client); + + void guide(MetavoxelVisitor& visitor); }; /// Base class for metavoxel clients. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 3792f5ec95..112012e37f 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -126,6 +126,16 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { } void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { + // if the other data is smaller, we need to expand it to compare + const MetavoxelData* expandedOther = &other; + if (_size > other._size) { + MetavoxelData* expanded = new MetavoxelData(other); + while (expanded->_size < _size) { + expanded->expand(); + } + expandedOther = expanded; + } + // let the visitor know we're about to begin a tour visitor.prepare(); @@ -142,7 +152,7 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito MetavoxelNode* node = _roots.value(input); firstVisitation.inputNodes[i] = node; firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(input) : input; - MetavoxelNode* compareNode = other._roots.value(input); + MetavoxelNode* compareNode = expandedOther->_roots.value(input); firstVisitation.compareNodes[i] = compareNode; allNodesSame &= (node == compareNode); } @@ -150,38 +160,41 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito MetavoxelNode* node = _roots.value(guideAttribute); firstVisitation.inputNodes.last() = node; firstVisitation.info.inputValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute; - MetavoxelNode* compareNode = other._roots.value(guideAttribute); + MetavoxelNode* compareNode = expandedOther->_roots.value(guideAttribute); firstVisitation.compareNodes.last() = compareNode; allNodesSame &= (node == compareNode); - if (allNodesSame) { - visitor.releaseVisitation(); - return; - } - for (int i = 0; i < outputs.size(); i++) { - MetavoxelNode* node = _roots.value(outputs.at(i)); - firstVisitation.outputNodes[i] = node; - } - static_cast(firstVisitation.info.inputValues.last().getInlineValue< - SharedObjectPointer>().data())->guideToDifferent(firstVisitation); - for (int i = 0; i < outputs.size(); i++) { - OwnedAttributeValue& value = firstVisitation.info.outputValues[i]; - if (!value.getAttribute()) { - continue; + if (!allNodesSame) { + for (int i = 0; i < outputs.size(); i++) { + MetavoxelNode* node = _roots.value(outputs.at(i)); + firstVisitation.outputNodes[i] = node; } - // replace the old node with the new - MetavoxelNode*& node = _roots[value.getAttribute()]; - if (node) { - node->decrementReferenceCount(value.getAttribute()); + static_cast(firstVisitation.info.inputValues.last().getInlineValue< + SharedObjectPointer>().data())->guideToDifferent(firstVisitation); + for (int i = 0; i < outputs.size(); i++) { + OwnedAttributeValue& value = firstVisitation.info.outputValues[i]; + if (!value.getAttribute()) { + continue; + } + // replace the old node with the new + MetavoxelNode*& node = _roots[value.getAttribute()]; + if (node) { + node->decrementReferenceCount(value.getAttribute()); + } + node = firstVisitation.outputNodes.at(i); + if (node->isLeaf() && value.isDefault()) { + // immediately remove the new node if redundant + node->decrementReferenceCount(value.getAttribute()); + _roots.remove(value.getAttribute()); + } + value = AttributeValue(); } - node = firstVisitation.outputNodes.at(i); - if (node->isLeaf() && value.isDefault()) { - // immediately remove the new node if redundant - node->decrementReferenceCount(value.getAttribute()); - _roots.remove(value.getAttribute()); - } - value = AttributeValue(); } visitor.releaseVisitation(); + + // delete the expanded other if we had to expand + if (expandedOther != &other) { + delete expandedOther; + } } typedef void (*SpannerUpdateFunction)(SharedObjectSet& set, const SharedObjectPointer& object); @@ -1279,10 +1292,12 @@ MetavoxelVisitation& MetavoxelVisitor::acquireVisitation() { } SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, const QVector& spannerMasks, - const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : + const QVector& inputs, const QVector& outputs, + const MetavoxelLOD& lod, int order) : MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod), _spannerInputCount(spannerInputs.size()), - _spannerMaskCount(spannerMasks.size()) { + _spannerMaskCount(spannerMasks.size()), + _order(order) { } void SpannerVisitor::prepare() { @@ -1300,7 +1315,7 @@ int SpannerVisitor::visit(MetavoxelInfo& info) { } } if (!info.isLeaf) { - return DEFAULT_ORDER; + return _order; } for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) { float maskValue = info.inputValues.at(i).getInlineValue(); @@ -1416,7 +1431,32 @@ bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } -static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) { +bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); + visitation.info.isLeaf = visitation.info.isLODLeaf || 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()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { + // "set" to same value; disregard + value = AttributeValue(); + } else { + node = value.getAttribute()->createMetavoxelNode(value, node); + } + } + if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { + return true; + } MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.info.size = visitation.info.size * 0.5f; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { @@ -1509,32 +1549,6 @@ static bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBas return true; } -bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); - visitation.info.isLeaf = visitation.info.isLODLeaf || 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()) { - continue; - } - MetavoxelNode*& node = visitation.outputNodes[i]; - if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { - // "set" to same value; disregard - value = AttributeValue(); - } else { - node = value.getAttribute()->createMetavoxelNode(value, node); - } - } - return (encodedOrder == MetavoxelVisitor::STOP_RECURSION) || defaultGuideToChildren(visitation, lodBase, encodedOrder); -} - bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { // 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()) * @@ -1561,9 +1575,7 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { return true; } - if (encodedOrder & MetavoxelVisitor::ALL_NODES) { - return defaultGuideToChildren(visitation, lodBase, encodedOrder); - } + bool onlyVisitDifferent = !(encodedOrder & MetavoxelVisitor::ALL_NODES); MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.compareNodes.resize(visitation.compareNodes.size()); nextVisitation.info.size = visitation.info.size * 0.5f; @@ -1571,7 +1583,7 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { // the encoded order tells us the child indices for each iteration int index = encodedOrder & ORDER_ELEMENT_MASK; encodedOrder >>= ORDER_ELEMENT_BITS; - bool allNodesSame = true; + bool allNodesSame = onlyVisitDifferent; for (int j = 0; j < visitation.inputNodes.size(); j++) { MetavoxelNode* node = visitation.inputNodes.at(j); const AttributeValue& parentValue = visitation.info.inputValues.at(j); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 17bbd6ce82..1944090a38 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -343,7 +343,8 @@ public: const QVector& spannerMasks = QVector(), const QVector& inputs = QVector(), const QVector& outputs = QVector(), - const MetavoxelLOD& lod = MetavoxelLOD()); + const MetavoxelLOD& lod = MetavoxelLOD(), + int order = DEFAULT_ORDER); /// Visits a spanner (or part thereof). /// \param clipSize the size of the clip volume, or zero if unclipped @@ -357,6 +358,7 @@ protected: int _spannerInputCount; int _spannerMaskCount; + int _order; }; /// Base class for ray intersection visitors. From 0ddd3e650cf6b792d4281d7332bb203fa9498457 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 21 Jul 2014 19:00:13 -0700 Subject: [PATCH 09/24] More point bits (trying a different tack). --- .../src/metavoxels/MetavoxelServer.cpp | 12 ++ .../src/metavoxels/MetavoxelServer.h | 2 + .../resources/shaders/metavoxel_point.vert | 2 +- interface/src/MetavoxelSystem.cpp | 120 +++++++++++++++++- interface/src/MetavoxelSystem.h | 43 ++++--- libraries/metavoxels/src/Endpoint.cpp | 2 +- .../metavoxels/src/MetavoxelClientManager.cpp | 23 +++- .../metavoxels/src/MetavoxelClientManager.h | 3 +- 8 files changed, 179 insertions(+), 28 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 598d8ea722..eed0f3a226 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -44,6 +44,7 @@ void MetavoxelServer::run() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&))); + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteSession(const SharedNodePointer&))); _lastSend = QDateTime::currentMSecsSinceEpoch(); _sendTimer.start(SEND_INTERVAL); @@ -96,6 +97,17 @@ void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) { } } +void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) { + if (node->getType() == NodeType::Agent) { + QMutexLocker locker(&node->getMutex()); + MetavoxelSession* session = static_cast(node->getLinkedData()); + if (session) { + node->setLinkedData(NULL); + session->deleteLater(); + } + } +} + void MetavoxelServer::sendDeltas() { // send deltas for all sessions foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 9ed765f65f..42694b03bf 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -21,6 +21,7 @@ class MetavoxelEditMessage; class MetavoxelPersister; +class MetavoxelSender; class MetavoxelSession; /// Maintains a shared metavoxel system, accepting change requests and broadcasting updates. @@ -46,6 +47,7 @@ public: private slots: void maybeAttachSession(const SharedNodePointer& node); + void maybeDeleteSession(const SharedNodePointer& node); void sendDeltas(); private: diff --git a/interface/resources/shaders/metavoxel_point.vert b/interface/resources/shaders/metavoxel_point.vert index fa585be099..1a4a4c56ce 100644 --- a/interface/resources/shaders/metavoxel_point.vert +++ b/interface/resources/shaders/metavoxel_point.vert @@ -18,7 +18,7 @@ void main(void) { // standard diffuse lighting gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb + gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))), - gl_Color.a); + 0.0); // extract the first three components of the vertex for position gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index c30976d83e..2b3528b1b3 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -26,6 +26,8 @@ REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) +static int bufferPointVectorMetaTypeId = qRegisterMetaType(); + ProgramObject MetavoxelSystem::_program; int MetavoxelSystem::_pointScaleLocation; @@ -152,8 +154,22 @@ void MetavoxelSystem::render() { glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - PointBufferRenderVisitor pointBufferRenderVisitor; - guide(pointBufferRenderVisitor); + glDisable(GL_BLEND); + + //PointBufferRenderVisitor pointBufferRenderVisitor; + //guide(pointBufferRenderVisitor); + + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::MetavoxelServer) { + QMutexLocker locker(&node->getMutex()); + MetavoxelSystemClient* client = static_cast(node->getLinkedData()); + if (client) { + client->render(); + } + } + } + + glEnable(GL_BLEND); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); @@ -176,7 +192,35 @@ void MetavoxelSystem::updateClient(MetavoxelClient* client) { } MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) : - MetavoxelClient(node, system) { + MetavoxelClient(node, system), + _pointCount(0) { + + _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + _buffer.create(); +} + +void MetavoxelSystemClient::render() { + _buffer.bind(); + + BufferPoint* point = 0; + glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex); + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); + glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); + + glDrawArrays(GL_POINTS, 0, _pointCount); + + _buffer.release(); +} + +void MetavoxelSystemClient::setPoints(const BufferPointVector& points) { + qint64 now = QDateTime::currentMSecsSinceEpoch(); + _buffer.bind(); + _buffer.allocate(points.constData(), points.size() * sizeof(BufferPoint)); + _buffer.release(); + _pointCount = points.size(); + qDebug() << "upload" << (QDateTime::currentMSecsSinceEpoch() - now); + qDebug() << _pointCount; + } int MetavoxelSystemClient::parseData(const QByteArray& packet) { @@ -280,8 +324,73 @@ bool BufferBuilder::postVisit(MetavoxelInfo& info) { return true; } +class PointCollector : public MetavoxelVisitor { +public: + + QVector points; + + PointCollector(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +PointCollector::PointCollector(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << + AttributeRegistry::getInstance()->getNormalAttribute(), QVector(), lod) { +} + +int PointCollector::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + QRgb color = info.inputValues.at(0).getInlineValue(); + quint8 alpha = qAlpha(color); + if (alpha <= ALPHA_RENDER_THRESHOLD) { + return STOP_RECURSION; + } + QRgb normal = info.inputValues.at(1).getInlineValue(); + BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + points.append(point); + return STOP_RECURSION; +} + +/// Builds a point buffer. +class PointBufferBuilder : public QRunnable { +public: + + PointBufferBuilder(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelLOD& lod); + + virtual void run(); + +private: + + QWeakPointer _node; + MetavoxelData _data; + MetavoxelLOD _lod; +}; + +PointBufferBuilder::PointBufferBuilder(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelLOD& lod) : + _node(node), + _data(data), + _lod(lod) { +} + +void PointBufferBuilder::run() { + SharedNodePointer node = _node; + if (!node) { + return; + } + qint64 now = QDateTime::currentMSecsSinceEpoch(); + PointCollector collector(_lod); + _data.guide(collector); + QMetaObject::invokeMethod(node->getLinkedData(), "setPoints", Q_ARG(const BufferPointVector&, collector.points)); + qDebug() << "collect" << (QDateTime::currentMSecsSinceEpoch() - now); +} + void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { - BufferBuilder builder(_remoteDataLOD); + /* BufferBuilder builder(_remoteDataLOD); const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); MetavoxelNode* oldRoot = oldData.getRoot(pointBufferAttribute); if (oldRoot && oldData.getSize() == _data.getSize()) { @@ -292,7 +401,8 @@ void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { } else { _data.clear(pointBufferAttribute); _data.guide(builder); - } + } */ + QThreadPool::globalInstance()->start(new PointBufferBuilder(_node, _data, _remoteDataLOD)); } void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 6557dc5018..afbfd9444f 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -52,22 +52,6 @@ private: AttributePointer _pointBufferAttribute; }; -/// A client session associated with a single server. -class MetavoxelSystemClient : public MetavoxelClient { - Q_OBJECT - -public: - - MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system); - - virtual int parseData(const QByteArray& packet); - -protected: - - virtual void dataChanged(const MetavoxelData& oldData); - virtual void sendDatagram(const QByteArray& data); -}; - /// Describes contents of a point in a point buffer. class BufferPoint { public: @@ -79,6 +63,33 @@ public: typedef QVector BufferPointVector; typedef QPair BufferPointVectorPair; +Q_DECLARE_METATYPE(BufferPointVector) + +/// A client session associated with a single server. +class MetavoxelSystemClient : public MetavoxelClient { + Q_OBJECT + +public: + + MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system); + + void render(); + + Q_INVOKABLE void setPoints(const BufferPointVector& points); + + virtual int parseData(const QByteArray& packet); + +protected: + + virtual void dataChanged(const MetavoxelData& oldData); + virtual void sendDatagram(const QByteArray& data); + +private: + + QOpenGLBuffer _buffer; + int _pointCount; +}; + /// Contains the information necessary to render a group of points at variable detail levels. class PointBuffer : public QSharedData { public: diff --git a/libraries/metavoxels/src/Endpoint.cpp b/libraries/metavoxels/src/Endpoint.cpp index 420a52ef95..9672b245cc 100644 --- a/libraries/metavoxels/src/Endpoint.cpp +++ b/libraries/metavoxels/src/Endpoint.cpp @@ -49,7 +49,7 @@ void Endpoint::update() { int Endpoint::parseData(const QByteArray& packet) { // process through sequencer - _sequencer.receivedDatagram(packet); + QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); return packet.size(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index d1ea3021a6..af97551ade 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -16,6 +16,7 @@ void MetavoxelClientManager::init() { connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&))); + connect(NodeList::getInstance(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteClient(const SharedNodePointer&))); } void MetavoxelClientManager::update() { @@ -95,6 +96,17 @@ void MetavoxelClientManager::maybeAttachClient(const SharedNodePointer& node) { } } +void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) { + if (node->getType() == NodeType::MetavoxelServer) { + QMutexLocker locker(&node->getMutex()); + MetavoxelClient* client = static_cast(node->getLinkedData()); + if (client) { + node->setLinkedData(NULL); + client->deleteLater(); + } + } +} + MetavoxelClient* MetavoxelClientManager::createClient(const SharedNodePointer& node) { return new MetavoxelClient(node, this); } @@ -138,8 +150,10 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) // apply immediately to local tree MetavoxelData oldData = _data; edit.apply(_data, _sequencer.getWeakSharedObjectHash()); - dataChanged(oldData); - + if (_data != oldData) { + dataChanged(oldData); + } + // start sending it out _sequencer.sendHighPriorityMessage(QVariant::fromValue(edit)); } @@ -177,8 +191,9 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { message.data.value().apply(_data, _sequencer.getWeakSharedObjectHash()); } } - dataChanged(oldData); - + if (_data != oldData) { + dataChanged(oldData); + } } else if (userType == MetavoxelDeltaPendingMessage::Type) { // check the id to make sure this is not a delta we've already processed int id = message.value().id; diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index fcc8b31a1f..a915ba9c3c 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -40,7 +40,8 @@ public: private slots: void maybeAttachClient(const SharedNodePointer& node); - + void maybeDeleteClient(const SharedNodePointer& node); + protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); From 3ea7e7962273ea53fc004ab05581c5ca00a43dd3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 21 Jul 2014 20:03:50 -0700 Subject: [PATCH 10/24] Working on distributing metavoxel session handling over multiple threads. --- .../src/metavoxels/MetavoxelServer.cpp | 84 +++++++++++++++---- .../src/metavoxels/MetavoxelServer.h | 46 ++++++++-- .../metavoxels/src/DatagramSequencer.cpp | 6 +- libraries/metavoxels/src/Endpoint.cpp | 2 +- 4 files changed, 109 insertions(+), 29 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index eed0f3a226..cd80650638 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -25,14 +25,19 @@ const int SEND_INTERVAL = 50; MetavoxelServer::MetavoxelServer(const QByteArray& packet) : ThreadedAssignment(packet), - _sendTimer(this) { - - _sendTimer.setSingleShot(true); - connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); + _nextSender(0) { } void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) { - edit.apply(_data, SharedObject::getWeakHash()); + MetavoxelData data = _data; + edit.apply(data, SharedObject::getWeakHash()); + setData(data); +} + +void MetavoxelServer::setData(const MetavoxelData& data) { + if (_data != data) { + emit dataChanged(_data = data); + } } const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server"; @@ -46,12 +51,26 @@ void MetavoxelServer::run() { connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteSession(const SharedNodePointer&))); - _lastSend = QDateTime::currentMSecsSinceEpoch(); - _sendTimer.start(SEND_INTERVAL); - // initialize Bitstream before using it in multiple threads Bitstream::preThreadingInit(); + // create the senders, each with its own thread + int threadCount = QThread::idealThreadCount(); + if (threadCount == -1) { + const int DEFAULT_THREAD_COUNT = 4; + threadCount = DEFAULT_THREAD_COUNT; + } + qDebug() << "Creating" << threadCount << "sender threads"; + for (int i = 0; i < threadCount; i++) { + QThread* thread = new QThread(this); + MetavoxelSender* sender = new MetavoxelSender(this); + sender->moveToThread(thread); + sender->connect(thread, SIGNAL(finished()), SLOT(deleteLater())); + thread->start(); + QMetaObject::invokeMethod(sender, "start"); + _senders.append(sender); + } + // create the persister and start it in its own thread _persister = new MetavoxelPersister(this); QThread* persistenceThread = new QThread(this); @@ -86,6 +105,11 @@ void MetavoxelServer::readPendingDatagrams() { void MetavoxelServer::aboutToFinish() { QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _data)); + + foreach (MetavoxelSender* sender, _senders) { + sender->thread()->quit(); + sender->thread()->wait(); + } _persister->thread()->quit(); _persister->thread()->wait(); } @@ -93,7 +117,11 @@ void MetavoxelServer::aboutToFinish() { void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) { if (node->getType() == NodeType::Agent) { QMutexLocker locker(&node->getMutex()); - node->setLinkedData(new MetavoxelSession(node, this)); + MetavoxelSender* sender = _senders.at(_nextSender); + _nextSender = (_nextSender + 1) % _senders.size(); + MetavoxelSession* session = new MetavoxelSession(node, sender); + session->moveToThread(sender->thread()); + node->setLinkedData(session); } } @@ -108,11 +136,30 @@ void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) { } } -void MetavoxelServer::sendDeltas() { - // send deltas for all sessions +MetavoxelSender::MetavoxelSender(MetavoxelServer* server) : + _server(server), + _sendTimer(this) { + + _sendTimer.setSingleShot(true); + connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); + + connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData); +} + +void MetavoxelSender::start() { + _lastSend = QDateTime::currentMSecsSinceEpoch(); + _sendTimer.start(SEND_INTERVAL); +} + +void MetavoxelSender::sendDeltas() { + // send deltas for all sessions associated with our thread foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::Agent) { - static_cast(node->getLinkedData())->update(); + QMutexLocker locker(&node->getMutex()); + MetavoxelSession* session = static_cast(node->getLinkedData()); + if (session && session->thread() == QThread::currentThread()) { + session->update(); + } } } @@ -124,9 +171,9 @@ void MetavoxelServer::sendDeltas() { _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL))); } -MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) : +MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) : Endpoint(node, new PacketRecord(), NULL), - _server(server), + _sender(sender), _reliableDeltaChannel(NULL), _reliableDeltaID(0) { @@ -150,7 +197,7 @@ void MetavoxelSession::update() { int start = _sequencer.getOutputStream().getUnderlying().device()->pos(); out << QVariant::fromValue(MetavoxelDeltaMessage()); PacketRecord* sendRecord = getLastAcknowledgedSendRecord(); - _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + _sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); out.flush(); int end = _sequencer.getOutputStream().getUnderlying().device()->pos(); if (end > _sequencer.getMaxPacketSize()) { @@ -162,7 +209,7 @@ void MetavoxelSession::update() { _reliableDeltaWriteMappings = out.getAndResetWriteMappings(); _reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten(); - _reliableDeltaData = _server->getData(); + _reliableDeltaData = _sender->getData(); _reliableDeltaLOD = _lod; // go back to the beginning with the current packet and note that there's a delta pending @@ -185,7 +232,7 @@ void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) { PacketRecord* MetavoxelSession::maybeCreateSendRecord() const { return _reliableDeltaChannel ? new PacketRecord(_reliableDeltaLOD, _reliableDeltaData) : - new PacketRecord(_lod, _server->getData()); + new PacketRecord(_lod, _sender->getData()); } void MetavoxelSession::handleMessage(const QVariant& message) { @@ -195,7 +242,8 @@ void MetavoxelSession::handleMessage(const QVariant& message) { _lod = state.lod; } else if (userType == MetavoxelEditMessage::Type) { - _server->applyEdit(message.value()); + QMetaObject::invokeMethod(_sender->getServer(), "applyEdit", Q_ARG(const MetavoxelEditMessage&, + message.value())); } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 42694b03bf..45478a4946 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -32,28 +32,60 @@ public: MetavoxelServer(const QByteArray& packet); - void applyEdit(const MetavoxelEditMessage& edit); + Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit); const MetavoxelData& getData() const { return _data; } - Q_INVOKABLE void setData(const MetavoxelData& data) { _data = data; } + Q_INVOKABLE void setData(const MetavoxelData& data); virtual void run(); virtual void readPendingDatagrams(); virtual void aboutToFinish(); - + +signals: + + void dataChanged(const MetavoxelData& data); + private slots: void maybeAttachSession(const SharedNodePointer& node); - void maybeDeleteSession(const SharedNodePointer& node); - void sendDeltas(); + void maybeDeleteSession(const SharedNodePointer& node); private: + QVector _senders; + int _nextSender; + MetavoxelPersister* _persister; + MetavoxelData _data; +}; + +/// Handles update sending for one thread. +class MetavoxelSender : public QObject { + Q_OBJECT + +public: + + MetavoxelSender(MetavoxelServer* server); + + MetavoxelServer* getServer() const { return _server; } + + const MetavoxelData& getData() const { return _data; } + + Q_INVOKABLE void start(); + +private slots: + + void setData(const MetavoxelData& data) { _data = data; } + void sendDeltas(); + +private: + + MetavoxelServer* _server; + QTimer _sendTimer; qint64 _lastSend; @@ -66,7 +98,7 @@ class MetavoxelSession : public Endpoint { public: - MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server); + MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender); virtual void update(); @@ -85,7 +117,7 @@ private: void sendPacketGroup(int alreadySent = 0); - MetavoxelServer* _server; + MetavoxelSender* _sender; MetavoxelLOD _lod; diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index c757e131bb..be3d684a3d 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -29,7 +29,7 @@ const float DEFAULT_SLOW_START_THRESHOLD = 1000.0f; DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* parent) : QObject(parent), _outgoingPacketStream(&_outgoingPacketData, QIODevice::WriteOnly), - _outputStream(_outgoingPacketStream), + _outputStream(_outgoingPacketStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this), _incomingDatagramStream(&_incomingDatagramBuffer), _datagramHeaderSize(datagramHeader.size()), _outgoingPacketNumber(0), @@ -38,7 +38,7 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* _outgoingDatagramStream(&_outgoingDatagramBuffer), _incomingPacketNumber(0), _incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly), - _inputStream(_incomingPacketStream), + _inputStream(_incomingPacketStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this), _receivedHighPriorityMessages(0), _maxPacketSize(DEFAULT_MAX_PACKET_SIZE), _packetsPerGroup(1.0f), @@ -752,7 +752,7 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o _index(index), _output(output), _dataStream(&_buffer), - _bitstream(_dataStream), + _bitstream(_dataStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this), _priority(1.0f), _offset(0), _writePosition(0), diff --git a/libraries/metavoxels/src/Endpoint.cpp b/libraries/metavoxels/src/Endpoint.cpp index 9672b245cc..65e088c75e 100644 --- a/libraries/metavoxels/src/Endpoint.cpp +++ b/libraries/metavoxels/src/Endpoint.cpp @@ -15,7 +15,7 @@ Endpoint::Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendRecord, PacketRecord* baselineReceiveRecord) : _node(node), - _sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) { + _sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData), this) { connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&))); From 4ea8e7de5d29ed1747540c6058f2ee5bad63db43 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Jul 2014 11:45:20 -0700 Subject: [PATCH 11/24] Atomics for better thread safety. --- libraries/metavoxels/src/MetavoxelData.cpp | 2 +- libraries/metavoxels/src/MetavoxelData.h | 4 ++-- libraries/metavoxels/src/SharedObject.cpp | 4 ++-- libraries/metavoxels/src/SharedObject.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 112012e37f..0f8773a896 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1117,7 +1117,7 @@ void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const { } void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) { - if (--_referenceCount == 0) { + if (!_referenceCount.deref()) { destroy(attribute); delete this; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 1944090a38..dfebbe4586 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -212,7 +212,7 @@ public: void writeSpannerSubdivision(MetavoxelStreamState& state) const; /// Increments the node's reference count. - void incrementReferenceCount() { _referenceCount++; } + void incrementReferenceCount() { _referenceCount.ref(); } /// Decrements the node's reference count. If the resulting reference count is zero, destroys the node /// and calls delete this. @@ -238,7 +238,7 @@ private: friend class MetavoxelVisitation; - int _referenceCount; + QAtomicInt _referenceCount; void* _attributeValue; MetavoxelNode* _children[CHILD_COUNT]; }; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index efc6aa4be6..053ef57bad 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -23,7 +23,7 @@ REGISTER_META_OBJECT(SharedObject) SharedObject::SharedObject() : - _id(++_lastID), + _id(_nextID.fetchAndAddOrdered(1)), _originID(_id), _remoteID(0), _remoteOriginID(0) { @@ -131,7 +131,7 @@ void SharedObject::dump(QDebug debug) const { } } -int SharedObject::_lastID = 0; +QAtomicInt SharedObject::_nextID(1); WeakSharedObjectHash SharedObject::_weakHash; QReadWriteLock SharedObject::_weakHashLock; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 5ff5aa9680..407fc820c8 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -87,7 +87,7 @@ private: int _remoteOriginID; QAtomicInt _referenceCount; - static int _lastID; + static QAtomicInt _nextID; static WeakSharedObjectHash _weakHash; static QReadWriteLock _weakHashLock; }; From 27f88e9f805b5b62b48c51097e16c9ba6cddb05f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Jul 2014 18:20:00 -0700 Subject: [PATCH 12/24] Progress on threading. --- .../src/metavoxels/MetavoxelServer.cpp | 38 ++--- .../src/metavoxels/MetavoxelServer.h | 6 +- interface/src/MetavoxelSystem.cpp | 53 ++++--- interface/src/MetavoxelSystem.h | 20 ++- interface/src/ui/Stats.cpp | 48 +++--- interface/src/ui/Stats.h | 11 ++ .../metavoxels/src/MetavoxelClientManager.cpp | 142 ++++++++++++------ .../metavoxels/src/MetavoxelClientManager.h | 67 ++++++++- libraries/metavoxels/src/MetavoxelData.cpp | 4 +- libraries/metavoxels/src/MetavoxelData.h | 4 + 10 files changed, 274 insertions(+), 119 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index cd80650638..3535a00573 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -21,8 +21,6 @@ #include "MetavoxelServer.h" -const int SEND_INTERVAL = 50; - MetavoxelServer::MetavoxelServer(const QByteArray& packet) : ThreadedAssignment(packet), _nextSender(0) { @@ -48,8 +46,8 @@ void MetavoxelServer::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->addNodeTypeToInterestSet(NodeType::Agent); - connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&))); - connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteSession(const SharedNodePointer&))); + connect(nodeList, &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession); + connect(nodeList, &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession); // initialize Bitstream before using it in multiple threads Bitstream::preThreadingInit(); @@ -65,7 +63,7 @@ void MetavoxelServer::run() { QThread* thread = new QThread(this); MetavoxelSender* sender = new MetavoxelSender(this); sender->moveToThread(thread); - sender->connect(thread, SIGNAL(finished()), SLOT(deleteLater())); + connect(thread, &QThread::finished, sender, &QObject::deleteLater); thread->start(); QMetaObject::invokeMethod(sender, "start"); _senders.append(sender); @@ -75,7 +73,7 @@ void MetavoxelServer::run() { _persister = new MetavoxelPersister(this); QThread* persistenceThread = new QThread(this); _persister->moveToThread(persistenceThread); - _persister->connect(persistenceThread, SIGNAL(finished()), SLOT(deleteLater())); + connect(persistenceThread, &QThread::finished, _persister, &QObject::deleteLater); persistenceThread->start(); // queue up the load @@ -121,15 +119,16 @@ void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) { _nextSender = (_nextSender + 1) % _senders.size(); MetavoxelSession* session = new MetavoxelSession(node, sender); session->moveToThread(sender->thread()); + QMetaObject::invokeMethod(sender, "addSession", Q_ARG(QObject*, session)); node->setLinkedData(session); } } void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) { if (node->getType() == NodeType::Agent) { - QMutexLocker locker(&node->getMutex()); + // we assume the node is already locked MetavoxelSession* session = static_cast(node->getLinkedData()); - if (session) { + if (session) { node->setLinkedData(NULL); session->deleteLater(); } @@ -141,26 +140,27 @@ MetavoxelSender::MetavoxelSender(MetavoxelServer* server) : _sendTimer(this) { _sendTimer.setSingleShot(true); - connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); + connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelSender::sendDeltas); connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData); } +const int SEND_INTERVAL = 50; + void MetavoxelSender::start() { _lastSend = QDateTime::currentMSecsSinceEpoch(); _sendTimer.start(SEND_INTERVAL); } +void MetavoxelSender::addSession(QObject* session) { + _sessions.insert(static_cast(session)); + connect(session, &QObject::destroyed, this, &MetavoxelSender::removeSession); +} + void MetavoxelSender::sendDeltas() { // send deltas for all sessions associated with our thread - foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - if (node->getType() == NodeType::Agent) { - QMutexLocker locker(&node->getMutex()); - MetavoxelSession* session = static_cast(node->getLinkedData()); - if (session && session->thread() == QThread::currentThread()) { - session->update(); - } - } + foreach (MetavoxelSession* session, _sessions) { + session->update(); } // restart the send timer @@ -171,6 +171,10 @@ void MetavoxelSender::sendDeltas() { _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL))); } +void MetavoxelSender::removeSession(QObject* session) { + _sessions.remove(static_cast(session)); +} + MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) : Endpoint(node, new PacketRecord(), NULL), _sender(sender), diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 45478a4946..6d62884633 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -77,14 +77,18 @@ public: Q_INVOKABLE void start(); + Q_INVOKABLE void addSession(QObject* session); + private slots: void setData(const MetavoxelData& data) { _data = data; } void sendDeltas(); + void removeSession(QObject* session); private: MetavoxelServer* _server; + QSet _sessions; QTimer _sendTimer; qint64 _lastSend; @@ -99,7 +103,7 @@ class MetavoxelSession : public Endpoint { public: MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender); - + virtual void update(); protected: diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 2b3528b1b3..685a07e85c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -10,6 +10,8 @@ // #include +#include +#include #include #include @@ -45,11 +47,9 @@ void MetavoxelSystem::init() { _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute()); } -MetavoxelLOD MetavoxelSystem::getLOD() const { - // the LOD threshold is temporarily tied to the avatar LOD parameter - const float BASE_LOD_THRESHOLD = 0.01f; - return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), - BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); +MetavoxelLOD MetavoxelSystem::getLOD() { + QReadLocker locker(&_lodLock); + return _lod; } class SpannerSimulateVisitor : public SpannerVisitor { @@ -77,9 +77,15 @@ bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimu } void MetavoxelSystem::simulate(float deltaTime) { - // update the clients - update(); - + // update the lod + { + // the LOD threshold is temporarily tied to the avatar LOD parameter + QWriteLocker locker(&_lodLock); + const float BASE_LOD_THRESHOLD = 0.01f; + _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), + BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); + } + SpannerSimulateVisitor spannerSimulateVisitor(deltaTime); guide(spannerSimulateVisitor); } @@ -183,16 +189,20 @@ void MetavoxelSystem::render() { guide(spannerRenderVisitor); } +void MetavoxelSystem::setClientPoints(const SharedNodePointer& node, const BufferPointVector& points) { + QMutexLocker locker(&node->getMutex()); + MetavoxelSystemClient* client = static_cast(node->getLinkedData()); + if (client) { + client->setPoints(points); + } +} + MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { - return new MetavoxelSystemClient(node, this); + return new MetavoxelSystemClient(node, _updater); } -void MetavoxelSystem::updateClient(MetavoxelClient* client) { - MetavoxelClientManager::updateClient(client); -} - -MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) : - MetavoxelClient(node, system), +MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : + MetavoxelClient(node, updater), _pointCount(0) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); @@ -385,11 +395,14 @@ void PointBufferBuilder::run() { qint64 now = QDateTime::currentMSecsSinceEpoch(); PointCollector collector(_lod); _data.guide(collector); - QMetaObject::invokeMethod(node->getLinkedData(), "setPoints", Q_ARG(const BufferPointVector&, collector.points)); + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "setClientPoints", + Q_ARG(const SharedNodePointer&, node), Q_ARG(const BufferPointVector&, collector.points)); qDebug() << "collect" << (QDateTime::currentMSecsSinceEpoch() - now); } void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { + MetavoxelClient::dataChanged(oldData); + /* BufferBuilder builder(_remoteDataLOD); const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); MetavoxelNode* oldRoot = oldData.getRoot(pointBufferAttribute); @@ -500,7 +513,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum return; } // slight performance optimization: don't render if clip bounds are entirely within sphere - Sphere* sphere = static_cast(parent()); + Sphere* sphere = static_cast(_spanner); Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize)); for (int i = 0; i < Box::VERTEX_COUNT; i++) { const float CLIP_PROPORTION = 0.95f; @@ -512,7 +525,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum } void SphereRenderer::renderUnclipped(float alpha, Mode mode) { - Sphere* sphere = static_cast(parent()); + Sphere* sphere = static_cast(_spanner); const QColor& color = sphere->getColor(); glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha); @@ -533,6 +546,8 @@ StaticModelRenderer::StaticModelRenderer() : } void StaticModelRenderer::init(Spanner* spanner) { + SpannerRenderer::init(spanner); + _model->init(); StaticModel* staticModel = static_cast(spanner); @@ -554,7 +569,7 @@ void StaticModelRenderer::simulate(float deltaTime) { const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents; bounds = Box(extents.minimum, extents.maximum); } - static_cast(parent())->setBounds(glm::translate(_model->getTranslation()) * + static_cast(_spanner)->setBounds(glm::translate(_model->getTranslation()) * glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds); _model->simulate(deltaTime); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index afbfd9444f..71bc9dc231 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -22,8 +23,12 @@ #include "renderer/ProgramObject.h" +class BufferPoint; class Model; +typedef QVector BufferPointVector; +typedef QPair BufferPointVectorPair; + /// Renders a metavoxel tree. class MetavoxelSystem : public MetavoxelClientManager { Q_OBJECT @@ -34,15 +39,16 @@ public: virtual void init(); - virtual MetavoxelLOD getLOD() const; + virtual MetavoxelLOD getLOD(); void simulate(float deltaTime); void render(); + Q_INVOKABLE void setClientPoints(const SharedNodePointer& node, const BufferPointVector& points); + protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); - virtual void updateClient(MetavoxelClient* client); private: @@ -50,6 +56,9 @@ private: static int _pointScaleLocation; AttributePointer _pointBufferAttribute; + + MetavoxelLOD _lod; + QReadWriteLock _lodLock; }; /// Describes contents of a point in a point buffer. @@ -60,9 +69,6 @@ public: quint8 normal[3]; }; -typedef QVector BufferPointVector; -typedef QPair BufferPointVectorPair; - Q_DECLARE_METATYPE(BufferPointVector) /// A client session associated with a single server. @@ -71,11 +77,11 @@ class MetavoxelSystemClient : public MetavoxelClient { public: - MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system); + MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater); void render(); - Q_INVOKABLE void setPoints(const BufferPointVector& points); + void setPoints(const BufferPointVector& points); virtual int parseData(const QByteArray& packet); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index f82bc7ba17..728ed04e31 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -48,7 +48,13 @@ Stats::Stats(): _pingStatsWidth(STATS_PING_MIN_WIDTH), _geoStatsWidth(STATS_GEO_MIN_WIDTH), _voxelStatsWidth(STATS_VOXEL_MIN_WIDTH), - _lastHorizontalOffset(0) + _lastHorizontalOffset(0), + _metavoxelInternal(0), + _metavoxelLeaves(0), + _metavoxelSendProgress(0), + _metavoxelSendTotal(0), + _metavoxelReceiveProgress(0), + _metavoxelReceiveTotal(0) { QGLWidget* glWidget = Application::getInstance()->getGLWidget(); resetWidth(glWidget->width(), 0); @@ -487,36 +493,26 @@ void Stats::display( verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color); - int internal = 0, leaves = 0; - int sendProgress = 0, sendTotal = 0; - int receiveProgress = 0, receiveTotal = 0; - 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->getData().countNodes(internal, leaves, Application::getInstance()->getMetavoxels()->getLOD()); - client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal); - } - } - } + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels()->getUpdater(), "getStats", + Q_ARG(QObject*, this), Q_ARG(const QByteArray&, "setMetavoxelStats")); + stringstream nodes; - nodes << "Metavoxels: " << (internal + leaves); + nodes << "Metavoxels: " << (_metavoxelInternal + _metavoxelLeaves); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodes.str().c_str(), color); stringstream nodeTypes; - nodeTypes << "Internal: " << internal << " Leaves: " << leaves; + nodeTypes << "Internal: " << _metavoxelInternal << " Leaves: " << _metavoxelLeaves; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodeTypes.str().c_str(), color); - if (sendTotal > 0 || receiveTotal > 0) { + if (_metavoxelSendTotal > 0 || _metavoxelReceiveTotal > 0) { stringstream reliableStats; - if (sendTotal > 0) { - reliableStats << "Upload: " << (sendProgress * 100 / sendTotal) << "% "; + if (_metavoxelSendTotal > 0) { + reliableStats << "Upload: " << (_metavoxelSendProgress * 100 / _metavoxelSendTotal) << "% "; } - if (receiveTotal > 0) { - reliableStats << "Download: " << (receiveProgress * 100 / receiveTotal) << "%"; + if (_metavoxelReceiveTotal > 0) { + reliableStats << "Download: " << (_metavoxelReceiveProgress * 100 / _metavoxelReceiveTotal) << "%"; } verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, reliableStats.str().c_str(), color); @@ -849,3 +845,13 @@ void Stats::display( } + +void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress, + int sendTotal, int receiveProgress, int receiveTotal) { + _metavoxelInternal = internal; + _metavoxelLeaves = leaves; + _metavoxelSendProgress = sendProgress; + _metavoxelSendTotal = sendTotal; + _metavoxelReceiveProgress = receiveProgress; + _metavoxelReceiveTotal = receiveTotal; +} diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 66d6ec99f0..5a38b5ed9f 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -31,6 +31,10 @@ public: void resetWidth(int width, int horizontalOffset); void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess); bool includeTimingRecord(const QString& name); + + Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress, + int sendTotal, int receiveProgress, int receiveTotal); + private: static Stats* _sharedInstance; @@ -45,6 +49,13 @@ private: int _voxelStatsWidth; int _lastHorizontalOffset; + + int _metavoxelInternal; + int _metavoxelLeaves; + int _metavoxelSendProgress; + int _metavoxelSendTotal; + int _metavoxelReceiveProgress; + int _metavoxelReceiveTotal; }; #endif // hifi_Stats_h diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index af97551ade..a2d3410314 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -9,26 +9,31 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include +#include #include "MetavoxelClientManager.h" #include "MetavoxelMessages.h" -void MetavoxelClientManager::init() { - connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&))); - connect(NodeList::getInstance(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteClient(const SharedNodePointer&))); +MetavoxelClientManager::MetavoxelClientManager() : + _updater(new MetavoxelUpdater(this)) { + QThread* thread = new QThread(this); + _updater->moveToThread(thread); + connect(thread, &QThread::finished, _updater, &QObject::deleteLater); + thread->start(); + QMetaObject::invokeMethod(_updater, "start"); } -void MetavoxelClientManager::update() { - foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - if (node->getType() == NodeType::MetavoxelServer) { - QMutexLocker locker(&node->getMutex()); - MetavoxelClient* client = static_cast(node->getLinkedData()); - if (client) { - updateClient(client); - } - } - } +MetavoxelClientManager::~MetavoxelClientManager() { + _updater->thread()->quit(); + _updater->thread()->wait(); +} + +void MetavoxelClientManager::init() { + connect(NodeList::getInstance(), &NodeList::nodeAdded, this, &MetavoxelClientManager::maybeAttachClient); + connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &MetavoxelClientManager::maybeDeleteClient); } SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(const glm::vec3& origin, @@ -41,7 +46,7 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { float clientDistance; - SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection( + SharedObjectPointer clientSpanner = client->getDataCopy().findFirstRaySpannerIntersection( origin, direction, attribute, clientDistance); if (clientSpanner && clientDistance < closestDistance) { closestSpanner = clientSpanner; @@ -70,35 +75,26 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool } void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); - return; - } - 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->applyEdit(edit, reliable); - } - } - } + QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); } -MetavoxelLOD MetavoxelClientManager::getLOD() const { +MetavoxelLOD MetavoxelClientManager::getLOD() { return MetavoxelLOD(); } void MetavoxelClientManager::maybeAttachClient(const SharedNodePointer& node) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); - node->setLinkedData(createClient(node)); + MetavoxelClient* client = createClient(node); + client->moveToThread(_updater->thread()); + QMetaObject::invokeMethod(_updater, "addClient", Q_ARG(QObject*, client)); + node->setLinkedData(client); } } void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) { if (node->getType() == NodeType::MetavoxelServer) { - QMutexLocker locker(&node->getMutex()); + // we assume the node is already locked MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { node->setLinkedData(NULL); @@ -108,11 +104,7 @@ void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) { } MetavoxelClient* MetavoxelClientManager::createClient(const SharedNodePointer& node) { - return new MetavoxelClient(node, this); -} - -void MetavoxelClientManager::updateClient(MetavoxelClient* client) { - client->update(); + return new MetavoxelClient(node, _updater); } void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) { @@ -121,15 +113,75 @@ void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) { QMutexLocker locker(&node->getMutex()); MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { - client->guide(visitor); + client->getDataCopy().guide(visitor); } } } } -MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) : +MetavoxelUpdater::MetavoxelUpdater(MetavoxelClientManager* clientManager) : + _clientManager(clientManager), + _sendTimer(this) { + + _sendTimer.setSingleShot(true); + connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelUpdater::sendUpdates); +} + +const int SEND_INTERVAL = 33; + +void MetavoxelUpdater::start() { + _lastSend = QDateTime::currentMSecsSinceEpoch(); + _sendTimer.start(SEND_INTERVAL); +} + +void MetavoxelUpdater::addClient(QObject* client) { + _clients.insert(static_cast(client)); + connect(client, &QObject::destroyed, this, &MetavoxelUpdater::removeClient); +} + +void MetavoxelUpdater::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { + // apply to all clients + foreach (MetavoxelClient* client, _clients) { + client->applyEdit(edit, reliable); + } +} + +void MetavoxelUpdater::getStats(QObject* receiver, const QByteArray& method) { + int internal = 0, leaves = 0; + int sendProgress = 0, sendTotal = 0; + int receiveProgress = 0, receiveTotal = 0; + foreach (MetavoxelClient* client, _clients) { + client->getData().countNodes(internal, leaves, _lod); + client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal); + } + QMetaObject::invokeMethod(receiver, method.constData(), Q_ARG(int, internal), Q_ARG(int, leaves), Q_ARG(int, sendProgress), + Q_ARG(int, sendTotal), Q_ARG(int, receiveProgress), Q_ARG(int, receiveTotal)); +} + +void MetavoxelUpdater::sendUpdates() { + // get the latest LOD from the client manager + _lod = _clientManager->getLOD(); + + // send updates for all clients + foreach (MetavoxelClient* client, _clients) { + client->update(); + } + + // restart the send timer + qint64 now = QDateTime::currentMSecsSinceEpoch(); + int elapsed = now - _lastSend; + _lastSend = now; + + _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL))); +} + +void MetavoxelUpdater::removeClient(QObject* client) { + _clients.remove(static_cast(client)); +} + +MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : Endpoint(node, new PacketRecord(), new PacketRecord()), - _manager(manager), + _updater(updater), _reliableDeltaChannel(NULL), _reliableDeltaID(0) { @@ -137,9 +189,9 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientM SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); } -void MetavoxelClient::guide(MetavoxelVisitor& visitor) { - visitor.setLOD(_manager->getLOD()); - _data.guide(visitor); +MetavoxelData MetavoxelClient::getDataCopy() { + QReadLocker locker(&_dataCopyLock); + return _dataCopy; } void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { @@ -160,11 +212,13 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) } void MetavoxelClient::dataChanged(const MetavoxelData& oldData) { - // nothing by default + // make thread-safe copy + QWriteLocker locker(&_dataCopyLock); + _dataCopy = _data; } void MetavoxelClient::writeUpdateMessage(Bitstream& out) { - ClientStateMessage state = { _manager->getLOD() }; + ClientStateMessage state = { _updater->getLOD() }; out << QVariant::fromValue(state); } @@ -212,7 +266,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } PacketRecord* MetavoxelClient::maybeCreateSendRecord() const { - return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _manager->getLOD()); + return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _updater->getLOD()); } PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const { diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index a915ba9c3c..333b709b9e 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -12,10 +12,14 @@ #ifndef hifi_MetavoxelClientManager_h #define hifi_MetavoxelClientManager_h +#include +#include + #include "Endpoint.h" class MetavoxelClient; class MetavoxelEditMessage; +class MetavoxelUpdater; /// Manages the set of connected metavoxel clients. class MetavoxelClientManager : public QObject { @@ -23,8 +27,12 @@ class MetavoxelClientManager : public QObject { public: + MetavoxelClientManager(); + virtual ~MetavoxelClientManager(); + virtual void init(); - void update(); + + MetavoxelUpdater* getUpdater() const { return _updater; } SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance); @@ -35,7 +43,8 @@ public: Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); - virtual MetavoxelLOD getLOD() const; + /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. + virtual MetavoxelLOD getLOD(); private slots: @@ -45,9 +54,46 @@ private slots: protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); - virtual void updateClient(MetavoxelClient* client); void guide(MetavoxelVisitor& visitor); + + MetavoxelUpdater* _updater; +}; + +/// Handles updates in a dedicated thread. +class MetavoxelUpdater : public QObject { + Q_OBJECT + +public: + + MetavoxelUpdater(MetavoxelClientManager* clientManager); + + const MetavoxelLOD& getLOD() const { return _lod; } + + Q_INVOKABLE void start(); + + Q_INVOKABLE void addClient(QObject* client); + + Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable); + + /// Requests a set of statistics. The receiving method should take six integer arguments: internal node count, leaf count, + /// send progress, send total, receive progress, receive total. + Q_INVOKABLE void getStats(QObject* receiver, const QByteArray& method); + +private slots: + + void sendUpdates(); + void removeClient(QObject* client); + +private: + + MetavoxelClientManager* _clientManager; + QSet _clients; + + QTimer _sendTimer; + qint64 _lastSend; + + MetavoxelLOD _lod; }; /// Base class for metavoxel clients. @@ -56,12 +102,14 @@ class MetavoxelClient : public Endpoint { public: - MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager); + MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater); - MetavoxelData& getData() { return _data; } + /// Returns a reference to the most recent data. This function is *not* thread-safe. + const MetavoxelData& getData() const { return _data; } + + /// Returns a copy of the most recent data. This function *is* thread-safe. + MetavoxelData getDataCopy(); - void guide(MetavoxelVisitor& visitor); - void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); protected: @@ -74,7 +122,7 @@ protected: virtual PacketRecord* maybeCreateSendRecord() const; virtual PacketRecord* maybeCreateReceiveRecord() const; - MetavoxelClientManager* _manager; + MetavoxelUpdater* _updater; MetavoxelData _data; MetavoxelData _remoteData; MetavoxelLOD _remoteDataLOD; @@ -82,6 +130,9 @@ protected: ReliableChannel* _reliableDeltaChannel; MetavoxelLOD _reliableDeltaLOD; int _reliableDeltaID; + + MetavoxelData _dataCopy; + QReadWriteLock _dataCopyLock; }; #endif // hifi_MetavoxelClientManager_h diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 0f8773a896..400ae6bfdd 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1899,7 +1899,7 @@ SpannerRenderer* Spanner::getRenderer() { metaObject = &SpannerRenderer::staticMetaObject; } _renderer = static_cast(metaObject->newInstance()); - _renderer->setParent(this); + connect(this, &QObject::destroyed, _renderer, &QObject::deleteLater); _renderer->init(this); } return _renderer; @@ -1920,7 +1920,7 @@ SpannerRenderer::SpannerRenderer() { } void SpannerRenderer::init(Spanner* spanner) { - // nothing by default + _spanner = spanner; } void SpannerRenderer::simulate(float deltaTime) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index dfebbe4586..546f31c321 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -599,6 +599,10 @@ public: virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& clipMinimum, float clipSize, float& distance) const; + +protected: + + Spanner* _spanner; }; /// An object with a 3D transform. From 5bd3d1fe20fe6ab9eb758adfb530fd001484617d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Jul 2014 13:16:18 -0700 Subject: [PATCH 13/24] Working on renderer attribute. --- interface/src/MetavoxelSystem.cpp | 4 ++ interface/src/MetavoxelSystem.h | 9 ++++ .../metavoxels/src/AttributeRegistry.cpp | 4 +- libraries/metavoxels/src/AttributeRegistry.h | 4 ++ libraries/metavoxels/src/MetavoxelData.cpp | 39 ++++++++++++++++ libraries/metavoxels/src/MetavoxelData.h | 46 +++++++++++++++++++ 6 files changed, 105 insertions(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 685a07e85c..484764d3e2 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -25,6 +25,7 @@ #include "MetavoxelSystem.h" #include "renderer/Model.h" +REGISTER_META_OBJECT(PointMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) @@ -476,6 +477,9 @@ AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) return AttributeValue(parentValue.getAttribute()); } +PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() { +} + static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; glClipPlane(plane, coefficients); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 71bc9dc231..986f6d2563 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -126,6 +126,15 @@ public: virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; +/// Renders metavoxels as points. +class PointMetavoxelRendererImplementation : public MetavoxelRendererImplementation { + Q_OBJECT + +public: + + Q_INVOKABLE PointMetavoxelRendererImplementation(); +}; + /// Base class for spanner renderers; provides clipping. class ClippedRenderer : public SpannerRenderer { Q_OBJECT diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 1cd41500fc..d7f2a309bb 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -35,7 +35,9 @@ AttributeRegistry* AttributeRegistry::getInstance() { AttributeRegistry::AttributeRegistry() : _guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject, - SharedObjectPointer(new DefaultMetavoxelGuide())))), + new DefaultMetavoxelGuide()))), + _rendererAttribute(registerAttribute(new SharedObjectAttribute("renderer", &MetavoxelRenderer::staticMetaObject, + new PointMetavoxelRenderer()))), _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))), diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 23e3c1fa97..d07503335f 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -73,6 +73,9 @@ public: /// Returns a reference to the standard SharedObjectPointer "guide" attribute. const AttributePointer& getGuideAttribute() const { return _guideAttribute; } + /// Returns a reference to the standard SharedObjectPointer "renderer" attribute. + const AttributePointer& getRendererAttribute() const { return _rendererAttribute; } + /// Returns a reference to the standard SharedObjectSet "spanners" attribute. const AttributePointer& getSpannersAttribute() const { return _spannersAttribute; } @@ -99,6 +102,7 @@ private: QReadWriteLock _attributesLock; AttributePointer _guideAttribute; + AttributePointer _rendererAttribute; AttributePointer _spannersAttribute; AttributePointer _colorAttribute; AttributePointer _normalAttribute; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 400ae6bfdd..6e68610557 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -24,6 +24,8 @@ REGISTER_META_OBJECT(MetavoxelGuide) REGISTER_META_OBJECT(DefaultMetavoxelGuide) REGISTER_META_OBJECT(ScriptedMetavoxelGuide) REGISTER_META_OBJECT(ThrobbingMetavoxelGuide) +REGISTER_META_OBJECT(MetavoxelRenderer) +REGISTER_META_OBJECT(PointMetavoxelRenderer) REGISTER_META_OBJECT(Spanner) REGISTER_META_OBJECT(Sphere) REGISTER_META_OBJECT(StaticModel) @@ -1845,6 +1847,43 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor->getOutputs().at(index)); } +MetavoxelRenderer::MetavoxelRenderer() : + _implementation(NULL) { +} + +MetavoxelRendererImplementation* MetavoxelRenderer::getImplementation() { + if (!_implementation) { + QByteArray className = getImplementationClassName(); + const QMetaObject* metaObject = Bitstream::getMetaObject(className); + if (!metaObject) { + qDebug() << "Unknown class name:" << className; + metaObject = &MetavoxelRendererImplementation::staticMetaObject; + } + _implementation = static_cast(metaObject->newInstance()); + connect(this, &QObject::destroyed, _implementation, &QObject::deleteLater); + _implementation->init(this); + } + return _implementation; +} + +MetavoxelRendererImplementation::MetavoxelRendererImplementation() { +} + +void MetavoxelRendererImplementation::init(MetavoxelRenderer* renderer) { + _renderer = renderer; +} + +QByteArray MetavoxelRenderer::getImplementationClassName() const { + return "MetavoxelRendererImplementation"; +} + +PointMetavoxelRenderer::PointMetavoxelRenderer() { +} + +QByteArray PointMetavoxelRenderer::getImplementationClassName() const { + return "PointMetavoxelRendererImplementation"; +} + const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f; const float DEFAULT_VOXELIZATION_GRANULARITY = powf(2.0f, -3.0f); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 546f31c321..a7e3d085be 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -28,6 +28,7 @@ class QScriptContext; class MetavoxelNode; +class MetavoxelRendererImplementation; class MetavoxelVisitation; class MetavoxelVisitor; class NetworkValue; @@ -507,6 +508,51 @@ public: AttributeValue getInheritedOutputValue(int index) const; }; +/// Base class for objects that render metavoxels. +class MetavoxelRenderer : public SharedObject { + Q_OBJECT + +public: + + MetavoxelRenderer(); + + /// Returns a pointer to the implementation, creating it if necessary. + MetavoxelRendererImplementation* getImplementation(); + +protected: + + MetavoxelRendererImplementation* _implementation; + + /// Returns the name of the class to instantiate for the implementation. + virtual QByteArray getImplementationClassName() const; +}; + +/// Base class for renderer implementations. +class MetavoxelRendererImplementation : public SharedObject { + Q_OBJECT + +public: + + Q_INVOKABLE MetavoxelRendererImplementation(); + + virtual void init(MetavoxelRenderer* renderer); + +protected: + + MetavoxelRenderer* _renderer; +}; + +/// Renders metavoxels as points. +class PointMetavoxelRenderer : public MetavoxelRenderer { + Q_OBJECT + +public: + + Q_INVOKABLE PointMetavoxelRenderer(); + + virtual QByteArray getImplementationClassName() const; +}; + /// An object that spans multiple octree cells. class Spanner : public SharedObject { Q_OBJECT From d0c5fec777a53f1f8c8cdcce62f0904022da6440 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Jul 2014 14:28:49 -0700 Subject: [PATCH 14/24] Thread safety for spanners. --- .../metavoxels/src/AttributeRegistry.cpp | 40 ++--- libraries/metavoxels/src/MetavoxelData.cpp | 148 +++++++++--------- libraries/metavoxels/src/MetavoxelData.h | 29 ++-- 3 files changed, 111 insertions(+), 106 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index d7f2a309bb..7c7ded0fb7 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -199,7 +199,7 @@ MetavoxelNode* Attribute::createMetavoxelNode(const AttributeValue& value, const } void Attribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) { - data.createRoot(state.attribute)->read(state); + data.createRoot(state.base.attribute)->read(state); } void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { @@ -207,7 +207,7 @@ void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamSta } void Attribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { - data.createRoot(state.attribute)->readDelta(reference, state); + data.createRoot(state.base.attribute)->readDelta(reference, state); } void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { @@ -216,10 +216,10 @@ void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNo void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { // copy if changed - MetavoxelNode* oldRoot = data.getRoot(state.attribute); + MetavoxelNode* oldRoot = data.getRoot(state.base.attribute); MetavoxelNode* newRoot = oldRoot->readSubdivision(state); if (newRoot != oldRoot) { - data.setRoot(state.attribute, newRoot); + data.setRoot(state.base.attribute, newRoot); } } @@ -569,62 +569,62 @@ SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; - state.stream >> object; + state.base.stream >> object; if (!object) { break; } - data.insert(state.attribute, object); + data.insert(state.base.attribute, object); } // even if the root is empty, it should still exist - if (!data.getRoot(state.attribute)) { - data.createRoot(state.attribute); + if (!data.getRoot(state.base.attribute)) { + data.createRoot(state.base.attribute); } } void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { - Spanner::incrementVisit(); + state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpanners(state); - state.stream << SharedObjectPointer(); + state.base.stream << SharedObjectPointer(); } void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { forever { SharedObjectPointer object; - state.stream >> object; + state.base.stream >> object; if (!object) { break; } - data.toggle(state.attribute, object); + data.toggle(state.base.attribute, object); } // even if the root is empty, it should still exist - if (!data.getRoot(state.attribute)) { - data.createRoot(state.attribute); + if (!data.getRoot(state.base.attribute)) { + data.createRoot(state.base.attribute); } } void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { - Spanner::incrementVisit(); + state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpannerDelta(reference, state); - state.stream << SharedObjectPointer(); + state.base.stream << SharedObjectPointer(); } void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; - state.stream >> object; + state.base.stream >> object; if (!object) { break; } - data.insert(state.attribute, object); + data.insert(state.base.attribute, object); } } void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { - Spanner::incrementVisit(); + state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpannerSubdivision(state); - state.stream << SharedObjectPointer(); + state.base.stream << SharedObjectPointer(); } bool SpannerSetAttribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 6e68610557..2eaf4c843b 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -544,7 +545,8 @@ void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) { if (!attribute) { break; } - MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, lod }; + MetavoxelStreamBase base = { attribute, in, lod, lod }; + MetavoxelStreamState state = { base, getMinimum(), _size }; attribute->readMetavoxelRoot(*this, state); } } @@ -553,7 +555,8 @@ void MetavoxelData::write(Bitstream& out, const MetavoxelLOD& lod) const { out << _size; for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { out << it.key(); - MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, lod }; + MetavoxelStreamBase base = { it.key(), out, lod, lod }; + MetavoxelStreamState state = { base, getMinimum(), _size }; it.key()->writeMetavoxelRoot(*it.value(), state); } out << AttributePointer(); @@ -586,7 +589,8 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD if (!attribute) { break; } - MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD }; + MetavoxelStreamBase base = { attribute, in, lod, referenceLOD }; + MetavoxelStreamState state = { base, getMinimum(), _size }; MetavoxelNode* oldRoot = _roots.value(attribute); if (oldRoot) { bool changed; @@ -642,7 +646,8 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO // write the added/changed/subdivided roots for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); - MetavoxelStreamState state = { minimum, _size, it.key(), out, lod, referenceLOD }; + MetavoxelStreamBase base = { it.key(), out, lod, referenceLOD }; + MetavoxelStreamState state = { base, minimum, _size }; if (it.value() != referenceRoot || becameSubdivided) { out << it.key(); if (referenceRoot) { @@ -772,15 +777,15 @@ template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData& } bool MetavoxelStreamState::shouldSubdivide() const { - return lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier()); + return base.lod.shouldSubdivide(minimum, size, base.attribute->getLODThresholdMultiplier()); } bool MetavoxelStreamState::shouldSubdivideReference() const { - return referenceLOD.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier()); + return base.referenceLOD.shouldSubdivide(minimum, size, base.attribute->getLODThresholdMultiplier()); } bool MetavoxelStreamState::becameSubdivided() const { - return lod.becameSubdivided(minimum, size, referenceLOD, attribute->getLODThresholdMultiplier()); + return base.lod.becameSubdivided(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier()); } void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { @@ -854,38 +859,36 @@ bool MetavoxelNode::isLeaf() const { } void MetavoxelNode::read(MetavoxelStreamState& state) { - clearChildren(state.attribute); + clearChildren(state.base.attribute); if (!state.shouldSubdivide()) { - state.attribute->read(state.stream, _attributeValue, true); + state.base.attribute->read(state.base.stream, _attributeValue, true); return; } bool leaf; - state.stream >> leaf; - state.attribute->read(state.stream, _attributeValue, leaf); + state.base.stream >> leaf; + state.base.attribute->read(state.base.stream, _attributeValue, leaf); if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); - _children[i] = new MetavoxelNode(state.attribute); + _children[i] = new MetavoxelNode(state.base.attribute); _children[i]->read(nextState); } - mergeChildren(state.attribute, true); + mergeChildren(state.base.attribute, true); } } void MetavoxelNode::write(MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { - state.attribute->write(state.stream, _attributeValue, true); + state.base.attribute->write(state.base.stream, _attributeValue, true); return; } bool leaf = isLeaf(); - state.stream << leaf; - state.attribute->write(state.stream, _attributeValue, leaf); + state.base.stream << leaf; + state.base.attribute->write(state.base.stream, _attributeValue, leaf); if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); _children[i]->write(nextState); @@ -894,31 +897,30 @@ void MetavoxelNode::write(MetavoxelStreamState& state) const { } void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) { - clearChildren(state.attribute); + clearChildren(state.base.attribute); if (!state.shouldSubdivide()) { - state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, true); + state.base.attribute->readDelta(state.base.stream, _attributeValue, reference._attributeValue, true); return; } bool leaf; - state.stream >> leaf; - state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, leaf); + state.base.stream >> leaf; + state.base.attribute->readDelta(state.base.stream, _attributeValue, reference._attributeValue, leaf); if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; if (reference.isLeaf() || !state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); - _children[i] = new MetavoxelNode(state.attribute); + _children[i] = new MetavoxelNode(state.base.attribute); _children[i]->read(nextState); } } else { for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); bool changed; - state.stream >> changed; + state.base.stream >> changed; if (changed) { - _children[i] = new MetavoxelNode(state.attribute); + _children[i] = new MetavoxelNode(state.base.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { if (nextState.becameSubdivided()) { @@ -933,21 +935,20 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta } } } - mergeChildren(state.attribute, true); + mergeChildren(state.base.attribute, true); } } void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { - state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true); + state.base.attribute->writeDelta(state.base.stream, _attributeValue, reference._attributeValue, true); return; } bool leaf = isLeaf(); - state.stream << leaf; - state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf); + state.base.stream << leaf; + state.base.attribute->writeDelta(state.base.stream, _attributeValue, reference._attributeValue, leaf); if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; if (reference.isLeaf() || !state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); @@ -957,12 +958,12 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); if (_children[i] == reference._children[i]) { - state.stream << false; + state.base.stream << false; if (nextState.becameSubdivided()) { _children[i]->writeSubdivision(nextState); } } else { - state.stream << true; + state.base.stream << true; _children[i]->writeDelta(*reference._children[i], nextState); } } @@ -973,40 +974,38 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { if (!state.shouldSubdivideReference()) { bool leaf; - state.stream >> leaf; + state.base.stream >> leaf; if (leaf) { - return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.attribute)); + return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); } else { - MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.attribute)); - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute)); + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); - newNode->_children[i] = new MetavoxelNode(state.attribute); + newNode->_children[i] = new MetavoxelNode(state.base.attribute); newNode->_children[i]->read(nextState); } return newNode; } } else if (!isLeaf()) { MetavoxelNode* node = this; - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); if (nextState.becameSubdivided()) { MetavoxelNode* child = _children[i]->readSubdivision(nextState); if (child != _children[i]) { if (node == this) { - node = new MetavoxelNode(state.attribute, this); + node = new MetavoxelNode(state.base.attribute, this); } node->_children[i] = child; - _children[i]->decrementReferenceCount(state.attribute); + _children[i]->decrementReferenceCount(state.base.attribute); } } } if (node != this) { - node->mergeChildren(state.attribute, true); + node->mergeChildren(state.base.attribute, true); } return node; } @@ -1016,18 +1015,16 @@ MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { bool leaf = isLeaf(); if (!state.shouldSubdivideReference()) { - state.stream << leaf; + state.base.stream << leaf; if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); _children[i]->write(nextState); } } } else if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); if (nextState.becameSubdivided()) { @@ -1039,15 +1036,14 @@ void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { - if (static_cast(object.data())->testAndSetVisited()) { - state.stream << object; + if (static_cast(object.data())->testAndSetVisited(state.base.visit)) { + state.base.stream << object; } } if (!state.shouldSubdivide() || isLeaf()) { return; } - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); _children[i]->writeSpanners(nextState); @@ -1058,19 +1054,18 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS 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; + if (static_cast(object.data())->testAndSetVisited(state.base.visit) && !newSet.contains(object)) { + state.base.stream << object; } } foreach (const SharedObjectPointer& object, newSet) { - if (static_cast(object.data())->testAndSetVisited() && !oldSet.contains(object)) { - state.stream << object; + if (static_cast(object.data())->testAndSetVisited(state.base.visit) && !oldSet.contains(object)) { + state.base.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 }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); reference._children[i]->writeSpanners(nextState); @@ -1078,8 +1073,7 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS } return; } - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; if (reference.isLeaf() || !state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); @@ -1100,8 +1094,7 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const { if (!isLeaf()) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; if (!state.shouldSubdivideReference()) { for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); @@ -1303,14 +1296,14 @@ SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, c } void SpannerVisitor::prepare() { - Spanner::incrementVisit(); + _visit = Spanner::getAndIncrementNextVisit(); } int SpannerVisitor::visit(MetavoxelInfo& info) { for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { Spanner* spanner = static_cast(object.data()); - if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited() && + if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit) && !visit(spanner, glm::vec3(), 0.0f)) { return SHORT_CIRCUIT; } @@ -1362,7 +1355,7 @@ RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& or } void RaySpannerIntersectionVisitor::prepare() { - Spanner::incrementVisit(); + _visit = Spanner::getAndIncrementNextVisit(); } class SpannerDistance { @@ -1380,7 +1373,7 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { Spanner* spanner = static_cast(object.data()); - if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited()) { + if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit)) { SpannerDistance spannerDistance = { spanner }; if (spanner->findRayIntersection(_origin, _direction, glm::vec3(), 0.0f, spannerDistance.distance)) { spannerDistances.append(spannerDistance); @@ -1891,8 +1884,7 @@ Spanner::Spanner() : _renderer(NULL), _placementGranularity(DEFAULT_PLACEMENT_GRANULARITY), _voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY), - _masked(false), - _lastVisit(0) { + _masked(false) { } void Spanner::setBounds(const Box& bounds) { @@ -1921,11 +1913,13 @@ bool Spanner::blendAttributeValues(MetavoxelInfo& info, bool force) const { return false; } -bool Spanner::testAndSetVisited() { - if (_lastVisit == _visit) { +bool Spanner::testAndSetVisited(int visit) { + QMutexLocker locker(&_lastVisitsMutex); + int& lastVisit = _lastVisits[QThread::currentThread()]; + if (lastVisit == visit) { return false; } - _lastVisit = _visit; + lastVisit = visit; return true; } @@ -1953,7 +1947,7 @@ QByteArray Spanner::getRendererClassName() const { return "SpannerRendererer"; } -int Spanner::_visit = 0; +QAtomicInt Spanner::_nextVisit(1); SpannerRenderer::SpannerRenderer() { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index a7e3d085be..ae9f2b4b99 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -159,15 +160,22 @@ template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData& Q_DECLARE_METATYPE(MetavoxelData) -/// Holds the state used in streaming metavoxel data. -class MetavoxelStreamState { +/// Holds the base state used in streaming metavoxel data. +class MetavoxelStreamBase { public: - glm::vec3 minimum; - float size; const AttributePointer& attribute; Bitstream& stream; const MetavoxelLOD& lod; const MetavoxelLOD& referenceLOD; + int visit; +}; + +/// Holds the state used in streaming a metavoxel node. +class MetavoxelStreamState { +public: + MetavoxelStreamBase& base; + glm::vec3 minimum; + float size; bool shouldSubdivide() const; bool shouldSubdivideReference() const; @@ -360,6 +368,7 @@ protected: int _spannerInputCount; int _spannerMaskCount; int _order; + int _visit; }; /// Base class for ray intersection visitors. @@ -405,6 +414,7 @@ protected: int _spannerInputCount; int _spannerMaskCount; + int _visit; }; /// Interface for objects that guide metavoxel visitors. @@ -563,8 +573,8 @@ class Spanner : public SharedObject { public: - /// Increments the value of the global visit counter. - static void incrementVisit() { _visit++; } + /// Returns the value of the global visit counter and increments it. + static int getAndIncrementNextVisit() { return _nextVisit.fetchAndAddOrdered(1); } Spanner(); @@ -597,7 +607,7 @@ public: /// 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(); + bool testAndSetVisited(int visit); /// Returns a pointer to the renderer, creating it if necessary. SpannerRenderer* getRenderer(); @@ -625,9 +635,10 @@ private: float _placementGranularity; float _voxelizationGranularity; bool _masked; - int _lastVisit; ///< the identifier of the last visit + QHash _lastVisits; ///< last visit identifiers for each thread + QMutex _lastVisitsMutex; - static int _visit; ///< the global visit counter + static QAtomicInt _nextVisit; ///< the global visit counter }; /// Base class for objects that can render spanners. From 605b3282e77707ccb258e38be09f7c3a316e54a1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 24 Jul 2014 17:01:15 -0700 Subject: [PATCH 15/24] Working on render bits. --- interface/src/MetavoxelSystem.cpp | 28 ++++++++++++++++++++++ interface/src/MetavoxelSystem.h | 2 ++ libraries/metavoxels/src/MetavoxelData.cpp | 17 ++++++++----- libraries/metavoxels/src/MetavoxelData.h | 8 ++++--- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 484764d3e2..b7b8e9dca1 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -140,7 +140,32 @@ bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, return true; } +class RenderVisitor : public MetavoxelVisitor { +public: + + RenderVisitor(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +RenderVisitor::RenderVisitor(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getRendererAttribute(), + QVector(), lod) { +} + +int RenderVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + static_cast(info.inputValues.at(0).getInlineValue< + SharedObjectPointer>().data())->getImplementation()->render(info); + return STOP_RECURSION; +} + void MetavoxelSystem::render() { + RenderVisitor renderVisitor(getLOD()); + guide(renderVisitor); + int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_WIDTH_INDEX = 2; @@ -480,6 +505,9 @@ AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() { } +void PointMetavoxelRendererImplementation::render(MetavoxelInfo& info) { +} + static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; glClipPlane(plane, coefficients); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 986f6d2563..49003928c7 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -133,6 +133,8 @@ class PointMetavoxelRendererImplementation : public MetavoxelRendererImplementat public: Q_INVOKABLE PointMetavoxelRendererImplementation(); + + virtual void render(MetavoxelInfo& info); }; /// Base class for spanner renderers; provides clipping. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 2eaf4c843b..f7e186a2b8 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -83,7 +83,7 @@ Box MetavoxelData::getBounds() const { void MetavoxelData::guide(MetavoxelVisitor& visitor) { // let the visitor know we're about to begin a tour - visitor.prepare(); + visitor.prepare(this); // start with the root values/defaults (plus the guide attribute) const QVector& inputs = visitor.getInputs(); @@ -140,7 +140,7 @@ void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisito } // let the visitor know we're about to begin a tour - visitor.prepare(); + visitor.prepare(this); // start with the root values/defaults (plus the guide attribute) const QVector& inputs = visitor.getInputs(); @@ -1270,8 +1270,8 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, MetavoxelVisitor::~MetavoxelVisitor() { } -void MetavoxelVisitor::prepare() { - // nothing by default +void MetavoxelVisitor::prepare(MetavoxelData* data) { + _data = data; } bool MetavoxelVisitor::postVisit(MetavoxelInfo& info) { @@ -1295,7 +1295,8 @@ SpannerVisitor::SpannerVisitor(const QVector& spannerInputs, c _order(order) { } -void SpannerVisitor::prepare() { +void SpannerVisitor::prepare(MetavoxelData* data) { + MetavoxelVisitor::prepare(data); _visit = Spanner::getAndIncrementNextVisit(); } @@ -1354,7 +1355,8 @@ RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& or _spannerMaskCount(spannerMasks.size()) { } -void RaySpannerIntersectionVisitor::prepare() { +void RaySpannerIntersectionVisitor::prepare(MetavoxelData* data) { + MetavoxelVisitor::prepare(data); _visit = Spanner::getAndIncrementNextVisit(); } @@ -1866,6 +1868,9 @@ void MetavoxelRendererImplementation::init(MetavoxelRenderer* renderer) { _renderer = renderer; } +void MetavoxelRendererImplementation::render(MetavoxelInfo& info) { +} + QByteArray MetavoxelRenderer::getImplementationClassName() const { return "MetavoxelRendererImplementation"; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index ae9f2b4b99..b02fa31024 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -315,7 +315,7 @@ public: float getMinimumLODThresholdMultiplier() const { return _minimumLODThresholdMultiplier; } /// Prepares for a new tour of the metavoxel data. - virtual void prepare(); + virtual void prepare(MetavoxelData* data); /// Visits a metavoxel. /// \param info the metavoxel data @@ -340,6 +340,7 @@ protected: QVector _outputs; MetavoxelLOD _lod; float _minimumLODThresholdMultiplier; + MetavoxelData* _data; QList _visitations; int _depth; }; @@ -360,7 +361,7 @@ public: /// \return true to continue, false to short-circuit the tour virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) = 0; - virtual void prepare(); + virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); protected: @@ -407,7 +408,7 @@ public: /// \return true to continue, false to short-circuit the tour virtual bool visitSpanner(Spanner* spanner, float distance) = 0; - virtual void prepare(); + virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info, float distance); protected: @@ -546,6 +547,7 @@ public: Q_INVOKABLE MetavoxelRendererImplementation(); virtual void init(MetavoxelRenderer* renderer); + virtual void render(MetavoxelInfo& info); protected: From 57ca6064917ad36cd1895bfd7c5a0923c8731596 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 25 Jul 2014 16:59:48 -0700 Subject: [PATCH 16/24] Various kinds of progress towards generic rendering. --- interface/src/MetavoxelSystem.cpp | 140 ++++++++++++++++++++- interface/src/MetavoxelSystem.h | 13 +- libraries/metavoxels/src/MetavoxelData.cpp | 11 +- libraries/metavoxels/src/MetavoxelData.h | 11 +- 4 files changed, 165 insertions(+), 10 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b7b8e9dca1..49713ae688 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -158,13 +158,13 @@ int RenderVisitor::visit(MetavoxelInfo& info) { return DEFAULT_ORDER; } static_cast(info.inputValues.at(0).getInlineValue< - SharedObjectPointer>().data())->getImplementation()->render(info); + SharedObjectPointer>().data())->getImplementation()->render(*_data, info, _lod); return STOP_RECURSION; } void MetavoxelSystem::render() { RenderVisitor renderVisitor(getLOD()); - guide(renderVisitor); + guideToAugmented(renderVisitor); int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); @@ -227,6 +227,18 @@ MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } +void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor) { + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::MetavoxelServer) { + QMutexLocker locker(&node->getMutex()); + MetavoxelSystemClient* client = static_cast(node->getLinkedData()); + if (client) { + client->getAugmentedData().guide(visitor); + } + } + } +} + MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : MetavoxelClient(node, updater), _pointCount(0) { @@ -259,6 +271,16 @@ void MetavoxelSystemClient::setPoints(const BufferPointVector& points) { } +void MetavoxelSystemClient::setAugmentedData(const MetavoxelData& data) { + QWriteLocker locker(&_augmentedDataLock); + _augmentedData = data; +} + +MetavoxelData MetavoxelSystemClient::getAugmentedData() { + QReadLocker locker(&_augmentedDataLock); + return _augmentedData; +} + int MetavoxelSystemClient::parseData(const QByteArray& packet) { // process through sequencer QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); @@ -426,6 +448,67 @@ void PointBufferBuilder::run() { qDebug() << "collect" << (QDateTime::currentMSecsSinceEpoch() - now); } +class AugmentVisitor : public MetavoxelVisitor { +public: + + AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData); + + virtual int visit(MetavoxelInfo& info); + +private: + + const MetavoxelData& _previousData; +}; + +AugmentVisitor::AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getRendererAttribute(), + QVector(), lod), + _previousData(previousData) { +} + +int AugmentVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + static_cast(info.inputValues.at(0).getInlineValue< + SharedObjectPointer>().data())->getImplementation()->augment(*_data, _previousData, info, _lod); + return STOP_RECURSION; +} + +class Augmenter : public QRunnable { +public: + + Augmenter(const SharedNodePointer& node, const MetavoxelData& data, + const MetavoxelData& previousData, const MetavoxelLOD& lod); + + virtual void run(); + +private: + + QWeakPointer _node; + MetavoxelData _data; + MetavoxelData _previousData; + MetavoxelLOD _lod; +}; + +Augmenter::Augmenter(const SharedNodePointer& node, const MetavoxelData& data, + const MetavoxelData& previousData, const MetavoxelLOD& lod) : + _node(node), + _data(data), + _previousData(previousData), + _lod(lod) { +} + +void Augmenter::run() { + SharedNodePointer node = _node; + if (!node) { + return; + } + AugmentVisitor visitor(_lod, _previousData); + _data.guide(visitor); + QMetaObject::invokeMethod(node.data(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data)); +} + void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); @@ -442,6 +525,8 @@ void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { _data.guide(builder); } */ QThreadPool::globalInstance()->start(new PointBufferBuilder(_node, _data, _remoteDataLOD)); + + QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD)); } void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { @@ -505,7 +590,56 @@ AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() { } -void PointMetavoxelRendererImplementation::render(MetavoxelInfo& info) { +class PointAugmentVisitor : public MetavoxelVisitor { +public: + + PointAugmentVisitor(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << + AttributeRegistry::getInstance()->getNormalAttribute(), QVector() << + Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { +} + +int PointAugmentVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + return STOP_RECURSION; +} + +void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, + MetavoxelInfo& info, const MetavoxelLOD& lod) { + PointAugmentVisitor visitor(lod); + data.guideToDifferent(previous, visitor, &info); +} + +class PointRenderVisitor : public MetavoxelVisitor { +public: + + PointRenderVisitor(const MetavoxelLOD& lod); + + virtual int visit(MetavoxelInfo& info); +}; + +PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) : + MetavoxelVisitor(QVector() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), + QVector(), lod) { +} + +int PointRenderVisitor::visit(MetavoxelInfo& info) { + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + return STOP_RECURSION; +} + +void PointMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { + PointRenderVisitor visitor(lod); + data.guide(visitor, &info); } static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 49003928c7..e595f293b8 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -52,6 +52,8 @@ protected: private: + void guideToAugmented(MetavoxelVisitor& visitor); + static ProgramObject _program; static int _pointScaleLocation; @@ -82,6 +84,11 @@ public: void render(); void setPoints(const BufferPointVector& points); + + Q_INVOKABLE void setAugmentedData(const MetavoxelData& data); + + /// Returns a copy of the augmented data. This function is thread-safe. + MetavoxelData getAugmentedData(); virtual int parseData(const QByteArray& packet); @@ -94,6 +101,9 @@ private: QOpenGLBuffer _buffer; int _pointCount; + + MetavoxelData _augmentedData; + QReadWriteLock _augmentedDataLock; }; /// Contains the information necessary to render a group of points at variable detail levels. @@ -134,7 +144,8 @@ public: Q_INVOKABLE PointMetavoxelRendererImplementation(); - virtual void render(MetavoxelInfo& info); + virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); + virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod); }; /// Base class for spanner renderers; provides clipping. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index f7e186a2b8..3a1fe81259 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -81,7 +81,7 @@ Box MetavoxelData::getBounds() const { return Box(glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize)); } -void MetavoxelData::guide(MetavoxelVisitor& visitor) { +void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) { // let the visitor know we're about to begin a tour visitor.prepare(this); @@ -128,7 +128,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { visitor.releaseVisitation(); } -void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { +void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start) { // if the other data is smaller, we need to expand it to compare const MetavoxelData* expandedOther = &other; if (_size > other._size) { @@ -1847,6 +1847,7 @@ MetavoxelRenderer::MetavoxelRenderer() : } MetavoxelRendererImplementation* MetavoxelRenderer::getImplementation() { + QMutexLocker locker(&_implementationMutex); if (!_implementation) { QByteArray className = getImplementationClassName(); const QMetaObject* metaObject = Bitstream::getMetaObject(className); @@ -1868,7 +1869,11 @@ void MetavoxelRendererImplementation::init(MetavoxelRenderer* renderer) { _renderer = renderer; } -void MetavoxelRendererImplementation::render(MetavoxelInfo& info) { +void MetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, + MetavoxelInfo& info, const MetavoxelLOD& lod) { +} + +void MetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { } QByteArray MetavoxelRenderer::getImplementationClassName() const { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index b02fa31024..8f9ee8924e 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -28,6 +28,7 @@ class QScriptContext; +class MetavoxelInfo; class MetavoxelNode; class MetavoxelRendererImplementation; class MetavoxelVisitation; @@ -80,10 +81,12 @@ public: Box getBounds() const; /// Applies the specified visitor to the contained voxels. - void guide(MetavoxelVisitor& visitor); + /// \param start the location at which to start, or NULL for the root + void guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); /// Guides the specified visitor to the voxels that differ from those of the specified other. - void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor); + /// \param start the location at which to start, or NULL for the root + void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); /// Inserts a spanner into the specified attribute layer. void insert(const AttributePointer& attribute, const SharedObjectPointer& object); @@ -533,6 +536,7 @@ public: protected: MetavoxelRendererImplementation* _implementation; + QMutex _implementationMutex; /// Returns the name of the class to instantiate for the implementation. virtual QByteArray getImplementationClassName() const; @@ -547,7 +551,8 @@ public: Q_INVOKABLE MetavoxelRendererImplementation(); virtual void init(MetavoxelRenderer* renderer); - virtual void render(MetavoxelInfo& info); + virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); + virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod); protected: From 4f5448f529c851082d13f27e98c09b8c07ba9aed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 25 Jul 2014 18:19:50 -0700 Subject: [PATCH 17/24] Basic rendering working again. --- interface/src/MetavoxelSystem.cpp | 444 +++++++++--------------------- interface/src/MetavoxelSystem.h | 26 +- 2 files changed, 145 insertions(+), 325 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 49713ae688..90adcef38c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -31,20 +31,9 @@ REGISTER_META_OBJECT(StaticModelRenderer) static int bufferPointVectorMetaTypeId = qRegisterMetaType(); -ProgramObject MetavoxelSystem::_program; -int MetavoxelSystem::_pointScaleLocation; - void MetavoxelSystem::init() { MetavoxelClientManager::init(); - - if (!_program.isLinked()) { - _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); - _program.link(); - - _program.bind(); - _pointScaleLocation = _program.uniformLocation("pointScale"); - _program.release(); - } + PointMetavoxelRendererImplementation::init(); _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute()); } @@ -91,35 +80,6 @@ void MetavoxelSystem::simulate(float deltaTime) { guide(spannerSimulateVisitor); } -class PointBufferRenderVisitor : public MetavoxelVisitor { -public: - - PointBufferRenderVisitor(); - - virtual int visit(MetavoxelInfo& info); - -private: - - int _order; -}; - -PointBufferRenderVisitor::PointBufferRenderVisitor() : - MetavoxelVisitor(QVector() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), - QVector(), Application::getInstance()->getMetavoxels()->getLOD()), - _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { -} - -int PointBufferRenderVisitor::visit(MetavoxelInfo& info) { - PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); - if (buffer) { - buffer->render(1000); - } - if (info.isLeaf) { - return STOP_RECURSION; - } - return _order; -} - class SpannerRenderVisitor : public SpannerVisitor { public: @@ -165,64 +125,11 @@ int RenderVisitor::visit(MetavoxelInfo& info) { void MetavoxelSystem::render() { RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor); - - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - const int VIEWPORT_WIDTH_INDEX = 2; - const int VIEWPORT_HEIGHT_INDEX = 3; - float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX]; - float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX]; - float viewportDiagonal = sqrtf(viewportWidth*viewportWidth + viewportHeight*viewportHeight); - float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(), - Application::getInstance()->getViewFrustum()->getNearTopRight()); - - _program.bind(); - _program.setUniformValue(_pointScaleLocation, viewportDiagonal * - Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - - glDisable(GL_BLEND); - - //PointBufferRenderVisitor pointBufferRenderVisitor; - //guide(pointBufferRenderVisitor); - - foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - if (node->getType() == NodeType::MetavoxelServer) { - QMutexLocker locker(&node->getMutex()); - MetavoxelSystemClient* client = static_cast(node->getLinkedData()); - if (client) { - client->render(); - } - } - } - - glEnable(GL_BLEND); - - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - - _program.release(); SpannerRenderVisitor spannerRenderVisitor; guide(spannerRenderVisitor); } -void MetavoxelSystem::setClientPoints(const SharedNodePointer& node, const BufferPointVector& points) { - QMutexLocker locker(&node->getMutex()); - MetavoxelSystemClient* client = static_cast(node->getLinkedData()); - if (client) { - client->setPoints(points); - } -} - MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } @@ -240,35 +147,7 @@ void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor) { } MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : - MetavoxelClient(node, updater), - _pointCount(0) { - - _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - _buffer.create(); -} - -void MetavoxelSystemClient::render() { - _buffer.bind(); - - BufferPoint* point = 0; - glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); - glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); - - glDrawArrays(GL_POINTS, 0, _pointCount); - - _buffer.release(); -} - -void MetavoxelSystemClient::setPoints(const BufferPointVector& points) { - qint64 now = QDateTime::currentMSecsSinceEpoch(); - _buffer.bind(); - _buffer.allocate(points.constData(), points.size() * sizeof(BufferPoint)); - _buffer.release(); - _pointCount = points.size(); - qDebug() << "upload" << (QDateTime::currentMSecsSinceEpoch() - now); - qDebug() << _pointCount; - + MetavoxelClient(node, updater) { } void MetavoxelSystemClient::setAugmentedData(const MetavoxelData& data) { @@ -288,166 +167,6 @@ int MetavoxelSystemClient::parseData(const QByteArray& packet) { return packet.size(); } -class BufferBuilder : public MetavoxelVisitor { -public: - - BufferBuilder(const MetavoxelLOD& lod); - - virtual int visit(MetavoxelInfo& info); - virtual bool postVisit(MetavoxelInfo& info); - -private: - - QVector _depthPoints; -}; - -BufferBuilder::BufferBuilder(const MetavoxelLOD& lod) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute() << - Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), QVector() << - Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { -} - -const int ALPHA_RENDER_THRESHOLD = 0; - -const int BUFFER_LEVELS = 5; -const int LAST_BUFFER_LEVEL = BUFFER_LEVELS - 1; - -int BufferBuilder::visit(MetavoxelInfo& info) { - if (info.inputValues.at(2).getInlineValue()) { - info.outputValues[0] = AttributeValue(_outputs.at(0)); - } - if (_depth >= _depthPoints.size()) { - _depthPoints.resize(_depth + 1); - } - QRgb color = info.inputValues.at(0).getInlineValue(); - quint8 alpha = qAlpha(color); - if (alpha <= ALPHA_RENDER_THRESHOLD) { - return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; - } - QRgb normal = info.inputValues.at(1).getInlineValue(); - BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - if (info.isLeaf) { - _depthPoints[_depth].first.append(point); - return STOP_RECURSION; - } - _depthPoints[_depth].second.append(point); - return DEFAULT_ORDER | ((_depth % BUFFER_LEVELS) == LAST_BUFFER_LEVEL ? 0 : ALL_NODES); -} - -bool BufferBuilder::postVisit(MetavoxelInfo& info) { - if (_depth % BUFFER_LEVELS != 0) { - return false; - } - QVector offsets; - offsets.append(0); - int leafCount = 0; - int totalPoints = 0; - int lastDepth = qMin(_depth + BUFFER_LEVELS, _depthPoints.size()); - for (int i = _depth; i < lastDepth; i++) { - const BufferPointVectorPair& pair = _depthPoints.at(i); - offsets.append(totalPoints += ((leafCount += pair.first.size()) + pair.second.size())); - } - QOpenGLBuffer buffer; - buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - buffer.create(); - buffer.bind(); - buffer.allocate(totalPoints * sizeof(BufferPoint)); - int offset = 0; - for (int i = _depth; i < lastDepth; i++) { - // write the internal nodes from the current level - BufferPointVector& internal = _depthPoints[i].second; - int length = internal.size() * sizeof(BufferPoint); - buffer.write(offset, internal.constData(), length); - offset += length; - internal.clear(); - - // and the leaves from the top down - for (int j = _depth; j <= i; j++) { - const BufferPointVector& leaves = _depthPoints.at(j).first; - length = leaves.size() * sizeof(BufferPoint); - buffer.write(offset, leaves.constData(), length); - offset += length; - } - } - // clear the leaves now that we're done with them - for (int i = _depth; i < lastDepth; i++) { - _depthPoints[i].first.clear(); - } - buffer.release(); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( - new PointBuffer(buffer, offsets, leafCount)))); - return true; -} - -class PointCollector : public MetavoxelVisitor { -public: - - QVector points; - - PointCollector(const MetavoxelLOD& lod); - - virtual int visit(MetavoxelInfo& info); -}; - -PointCollector::PointCollector(const MetavoxelLOD& lod) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute(), QVector(), lod) { -} - -int PointCollector::visit(MetavoxelInfo& info) { - if (!info.isLeaf) { - return DEFAULT_ORDER; - } - QRgb color = info.inputValues.at(0).getInlineValue(); - quint8 alpha = qAlpha(color); - if (alpha <= ALPHA_RENDER_THRESHOLD) { - return STOP_RECURSION; - } - QRgb normal = info.inputValues.at(1).getInlineValue(); - BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - points.append(point); - return STOP_RECURSION; -} - -/// Builds a point buffer. -class PointBufferBuilder : public QRunnable { -public: - - PointBufferBuilder(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelLOD& lod); - - virtual void run(); - -private: - - QWeakPointer _node; - MetavoxelData _data; - MetavoxelLOD _lod; -}; - -PointBufferBuilder::PointBufferBuilder(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelLOD& lod) : - _node(node), - _data(data), - _lod(lod) { -} - -void PointBufferBuilder::run() { - SharedNodePointer node = _node; - if (!node) { - return; - } - qint64 now = QDateTime::currentMSecsSinceEpoch(); - PointCollector collector(_lod); - _data.guide(collector); - QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "setClientPoints", - Q_ARG(const SharedNodePointer&, node), Q_ARG(const BufferPointVector&, collector.points)); - qDebug() << "collect" << (QDateTime::currentMSecsSinceEpoch() - now); -} - class AugmentVisitor : public MetavoxelVisitor { public: @@ -506,26 +225,12 @@ void Augmenter::run() { } AugmentVisitor visitor(_lod, _previousData); _data.guide(visitor); - QMetaObject::invokeMethod(node.data(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data)); + QMutexLocker locker(&node->getMutex()); + QMetaObject::invokeMethod(node->getLinkedData(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data)); } void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); - - /* BufferBuilder builder(_remoteDataLOD); - const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); - MetavoxelNode* oldRoot = oldData.getRoot(pointBufferAttribute); - if (oldRoot && oldData.getSize() == _data.getSize()) { - oldRoot->incrementReferenceCount(); - _data.setRoot(pointBufferAttribute, oldRoot); - _data.guideToDifferent(oldData, builder); - - } else { - _data.clear(pointBufferAttribute); - _data.guide(builder); - } */ - QThreadPool::globalInstance()->start(new PointBufferBuilder(_node, _data, _remoteDataLOD)); - QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD)); } @@ -534,13 +239,42 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } -PointBuffer::PointBuffer(const QOpenGLBuffer& buffer, const QVector& offsets, int lastLeafCount) : - _buffer(buffer), - _offsets(offsets), - _lastLeafCount(lastLeafCount) { +PointBuffer::PointBuffer(const QVector& levelPoints) : + _levelPoints(levelPoints) { } void PointBuffer::render(int level) { + // initalize buffer, etc. on first render + if (!_buffer.isCreated()) { + _offsets.append(0); + _lastLeafCount = 0; + int totalPoints = 0; + foreach (const BufferPointVectorPair& pair, _levelPoints) { + _offsets.append(totalPoints += ((_lastLeafCount += pair.first.size()) + pair.second.size())); + } + _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + _buffer.create(); + _buffer.bind(); + _buffer.allocate(totalPoints * sizeof(BufferPoint)); + int offset = 0; + for (int i = 0; i < _levelPoints.size(); i++) { + // write the internal nodes from the current level + const BufferPointVector& internal = _levelPoints.at(i).second; + int length = internal.size() * sizeof(BufferPoint); + _buffer.write(offset, internal.constData(), length); + offset += length; + + // and the leaves from the top down + for (int j = 0; j <= i; j++) { + const BufferPointVector& leaves = _levelPoints.at(j).first; + length = leaves.size() * sizeof(BufferPoint); + _buffer.write(offset, leaves.constData(), length); + offset += length; + } + } + _levelPoints.clear(); + _buffer.release(); + } int first, count; int nextLevel = level + 1; if (nextLevel >= _offsets.size()) { @@ -587,6 +321,17 @@ AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) return AttributeValue(parentValue.getAttribute()); } +void PointMetavoxelRendererImplementation::init() { + if (!_program.isLinked()) { + _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); + _program.link(); + + _program.bind(); + _pointScaleLocation = _program.uniformLocation("pointScale"); + _program.release(); + } +} + PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() { } @@ -596,6 +341,11 @@ public: PointAugmentVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); + virtual bool postVisit(MetavoxelInfo& info); + +private: + + QVector _depthPoints; }; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : @@ -604,11 +354,44 @@ PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { } +const int ALPHA_RENDER_THRESHOLD = 0; + int PointAugmentVisitor::visit(MetavoxelInfo& info) { - if (!info.isLeaf) { - return DEFAULT_ORDER; + if (_depth >= _depthPoints.size()) { + _depthPoints.resize(_depth + 1); } - return STOP_RECURSION; + QRgb color = info.inputValues.at(0).getInlineValue(); + quint8 alpha = qAlpha(color); + if (alpha <= ALPHA_RENDER_THRESHOLD) { + return info.isLeaf ? STOP_RECURSION : (DEFAULT_ORDER | ALL_NODES); + } + QRgb normal = info.inputValues.at(1).getInlineValue(); + BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + if (info.isLeaf) { + _depthPoints[_depth].first.append(point); + return STOP_RECURSION; + } + _depthPoints[_depth].second.append(point); + return DEFAULT_ORDER | ALL_NODES; +} + +bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { + if (_depth != 0) { + return false; + } + int lastDepth = _depthPoints.size(); + QVector levelPoints(lastDepth - _depth); + for (int i = 0; i < levelPoints.size(); i++) { + BufferPointVectorPair& levelPair = levelPoints[i]; + BufferPointVectorPair& depthPair = _depthPoints[_depth + i]; + levelPair.first.swap(depthPair.first); + levelPair.second.swap(depthPair.second); + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + new PointBuffer(levelPoints)))); + return true; } void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, @@ -623,24 +406,65 @@ public: PointRenderVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); + +private: + + int _order; }; PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), - QVector(), lod) { + QVector(), lod), + _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { } int PointRenderVisitor::visit(MetavoxelInfo& info) { - if (!info.isLeaf) { - return DEFAULT_ORDER; + PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); + if (buffer) { + buffer->render(1000); } - return STOP_RECURSION; + return info.isLeaf ? STOP_RECURSION : _order; } void PointMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + const int VIEWPORT_WIDTH_INDEX = 2; + const int VIEWPORT_HEIGHT_INDEX = 3; + float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX]; + float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX]; + float viewportDiagonal = sqrtf(viewportWidth * viewportWidth + viewportHeight * viewportHeight); + float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(), + Application::getInstance()->getViewFrustum()->getNearTopRight()); + + _program.bind(); + _program.setUniformValue(_pointScaleLocation, viewportDiagonal * + Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + + glDisable(GL_BLEND); + PointRenderVisitor visitor(lod); data.guide(visitor, &info); + + glEnable(GL_BLEND); + + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + _program.release(); } + +ProgramObject PointMetavoxelRendererImplementation::_program; +int PointMetavoxelRendererImplementation::_pointScaleLocation; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index e595f293b8..a765f9fdd9 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -35,17 +35,15 @@ class MetavoxelSystem : public MetavoxelClientManager { public: - const AttributePointer& getPointBufferAttribute() const { return _pointBufferAttribute; } - virtual void init(); virtual MetavoxelLOD getLOD(); + const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; } + void simulate(float deltaTime); void render(); - Q_INVOKABLE void setClientPoints(const SharedNodePointer& node, const BufferPointVector& points); - protected: virtual MetavoxelClient* createClient(const SharedNodePointer& node); @@ -54,9 +52,6 @@ private: void guideToAugmented(MetavoxelVisitor& visitor); - static ProgramObject _program; - static int _pointScaleLocation; - AttributePointer _pointBufferAttribute; MetavoxelLOD _lod; @@ -81,10 +76,6 @@ public: MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater); - void render(); - - void setPoints(const BufferPointVector& points); - Q_INVOKABLE void setAugmentedData(const MetavoxelData& data); /// Returns a copy of the augmented data. This function is thread-safe. @@ -99,9 +90,6 @@ protected: private: - QOpenGLBuffer _buffer; - int _pointCount; - MetavoxelData _augmentedData; QReadWriteLock _augmentedDataLock; }; @@ -110,12 +98,13 @@ private: class PointBuffer : public QSharedData { public: - PointBuffer(const QOpenGLBuffer& buffer, const QVector& offsets, int lastLeafCount); + PointBuffer(const QVector& levelPoints); void render(int level); private: + QVector _levelPoints; QOpenGLBuffer _buffer; QVector _offsets; int _lastLeafCount; @@ -142,10 +131,17 @@ class PointMetavoxelRendererImplementation : public MetavoxelRendererImplementat public: + static void init(); + Q_INVOKABLE PointMetavoxelRendererImplementation(); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod); + +private: + + static ProgramObject _program; + static int _pointScaleLocation; }; /// Base class for spanner renderers; provides clipping. From e05884d4a3929b84f8efa45d6950f1d89d6b8ea0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 28 Jul 2014 16:18:16 -0700 Subject: [PATCH 18/24] Simpler rendering. --- interface/src/MetavoxelSystem.cpp | 135 +++++++++------------ interface/src/MetavoxelSystem.h | 19 ++- libraries/metavoxels/src/MetavoxelData.cpp | 64 +++++----- libraries/metavoxels/src/MetavoxelData.h | 13 +- 4 files changed, 108 insertions(+), 123 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 90adcef38c..9b4dcff807 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -90,8 +90,8 @@ public: SpannerRenderVisitor::SpannerRenderVisitor() : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector() << AttributeRegistry::getInstance()->getSpannerMaskAttribute(), - QVector(), QVector(), Application::getInstance()->getMetavoxels()->getLOD(), + QVector(), QVector(), QVector(), + Application::getInstance()->getMetavoxels()->getLOD(), encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { } @@ -239,53 +239,22 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } -PointBuffer::PointBuffer(const QVector& levelPoints) : - _levelPoints(levelPoints) { +PointBuffer::PointBuffer(const BufferPointVector& points) : + _points(points) { } -void PointBuffer::render(int level) { +void PointBuffer::render() { // initalize buffer, etc. on first render if (!_buffer.isCreated()) { - _offsets.append(0); - _lastLeafCount = 0; - int totalPoints = 0; - foreach (const BufferPointVectorPair& pair, _levelPoints) { - _offsets.append(totalPoints += ((_lastLeafCount += pair.first.size()) + pair.second.size())); - } _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); _buffer.create(); _buffer.bind(); - _buffer.allocate(totalPoints * sizeof(BufferPoint)); - int offset = 0; - for (int i = 0; i < _levelPoints.size(); i++) { - // write the internal nodes from the current level - const BufferPointVector& internal = _levelPoints.at(i).second; - int length = internal.size() * sizeof(BufferPoint); - _buffer.write(offset, internal.constData(), length); - offset += length; - - // and the leaves from the top down - for (int j = 0; j <= i; j++) { - const BufferPointVector& leaves = _levelPoints.at(j).first; - length = leaves.size() * sizeof(BufferPoint); - _buffer.write(offset, leaves.constData(), length); - offset += length; - } - } - _levelPoints.clear(); + _pointCount = _points.size(); + _buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint)); + _points.clear(); _buffer.release(); } - int first, count; - int nextLevel = level + 1; - if (nextLevel >= _offsets.size()) { - first = _offsets.last() - _lastLeafCount; - count = _lastLeafCount; - - } else { - first = _offsets.at(level); - count = _offsets.at(nextLevel) - first; - } - if (count == 0) { + if (_pointCount == 0) { return; } _buffer.bind(); @@ -295,7 +264,7 @@ void PointBuffer::render(int level) { glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); - glDrawArrays(GL_POINTS, first, count); + glDrawArrays(GL_POINTS, 0, _pointCount); _buffer.release(); } @@ -304,23 +273,18 @@ PointBufferAttribute::PointBufferAttribute() : InlineAttribute("pointBuffer") { } -MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const { - return new MetavoxelNode(value, original); -} - bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const { - for (int i = 0; i < MERGE_COUNT; i++) { - if (decodeInline(children[i])) { + PointBufferPointer firstChild = decodeInline(children[0]); + for (int i = 1; i < MERGE_COUNT; i++) { + if (firstChild != decodeInline(children[i])) { + *(PointBufferPointer*)&parent = _defaultValue; return false; } } + *(PointBufferPointer*)&parent = firstChild; return true; } -AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) const { - return AttributeValue(parentValue.getAttribute()); -} - void PointMetavoxelRendererImplementation::init() { if (!_program.isLinked()) { _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); @@ -340,12 +304,14 @@ public: PointAugmentVisitor(const MetavoxelLOD& lod); + virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: - QVector _depthPoints; + BufferPointVector _points; + float _pointLeafSize; }; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : @@ -356,48 +322,61 @@ PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : const int ALPHA_RENDER_THRESHOLD = 0; +void PointAugmentVisitor::prepare(MetavoxelData* data) { + MetavoxelVisitor::prepare(data); + const float MAX_POINT_LEAF_SIZE = 64.0f; + _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE); +} + int PointAugmentVisitor::visit(MetavoxelInfo& info) { - if (_depth >= _depthPoints.size()) { - _depthPoints.resize(_depth + 1); + if (!info.isLeaf) { + return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST); } QRgb color = info.inputValues.at(0).getInlineValue(); quint8 alpha = qAlpha(color); - if (alpha <= ALPHA_RENDER_THRESHOLD) { - return info.isLeaf ? STOP_RECURSION : (DEFAULT_ORDER | ALL_NODES); + if (alpha > ALPHA_RENDER_THRESHOLD) { + QRgb normal = info.inputValues.at(1).getInlineValue(); + BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + _points.append(point); } - QRgb normal = info.inputValues.at(1).getInlineValue(); - BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - if (info.isLeaf) { - _depthPoints[_depth].first.append(point); - return STOP_RECURSION; + if (info.size >= _pointLeafSize) { + BufferPointVector swapPoints; + _points.swap(swapPoints); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + new PointBuffer(swapPoints)))); } - _depthPoints[_depth].second.append(point); - return DEFAULT_ORDER | ALL_NODES; + return STOP_RECURSION; } bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { - if (_depth != 0) { + if (info.size != _pointLeafSize) { return false; } - int lastDepth = _depthPoints.size(); - QVector levelPoints(lastDepth - _depth); - for (int i = 0; i < levelPoints.size(); i++) { - BufferPointVectorPair& levelPair = levelPoints[i]; - BufferPointVectorPair& depthPair = _depthPoints[_depth + i]; - levelPair.first.swap(depthPair.first); - levelPair.second.swap(depthPair.second); - } + BufferPointVector swapPoints; + _points.swap(swapPoints); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( - new PointBuffer(levelPoints)))); + new PointBuffer(swapPoints)))); return true; } void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod) { + // copy the previous buffers + MetavoxelData expandedPrevious = previous; + while (expandedPrevious.getSize() < data.getSize()) { + expandedPrevious.expand(); + } + const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); + MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute); + if (root) { + data.setRoot(pointBufferAttribute, root); + root->incrementReferenceCount(); + } + PointAugmentVisitor visitor(lod); - data.guideToDifferent(previous, visitor, &info); + data.guideToDifferent(expandedPrevious, visitor); } class PointRenderVisitor : public MetavoxelVisitor { @@ -421,7 +400,7 @@ PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) : int PointRenderVisitor::visit(MetavoxelInfo& info) { PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); if (buffer) { - buffer->render(1000); + buffer->render(); } return info.isLeaf ? STOP_RECURSION : _order; } @@ -450,7 +429,7 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel glDisable(GL_BLEND); PointRenderVisitor visitor(lod); - data.guide(visitor, &info); + data.guide(visitor); glEnable(GL_BLEND); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index a765f9fdd9..4a5b99aa47 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -23,12 +23,8 @@ #include "renderer/ProgramObject.h" -class BufferPoint; class Model; -typedef QVector BufferPointVector; -typedef QPair BufferPointVectorPair; - /// Renders a metavoxel tree. class MetavoxelSystem : public MetavoxelClientManager { Q_OBJECT @@ -66,6 +62,8 @@ public: quint8 normal[3]; }; +typedef QVector BufferPointVector; + Q_DECLARE_METATYPE(BufferPointVector) /// A client session associated with a single server. @@ -94,20 +92,19 @@ private: QReadWriteLock _augmentedDataLock; }; -/// Contains the information necessary to render a group of points at variable detail levels. +/// Contains the information necessary to render a group of points. class PointBuffer : public QSharedData { public: - PointBuffer(const QVector& levelPoints); + PointBuffer(const BufferPointVector& points); - void render(int level); + void render(); private: - QVector _levelPoints; + BufferPointVector _points; QOpenGLBuffer _buffer; - QVector _offsets; - int _lastLeafCount; + int _pointCount; }; typedef QExplicitlySharedDataPointer PointBufferPointer; @@ -120,9 +117,7 @@ public: Q_INVOKABLE PointBufferAttribute(); - virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const; virtual bool merge(void*& parent, void* children[], bool postRead = false) const; - virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; /// Renders metavoxels as points. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 3a1fe81259..3bf43ef8d4 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -81,7 +81,7 @@ Box MetavoxelData::getBounds() const { return Box(glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize)); } -void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) { +void MetavoxelData::guide(MetavoxelVisitor& visitor) { // let the visitor know we're about to begin a tour visitor.prepare(this); @@ -128,7 +128,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) visitor.releaseVisitation(); } -void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start) { +void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { // if the other data is smaller, we need to expand it to compare const MetavoxelData* expandedOther = &other; if (_size > other._size) { @@ -1249,6 +1249,7 @@ 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; const int MetavoxelVisitor::ALL_NODES = 1 << 24; +const int MetavoxelVisitor::ALL_NODES_REST = 1 << 25; MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : @@ -1428,32 +1429,7 @@ bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } -bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); - visitation.info.isLeaf = visitation.info.isLODLeaf || 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()) { - continue; - } - MetavoxelNode*& node = visitation.outputNodes[i]; - if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { - // "set" to same value; disregard - value = AttributeValue(); - } else { - node = value.getAttribute()->createMetavoxelNode(value, node); - } - } - if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { - return true; - } +static inline bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) { MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.info.size = visitation.info.size * 0.5f; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { @@ -1546,6 +1522,35 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { return true; } +bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + // 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.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); + visitation.info.isLeaf = visitation.info.isLODLeaf || 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()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { + // "set" to same value; disregard + value = AttributeValue(); + } else { + node = value.getAttribute()->createMetavoxelNode(value, node); + } + } + if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { + return true; + } + return (encodedOrder == MetavoxelVisitor::STOP_RECURSION || defaultGuideToChildren(visitation, lodBase, encodedOrder)); +} + bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { // 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()) * @@ -1572,6 +1577,9 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { return true; } + if (encodedOrder & MetavoxelVisitor::ALL_NODES_REST) { + return defaultGuideToChildren(visitation, lodBase, encodedOrder); + } bool onlyVisitDifferent = !(encodedOrder & MetavoxelVisitor::ALL_NODES); MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.compareNodes.resize(visitation.compareNodes.size()); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 8f9ee8924e..2dc778cf71 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -81,12 +81,10 @@ public: Box getBounds() const; /// Applies the specified visitor to the contained voxels. - /// \param start the location at which to start, or NULL for the root - void guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); + void guide(MetavoxelVisitor& visitor); /// Guides the specified visitor to the voxels that differ from those of the specified other. - /// \param start the location at which to start, or NULL for the root - void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); + void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor); /// Inserts a spanner into the specified attribute layer. void insert(const AttributePointer& attribute, const SharedObjectPointer& object); @@ -296,9 +294,14 @@ public: /// A special "order" that short-circuits the tour. static const int SHORT_CIRCUIT; - /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones). + /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for + /// just this level. static const int ALL_NODES; + /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for + /// this level and all beneath it. + static const int ALL_NODES_REST; + MetavoxelVisitor(const QVector& inputs, const QVector& outputs = QVector(), const MetavoxelLOD& lod = MetavoxelLOD()); From cc909e22862b14a4b9b78ebb6dde9cd3c062ce27 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 28 Jul 2014 16:24:49 -0700 Subject: [PATCH 19/24] Fixed spelling error. --- interface/src/MetavoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 9b4dcff807..00d69c8c25 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -244,7 +244,7 @@ PointBuffer::PointBuffer(const BufferPointVector& points) : } void PointBuffer::render() { - // initalize buffer, etc. on first render + // initialize buffer, etc. on first render if (!_buffer.isCreated()) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); _buffer.create(); From 56f335bb65a072e1e0740d5a01100f9638ab8b5d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 29 Jul 2014 11:51:24 -0700 Subject: [PATCH 20/24] Make sure models are in range before adding them --- examples/sit.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index c157d4854d..793a1b1d67 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -274,7 +274,10 @@ function update(deltaTime){ for (var i = 0; i < foundModels.length; ++i) { var model = foundModels[i]; if (typeof(models[model.id]) == "undefined") { - addIndicators(model); + model.properties = Models.getModelProperties(model); + if (Vec3.distance(model.properties.position, MyAvatar.position) < SEARCH_RADIUS) { + addIndicators(model); + } } } @@ -285,7 +288,6 @@ function update(deltaTime){ } function addIndicators(modelID) { - modelID.properties = Models.getModelProperties(modelID); if (modelID.properties.sittingPoints.length > 0) { for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) { modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i); From 6c21c44beb11587d582b566ad7ffa4433e09ef8f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 29 Jul 2014 11:52:25 -0700 Subject: [PATCH 21/24] Bumped up the search radius to 50 --- examples/sit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sit.js b/examples/sit.js index 793a1b1d67..f8436a0fc8 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -261,7 +261,7 @@ function update(deltaTime){ MyAvatar.position.z != avatarOldPosition.z) { avatarOldPosition = MyAvatar.position; - var SEARCH_RADIUS = 10; + var SEARCH_RADIUS = 50; var foundModels = Models.findModels(MyAvatar.position, SEARCH_RADIUS); // Let's remove indicator that got out of radius for (model in models) { From f2dbaaf65c9fa48752836b03a7c837ca91005a98 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 29 Jul 2014 13:13:16 -0700 Subject: [PATCH 22/24] Clean sitting targets when changing domain --- examples/sit.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/sit.js b/examples/sit.js index f8436a0fc8..3d41ebf64d 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -285,7 +285,16 @@ function update(deltaTime){ showIndicators(true); } } + + if (location.hostname != oldHost) { + print("Changed domain"); + for (model in models) { + removeIndicators(models[model]); + } + oldHost = location.hostname; + } } +var oldHost = location.hostname; function addIndicators(modelID) { if (modelID.properties.sittingPoints.length > 0) { From 28d4efbad6da71700113a55f30298fe34f837602 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 29 Jul 2014 13:13:35 -0700 Subject: [PATCH 23/24] Don't display anything if overlays not loaded --- interface/src/ui/overlays/BillboardOverlay.cpp | 14 ++++---------- interface/src/ui/overlays/ImageOverlay.cpp | 5 ++++- interface/src/ui/overlays/ModelOverlay.cpp | 6 +++++- interface/src/ui/overlays/Overlay.cpp | 1 + interface/src/ui/overlays/Overlay.h | 2 ++ 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index e7d5cef3be..7d85d54fef 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -17,10 +17,11 @@ BillboardOverlay::BillboardOverlay() : _fromImage(-1,-1,-1,-1), _scale(1.0f), _isFacingAvatar(true) { + _isLoaded = false; } void BillboardOverlay::render() { - if (!_visible) { + if (!_visible || !_isLoaded) { return; } @@ -85,16 +86,7 @@ void BillboardOverlay::render() { ((float)_fromImage.y() + (float)_fromImage.height()) / (float)_size.height()); glVertex2f(-x, y); } glEnd(); - } else { - glColor4f(0.5f, 0.5f, 0.5f, 1.0f); - glBegin(GL_QUADS); { - glVertex2f(-1.0f, -1.0f); - glVertex2f(1.0f, -1.0f); - glVertex2f(1.0f, 1.0f); - glVertex2f(-1.0f, 1.0f); - } glEnd(); } - } glPopMatrix(); glDisable(GL_TEXTURE_2D); @@ -167,6 +159,7 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) { } void BillboardOverlay::setBillboardURL(const QUrl url) { + _isLoaded = false; QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished); } @@ -175,4 +168,5 @@ void BillboardOverlay::replyFinished() { // replace our byte array with the downloaded data QNetworkReply* reply = static_cast(sender()); _billboard = reply->readAll(); + _isLoaded = true; } diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index aeea781eb6..7104b3aced 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -24,6 +24,7 @@ ImageOverlay::ImageOverlay() : _textureBound(false), _wantClipFromImage(false) { + _isLoaded = false; } ImageOverlay::~ImageOverlay() { @@ -35,6 +36,7 @@ ImageOverlay::~ImageOverlay() { // TODO: handle setting image multiple times, how do we manage releasing the bound texture? void ImageOverlay::setImageURL(const QUrl& url) { + _isLoaded = false; NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); @@ -47,10 +49,11 @@ void ImageOverlay::replyFinished() { QByteArray rawData = reply->readAll(); _textureImage.loadFromData(rawData); _renderImage = true; + _isLoaded = true; } void ImageOverlay::render() { - if (!_visible) { + if (!_visible || !_isLoaded) { return; // do nothing if we're not visible } if (_renderImage && !_textureBound) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 57f098aee3..b1d55de12a 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -15,8 +15,10 @@ ModelOverlay::ModelOverlay() : _model(), _scale(1.0f), - _updateModel(false) { + _updateModel(false) +{ _model.init(); + _isLoaded = false; } void ModelOverlay::update(float deltatime) { @@ -32,6 +34,7 @@ void ModelOverlay::update(float deltatime) { } else { _model.simulate(deltatime); } + _isLoaded = _model.isActive(); } void ModelOverlay::render() { @@ -90,6 +93,7 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { if (urlValue.isValid()) { _url = urlValue.toVariant().toString(); _updateModel = true; + _isLoaded = false; } QScriptValue scaleValue = properties.property("scale"); diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index bc7096c471..9d492c6e50 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -21,6 +21,7 @@ Overlay::Overlay() : _parent(NULL), + _isLoaded(true), _alpha(DEFAULT_ALPHA), _color(DEFAULT_OVERLAY_COLOR), _visible(true), diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index f8d6400bf6..c5329688ff 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -40,6 +40,7 @@ public: virtual void render() = 0; // getters + bool isLoaded() { return _isLoaded; } bool getVisible() const { return _visible; } const xColor& getColor() const { return _color; } float getAlpha() const { return _alpha; } @@ -55,6 +56,7 @@ public: protected: QGLWidget* _parent; + bool _isLoaded; float _alpha; xColor _color; bool _visible; // should the overlay be drawn at all From 0bad10b09c0f52373ddc174d98292bc076223d7e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 29 Jul 2014 13:25:34 -0700 Subject: [PATCH 24/24] Add isLoaded to Overlays --- examples/sit.js | 25 ++++++++++++++----------- interface/src/ui/overlays/Overlays.cpp | 14 +++++++++++++- interface/src/ui/overlays/Overlays.h | 3 +++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index 3d41ebf64d..0f4b199855 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -255,10 +255,21 @@ function update(deltaTime){ } frame++; } + + var locationChanged = false; + if (location.hostname != oldHost) { + print("Changed domain"); + for (model in models) { + removeIndicators(models[model]); + } + oldHost = location.hostname; + locationChanged = true; + } - if (MyAvatar.position.x != avatarOldPosition.x && - MyAvatar.position.y != avatarOldPosition.y && - MyAvatar.position.z != avatarOldPosition.z) { + if (MyAvatar.position.x != avatarOldPosition.x || + MyAvatar.position.y != avatarOldPosition.y || + MyAvatar.position.z != avatarOldPosition.z || + locationChanged) { avatarOldPosition = MyAvatar.position; var SEARCH_RADIUS = 50; @@ -285,14 +296,6 @@ function update(deltaTime){ showIndicators(true); } } - - if (location.hostname != oldHost) { - print("Changed domain"); - for (model in models) { - removeIndicators(models[model]); - } - oldHost = location.hostname; - } } var oldHost = location.hostname; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 581947c074..5d16bd78e5 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -227,11 +227,23 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { i.previous(); unsigned int thisID = i.key(); Overlay2D* thisOverlay = static_cast(i.value()); - if (thisOverlay->getVisible() && thisOverlay->getBounds().contains(point.x, point.y, false)) { + if (thisOverlay->getVisible() && thisOverlay->isLoaded() && thisOverlay->getBounds().contains(point.x, point.y, false)) { return thisID; } } return 0; // not found } +bool Overlays::isLoaded(unsigned int id) { + QReadLocker lock(&_lock); + Overlay* overlay = _overlays2D.value(id); + if (!overlay) { + _overlays3D.value(id); + } + if (!overlay) { + return false; // not found + } + + return overlay->isLoaded(); +} diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 2fbdb993f4..8bd8224f82 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -38,6 +38,9 @@ public slots: /// returns the top most overlay at the screen point, or 0 if not overlay at that point unsigned int getOverlayAtPoint(const glm::vec2& point); + + /// returns whether the overlay's assets are loaded or not + bool isLoaded(unsigned int id); private: QMap _overlays2D;