Don't show grid for tools where it isn't needed, started on "fill" tool.

This commit is contained in:
Andrzej Kapolka 2015-01-09 11:46:40 -08:00
parent 0dc4b26367
commit d82f269263
6 changed files with 167 additions and 8 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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<SharedObjectPointer> results;
data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(),
Box(position - extents, position + extents), results);
foreach (const SharedObjectPointer& spanner, results) {
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->fillHeight(position, radius);
if (newSpanner != spanner) {
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner);
}
}
}

View file

@ -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

View file

@ -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<quint16>::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<quint16> newHeightContents = _height->getContents();
int stackWidth = _stack->getWidth();
QVector<StackArray> newStackContents = _stack->getContents();
QVector<SharedObjectPointer> 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<Heightfield*>(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

View file

@ -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);