Fix for merging after streaming, added ability to "set" a spanner's attributes

in the actual metavoxel data.
This commit is contained in:
Andrzej Kapolka 2014-03-06 12:38:11 -08:00
parent 0448596e58
commit 23556f0cf7
8 changed files with 218 additions and 16 deletions

View file

@ -100,6 +100,7 @@ MetavoxelEditor::MetavoxelEditor() :
addTool(new InsertSpannerTool(this));
addTool(new RemoveSpannerTool(this));
addTool(new ClearSpannersTool(this));
addTool(new SetSpannerTool(this));
updateAttributes();
@ -529,15 +530,15 @@ void GlobalSetTool::apply() {
Application::getInstance()->getMetavoxels()->applyEdit(message);
}
InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) :
MetavoxelTool(editor, "Insert Spanner") {
PlaceSpannerTool::PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText) :
MetavoxelTool(editor, name) {
QPushButton* button = new QPushButton("Insert");
QPushButton* button = new QPushButton(placeText);
layout()->addWidget(button);
connect(button, SIGNAL(clicked()), SLOT(insert()));
connect(button, SIGNAL(clicked()), SLOT(place()));
}
void InsertSpannerTool::simulate(float deltaTime) {
void PlaceSpannerTool::simulate(float deltaTime) {
if (Application::getInstance()->isMouseHidden()) {
return;
}
@ -558,7 +559,7 @@ void InsertSpannerTool::simulate(float deltaTime) {
spanner->getRenderer()->simulate(deltaTime);
}
void InsertSpannerTool::render() {
void PlaceSpannerTool::render() {
if (Application::getInstance()->isMouseHidden()) {
return;
}
@ -567,28 +568,36 @@ void InsertSpannerTool::render() {
spanner->getRenderer()->render(SPANNER_ALPHA);
}
bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const {
bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const {
return attribute->inherits("SpannerSetAttribute");
}
bool InsertSpannerTool::eventFilter(QObject* watched, QEvent* event) {
bool PlaceSpannerTool::eventFilter(QObject* watched, QEvent* event) {
if (event->type() == QEvent::MouseButtonPress) {
insert();
place();
return true;
}
return false;
}
void InsertSpannerTool::insert() {
void PlaceSpannerTool::place() {
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
if (!attribute) {
return;
}
SharedObjectPointer spanner = _editor->getValue().value<SharedObjectPointer>();
MetavoxelEditMessage message = { QVariant::fromValue(InsertSpannerEdit(attribute, spanner)) };
MetavoxelEditMessage message = { createEdit(attribute, spanner) };
Application::getInstance()->getMetavoxels()->applyEdit(message);
}
InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) :
PlaceSpannerTool(editor, "Insert Spanner", "Insert") {
}
QVariant InsertSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
return QVariant::fromValue(InsertSpannerEdit(attribute, spanner));
}
RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) :
MetavoxelTool(editor, "Remove Spanner", false) {
}
@ -625,3 +634,16 @@ void ClearSpannersTool::clear() {
MetavoxelEditMessage message = { QVariant::fromValue(ClearSpannersEdit(attribute)) };
Application::getInstance()->getMetavoxels()->applyEdit(message);
}
SetSpannerTool::SetSpannerTool(MetavoxelEditor* editor) :
PlaceSpannerTool(editor, "Set Spanner", "Set") {
}
bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const {
return attribute == AttributeRegistry::getInstance()->getSpannersAttribute();
}
QVariant SetSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
static_cast<Spanner*>(spanner.data())->setGranularity(_editor->getGridSpacing());
return QVariant::fromValue(SetSpannerEdit(spanner));
}

View file

@ -139,13 +139,13 @@ private slots:
void apply();
};
/// Allows inserting a spanner into the scene.
class InsertSpannerTool : public MetavoxelTool {
/// Base class for insert/set spanner tools.
class PlaceSpannerTool : public MetavoxelTool {
Q_OBJECT
public:
InsertSpannerTool(MetavoxelEditor* editor);
PlaceSpannerTool(MetavoxelEditor* editor, const QString& name, const QString& placeText);
virtual void simulate(float deltaTime);
@ -155,9 +155,26 @@ public:
virtual bool eventFilter(QObject* watched, QEvent* event);
protected:
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0;
private slots:
void insert();
void place();
};
/// Allows inserting a spanner into the scene.
class InsertSpannerTool : public PlaceSpannerTool {
Q_OBJECT
public:
InsertSpannerTool(MetavoxelEditor* editor);
protected:
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
};
/// Allows removing a spanner from the scene.
@ -188,4 +205,19 @@ private slots:
void clear();
};
/// Allows setting the value by placing a spanner.
class SetSpannerTool : public PlaceSpannerTool {
Q_OBJECT
public:
SetSpannerTool(MetavoxelEditor* editor);
virtual bool appliesTo(const AttributePointer& attribute) const;
protected:
virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
};
#endif /* defined(__interface__MetavoxelEditor__) */

View file

@ -493,6 +493,7 @@ void MetavoxelNode::read(MetavoxelStreamState& state) {
_children[i] = new MetavoxelNode(state.attribute);
_children[i]->read(nextState);
}
mergeChildren(state.attribute);
}
}
@ -549,7 +550,8 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta
}
}
}
}
}
mergeChildren(state.attribute);
}
}
@ -1085,6 +1087,15 @@ void Spanner::setBounds(const Box& bounds) {
emit boundsChanged(_bounds = bounds);
}
const QVector<AttributePointer>& Spanner::getAttributes() const {
static QVector<AttributePointer> emptyVector;
return emptyVector;
}
bool Spanner::getAttributeValues(MetavoxelInfo& info) const {
return false;
}
bool Spanner::testAndSetVisited() {
if (_lastVisit == _visit) {
return false;
@ -1164,6 +1175,43 @@ void Sphere::setColor(const QColor& color) {
}
}
const QVector<AttributePointer>& Sphere::getAttributes() const {
static QVector<AttributePointer> attributes = QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute();
return attributes;
}
bool Sphere::getAttributeValues(MetavoxelInfo& info) const {
// bounds check
Box bounds = info.getBounds();
if (!getBounds().intersects(bounds)) {
return false;
}
// count the points inside the sphere
int pointsWithin = 0;
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
if (glm::distance(bounds.getVertex(i), getTranslation()) <= getScale()) {
pointsWithin++;
}
}
if (pointsWithin == Box::VERTEX_COUNT) {
// entirely contained
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(_color.rgba()));
getNormal(info);
return false;
}
if (info.size <= getGranularity()) {
// best guess
if (pointsWithin > 0) {
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(qRgba(
_color.red(), _color.green(), _color.blue(), _color.alpha() * pointsWithin / Box::VERTEX_COUNT)));
getNormal(info);
}
return false;
}
return true;
}
QByteArray Sphere::getRendererClassName() const {
return "SphereRenderer";
}
@ -1173,6 +1221,24 @@ void Sphere::updateBounds() {
setBounds(Box(getTranslation() - extent, getTranslation() + extent));
}
void Sphere::getNormal(MetavoxelInfo& info) const {
glm::vec3 normal = info.getCenter() - getTranslation();
float length = glm::length(normal);
QRgb color;
if (length > EPSILON) {
const float NORMAL_SCALE = 127.0f;
float scale = NORMAL_SCALE / length;
const int BYTE_MASK = 0xFF;
color = qRgb((int)(normal.x * scale) & BYTE_MASK, (int)(normal.y * scale) & BYTE_MASK,
(int)(normal.z * scale) & BYTE_MASK);
} else {
const QRgb DEFAULT_NORMAL = 0x007F00;
color = DEFAULT_NORMAL;
}
info.outputValues[1] = AttributeValue(getAttributes().at(1), encodeInline<QRgb>(color));
}
StaticModel::StaticModel() {
}

View file

@ -188,6 +188,7 @@ public:
bool isLeaf;
Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); }
glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; }
};
/// Interface for visitors to metavoxels.
@ -374,6 +375,13 @@ public:
void setGranularity(float granularity) { _granularity = granularity; }
float getGranularity() const { return _granularity; }
/// Returns a reference to the list of attributes associated with this spanner.
virtual const QVector<AttributePointer>& getAttributes() const;
/// Sets the attribute values associated with this spanner in the supplied info.
/// \return true to recurse, false to stop
virtual bool getAttributeValues(MetavoxelInfo& info) const;
/// Checks whether we've visited this object on the current traversal. If we have, returns false.
/// If we haven't, sets the last visit identifier and returns true.
bool testAndSetVisited();
@ -459,6 +467,9 @@ public:
void setColor(const QColor& color);
const QColor& getColor() const { return _color; }
virtual const QVector<AttributePointer>& getAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info) const;
signals:
void colorChanged(const QColor& color);
@ -473,6 +484,8 @@ private slots:
private:
void getNormal(MetavoxelInfo& info) const;
QColor _color;
};

View file

@ -123,3 +123,40 @@ ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
void ClearSpannersEdit::apply(MetavoxelData& data) const {
data.clear(attribute);
}
class SetSpannerEditVisitor : public MetavoxelVisitor {
public:
SetSpannerEditVisitor(Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private:
Spanner* _spanner;
};
SetSpannerEditVisitor::SetSpannerEditVisitor(Spanner* spanner) :
MetavoxelVisitor(QVector<AttributePointer>(), spanner->getAttributes()),
_spanner(spanner) {
}
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
return _spanner->getAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION;
}
SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) :
spanner(spanner) {
}
void SetSpannerEdit::apply(MetavoxelData& data) const {
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
// expand to fit the entire spanner
while (!data.getBounds().contains(spanner->getBounds())) {
data.expand();
}
SetSpannerEditVisitor visitor(spanner);
data.guide(visitor);
}

View file

@ -161,4 +161,19 @@ public:
DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit)
/// An edit that sets a spanner's attributes in the voxel tree.
class SetSpannerEdit : public MetavoxelEdit {
STREAMABLE
public:
STREAM SharedObjectPointer spanner;
SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer());
virtual void apply(MetavoxelData& data) const;
};
DECLARE_STREAMABLE_METATYPE(SetSpannerEdit)
#endif /* defined(__interface__MetavoxelMessages__) */

View file

@ -162,6 +162,17 @@ bool Box::intersects(const Box& other) const {
other.maximum.z >= minimum.z && other.minimum.z <= maximum.z;
}
const int X_MAXIMUM_FLAG = 1;
const int Y_MAXIMUM_FLAG = 2;
const int Z_MAXIMUM_FLAG = 4;
glm::vec3 Box::getVertex(int index) const {
return glm::vec3(
(index & X_MAXIMUM_FLAG) ? maximum.x : minimum.x,
(index & Y_MAXIMUM_FLAG) ? maximum.y : minimum.y,
(index & Z_MAXIMUM_FLAG) ? maximum.z : minimum.z);
}
Box operator*(const glm::mat4& matrix, const Box& box) {
// start with the constant component
Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]));

View file

@ -34,6 +34,8 @@ class Box {
public:
static const int VERTEX_COUNT = 8;
STREAM glm::vec3 minimum;
STREAM glm::vec3 maximum;
@ -44,6 +46,10 @@ public:
bool intersects(const Box& other) const;
float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); }
glm::vec3 getVertex(int index) const;
glm::vec3 getCenter() const { return (minimum + maximum) * 0.5f; }
};
DECLARE_STREAMABLE_METATYPE(Box)