From d82f2692634ecfc2ec6cf10eaa9fd3039f3d6eed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 9 Jan 2015 11:46:40 -0800 Subject: [PATCH] Don't show grid for tools where it isn't needed, started on "fill" tool. --- interface/src/ui/MetavoxelEditor.cpp | 25 ++++-- interface/src/ui/MetavoxelEditor.h | 19 +++- .../metavoxels/src/MetavoxelMessages.cpp | 18 ++++ libraries/metavoxels/src/MetavoxelMessages.h | 16 ++++ libraries/metavoxels/src/Spanner.cpp | 88 ++++++++++++++++++- libraries/metavoxels/src/Spanner.h | 9 ++ 6 files changed, 167 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 186aa7a48e..98ed64590e 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -129,6 +129,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new HeightfieldHeightBrushTool(this)); addTool(new HeightfieldMaterialBrushTool(this)); addTool(new HeightfieldSculptBrushTool(this)); + addTool(new HeightfieldFillBrushTool(this)); addTool(new HeightfieldMaterialBoxTool(this)); addTool(new HeightfieldMaterialSpannerTool(this)); @@ -330,6 +331,9 @@ void MetavoxelEditor::render() { MetavoxelTool* tool = getActiveTool(); if (tool) { tool->render(); + if (!tool->getUsesGrid()) { + return; + } } glDepthMask(GL_FALSE); @@ -385,10 +389,11 @@ MetavoxelTool* MetavoxelEditor::getActiveTool() const { ProgramObject MetavoxelEditor::_gridProgram; -MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) : +MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing, bool usesGrid) : _editor(editor), _usesValue(usesValue), - _userFacing(userFacing) { + _userFacing(userFacing), + _usesGrid(usesGrid) { QVBoxLayout* layout = new QVBoxLayout(); setLayout(layout); @@ -669,7 +674,7 @@ void InsertSpannerTool::applyEdit(const AttributePointer& attribute, const Share } RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : - MetavoxelTool(editor, "Remove Spanner", false) { + MetavoxelTool(editor, "Remove Spanner", false, true, false) { } bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const { @@ -696,7 +701,7 @@ bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) { } ClearSpannersTool::ClearSpannersTool(MetavoxelEditor* editor) : - MetavoxelTool(editor, "Clear Spanners", false) { + MetavoxelTool(editor, "Clear Spanners", false, true, false) { QPushButton* button = new QPushButton("Clear"); layout()->addWidget(button); @@ -717,7 +722,7 @@ void ClearSpannersTool::clear() { } HeightfieldTool::HeightfieldTool(MetavoxelEditor* editor, const QString& name) : - MetavoxelTool(editor, name, false) { + MetavoxelTool(editor, name, false, true, false) { QWidget* widget = new QWidget(); widget->setLayout(_form = new QFormLayout()); @@ -806,7 +811,7 @@ void ImportHeightfieldTool::updateSpanner() { } HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name) : - MetavoxelTool(editor, name, false), + MetavoxelTool(editor, name, false, true, false), _positionValid(false) { QWidget* widget = new QWidget(); @@ -968,6 +973,14 @@ QVariant HeightfieldSculptBrushTool::createEdit(bool alternate) { } } +HeightfieldFillBrushTool::HeightfieldFillBrushTool(MetavoxelEditor* editor) : + HeightfieldBrushTool(editor, "Fill Brush") { +} + +QVariant HeightfieldFillBrushTool::createEdit(bool alternate) { + return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value())); +} + HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) : BoxTool(editor, "Set Material (Box)", false) { diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index e3e2f38746..922cb298c4 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -92,12 +92,15 @@ class MetavoxelTool : public QWidget { public: - MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true); + MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, + bool userFacing = true, bool usesGrid = true); bool getUsesValue() const { return _usesValue; } bool isUserFacing() const { return _userFacing; } + bool getUsesGrid() const { return _usesGrid; } + virtual bool appliesTo(const AttributePointer& attribute) const; virtual void simulate(float deltaTime); @@ -113,6 +116,7 @@ protected: MetavoxelEditor* _editor; bool _usesValue; bool _userFacing; + bool _usesGrid; }; /// Base class for tools that allow dragging out a 3D box. @@ -404,6 +408,19 @@ private: MaterialControl* _materialControl; }; +/// Allows "filling" (removing dual contour stack data) parts of the heightfield. +class HeightfieldFillBrushTool : public HeightfieldBrushTool { + Q_OBJECT + +public: + + HeightfieldFillBrushTool(MetavoxelEditor* editor); + +protected: + + virtual QVariant createEdit(bool alternate); +}; + /// Allows setting heightfield materials by dragging out a box. class HeightfieldMaterialBoxTool : public BoxTool { Q_OBJECT diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 50808156a7..5ba16ee754 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -201,3 +201,21 @@ void HeightfieldMaterialSpannerEdit::apply(MetavoxelData& data, const WeakShared } } +FillHeightfieldHeightEdit::FillHeightfieldHeightEdit(const glm::vec3& position, float radius) : + position(position), + radius(radius) { +} + +void FillHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + glm::vec3 extents = glm::vec3(radius, radius, radius); + QVector results; + data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(), + Box(position - extents, position + extents), results); + + foreach (const SharedObjectPointer& spanner, results) { + Spanner* newSpanner = static_cast(spanner.data())->fillHeight(position, radius); + 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 4b941eaad2..0605fb4dd2 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -243,4 +243,20 @@ public: DECLARE_STREAMABLE_METATYPE(HeightfieldMaterialSpannerEdit) +/// An edit that sets a region of a heightfield height. +class FillHeightfieldHeightEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM glm::vec3 position; + STREAM float radius; + + FillHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f); + + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; +}; + +DECLARE_STREAMABLE_METATYPE(FillHeightfieldHeightEdit) + #endif // hifi_MetavoxelMessages_h diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index e53da2329c..3840fda465 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -115,6 +115,10 @@ Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float hei return this; } +Spanner* Spanner::fillHeight(const glm::vec3& position, float radius) { + return this; +} + Spanner* Spanner::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, const QColor& color, bool paint) { return this; @@ -1926,7 +1930,8 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons maybeRenormalize(scale, normalizeScale, normalizeOffset, innerStackWidth, newHeightContents, newStackContents); if (!intersects) { return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)), - _color, _material, HeightfieldStackPointer(new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); + _color, _material, HeightfieldStackPointer(newStackContents.isEmpty() ? NULL : + new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); } // now apply the actual change @@ -1956,6 +1961,80 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons lineDest += heightWidth; } + return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)), + _color, _material, HeightfieldStackPointer(newStackContents.isEmpty() ? NULL : + new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); +} + +HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, + const glm::vec3& position, float radius) { + if (!_height) { + return this; + } + int heightWidth = _height->getWidth(); + int heightHeight = _height->getContents().size() / heightWidth; + int innerHeightWidth = heightWidth - HeightfieldHeight::HEIGHT_EXTENSION; + int innerHeightHeight = heightHeight - HeightfieldHeight::HEIGHT_EXTENSION; + int highestHeightX = heightWidth - 1; + int highestHeightZ = heightHeight - 1; + + glm::vec3 inverseScale(innerHeightWidth / scale.x, numeric_limits::max() / scale.y, innerHeightHeight / scale.z); + glm::vec3 center = glm::inverse(rotation) * (position - translation) * inverseScale + glm::vec3(1.0f, 0.0f, 1.0f); + glm::vec3 extents = radius * inverseScale; + + if (center.x + extents.x < 0.0f || center.z + extents.z < 0.0f || center.x - extents.x > highestHeightX || + center.z - extents.z > highestHeightZ) { + return this; + } + if (!isLeaf()) { + HeightfieldNode* newNode = this; + for (int i = 0; i < CHILD_COUNT; i++) { + glm::vec3 nextScale = scale * glm::vec3(0.5f, 1.0f, 0.5f); + 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); + if (_children[i] != newChild) { + if (newNode == this) { + newNode = new HeightfieldNode(*this); + } + newNode->setChild(i, HeightfieldNodePointer(newChild)); + } + } + if (newNode != this) { + newNode->mergeChildren(true, false); + } + return newNode; + } + if (!_stack) { + return this; + } + QVector newHeightContents = _height->getContents(); + + int stackWidth = _stack->getWidth(); + QVector newStackContents = _stack->getContents(); + QVector newStackMaterials = _stack->getMaterials(); + + glm::vec3 start = glm::clamp(glm::floor(center - extents), glm::vec3(), + glm::vec3((float)highestHeightX, 0.0f, (float)highestHeightZ)); + glm::vec3 end = glm::clamp(glm::ceil(center + extents), glm::vec3(), + glm::vec3((float)highestHeightX, 0.0f, (float)highestHeightZ)); + + quint16* lineDest = newHeightContents.data() + (int)start.z * heightWidth + (int)start.x; + float squaredRadius = extents.x * extents.x; + float multiplierZ = extents.x / extents.z; + for (float z = start.z; z <= end.z; z += 1.0f) { + quint16* dest = lineDest; + for (float x = start.x; x <= end.x; x += 1.0f, dest++) { + float dx = x - center.x, dz = (z - center.z) * multiplierZ; + float distanceSquared = dx * dx + dz * dz; + if (distanceSquared <= squaredRadius) { + + } + } + lineDest += heightWidth; + } + return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)), _color, _material, HeightfieldStackPointer(new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); } @@ -3239,6 +3318,13 @@ Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float return newHeightfield; } +Spanner* Heightfield::fillHeight(const glm::vec3& position, float radius) { + Heightfield* newHeightfield = static_cast(clone(true)); + newHeightfield->setRoot(HeightfieldNodePointer(_root->fillHeight(getTranslation(), getRotation(), + glm::vec3(getScale(), getScale() * _aspectY, getScale() * _aspectZ), position, radius))); + return newHeightfield; +} + Spanner* Heightfield::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, const QColor& color, bool paint) { // first see if we're going to exceed the range limits, normalizing if necessary diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 53dc40767a..3a7807dc1d 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -77,6 +77,10 @@ public: /// \return the modified spanner, or this if no modification was performed virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height); + /// Attempts to fill the spanner's height (removing volumetric information). + /// \return the modified spanner, or this if no modification was performed + virtual Spanner* fillHeight(const glm::vec3& position, float radius); + /// Attempts to "sculpt" or "paint" with the supplied spanner. /// \return the modified spanner, or this if no modification was performed virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, @@ -691,6 +695,9 @@ public: HeightfieldNode* paintHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& position, float radius, float height, float normalizeScale, float normalizeOffset); + HeightfieldNode* fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, + const glm::vec3& position, float radius); + void getRangeAfterEdit(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const Box& editBounds, float& minimum, float& maximum) const; @@ -795,6 +802,8 @@ public: virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height); + virtual Spanner* fillHeight(const glm::vec3& position, float radius); + virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, const QColor& color, bool paint);