Set/erase brushes.

This commit is contained in:
Andrzej Kapolka 2015-01-18 16:20:55 -08:00
parent 52641bd20f
commit a9f7533477
6 changed files with 48 additions and 19 deletions

View file

@ -869,11 +869,16 @@ HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor)
_height->setMinimum(-FLT_MAX);
_height->setMaximum(FLT_MAX);
_height->setValue(1.0);
_form->addRow("Mode:", _mode = new QComboBox());
_mode->addItem("Raise/Lower");
_mode->addItem("Set");
_mode->addItem("Erase");
}
QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) {
return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(),
alternate ? -_height->value() : _height->value()));
alternate ? -_height->value() : _height->value(), _mode->currentIndex() == 1, _mode->currentIndex() == 2));
}
MaterialControl::MaterialControl(QWidget* widget, QFormLayout* form, bool clearable) :

View file

@ -346,6 +346,7 @@ protected:
private:
QDoubleSpinBox* _height;
QComboBox* _mode;
};
/// Contains widgets for editing materials.

View file

@ -148,10 +148,13 @@ void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects
data.set(minimum, this->data, blend);
}
PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) :
PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius,
float height, bool set, bool erase) :
position(position),
radius(radius),
height(height) {
height(height),
set(set),
erase(erase) {
}
void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
@ -163,7 +166,7 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje
Box(position - extents, position + extents), results);
foreach (const SharedObjectPointer& spanner, results) {
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paintHeight(position, radius, height);
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paintHeight(position, radius, height, set, erase);
if (newSpanner != spanner) {
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner);
}

View file

@ -203,8 +203,11 @@ public:
STREAM glm::vec3 position;
STREAM float radius;
STREAM float height;
STREAM bool set;
STREAM bool erase;
PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f);
PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
float height = 0.0f, bool set = false, bool erase = false);
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};

View file

@ -111,7 +111,7 @@ 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) {
Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) {
return this;
}
@ -1825,7 +1825,8 @@ 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, float normalizeScale, float normalizeOffset) {
const glm::vec3& position, float radius, float height, bool set, bool erase,
float normalizeScale, float normalizeOffset) {
if (!_height) {
return this;
}
@ -1852,7 +1853,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, normalizeScale, normalizeOffset);
nextScale, position, radius, height, set, erase, normalizeScale, normalizeOffset);
if (_children[i] != newChild) {
if (newNode == this) {
newNode = new HeightfieldNode(*this);
@ -1896,16 +1897,22 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons
float squaredRadiusReciprocal = 1.0f / squaredRadius;
float multiplierZ = extents.x / extents.z;
float relativeHeight = height * numeric_limits<quint16>::max() / scale.y;
quint16 heightValue = erase ? 0 : relativeHeight;
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) {
// height falls off towards edges
int value = *dest;
if (value != 0) {
*dest = value + relativeHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
if (erase || set) {
*dest = heightValue;
} else {
// height falls off towards edges
int value = *dest;
if (value != 0) {
*dest = value + relativeHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
}
}
}
}
@ -3352,18 +3359,25 @@ 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) {
Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) {
// first see if we're going to exceed the range limits
float minimumValue = 1.0f, maximumValue = numeric_limits<quint16>::max();
_root->getRangeAfterHeightPaint(getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * _aspectY,
getScale() * _aspectZ), position, radius, height, minimumValue, maximumValue);
if (set) {
float heightValue = height * numeric_limits<quint16>::max() / (getScale() * _aspectY);
minimumValue = qMin(minimumValue, heightValue);
maximumValue = qMax(maximumValue, heightValue);
} else if (!erase) {
_root->getRangeAfterHeightPaint(getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * _aspectY,
getScale() * _aspectZ), position, radius, height, minimumValue, maximumValue);
}
// normalize if necessary
float normalizeScale, normalizeOffset;
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,
normalizeScale, normalizeOffset)));
set, erase, normalizeScale, normalizeOffset)));
return newHeightfield;
}

View file

@ -74,8 +74,10 @@ public:
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// Attempts to modify the spanner's height.
/// \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);
virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase);
/// Attempts to fill the spanner's height (adding removing volumetric information).
/// \return the modified spanner, or this if no modification was performed
@ -693,7 +695,8 @@ public:
const glm::vec3& position, float radius, float height, float& minimum, float& maximum) const;
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);
const glm::vec3& position, float radius, float height, bool set, bool erase,
float normalizeScale, float normalizeOffset);
HeightfieldNode* fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
const glm::vec3& position, float radius);
@ -800,7 +803,7 @@ 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);
virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase);
virtual Spanner* fillHeight(const glm::vec3& position, float radius);