From 6ba750a9634c7111fdc42579ee31d34a9b8e8a54 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 10 Dec 2013 15:44:48 -0800 Subject: [PATCH] More progress on generic attributes, metavoxel node management. --- interface/src/Application.cpp | 2 + interface/src/Application.h | 5 +- interface/src/renderer/MetavoxelSystem.cpp | 16 +++ interface/src/renderer/MetavoxelSystem.h | 25 ++++ .../metavoxels/src/AttributeRegistry.cpp | 72 +++++++++-- libraries/metavoxels/src/AttributeRegistry.h | 96 +++++++++++++-- libraries/metavoxels/src/MetavoxelData.cpp | 114 +++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 69 ++++++++--- 8 files changed, 354 insertions(+), 45 deletions(-) create mode 100644 interface/src/renderer/MetavoxelSystem.cpp create mode 100644 interface/src/renderer/MetavoxelSystem.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e75c708841..a9ff0a3681 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1800,6 +1800,8 @@ void Application::init() { _voxels.setDisableFastVoxelPipeline(false); _voxels.init(); + _metavoxels.init(); + _palette.init(_glWidget->width(), _glWidget->height()); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1); diff --git a/interface/src/Application.h b/interface/src/Application.h index 67cb1709c9..c1e178838b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -55,9 +55,10 @@ #include "renderer/AmbientOcclusionEffect.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" -#include "renderer/VoxelShader.h" +#include "renderer/MetavoxelSystem.h" #include "renderer/PointShader.h" #include "renderer/TextureCache.h" +#include "renderer/VoxelShader.h" #include "ui/BandwidthDialog.h" #include "ui/ChatEntry.h" #include "ui/VoxelStatsDialog.h" @@ -345,6 +346,8 @@ private: QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; + MetavoxelSystem _metavoxels; + ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. Oscilloscope _audioScope; diff --git a/interface/src/renderer/MetavoxelSystem.cpp b/interface/src/renderer/MetavoxelSystem.cpp new file mode 100644 index 0000000000..ef6692c2d2 --- /dev/null +++ b/interface/src/renderer/MetavoxelSystem.cpp @@ -0,0 +1,16 @@ +// +// MetavoxelSystem.cpp +// interface +// +// Created by Andrzej Kapolka on 12/10/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "MetavoxelSystem.h" + +void MetavoxelSystem::init() { + qDebug() << "Howdy hello\n"; +} + diff --git a/interface/src/renderer/MetavoxelSystem.h b/interface/src/renderer/MetavoxelSystem.h new file mode 100644 index 0000000000..107f6f49f4 --- /dev/null +++ b/interface/src/renderer/MetavoxelSystem.h @@ -0,0 +1,25 @@ +// +// MetavoxelSystem.h +// interface +// +// Created by Andrzej Kapolka on 12/10/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__MetavoxelSystem__ +#define __interface__MetavoxelSystem__ + +#include + +/// Renders a metavoxel tree. +class MetavoxelSystem { +public: + + void init(); + +private: + + MetavoxelData _data; +}; + +#endif /* defined(__interface__MetavoxelSystem__) */ diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 9d7e2b1210..dcf5008500 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -10,22 +10,68 @@ AttributeRegistry AttributeRegistry::_instance; -AttributeRegistry::AttributeRegistry() : _lastAttributeID(0) { +AttributeRegistry::AttributeRegistry() { + registerAttribute(AttributePointer(new InlineAttribute("blerp"))); } -AttributeID AttributeRegistry::getAttributeID(const QString& name) { - AttributeID& id = _attributeIDs[name]; - if (id == 0) { - id = ++_lastAttributeID; - _attributes.insert(id, Attribute(id, name)); +AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { + AttributePointer& pointer = _attributes[attribute->getName()]; + if (!pointer) { + pointer = attribute; } - return id; + return pointer; } -Attribute AttributeRegistry::getAttribute(AttributeID id) const { - return _attributes.value(id); -} - -Attribute::Attribute(AttributeID id, const QString& name) : - _id(id), _name(name) { +AttributeValue::AttributeValue(const AttributePointer& attribute, void* const* value) : + _attribute(attribute) { + + if (_attribute) { + _value = _attribute->create(value); + } } + +AttributeValue::AttributeValue(const AttributeValue& other) : + _attribute(other._attribute) { + + if (_attribute) { + _value = _attribute->create(&other._value); + } +} + +AttributeValue::~AttributeValue() { + if (_attribute) { + _attribute->destroy(_value); + } +} + +AttributeValue& AttributeValue::operator=(const AttributeValue& other) { + if (_attribute) { + _attribute->destroy(_value); + } + if ((_attribute = other._attribute)) { + _value = _attribute->create(&other._value); + } +} + +void* AttributeValue::copy() const { + return _attribute->create(&_value); +} + +bool AttributeValue::isDefault() const { + return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue()); +} + +bool AttributeValue::operator==(const AttributeValue& other) const { + return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value)); +} + +bool AttributeValue::operator==(void* other) const { + return _attribute && _attribute->equal(_value, other); +} + +Attribute::Attribute(const QString& name) : _name(name) { +} + +Attribute::~Attribute() { +} + diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 183efaf8b4..1ccff349c9 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -10,12 +10,15 @@ #define __interface__AttributeRegistry__ #include +#include #include -typedef int AttributeID; +#include "Bitstream.h" class Attribute; +typedef QSharedPointer AttributePointer; + /// Maintains information about metavoxel attribute types. class AttributeRegistry { public: @@ -25,36 +28,103 @@ public: AttributeRegistry(); - /// Returns a unique id for the described attribute, creating one if necessary. - AttributeID getAttributeID(const QString& name); + /// Registers an attribute with the system. + /// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing + /// attribute + AttributePointer registerAttribute(AttributePointer attribute); - /// Returns the identified attribute, or an invalid attribute if not found. - Attribute getAttribute(AttributeID id) const; + /// Retrieves an attribute by name. + AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); } private: static AttributeRegistry _instance; - AttributeID _lastAttributeID; - QHash _attributeIDs; - QHash _attributes; + QHash _attributes; +}; + +/// Pairs an attribute value with its type. +class AttributeValue { +public: + + AttributeValue(const AttributePointer& attribute = AttributePointer(), void* const* value = NULL); + AttributeValue(const AttributeValue& other); + ~AttributeValue(); + + AttributeValue& operator=(const AttributeValue& other); + + AttributePointer getAttribute() const { return _attribute; } + void* getValue() const { return _value; } + + void* copy() const; + + bool isDefault() const; + + bool operator==(const AttributeValue& other) const; + bool operator==(void* other) const; + +private: + + AttributePointer _attribute; + void* _value; }; /// Represents a registered attribute. class Attribute { public: - Attribute(AttributeID id = 0, const QString& name = QString()); + Attribute(const QString& name); + virtual ~Attribute(); - bool isValid() const { return !_name.isNull(); } - - AttributeID getID() const { return _id; } const QString& getName() const { return _name; } + virtual void* create(void* const* copy = NULL) const = 0; + virtual void destroy(void* value) const = 0; + + virtual bool read(Bitstream& in, void*& value) const = 0; + virtual bool write(Bitstream& out, void* value) const = 0; + + virtual bool equal(void* first, void* second) const = 0; + + virtual void* createAveraged(void* values[]) const = 0; + + virtual void* getDefaultValue() const = 0; + private: - AttributeID _id; QString _name; }; +/// A simple attribute class that stores its values inline. +template class InlineAttribute : public Attribute { +public: + + InlineAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(*(void**)&defaultValue) { } + + virtual void* create(void* const* copy = NULL) const { return (copy == NULL) ? _defaultValue : *copy; } + virtual void destroy(void* value) const { /* no-op */ } + + virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; } + virtual bool write(Bitstream& out, void* value) const { out.write(&value, bits); return false; } + + virtual bool equal(void* first, void* second) const { return first == second; } + + virtual void* createAveraged(void* values[]) const; + + virtual void* getDefaultValue() const { return _defaultValue; } + +private: + + void* _defaultValue; +}; + +template inline void* InlineAttribute::createAveraged(void* values[]) const { + T total = T(); + for (int i = 0; i < 8; i++) { + total += *(T*)(values + i); + } + total /= 8; + return *(void**)&total; +} + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5f1d6c5d56..41b2fd3317 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -8,7 +8,119 @@ #include "MetavoxelData.h" -void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { +MetavoxelData::~MetavoxelData() { + for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { + it.value()->destroy(it.key()); + delete it.value(); + } +} + +void MetavoxelData::visitVoxels(const QVector& attributes, VoxelVisitor* visitor) { // map attributes to layers, indices } + +void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) { + MetavoxelNode*& node = _roots[attributeValue.getAttribute()]; + if (node == NULL) { + node = new MetavoxelNode(attributeValue.getAttribute()); + } + if (node->setAttributeValue(path, 0, attributeValue)) { + node->destroy(attributeValue.getAttribute()); + delete node; + _roots.remove(attributeValue.getAttribute()); + } +} + +AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const { + MetavoxelNode* node = _roots.value(attribute); + if (node == NULL) { + return AttributeValue(attribute); + } + for (int i = 0, n = path.getSize(); i < n; i++) { + int index = path[i]; + MetavoxelNode* child = node->getChild(i); + if (child == NULL) { + return AttributeValue(attribute); + } + node = child; + } + return node->getAttributeValue(attribute); +} + +MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) { + _attributeValue = attributeValue.copy(); + for (int i = 0; i < CHILD_COUNT; i++) { + _children[i] = NULL; + } +} + +bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue) { + if (index == path.getSize()) { + setAttributeValue(attributeValue); + return attributeValue.isDefault(); + } + int element = path[index]; + if (_children[element] == NULL) { + _children[element] = new MetavoxelNode(attributeValue.getAttribute()); + } + if (_children[element]->setAttributeValue(path, index + 1, attributeValue)) { + _children[element]->destroy(attributeValue.getAttribute()); + delete _children[element]; + _children[element] = NULL; + if (allChildrenNull()) { + return true; + } + } + void* childValues[CHILD_COUNT]; + for (int i = 0; i < CHILD_COUNT; i++) { + childValues[i] = (_children[i] == NULL) ? attributeValue.getAttribute()->getDefaultValue() : + _children[i]->_attributeValue; + } + attributeValue.getAttribute()->destroy(_attributeValue); + _attributeValue = attributeValue.getAttribute()->createAveraged(childValues); + return false; +} + +void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) { + attributeValue.getAttribute()->destroy(_attributeValue); + _attributeValue = attributeValue.copy(); +} + +AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const { + return AttributeValue(attribute, &_attributeValue); +} + +void MetavoxelNode::destroy(const AttributePointer& attribute) { + attribute->destroy(_attributeValue); + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i]) { + _children[i]->destroy(attribute); + delete _children[i]; + } + } +} + +bool MetavoxelNode::allChildrenNull() const { + for (int i = 0; i < CHILD_COUNT; i++) { + if (_children[i] != NULL) { + return false; + } + } + return true; +} + +int MetavoxelPath::operator[](int index) const { + return _array.at(index * BITS_PER_ELEMENT) | (_array.at(index * BITS_PER_ELEMENT + 1) << 1) | + (_array.at(index * BITS_PER_ELEMENT + 2) << 2); +} + +MetavoxelPath& MetavoxelPath::operator+=(int element) { + int offset = _array.size(); + _array.resize(offset + BITS_PER_ELEMENT); + _array.setBit(offset, element & 0x01); + _array.setBit(offset + 1, (element >> 1) & 0x01); + _array.setBit(offset + 2, element >> 2); + return *this; +} + diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 0b04cd0f86..becdc62348 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -9,36 +9,35 @@ #ifndef __interface__MetavoxelData__ #define __interface__MetavoxelData__ +#include +#include #include -#include #include "AttributeRegistry.h" -class MetavoxelLayer; class MetavoxelNode; +class MetavoxelPath; class VoxelVisitor; /// The base metavoxel representation shared between server and client. class MetavoxelData { public: + ~MetavoxelData(); + /// Applies the specified function to the contained voxels. /// \param attributes the list of attributes desired - void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + void visitVoxels(const QVector& attributes, VoxelVisitor* visitor); + + /// Sets the attribute value corresponding to the specified path. + void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue); + + /// Retrieves the attribute value corresponding to the specified path. + AttributeValue getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const; private: - QVector _layers; -}; - -/// A single layer of metavoxel data (a tree containing nodes of the same type). -class MetavoxelLayer { -public: - -private: - - QVector _attributes; - QScopedPointer _root; + QHash _roots; }; /// A single node within a metavoxel layer. @@ -47,12 +46,48 @@ public: static const int CHILD_COUNT = 8; - + MetavoxelNode(const AttributeValue& attributeValue); + + /// Descends the voxel tree in order to set the value of a node. + /// \param path the path to follow + /// \param index the position in the path + /// \return whether or not the node is entirely equal to the default attribute, and can thus be collapsed + bool setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue); + + void setAttributeValue(const AttributeValue& attributeValue); + + AttributeValue getAttributeValue(const AttributePointer& attribute) const; + + MetavoxelNode* getChild(int index) const { return _children[index]; } + void setChild(int index, MetavoxelNode* child) { _children[index] = child; } + + void destroy(const AttributePointer& attribute); private: + Q_DISABLE_COPY(MetavoxelNode) - void* _attributeValues; - QScopedPointer _children[CHILD_COUNT]; + bool allChildrenNull() const; + + void* _attributeValue; + MetavoxelNode* _children[CHILD_COUNT]; +}; + +/// A path down an octree. +class MetavoxelPath { +public: + + int getSize() const { return _array.size() / BITS_PER_ELEMENT; } + bool isEmpty() const { return _array.isEmpty(); } + + int operator[](int index) const; + + MetavoxelPath& operator+=(int element); + +private: + + static const int BITS_PER_ELEMENT = 3; + + QBitArray _array; }; /// Interface for visitors to voxels.