mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 19:16:56 +02:00
Basic color/height painting.
This commit is contained in:
parent
b7b1b018ee
commit
e24ff0130f
5 changed files with 262 additions and 6 deletions
|
@ -118,7 +118,8 @@ MetavoxelEditor::MetavoxelEditor() :
|
||||||
addTool(new SetSpannerTool(this));
|
addTool(new SetSpannerTool(this));
|
||||||
addTool(new ImportHeightfieldTool(this));
|
addTool(new ImportHeightfieldTool(this));
|
||||||
addTool(new EraseHeightfieldTool(this));
|
addTool(new EraseHeightfieldTool(this));
|
||||||
addTool(new HeightBrushTool(this));
|
addTool(new HeightfieldHeightBrushTool(this));
|
||||||
|
addTool(new HeightfieldColorBrushTool(this));
|
||||||
|
|
||||||
updateAttributes();
|
updateAttributes();
|
||||||
|
|
||||||
|
@ -1108,11 +1109,26 @@ void HeightfieldBrushTool::render() {
|
||||||
if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) {
|
if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glm::vec3 point = origin + distance * direction;
|
Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(
|
||||||
Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(point, _radius->value());
|
_position = origin + distance * direction, _radius->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) :
|
bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) {
|
||||||
|
if (event->type() == QEvent::Wheel) {
|
||||||
|
float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
|
||||||
|
const float ANGLE_SCALE = 1.0f / 1000.0f;
|
||||||
|
_radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||||
|
MetavoxelEditMessage message = { createEdit(static_cast<QMouseEvent*>(event)->button() == Qt::RightButton) };
|
||||||
|
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) :
|
||||||
HeightfieldBrushTool(editor, "Height Brush") {
|
HeightfieldBrushTool(editor, "Height Brush") {
|
||||||
|
|
||||||
_form->addRow("Height:", _height = new QDoubleSpinBox());
|
_form->addRow("Height:", _height = new QDoubleSpinBox());
|
||||||
|
@ -1121,3 +1137,16 @@ HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) :
|
||||||
_height->setValue(1.0);
|
_height->setValue(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) {
|
||||||
|
return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), _height->value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) :
|
||||||
|
HeightfieldBrushTool(editor, "Color Brush") {
|
||||||
|
|
||||||
|
_form->addRow("Color:", _color = new QColorEditor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant HeightfieldColorBrushTool::createEdit(bool alternate) {
|
||||||
|
return QVariant::fromValue(PaintHeightfieldColorEdit(_position, _radius->value(), _color->getColor()));
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "MetavoxelSystem.h"
|
#include "MetavoxelSystem.h"
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
|
||||||
|
class QColorEditor;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QDoubleSpinBox;
|
class QDoubleSpinBox;
|
||||||
class QGroupBox;
|
class QGroupBox;
|
||||||
|
@ -312,23 +313,50 @@ public:
|
||||||
|
|
||||||
virtual void render();
|
virtual void render();
|
||||||
|
|
||||||
|
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual QVariant createEdit(bool alternate) = 0;
|
||||||
|
|
||||||
QFormLayout* _form;
|
QFormLayout* _form;
|
||||||
QDoubleSpinBox* _radius;
|
QDoubleSpinBox* _radius;
|
||||||
|
|
||||||
|
glm::vec3 _position;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Allows raising or lowering parts of the heightfield.
|
/// Allows raising or lowering parts of the heightfield.
|
||||||
class HeightBrushTool : public HeightfieldBrushTool {
|
class HeightfieldHeightBrushTool : public HeightfieldBrushTool {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HeightBrushTool(MetavoxelEditor* editor);
|
HeightfieldHeightBrushTool(MetavoxelEditor* editor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual QVariant createEdit(bool alternate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QDoubleSpinBox* _height;
|
QDoubleSpinBox* _height;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Allows coloring parts of the heightfield.
|
||||||
|
class HeightfieldColorBrushTool : public HeightfieldBrushTool {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HeightfieldColorBrushTool(MetavoxelEditor* editor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual QVariant createEdit(bool alternate);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QColorEditor* _color;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_MetavoxelEditor_h
|
#endif // hifi_MetavoxelEditor_h
|
||||||
|
|
|
@ -318,3 +318,166 @@ SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bo
|
||||||
void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||||
data.set(minimum, this->data, blend);
|
data.set(minimum, this->data, blend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) :
|
||||||
|
position(position),
|
||||||
|
radius(radius),
|
||||||
|
height(height) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit);
|
||||||
|
|
||||||
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PaintHeightfieldHeightEdit _edit;
|
||||||
|
Box _bounds;
|
||||||
|
};
|
||||||
|
|
||||||
|
PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) :
|
||||||
|
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute(),
|
||||||
|
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute()),
|
||||||
|
_edit(edit) {
|
||||||
|
|
||||||
|
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||||
|
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
|
if (!info.getBounds().intersects(_bounds)) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
if (!info.isLeaf) {
|
||||||
|
return DEFAULT_ORDER;
|
||||||
|
}
|
||||||
|
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||||
|
if (!pointer) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
QByteArray contents(pointer->getContents());
|
||||||
|
int size = glm::sqrt((float)contents.size());
|
||||||
|
int highest = size - 1;
|
||||||
|
float heightScale = highest / info.size;
|
||||||
|
|
||||||
|
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||||
|
float scaledRadius = _edit.radius * heightScale;
|
||||||
|
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||||
|
|
||||||
|
glm::vec3 start = glm::floor(center - extents);
|
||||||
|
glm::vec3 end = glm::ceil(center + extents);
|
||||||
|
|
||||||
|
float z = qMax(start.z, 0.0f);
|
||||||
|
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||||
|
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||||
|
float squaredRadius = scaledRadius * scaledRadius;
|
||||||
|
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||||
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
|
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||||
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
|
uchar* dest = lineDest;
|
||||||
|
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||||
|
float dx = x - center.x, dz = z - center.z;
|
||||||
|
float distanceSquared = dx * dx + dz * dz;
|
||||||
|
if (distanceSquared <= squaredRadius) {
|
||||||
|
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
||||||
|
*dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineDest += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||||
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||||
|
PaintHeightfieldHeightEditVisitor visitor(*this);
|
||||||
|
data.guide(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position, float radius, const QColor& color) :
|
||||||
|
position(position),
|
||||||
|
radius(radius),
|
||||||
|
color(color) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit);
|
||||||
|
|
||||||
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PaintHeightfieldColorEdit _edit;
|
||||||
|
Box _bounds;
|
||||||
|
};
|
||||||
|
|
||||||
|
PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) :
|
||||||
|
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(),
|
||||||
|
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||||
|
_edit(edit) {
|
||||||
|
|
||||||
|
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||||
|
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
|
if (!info.getBounds().intersects(_bounds)) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
if (!info.isLeaf) {
|
||||||
|
return DEFAULT_ORDER;
|
||||||
|
}
|
||||||
|
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||||
|
if (!pointer) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
QByteArray contents(pointer->getContents());
|
||||||
|
const int BYTES_PER_PIXEL = 3;
|
||||||
|
int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL);
|
||||||
|
int highest = size - 1;
|
||||||
|
float heightScale = highest / info.size;
|
||||||
|
|
||||||
|
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||||
|
float scaledRadius = _edit.radius * heightScale;
|
||||||
|
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||||
|
|
||||||
|
glm::vec3 start = glm::floor(center - extents);
|
||||||
|
glm::vec3 end = glm::ceil(center + extents);
|
||||||
|
|
||||||
|
float z = qMax(start.z, 0.0f);
|
||||||
|
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||||
|
int stride = size * BYTES_PER_PIXEL;
|
||||||
|
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
||||||
|
float squaredRadius = scaledRadius * scaledRadius;
|
||||||
|
char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
|
||||||
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
|
char* dest = lineDest;
|
||||||
|
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
||||||
|
float dx = x - center.x, dz = z - center.z;
|
||||||
|
if (dx * dx + dz * dz <= squaredRadius) {
|
||||||
|
dest[0] = red;
|
||||||
|
dest[1] = green;
|
||||||
|
dest[2] = blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineDest += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||||
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||||
|
PaintHeightfieldColorEditVisitor visitor(*this);
|
||||||
|
data.guide(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,4 +207,38 @@ public:
|
||||||
|
|
||||||
DECLARE_STREAMABLE_METATYPE(SetDataEdit)
|
DECLARE_STREAMABLE_METATYPE(SetDataEdit)
|
||||||
|
|
||||||
|
/// An edit that sets a region of a heightfield height.
|
||||||
|
class PaintHeightfieldHeightEdit : public MetavoxelEdit {
|
||||||
|
STREAMABLE
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
STREAM glm::vec3 position;
|
||||||
|
STREAM float radius;
|
||||||
|
STREAM float height;
|
||||||
|
|
||||||
|
PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f);
|
||||||
|
|
||||||
|
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit)
|
||||||
|
|
||||||
|
/// An edit that sets a region of a heightfield color.
|
||||||
|
class PaintHeightfieldColorEdit : public MetavoxelEdit {
|
||||||
|
STREAMABLE
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
STREAM glm::vec3 position;
|
||||||
|
STREAM float radius;
|
||||||
|
STREAM QColor color;
|
||||||
|
|
||||||
|
PaintHeightfieldColorEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QColor& color = QColor());
|
||||||
|
|
||||||
|
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit)
|
||||||
|
|
||||||
#endif // hifi_MetavoxelMessages_h
|
#endif // hifi_MetavoxelMessages_h
|
||||||
|
|
|
@ -138,6 +138,8 @@ public:
|
||||||
|
|
||||||
QColorEditor(QWidget* parent);
|
QColorEditor(QWidget* parent);
|
||||||
|
|
||||||
|
const QColor& getColor() const { return _color; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void colorChanged(const QColor& color);
|
void colorChanged(const QColor& color);
|
||||||
|
|
Loading…
Reference in a new issue