Remove spanner bits.

This commit is contained in:
Andrzej Kapolka 2014-03-10 17:01:27 -07:00
parent 802cc3eeed
commit 9e5aae4a39
13 changed files with 175 additions and 31 deletions

View file

@ -25,7 +25,7 @@ MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
}
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
edit.apply(_data);
edit.apply(_data, SharedObject::getWeakHash());
}
const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";

View file

@ -44,6 +44,31 @@ void MetavoxelSystem::init() {
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
}
SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance) {
SharedObjectPointer closestSpanner;
float closestDistance = FLT_MAX;
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex());
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
if (client) {
float clientDistance;
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
origin, direction, attribute, clientDistance);
if (clientSpanner && clientDistance < closestDistance) {
closestSpanner = clientSpanner;
closestDistance = clientDistance;
}
}
}
}
if (closestSpanner) {
distance = closestDistance;
}
return closestSpanner;
}
void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) {
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
if (node->getType() == NodeType::MetavoxelServer) {
@ -215,7 +240,7 @@ void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
// apply immediately to local tree
edit.apply(_data);
edit.apply(_data, _sequencer.getWeakSharedObjectHash());
// start sending it out
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
@ -255,7 +280,7 @@ void MetavoxelClient::readPacket(Bitstream& in) {
// reapply local edits
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
if (message.data.userType() == MetavoxelEditMessage::Type) {
message.data.value<MetavoxelEditMessage>().apply(_data);
message.data.value<MetavoxelEditMessage>().apply(_data, _sequencer.getWeakSharedObjectHash());
}
}
}

View file

@ -35,6 +35,9 @@ public:
void init();
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, float& distance);
void applyEdit(const MetavoxelEditMessage& edit);
void simulate(float deltaTime);
@ -91,6 +94,8 @@ public:
MetavoxelClient(const SharedNodePointer& node);
virtual ~MetavoxelClient();
MetavoxelData& getData() { return _data; }
void guide(MetavoxelVisitor& visitor);
void applyEdit(const MetavoxelEditMessage& edit);

View file

@ -607,8 +607,19 @@ bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const {
}
bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) {
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
if (!attribute) {
return false;
}
if (event->type() == QEvent::MouseButtonPress) {
float distance;
SharedObjectPointer spanner = Application::getInstance()->getMetavoxels()->findFirstRaySpannerIntersection(
Application::getInstance()->getMouseRayOrigin(), Application::getInstance()->getMouseRayDirection(),
attribute, distance);
if (spanner) {
MetavoxelEditMessage message = { QVariant::fromValue(RemoveSpannerEdit(attribute, spanner->getRemoteID())) };
Application::getInstance()->getMetavoxels()->applyEdit(message);
}
return true;
}
return false;

View file

@ -201,6 +201,13 @@ void Bitstream::persistAndResetReadMappings() {
persistReadMappings(getAndResetReadMappings());
}
void Bitstream::clearSharedObject(int id) {
SharedObjectPointer object = _sharedObjectStreamer.takePersistentValue(id);
if (object) {
_weakSharedObjectHash.remove(object->getRemoteID());
}
}
Bitstream& Bitstream::operator<<(bool value) {
if (value) {
_byte |= (1 << _position);
@ -487,7 +494,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
object = SharedObjectPointer();
return *this;
}
QPointer<SharedObject>& pointer = _transientSharedObjects[id];
QPointer<SharedObject>& pointer = _weakSharedObjectHash[id];
if (pointer) {
const QMetaObject* metaObject;
_metaObjectStreamer >> metaObject;
@ -500,6 +507,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
QObject* rawObject;
*this >> rawObject;
pointer = static_cast<SharedObject*>(rawObject);
pointer->setRemoteID(id);
}
object = static_cast<SharedObject*>(pointer.data());
return *this;

View file

@ -71,7 +71,7 @@ public:
int takePersistentID(P value) { return _persistentIDs.take(value); }
void removePersistentValue(int id) { _persistentIDs.remove(_persistentValues.take(id)); }
T takePersistentValue(int id) { T value = _persistentValues.take(id); _persistentIDs.remove(value); return value; }
RepeatedValueStreamer& operator<<(T value);
RepeatedValueStreamer& operator>>(T& value);
@ -242,8 +242,11 @@ public:
/// Immediately persists and resets the read mappings.
void persistAndResetReadMappings();
/// Returns a reference to the weak hash storing shared objects for this stream.
const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _weakSharedObjectHash; }
/// Removes a shared object from the read mappings.
void clearSharedObject(int id) { _sharedObjectStreamer.removePersistentValue(id); }
void clearSharedObject(int id);
Bitstream& operator<<(bool value);
Bitstream& operator>>(bool& value);
@ -339,7 +342,7 @@ private:
RepeatedValueStreamer<QScriptString> _scriptStringStreamer;
RepeatedValueStreamer<SharedObjectPointer, SharedObject*> _sharedObjectStreamer;
QHash<int, QPointer<SharedObject> > _transientSharedObjects;
WeakSharedObjectHash _weakSharedObjectHash;
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();

View file

@ -34,6 +34,9 @@ public:
DatagramSequencer(const QByteArray& datagramHeader = QByteArray(), QObject* parent = NULL);
/// Returns a reference to the weak hash mapping remote ids to shared objects.
const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _inputStream.getWeakSharedObjectHash(); }
/// Returns the packet number of the last packet sent.
int getOutgoingPacketNumber() const { return _outgoingPacketNumber; }

View file

@ -218,6 +218,48 @@ void MetavoxelData::clear(const AttributePointer& attribute) {
}
}
class FirstRaySpannerIntersectionVisitor : public RaySpannerIntersectionVisitor {
public:
FirstRaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, const MetavoxelLOD& lod);
Spanner* getSpanner() const { return _spanner; }
float getDistance() const { return _distance; }
virtual bool visit(Spanner* spanner, float distance);
private:
Spanner* _spanner;
float _distance;
};
FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) :
RaySpannerIntersectionVisitor(origin, direction, QVector<AttributePointer>() << attribute,
QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
_spanner(NULL) {
}
bool FirstRaySpannerIntersectionVisitor::visit(Spanner* spanner, float distance) {
_spanner = spanner;
_distance = distance;
return false;
}
SharedObjectPointer MetavoxelData::findFirstRaySpannerIntersection(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute,
float& distance, const MetavoxelLOD& lod) {
FirstRaySpannerIntersectionVisitor visitor(origin, direction, attribute, lod);
guide(visitor);
if (!visitor.getSpanner()) {
return SharedObjectPointer();
}
distance = visitor.getDistance();
return SharedObjectPointer(visitor.getSpanner());
}
const int X_MAXIMUM_FLAG = 1;
const int Y_MAXIMUM_FLAG = 2;
const int Z_MAXIMUM_FLAG = 4;
@ -839,14 +881,14 @@ int RayIntersectionVisitor::visit(MetavoxelInfo& info) {
return visit(info, distance);
}
RayIntersectionSpannerVisitor::RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction,
RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()) {
}
void RayIntersectionSpannerVisitor::prepare() {
void RaySpannerIntersectionVisitor::prepare() {
Spanner::incrementVisit();
}
@ -860,7 +902,7 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
return first.distance < second.distance;
}
int RayIntersectionSpannerVisitor::visit(MetavoxelInfo& info, float distance) {
int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {

View file

@ -81,6 +81,10 @@ public:
void clear(const AttributePointer& attribute);
/// Convenience function that finds the first spanner intersecting the provided ray.
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD());
/// Expands the tree, increasing its capacity in all dimensions.
void expand();
@ -284,10 +288,10 @@ protected:
};
/// Base class for ray intersection spanner visitors.
class RayIntersectionSpannerVisitor : public RayIntersectionVisitor {
class RaySpannerIntersectionVisitor : public RayIntersectionVisitor {
public:
RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction,
RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),

View file

@ -8,8 +8,8 @@
#include "MetavoxelMessages.h"
void MetavoxelEditMessage::apply(MetavoxelData& data) const {
static_cast<const MetavoxelEdit*>(edit.data())->apply(data);
void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
static_cast<const MetavoxelEdit*>(edit.data())->apply(data, objects);
}
MetavoxelEdit::~MetavoxelEdit() {
@ -58,7 +58,7 @@ int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
return DEFAULT_ORDER; // subdivide
}
void BoxSetEdit::apply(MetavoxelData& data) const {
void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// expand to fit the entire edit
while (!data.getBounds().contains(region)) {
data.expand();
@ -94,7 +94,7 @@ int GlobalSetEditVisitor::visit(MetavoxelInfo& info) {
return STOP_RECURSION; // entirely contained
}
void GlobalSetEdit::apply(MetavoxelData& data) const {
void GlobalSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
GlobalSetEditVisitor visitor(*this);
data.guide(visitor);
}
@ -104,7 +104,7 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
spanner(spanner) {
}
void InsertSpannerEdit::apply(MetavoxelData& data) const {
void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
data.insert(attribute, spanner);
}
@ -113,14 +113,20 @@ RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id)
id(id) {
}
void RemoveSpannerEdit::apply(MetavoxelData& data) const {
void RemoveSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
SharedObject* object = objects.value(id);
if (!object) {
qDebug() << "Missing object to remove" << id;
return;
}
data.remove(attribute, object);
}
ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
attribute(attribute) {
}
void ClearSpannersEdit::apply(MetavoxelData& data) const {
void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
data.clear(attribute);
}
@ -149,7 +155,7 @@ SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) :
spanner(spanner) {
}
void SetSpannerEdit::apply(MetavoxelData& data) const {
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
// expand to fit the entire spanner

View file

@ -66,7 +66,7 @@ public:
STREAM QVariant edit;
void apply(MetavoxelData& data) const;
void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage)
@ -77,7 +77,7 @@ public:
virtual ~MetavoxelEdit();
virtual void apply(MetavoxelData& data) const = 0;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const = 0;
};
/// An edit that sets the region within a box to a value.
@ -93,7 +93,7 @@ public:
BoxSetEdit(const Box& region = Box(), float granularity = 0.0f,
const OwnedAttributeValue& value = OwnedAttributeValue());
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(BoxSetEdit)
@ -108,7 +108,7 @@ public:
GlobalSetEdit(const OwnedAttributeValue& value = OwnedAttributeValue());
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(GlobalSetEdit)
@ -125,7 +125,7 @@ public:
InsertSpannerEdit(const AttributePointer& attribute = AttributePointer(),
const SharedObjectPointer& spanner = SharedObjectPointer());
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(InsertSpannerEdit)
@ -141,7 +141,7 @@ public:
RemoveSpannerEdit(const AttributePointer& attribute = AttributePointer(), int id = 0);
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(RemoveSpannerEdit)
@ -156,7 +156,7 @@ public:
ClearSpannersEdit(const AttributePointer& attribute = AttributePointer());
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit)
@ -171,7 +171,7 @@ public:
SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer());
virtual void apply(MetavoxelData& data) const;
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(SetSpannerEdit)

View file

@ -18,7 +18,12 @@
REGISTER_META_OBJECT(SharedObject)
SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) {
SharedObject::SharedObject() :
_id(++_lastID),
_remoteID(0),
_referenceCount(0) {
_weakHash.insert(_id, this);
}
void SharedObject::incrementReferenceCount() {
@ -27,6 +32,7 @@ void SharedObject::incrementReferenceCount() {
void SharedObject::decrementReferenceCount() {
if (--_referenceCount == 0) {
_weakHash.remove(_id);
delete this;
}
}
@ -86,6 +92,17 @@ void SharedObject::dump(QDebug debug) const {
}
int SharedObject::_lastID = 0;
WeakSharedObjectHash SharedObject::_weakHash;
void pruneWeakSharedObjectHash(WeakSharedObjectHash& hash) {
for (WeakSharedObjectHash::iterator it = hash.begin(); it != hash.end(); ) {
if (!it.value()) {
it = hash.erase(it);
} else {
it++;
}
}
}
SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nullable, QWidget* parent) : QWidget(parent) {
QVBoxLayout* layout = new QVBoxLayout();

View file

@ -9,23 +9,38 @@
#ifndef __interface__SharedObject__
#define __interface__SharedObject__
#include <QHash>
#include <QMetaType>
#include <QObject>
#include <QPointer>
#include <QSet>
#include <QWidget>
#include <QtDebug>
class QComboBox;
class SharedObject;
typedef QHash<int, QPointer<SharedObject> > WeakSharedObjectHash;
/// A QObject that may be shared over the network.
class SharedObject : public QObject {
Q_OBJECT
public:
/// Returns the weak hash under which all local shared objects are registered.
static const WeakSharedObjectHash& getWeakHash() { return _weakHash; }
Q_INVOKABLE SharedObject();
int getID() { return _id; }
/// Returns the unique local ID for this object.
int getID() const { return _id; }
/// Returns the unique remote ID for this object, or zero if this is a local object.
int getRemoteID() const { return _remoteID; }
void setRemoteID(int remoteID) { _remoteID = remoteID; }
int getReferenceCount() const { return _referenceCount; }
void incrementReferenceCount();
@ -43,11 +58,16 @@ public:
private:
int _id;
int _remoteID;
int _referenceCount;
static int _lastID;
static WeakSharedObjectHash _weakHash;
};
/// Removes the null references from the supplied hash.
void pruneWeakSharedObjectHash(WeakSharedObjectHash& hash);
/// A pointer to a shared object.
template<class T> class SharedObjectPointerTemplate {
public: