More progress on generic attributes, metavoxel node management.

This commit is contained in:
Andrzej Kapolka 2013-12-10 15:44:48 -08:00
parent c423205709
commit 6ba750a963
8 changed files with 354 additions and 45 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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 <QtDebug>
#include "MetavoxelSystem.h"
void MetavoxelSystem::init() {
qDebug() << "Howdy hello\n";
}

View file

@ -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 <MetavoxelData.h>
/// Renders a metavoxel tree.
class MetavoxelSystem {
public:
void init();
private:
MetavoxelData _data;
};
#endif /* defined(__interface__MetavoxelSystem__) */

View file

@ -10,22 +10,68 @@
AttributeRegistry AttributeRegistry::_instance;
AttributeRegistry::AttributeRegistry() : _lastAttributeID(0) {
AttributeRegistry::AttributeRegistry() {
registerAttribute(AttributePointer(new InlineAttribute<float, 32>("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() {
}

View file

@ -10,12 +10,15 @@
#define __interface__AttributeRegistry__
#include <QHash>
#include <QSharedPointer>
#include <QString>
typedef int AttributeID;
#include "Bitstream.h"
class Attribute;
typedef QSharedPointer<Attribute> 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<QString, AttributeID> _attributeIDs;
QHash<AttributeID, Attribute> _attributes;
QHash<QString, AttributePointer> _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 T, int bits> 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<class T, int bits> inline void* InlineAttribute<T, bits>::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__) */

View file

@ -8,7 +8,119 @@
#include "MetavoxelData.h"
void MetavoxelData::visitVoxels(const QVector<AttributeID>& attributes, VoxelVisitor* visitor) {
MetavoxelData::~MetavoxelData() {
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
it.value()->destroy(it.key());
delete it.value();
}
}
void MetavoxelData::visitVoxels(const QVector<Attribute*>& 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;
}

View file

@ -9,36 +9,35 @@
#ifndef __interface__MetavoxelData__
#define __interface__MetavoxelData__
#include <QBitArray>
#include <QHash>
#include <QScopedPointer>
#include <QVector>
#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<AttributeID>& attributes, VoxelVisitor* visitor);
void visitVoxels(const QVector<Attribute*>& 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<MetavoxelLayer> _layers;
};
/// A single layer of metavoxel data (a tree containing nodes of the same type).
class MetavoxelLayer {
public:
private:
QVector<AttributeID> _attributes;
QScopedPointer<MetavoxelNode> _root;
QHash<AttributePointer, MetavoxelNode*> _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<MetavoxelNode> _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.