diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1df82a42a0..4cb6414966 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -822,6 +822,12 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin _radius->setSingleStep(0.01); _radius->setMaximum(FLT_MAX); _radius->setValue(5.0); + + _form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); } bool HeightfieldBrushTool::appliesTo(const AttributePointer& attribute) const { @@ -851,7 +857,7 @@ bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Wheel) { float angle = static_cast(event)->angleDelta().y(); const float ANGLE_SCALE = 1.0f / 1000.0f; - _radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE)); + _radius->setValue(_radius->value() * pow(2.0f, angle * ANGLE_SCALE)); return true; } else if (event->type() == QEvent::MouseButtonPress && _positionValid) { @@ -881,7 +887,7 @@ QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { const int ERASE_MODE_INDEX = 2; return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), alternate ? -_height->value() : _height->value(), _mode->currentIndex() == SET_MODE_INDEX, - _mode->currentIndex() == ERASE_MODE_INDEX)); + _mode->currentIndex() == ERASE_MODE_INDEX, pow(2.0f, _granularity->value()))); } MaterialControl::MaterialControl(QWidget* widget, QFormLayout* form, bool clearable) : @@ -956,10 +962,11 @@ QVariant HeightfieldMaterialBrushTool::createEdit(bool alternate) { sphere->setScale(_radius->value()); if (alternate) { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(0, 0, 0, 0), true)); + SharedObjectPointer(), QColor(0, 0, 0, 0), true, false, pow(2.0f, _granularity->value()))); } else { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - _materialControl->getMaterial(), _materialControl->getColor(), true)); + _materialControl->getMaterial(), _materialControl->getColor(), + true, false, pow(2.0f, _granularity->value()))); } } @@ -974,10 +981,11 @@ QVariant HeightfieldSculptBrushTool::createEdit(bool alternate) { sphere->setScale(_radius->value()); if (alternate) { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(0, 0, 0, 0))); + SharedObjectPointer(), QColor(0, 0, 0, 0), false, false, pow(2.0f, _granularity->value()))); } else { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - _materialControl->getMaterial(), _materialControl->getColor())); + _materialControl->getMaterial(), _materialControl->getColor(), + false, false, pow(2.0f, _granularity->value()))); } } @@ -992,13 +1000,14 @@ HeightfieldFillBrushTool::HeightfieldFillBrushTool(MetavoxelEditor* editor) : QVariant HeightfieldFillBrushTool::createEdit(bool alternate) { const int FILL_MODE_INDEX = 0; if (_mode->currentIndex() == FILL_MODE_INDEX) { - return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value())); + return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value(), + pow(2.0f, _granularity->value()))); } Sphere* sphere = new Sphere(); sphere->setTranslation(_position); sphere->setScale(_radius->value()); return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(), false, true)); + SharedObjectPointer(), QColor(), false, true, pow(2.0f, _granularity->value()))); } HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) : @@ -1017,6 +1026,12 @@ HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) _snapToGrid->setChecked(true); _materialControl = new MaterialControl(this, form, true); + + form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); } bool HeightfieldMaterialBoxTool::appliesTo(const AttributePointer& attribute) const { @@ -1039,7 +1054,7 @@ void HeightfieldMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm: cuboid->setAspectY(vector.y / vector.x); cuboid->setAspectZ(vector.z / vector.x); MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(cuboid), - _materialControl->getMaterial(), _materialControl->getColor())) }; + _materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } @@ -1056,6 +1071,12 @@ HeightfieldMaterialSpannerTool::HeightfieldMaterialSpannerTool(MetavoxelEditor* _materialControl = new MaterialControl(this, form, true); + form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); + QPushButton* place = new QPushButton("Set"); layout()->addWidget(place); connect(place, &QPushButton::clicked, this, &HeightfieldMaterialSpannerTool::place); @@ -1076,7 +1097,7 @@ QColor HeightfieldMaterialSpannerTool::getColor() { void HeightfieldMaterialSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { static_cast(spanner.data())->setWillBeVoxelized(true); MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(spanner, - _materialControl->getMaterial(), _materialControl->getColor())) }; + _materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 23feb940c9..a816b9ebe7 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -326,6 +326,7 @@ protected: QFormLayout* _form; QDoubleSpinBox* _radius; + QDoubleSpinBox* _granularity; glm::vec3 _position; bool _positionValid; @@ -448,6 +449,7 @@ private: QCheckBox* _snapToGrid; MaterialControl* _materialControl; + QDoubleSpinBox* _granularity; }; /// Allows setting heightfield materials by placing a spanner. @@ -470,6 +472,7 @@ private: SharedObjectEditor* _spannerEditor; MaterialControl* _materialControl; + QDoubleSpinBox* _granularity; }; #endif // hifi_MetavoxelEditor_h diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index bae5768068..98da28cafa 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -149,12 +149,13 @@ void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects } PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, - float height, bool set, bool erase) : + float height, bool set, bool erase, float granularity) : position(position), radius(radius), height(height), set(set), - erase(erase) { + erase(erase), + granularity(granularity) { } void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { @@ -166,7 +167,8 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje Box(position - extents, position + extents), results); foreach (const SharedObjectPointer& spanner, results) { - Spanner* newSpanner = static_cast(spanner.data())->paintHeight(position, radius, height, set, erase); + Spanner* newSpanner = static_cast(spanner.data())->paintHeight(position, radius, + height, set, erase, granularity); if (newSpanner != spanner) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner); } @@ -179,11 +181,12 @@ MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& av } HeightfieldMaterialSpannerEdit::HeightfieldMaterialSpannerEdit(const SharedObjectPointer& spanner, - const SharedObjectPointer& material, const QColor& averageColor, bool paint, bool voxelize) : + const SharedObjectPointer& material, const QColor& averageColor, bool paint, bool voxelize, float granularity) : MaterialEdit(material, averageColor), spanner(spanner), paint(paint), - voxelize(voxelize) { + voxelize(voxelize), + granularity(granularity) { } class SpannerProjectionFetchVisitor : public SpannerVisitor { @@ -250,16 +253,18 @@ void HeightfieldMaterialSpannerEdit::apply(MetavoxelData& data, const WeakShared } foreach (const SharedObjectPointer& result, results) { - Spanner* newResult = static_cast(result.data())->setMaterial(spanner, material, color, paint, voxelize); + Spanner* newResult = static_cast(result.data())->setMaterial(spanner, material, + color, paint, voxelize, granularity); if (newResult != result) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), result, newResult); } } } -FillHeightfieldHeightEdit::FillHeightfieldHeightEdit(const glm::vec3& position, float radius) : +FillHeightfieldHeightEdit::FillHeightfieldHeightEdit(const glm::vec3& position, float radius, float granularity) : position(position), - radius(radius) { + radius(radius), + granularity(granularity) { } void FillHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { @@ -269,7 +274,7 @@ void FillHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjec Box(position - extents, position + extents), results); foreach (const SharedObjectPointer& spanner, results) { - Spanner* newSpanner = static_cast(spanner.data())->fillHeight(position, radius); + Spanner* newSpanner = static_cast(spanner.data())->fillHeight(position, radius, granularity); if (newSpanner != spanner) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner); } diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 71013996c2..7fbe2b4243 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -205,9 +205,10 @@ public: STREAM float height; STREAM bool set; STREAM bool erase; + STREAM float granularity; PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, - float height = 0.0f, bool set = false, bool erase = false); + float height = 0.0f, bool set = false, bool erase = false, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; @@ -237,10 +238,11 @@ public: STREAM SharedObjectPointer spanner; STREAM bool paint; STREAM bool voxelize; + STREAM float granularity; HeightfieldMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(), const SharedObjectPointer& material = SharedObjectPointer(), - const QColor& averageColor = QColor(), bool paint = false, bool voxelize = false); + const QColor& averageColor = QColor(), bool paint = false, bool voxelize = false, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; @@ -255,8 +257,9 @@ public: STREAM glm::vec3 position; STREAM float radius; + STREAM float granularity; - FillHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f); + FillHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index c771b8fb4a..05d765f9d4 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -111,16 +111,16 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire return _bounds.findRayIntersection(origin, direction, distance); } -Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) { +Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase, float granularity) { return this; } -Spanner* Spanner::fillHeight(const glm::vec3& position, float radius) { +Spanner* Spanner::fillHeight(const glm::vec3& position, float radius, float granularity) { return this; } Spanner* Spanner::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize) { + const QColor& color, bool paint, bool voxelize, float granularity) { return this; } @@ -1786,7 +1786,7 @@ void HeightfieldNode::getRangeAfterHeightPaint(const glm::vec3& translation, con HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& position, float radius, float height, bool set, bool erase, - float normalizeScale, float normalizeOffset) { + float normalizeScale, float normalizeOffset, float granularity) { if (!_height) { return this; } @@ -1813,7 +1813,7 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons HeightfieldNode* newChild = _children[i]->paintHeight(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, - nextScale, position, radius, height, set, erase, normalizeScale, normalizeOffset); + nextScale, position, radius, height, set, erase, normalizeScale, normalizeOffset, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -1885,7 +1885,7 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons } HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, - const glm::vec3& position, float radius) { + const glm::vec3& position, float radius, float granularity) { if (!_height) { return this; } @@ -1911,7 +1911,7 @@ HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const HeightfieldNode* newChild = _children[i]->fillHeight(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, - nextScale, position, radius); + nextScale, position, radius, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -2088,7 +2088,7 @@ void HeightfieldNode::getRangeAfterEdit(const glm::vec3& translation, const glm: HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, Spanner* spanner, const SharedObjectPointer& material, const QColor& color, bool paint, bool voxelize, - float normalizeScale, float normalizeOffset) { + float normalizeScale, float normalizeOffset, float granularity) { if (!_height) { return this; } @@ -2109,7 +2109,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons HeightfieldNode* newChild = _children[i]->setMaterial(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, nextScale, spanner, - material, color, paint, voxelize, normalizeScale, normalizeOffset); + material, color, paint, voxelize, normalizeScale, normalizeOffset, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -3310,7 +3310,8 @@ bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3& getScale() * _aspectZ), origin, direction, distance); } -Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) { +Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity) { // first see if we're going to exceed the range limits float minimumValue = 1.0f, maximumValue = numeric_limits::max(); if (set) { @@ -3328,19 +3329,19 @@ Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float Heightfield* newHeightfield = prepareEdit(minimumValue, maximumValue, normalizeScale, normalizeOffset); newHeightfield->setRoot(HeightfieldNodePointer(_root->paintHeight(newHeightfield->getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * newHeightfield->getAspectY(), getScale() * _aspectZ), position, radius, height, - set, erase, normalizeScale, normalizeOffset))); + set, erase, normalizeScale, normalizeOffset, granularity))); return newHeightfield; } -Spanner* Heightfield::fillHeight(const glm::vec3& position, float radius) { +Spanner* Heightfield::fillHeight(const glm::vec3& position, float radius, float granularity) { Heightfield* newHeightfield = static_cast(clone(true)); newHeightfield->setRoot(HeightfieldNodePointer(_root->fillHeight(getTranslation(), getRotation(), - glm::vec3(getScale(), getScale() * _aspectY, getScale() * _aspectZ), position, radius))); + glm::vec3(getScale(), getScale() * _aspectY, getScale() * _aspectZ), position, radius, granularity))); return newHeightfield; } Spanner* Heightfield::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize) { + const QColor& color, bool paint, bool voxelize, float granularity) { // first see if we're going to exceed the range limits, normalizing if necessary Spanner* spannerData = static_cast(spanner.data()); float normalizeScale = 1.0f, normalizeOffset = 0.0f; @@ -3355,7 +3356,7 @@ Spanner* Heightfield::setMaterial(const SharedObjectPointer& spanner, const Shar } newHeightfield->setRoot(HeightfieldNodePointer(_root->setMaterial(newHeightfield->getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * newHeightfield->getAspectY(), getScale() * _aspectZ), spannerData, - material, color, paint, voxelize, normalizeScale, normalizeOffset))); + material, color, paint, voxelize, normalizeScale, normalizeOffset, granularity))); return newHeightfield; } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 653893c84d..42aad203c6 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -77,16 +77,17 @@ public: /// \param set whether to set the height as opposed to raising/lowering it /// \param erase whether to erase height values /// \return the modified spanner, or this if no modification was performed - virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase); + virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity); /// Attempts to fill the spanner's height (adding removing volumetric information). /// \return the modified spanner, or this if no modification was performed - virtual Spanner* fillHeight(const glm::vec3& position, float radius); + virtual Spanner* fillHeight(const glm::vec3& position, float radius, float granularity); /// Attempts to "sculpt" or "paint," etc., with the supplied spanner. /// \return the modified spanner, or this if no modification was performed virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize); + const QColor& color, bool paint, bool voxelize, float granularity); /// Checks whether this spanner has its own colors. virtual bool hasOwnColors() const; @@ -696,17 +697,17 @@ public: HeightfieldNode* paintHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& position, float radius, float height, bool set, bool erase, - float normalizeScale, float normalizeOffset); + float normalizeScale, float normalizeOffset, float granularity); HeightfieldNode* fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, - const glm::vec3& position, float radius); + const glm::vec3& position, float radius, float granularity); void getRangeAfterEdit(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const Box& editBounds, float& minimum, float& maximum) const; HeightfieldNode* setMaterial(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, Spanner* spanner, const SharedObjectPointer& material, const QColor& color, bool paint, bool voxelize, - float normalizeScale, float normalizeOffset); + float normalizeScale, float normalizeOffset, float granularity); void read(HeightfieldStreamState& state); void write(HeightfieldStreamState& state) const; @@ -803,12 +804,13 @@ public: virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; - virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase); + virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity); - virtual Spanner* fillHeight(const glm::vec3& position, float radius); + virtual Spanner* fillHeight(const glm::vec3& position, float radius, float granularity); virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize); + const QColor& color, bool paint, bool voxelize, float granularity); virtual bool hasOwnColors() const; virtual bool hasOwnMaterials() const; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 110892a106..7968c36e42 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -78,7 +78,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeAudioStreamStats: return 1; case PacketTypeMetavoxelData: - return 12; + return 13; default: return 0; }