mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-17 18:33:28 +02:00
Working on voxel edits.
This commit is contained in:
parent
c6486b7f23
commit
9c0888afff
6 changed files with 466 additions and 50 deletions
|
@ -66,13 +66,16 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
attributeLayout->addLayout(attributeButtonLayout);
|
||||
|
||||
QPushButton* newAttribute = new QPushButton("New...");
|
||||
attributeButtonLayout->addWidget(newAttribute);
|
||||
attributeButtonLayout->addWidget(newAttribute, 1);
|
||||
connect(newAttribute, SIGNAL(clicked()), SLOT(createNewAttribute()));
|
||||
|
||||
attributeButtonLayout->addWidget(_deleteAttribute = new QPushButton("Delete"));
|
||||
attributeButtonLayout->addWidget(_deleteAttribute = new QPushButton("Delete"), 1);
|
||||
_deleteAttribute->setEnabled(false);
|
||||
connect(_deleteAttribute, SIGNAL(clicked()), SLOT(deleteSelectedAttribute()));
|
||||
|
||||
attributeButtonLayout->addWidget(_showAll = new QCheckBox("Show All"));
|
||||
connect(_showAll, SIGNAL(clicked()), SLOT(updateAttributes()));
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout();
|
||||
topLayout->addLayout(formLayout);
|
||||
|
||||
|
@ -116,11 +119,13 @@ MetavoxelEditor::MetavoxelEditor() :
|
|||
addTool(new RemoveSpannerTool(this));
|
||||
addTool(new ClearSpannersTool(this));
|
||||
addTool(new SetSpannerTool(this));
|
||||
addTool(new ImportHeightfieldTool(this));
|
||||
addTool(new EraseHeightfieldTool(this));
|
||||
addTool(new HeightfieldHeightBrushTool(this));
|
||||
addTool(new HeightfieldColorBrushTool(this));
|
||||
addTool(new HeightfieldMaterialBrushTool(this));
|
||||
addTool(new ImportHeightfieldTool(this));
|
||||
addTool(new EraseHeightfieldTool(this));
|
||||
addTool(new VoxelColorBoxTool(this));
|
||||
addTool(new VoxelMaterialBoxTool(this));
|
||||
|
||||
updateAttributes();
|
||||
|
||||
|
@ -200,7 +205,7 @@ void MetavoxelEditor::selectedAttributeChanged() {
|
|||
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected);
|
||||
foreach (MetavoxelTool* tool, _tools) {
|
||||
if (tool->appliesTo(attribute)) {
|
||||
if (tool->appliesTo(attribute) && (tool->isUserFacing() || _showAll->isChecked())) {
|
||||
_toolBox->addItem(tool->objectName(), QVariant::fromValue(tool));
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +276,35 @@ void MetavoxelEditor::alignGridPosition() {
|
|||
_gridPosition->setValue(step * floor(_gridPosition->value() / step));
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateAttributes(const QString& select) {
|
||||
// remember the selection in order to preserve it
|
||||
QString selected = select.isNull() ? getSelectedAttribute() : select;
|
||||
_attributes->clear();
|
||||
|
||||
// sort the names for consistent ordering
|
||||
QList<QString> names;
|
||||
if (_showAll->isChecked()) {
|
||||
names = AttributeRegistry::getInstance()->getAttributes().keys();
|
||||
|
||||
} else {
|
||||
foreach (const AttributePointer& attribute, AttributeRegistry::getInstance()->getAttributes()) {
|
||||
if (attribute->isUserFacing()) {
|
||||
names.append(attribute->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
qSort(names);
|
||||
|
||||
foreach (const QString& name, names) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
_attributes->addItem(item);
|
||||
if (name == selected || selected.isNull()) {
|
||||
item->setSelected(true);
|
||||
selected = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateTool() {
|
||||
MetavoxelTool* active = getActiveTool();
|
||||
foreach (MetavoxelTool* tool, _tools) {
|
||||
|
@ -335,25 +369,6 @@ void MetavoxelEditor::addTool(MetavoxelTool* tool) {
|
|||
layout()->addWidget(tool);
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateAttributes(const QString& select) {
|
||||
// remember the selection in order to preserve it
|
||||
QString selected = select.isNull() ? getSelectedAttribute() : select;
|
||||
_attributes->clear();
|
||||
|
||||
// sort the names for consistent ordering
|
||||
QList<QString> names = AttributeRegistry::getInstance()->getAttributes().keys();
|
||||
qSort(names);
|
||||
|
||||
foreach (const QString& name, names) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
_attributes->addItem(item);
|
||||
if (name == selected || selected.isNull()) {
|
||||
item->setSelected(true);
|
||||
selected = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelTool* MetavoxelEditor::getActiveTool() const {
|
||||
int index = _toolBox->currentIndex();
|
||||
return (index == -1) ? NULL : static_cast<MetavoxelTool*>(_toolBox->itemData(index).value<QObject*>());
|
||||
|
@ -361,9 +376,10 @@ MetavoxelTool* MetavoxelEditor::getActiveTool() const {
|
|||
|
||||
ProgramObject MetavoxelEditor::_gridProgram;
|
||||
|
||||
MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue) :
|
||||
MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) :
|
||||
_editor(editor),
|
||||
_usesValue(usesValue) {
|
||||
_usesValue(usesValue),
|
||||
_userFacing(userFacing) {
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
setLayout(layout);
|
||||
|
@ -385,13 +401,13 @@ void MetavoxelTool::render() {
|
|||
// nothing by default
|
||||
}
|
||||
|
||||
BoxSetTool::BoxSetTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Set Value (Box)") {
|
||||
BoxTool::BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue, bool userFacing) :
|
||||
MetavoxelTool(editor, name, usesValue, userFacing) {
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
void BoxSetTool::render() {
|
||||
void BoxTool::render() {
|
||||
if (Application::getInstance()->isMouseHidden()) {
|
||||
resetState();
|
||||
return;
|
||||
|
@ -457,7 +473,7 @@ void BoxSetTool::render() {
|
|||
glTranslatef(0.5f, 0.5f, 0.5f);
|
||||
if (_state != HOVERING_STATE) {
|
||||
const float BOX_ALPHA = 0.25f;
|
||||
QColor color = _editor->getValue().value<QColor>();
|
||||
QColor color = getColor();
|
||||
if (color.isValid()) {
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA);
|
||||
} else {
|
||||
|
@ -476,7 +492,7 @@ void BoxSetTool::render() {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
bool BoxTool::eventFilter(QObject* watched, QEvent* event) {
|
||||
switch (_state) {
|
||||
case HOVERING_STATE:
|
||||
if (event->type() == QEvent::MouseButtonPress && _startPosition != INVALID_VECTOR) {
|
||||
|
@ -515,12 +531,20 @@ bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void BoxSetTool::resetState() {
|
||||
void BoxTool::resetState() {
|
||||
_state = HOVERING_STATE;
|
||||
_startPosition = INVALID_VECTOR;
|
||||
_height = 0.0f;
|
||||
}
|
||||
|
||||
BoxSetTool::BoxSetTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Value (Box)", true, false) {
|
||||
}
|
||||
|
||||
QColor BoxSetTool::getColor() {
|
||||
return _editor->getValue().value<QColor>();
|
||||
}
|
||||
|
||||
void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
|
@ -533,7 +557,7 @@ void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum)
|
|||
}
|
||||
|
||||
GlobalSetTool::GlobalSetTool(MetavoxelEditor* editor) :
|
||||
MetavoxelTool(editor, "Set Value (Global)") {
|
||||
MetavoxelTool(editor, "Set Value (Global)", true, false) {
|
||||
|
||||
QPushButton* button = new QPushButton("Apply");
|
||||
layout()->addWidget(button);
|
||||
|
@ -1199,3 +1223,61 @@ void HeightfieldMaterialBrushTool::updateTexture() {
|
|||
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
|
||||
VoxelColorBoxTool::VoxelColorBoxTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Voxel Color (Box)", false) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
QFormLayout* form = new QFormLayout();
|
||||
widget->setLayout(form);
|
||||
layout()->addWidget(widget);
|
||||
|
||||
form->addRow("Color:", _color = new QColorEditor(this));
|
||||
}
|
||||
|
||||
bool VoxelColorBoxTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelColorBoxTool::getColor() {
|
||||
return _color->getColor();
|
||||
}
|
||||
|
||||
void VoxelColorBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelColorBoxEdit(Box(minimum, maximum),
|
||||
_editor->getGridSpacing(), _color->getColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
VoxelMaterialBoxTool::VoxelMaterialBoxTool(MetavoxelEditor* editor) :
|
||||
BoxTool(editor, "Set Voxel Material (Box)", false) {
|
||||
|
||||
QWidget* widget = new QWidget();
|
||||
QFormLayout* form = new QFormLayout();
|
||||
widget->setLayout(form);
|
||||
layout()->addWidget(widget);
|
||||
|
||||
form->addRow(_materialEditor = new SharedObjectEditor(&MaterialObject::staticMetaObject, false));
|
||||
connect(_materialEditor, &SharedObjectEditor::objectChanged, this, &VoxelMaterialBoxTool::updateTexture);
|
||||
}
|
||||
|
||||
bool VoxelMaterialBoxTool::appliesTo(const AttributePointer& attribute) const {
|
||||
return attribute->inherits("VoxelColorAttribute");
|
||||
}
|
||||
|
||||
QColor VoxelMaterialBoxTool::getColor() {
|
||||
return _texture ? _texture->getAverageColor() : QColor();
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
SharedObjectPointer material = _materialEditor->getObject();
|
||||
_materialEditor->detachObject();
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialBoxEdit(Box(minimum, maximum),
|
||||
_editor->getGridSpacing(), material, _texture ? _texture->getAverageColor() : QColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxTool::updateTexture() {
|
||||
MaterialObject* material = static_cast<MaterialObject*>(_materialEditor->getObject().data());
|
||||
_texture = Application::getInstance()->getTextureCache()->getTexture(material->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ private slots:
|
|||
void deleteSelectedAttribute();
|
||||
void centerGridPosition();
|
||||
void alignGridPosition();
|
||||
void updateAttributes(const QString& select = QString());
|
||||
void updateTool();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
|
@ -65,11 +66,11 @@ private slots:
|
|||
private:
|
||||
|
||||
void addTool(MetavoxelTool* tool);
|
||||
void updateAttributes(const QString& select = QString());
|
||||
MetavoxelTool* getActiveTool() const;
|
||||
|
||||
QListWidget* _attributes;
|
||||
QPushButton* _deleteAttribute;
|
||||
QCheckBox* _showAll;
|
||||
|
||||
QComboBox* _gridPlane;
|
||||
QDoubleSpinBox* _gridSpacing;
|
||||
|
@ -90,10 +91,12 @@ class MetavoxelTool : public QWidget {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true);
|
||||
MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true);
|
||||
|
||||
bool getUsesValue() const { return _usesValue; }
|
||||
|
||||
bool isUserFacing() const { return _userFacing; }
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
@ -105,24 +108,30 @@ protected:
|
|||
|
||||
MetavoxelEditor* _editor;
|
||||
bool _usesValue;
|
||||
bool _userFacing;
|
||||
};
|
||||
|
||||
/// Allows setting the value of a region by dragging out a box.
|
||||
class BoxSetTool : public MetavoxelTool {
|
||||
/// Base class for tools that allow dragging out a 3D box.
|
||||
class BoxTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxSetTool(MetavoxelEditor* editor);
|
||||
|
||||
BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true);
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor() = 0;
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum) = 0;
|
||||
|
||||
private:
|
||||
|
||||
void resetState();
|
||||
void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
enum State { HOVERING_STATE, DRAGGING_STATE, RAISING_STATE };
|
||||
|
||||
|
@ -134,6 +143,21 @@ private:
|
|||
float _height; ///< the selection height
|
||||
};
|
||||
|
||||
/// Allows setting the value of a region by dragging out a box.
|
||||
class BoxSetTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxSetTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
};
|
||||
|
||||
/// Allows setting the value across the entire space.
|
||||
class GlobalSetTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
@ -384,4 +408,51 @@ private:
|
|||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
/// Allows setting voxel colors by dragging out a box.
|
||||
class VoxelColorBoxTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelColorBoxTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
private:
|
||||
|
||||
QColorEditor* _color;
|
||||
};
|
||||
|
||||
/// Allows setting voxel materials by dragging out a box.
|
||||
class VoxelMaterialBoxTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
VoxelMaterialBoxTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
private slots:
|
||||
|
||||
void updateTexture();
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectEditor* _materialEditor;
|
||||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelEditor_h
|
||||
|
|
|
@ -30,6 +30,8 @@ REGISTER_META_OBJECT(HeightfieldMaterialAttribute)
|
|||
REGISTER_META_OBJECT(SharedObjectAttribute)
|
||||
REGISTER_META_OBJECT(SharedObjectSetAttribute)
|
||||
REGISTER_META_OBJECT(SpannerSetAttribute)
|
||||
REGISTER_META_OBJECT(VoxelColorAttribute)
|
||||
REGISTER_META_OBJECT(VoxelMaterialAttribute)
|
||||
|
||||
static int attributePointerMetaTypeId = qRegisterMetaType<AttributePointer>();
|
||||
static int ownedAttributeValueMetaTypeId = qRegisterMetaType<OwnedAttributeValue>();
|
||||
|
@ -53,6 +55,7 @@ AttributeRegistry::AttributeRegistry() :
|
|||
_heightfieldAttribute(registerAttribute(new HeightfieldAttribute("heightfield"))),
|
||||
_heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))),
|
||||
_heightfieldMaterialAttribute(registerAttribute(new HeightfieldMaterialAttribute("heightfieldMaterial"))),
|
||||
_voxelColorAttribute(registerAttribute(new VoxelColorAttribute("voxelColor"))),
|
||||
_voxelMaterialAttribute(registerAttribute(new VoxelMaterialAttribute("voxelMaterial"))) {
|
||||
|
||||
// our baseline LOD threshold is for voxels; spanners and heightfields are a different story
|
||||
|
@ -61,10 +64,13 @@ AttributeRegistry::AttributeRegistry() :
|
|||
|
||||
const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f;
|
||||
_heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||
_heightfieldAttribute->setUserFacing(true);
|
||||
_heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||
_heightfieldMaterialAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||
|
||||
const float VOXEL_LOD_THRESHOLD_MULTIPLIER = 32.0f;
|
||||
_voxelColorAttribute->setLODThresholdMultiplier(VOXEL_LOD_THRESHOLD_MULTIPLIER);
|
||||
_voxelColorAttribute->setUserFacing(true);
|
||||
_voxelMaterialAttribute->setLODThresholdMultiplier(VOXEL_LOD_THRESHOLD_MULTIPLIER);
|
||||
}
|
||||
|
||||
|
@ -205,7 +211,8 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const OwnedAttributeValue& o
|
|||
}
|
||||
|
||||
Attribute::Attribute(const QString& name) :
|
||||
_lodThresholdMultiplier(1.0f) {
|
||||
_lodThresholdMultiplier(1.0f),
|
||||
_userFacing(false) {
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
|
@ -1390,8 +1397,41 @@ bool HeightfieldMaterialAttribute::merge(void*& parent, void* children[], bool p
|
|||
return maxSize == 0;
|
||||
}
|
||||
|
||||
VoxelColorData::VoxelColorData(const QVector<QRgb>& contents) :
|
||||
_contents(contents) {
|
||||
const int VOXEL_COLOR_HEADER_SIZE = sizeof(qint32) * 6;
|
||||
|
||||
static QByteArray encodeVoxelColor(int offsetX, int offsetY, int offsetZ,
|
||||
int sizeX, int sizeY, int sizeZ, const QVector<QRgb>& contents) {
|
||||
QByteArray inflated(VOXEL_COLOR_HEADER_SIZE, 0);
|
||||
qint32* header = (qint32*)inflated.data();
|
||||
*header++ = offsetX;
|
||||
*header++ = offsetY;
|
||||
*header++ = offsetZ;
|
||||
*header++ = sizeX;
|
||||
*header++ = sizeY;
|
||||
*header++ = sizeZ;
|
||||
inflated.append((const char*)contents.constData(), contents.size() * sizeof(QRgb));
|
||||
return qCompress(inflated);
|
||||
}
|
||||
|
||||
static QVector<QRgb> decodeVoxelColor(const QByteArray& encoded, int& offsetX, int& offsetY, int& offsetZ,
|
||||
int& sizeX, int& sizeY, int& sizeZ) {
|
||||
QByteArray inflated = qUncompress(encoded);
|
||||
const qint32* header = (const qint32*)inflated.constData();
|
||||
offsetX = *header++;
|
||||
offsetY = *header++;
|
||||
offsetZ = *header++;
|
||||
sizeX = *header++;
|
||||
sizeY = *header++;
|
||||
sizeZ = *header++;
|
||||
int payloadSize = inflated.size() - VOXEL_COLOR_HEADER_SIZE;
|
||||
QVector<QRgb> contents(payloadSize / sizeof(QRgb));
|
||||
memcpy(contents.data(), inflated.constData() + VOXEL_COLOR_HEADER_SIZE, payloadSize);
|
||||
return contents;
|
||||
}
|
||||
|
||||
VoxelColorData::VoxelColorData(const QVector<QRgb>& contents, int size) :
|
||||
_contents(contents),
|
||||
_size(size) {
|
||||
}
|
||||
|
||||
VoxelColorData::VoxelColorData(Bitstream& in, int bytes) {
|
||||
|
@ -1407,32 +1447,170 @@ VoxelColorData::VoxelColorData(Bitstream& in, int bytes, const VoxelColorDataPoi
|
|||
reference->setEncodedDelta(in.readAligned(bytes));
|
||||
reference->setDeltaData(DataBlockPointer(this));
|
||||
_contents = reference->getContents();
|
||||
_size = reference->getSize();
|
||||
|
||||
int offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ;
|
||||
QVector<QRgb> delta = decodeVoxelColor(reference->getEncodedDelta(), offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ);
|
||||
if (delta.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (offsetX == 0) {
|
||||
_contents = delta;
|
||||
_size = sizeX;
|
||||
return;
|
||||
}
|
||||
int minX = offsetX - 1;
|
||||
int minY = offsetY - 1;
|
||||
int minZ = offsetZ - 1;
|
||||
const QRgb* src = delta.constData();
|
||||
int size2 = _size * _size;
|
||||
QRgb* planeDest = _contents.data() + minZ * size2 + minY * _size + minX;
|
||||
int length = sizeX * sizeof(QRgb);
|
||||
for (int z = 0; z < sizeZ; z++, planeDest += size2) {
|
||||
QRgb* dest = planeDest;
|
||||
for (int y = 0; y < sizeY; y++, src += sizeX, dest += _size) {
|
||||
memcpy(dest, src, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelColorData::write(Bitstream& out) {
|
||||
QMutexLocker locker(&_encodedMutex);
|
||||
if (_encoded.isEmpty()) {
|
||||
|
||||
_encoded = encodeVoxelColor(0, 0, 0, _size, _size, _size, _contents);
|
||||
}
|
||||
out << _encoded.size();
|
||||
out.writeAligned(_encoded);
|
||||
}
|
||||
|
||||
void VoxelColorData::writeDelta(Bitstream& out, const VoxelColorDataPointer& reference) {
|
||||
if (!reference || reference->getContents().size() != _contents.size()) {
|
||||
if (!reference || reference->getSize() != _size) {
|
||||
write(out);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
if (reference->getEncodedDelta().isEmpty() || reference->getDeltaData() != this) {
|
||||
|
||||
int minX = _size, minY = _size, minZ = _size;
|
||||
int maxX = -1, maxY = -1, maxZ = -1;
|
||||
const QRgb* src = _contents.constData();
|
||||
const QRgb* ref = reference->getContents().constData();
|
||||
for (int z = 0; z < _size; z++) {
|
||||
bool differenceZ = false;
|
||||
for (int y = 0; y < _size; y++) {
|
||||
bool differenceY = false;
|
||||
for (int x = 0; x < _size; x++) {
|
||||
if (*src++ != *ref++) {
|
||||
minX = qMin(minX, x);
|
||||
maxX = qMax(maxX, x);
|
||||
differenceY = differenceZ = true;
|
||||
}
|
||||
}
|
||||
if (differenceY) {
|
||||
minY = qMin(minY, y);
|
||||
maxY = qMax(maxY, y);
|
||||
}
|
||||
}
|
||||
if (differenceZ) {
|
||||
minZ = qMin(minZ, z);
|
||||
maxZ = qMax(maxZ, z);
|
||||
}
|
||||
}
|
||||
QVector<QRgb> delta;
|
||||
int sizeX = 0, sizeY = 0, sizeZ = 0;
|
||||
if (maxX >= minX) {
|
||||
sizeX = maxX - minX + 1;
|
||||
sizeY = maxY - minY + 1;
|
||||
sizeZ = maxZ - minZ + 1;
|
||||
delta = QVector<QRgb>(sizeX * sizeY * sizeZ, 0);
|
||||
QRgb* dest = delta.data();
|
||||
int size2 = _size * _size;
|
||||
const QRgb* planeSrc = _contents.constData() + minZ * size2 + minY * _size + minX;
|
||||
int length = sizeX * sizeof(QRgb);
|
||||
for (int z = 0; z < sizeZ; z++, planeSrc += size2) {
|
||||
src = planeSrc;
|
||||
for (int y = 0; y < sizeY; y++, src += _size, dest += sizeX) {
|
||||
memcpy(dest, src, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
reference->setEncodedDelta(encodeVoxelColor(minX + 1, minY + 1, minZ + 1, sizeX, sizeY, sizeZ, delta));
|
||||
reference->setDeltaData(DataBlockPointer(this));
|
||||
}
|
||||
out << reference->getEncodedDelta().size();
|
||||
out.writeAligned(reference->getEncodedDelta());
|
||||
}
|
||||
|
||||
void VoxelColorData::read(Bitstream& in, int bytes) {
|
||||
|
||||
int offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ;
|
||||
_contents = decodeVoxelColor(_encoded = in.readAligned(bytes), offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ);
|
||||
_size = sizeX;
|
||||
}
|
||||
|
||||
VoxelColorAttribute::VoxelColorAttribute(const QString& name) :
|
||||
InlineAttribute<VoxelColorDataPointer>(name) {
|
||||
}
|
||||
|
||||
void VoxelColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(VoxelColorDataPointer*)&value = VoxelColorDataPointer();
|
||||
} else {
|
||||
*(VoxelColorDataPointer*)&value = VoxelColorDataPointer(new VoxelColorData(in, size));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
VoxelColorDataPointer data = decodeInline<VoxelColorDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(VoxelColorDataPointer*)&value = VoxelColorDataPointer();
|
||||
} else {
|
||||
*(VoxelColorDataPointer*)&value = VoxelColorDataPointer(new VoxelColorData(
|
||||
in, size, decodeInline<VoxelColorDataPointer>(reference)));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
VoxelColorDataPointer data = decodeInline<VoxelColorDataPointer>(value);
|
||||
if (data) {
|
||||
data->writeDelta(out, decodeInline<VoxelColorDataPointer>(reference));
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelColorAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
||||
int maxSize = 0;
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
VoxelColorDataPointer pointer = decodeInline<VoxelColorDataPointer>(children[i]);
|
||||
if (pointer) {
|
||||
maxSize = qMax(maxSize, pointer->getSize());
|
||||
}
|
||||
}
|
||||
*(VoxelColorDataPointer*)&parent = VoxelColorDataPointer();
|
||||
return maxSize == 0;
|
||||
}
|
||||
|
||||
const int VOXEL_MATERIAL_HEADER_SIZE = sizeof(qint32) * 6;
|
||||
|
@ -1461,7 +1639,7 @@ static QByteArray decodeVoxelMaterial(const QByteArray& encoded, int& offsetX, i
|
|||
sizeX = *header++;
|
||||
sizeY = *header++;
|
||||
sizeZ = *header++;
|
||||
return inflated.mid(HEIGHTFIELD_MATERIAL_HEADER_SIZE);
|
||||
return inflated.mid(VOXEL_MATERIAL_HEADER_SIZE);
|
||||
}
|
||||
|
||||
VoxelMaterialData::VoxelMaterialData(const QByteArray& contents, int size, const QVector<SharedObjectPointer>& materials) :
|
||||
|
@ -1644,7 +1822,7 @@ bool VoxelMaterialAttribute::merge(void*& parent, void* children[], bool postRea
|
|||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
VoxelMaterialDataPointer pointer = decodeInline<VoxelMaterialDataPointer>(children[i]);
|
||||
if (pointer) {
|
||||
maxSize = qMax(maxSize, pointer->getContents().size());
|
||||
maxSize = qMax(maxSize, pointer->getSize());
|
||||
}
|
||||
}
|
||||
*(VoxelMaterialDataPointer*)&parent = VoxelMaterialDataPointer();
|
||||
|
|
|
@ -111,6 +111,9 @@ public:
|
|||
/// Returns a reference to the standard HeightfieldMaterialDataPointer "heightfieldMaterial" attribute.
|
||||
const AttributePointer& getHeightfieldMaterialAttribute() const { return _heightfieldMaterialAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelColorDataPointer "voxelColor" attribute.
|
||||
const AttributePointer& getVoxelColorAttribute() const { return _voxelColorAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelMaterialDataPointer "voxelMaterial" attribute.
|
||||
const AttributePointer& getVoxelMaterialAttribute() const { return _voxelMaterialAttribute; }
|
||||
|
||||
|
@ -132,6 +135,7 @@ private:
|
|||
AttributePointer _heightfieldAttribute;
|
||||
AttributePointer _heightfieldColorAttribute;
|
||||
AttributePointer _heightfieldMaterialAttribute;
|
||||
AttributePointer _voxelColorAttribute;
|
||||
AttributePointer _voxelMaterialAttribute;
|
||||
};
|
||||
|
||||
|
@ -212,6 +216,7 @@ Q_DECLARE_METATYPE(OwnedAttributeValue)
|
|||
class Attribute : public SharedObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float lodThresholdMultiplier MEMBER _lodThresholdMultiplier)
|
||||
Q_PROPERTY(bool userFacing MEMBER _userFacing)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -225,6 +230,9 @@ public:
|
|||
float getLODThresholdMultiplier() const { return _lodThresholdMultiplier; }
|
||||
void setLODThresholdMultiplier(float multiplier) { _lodThresholdMultiplier = multiplier; }
|
||||
|
||||
bool isUserFacing() const { return _userFacing; }
|
||||
void setUserFacing(bool userFacing) { _userFacing = userFacing; }
|
||||
|
||||
void* create() const { return create(getDefaultValue()); }
|
||||
virtual void* create(void* copy) const = 0;
|
||||
virtual void destroy(void* value) const = 0;
|
||||
|
@ -289,6 +297,7 @@ public:
|
|||
private:
|
||||
|
||||
float _lodThresholdMultiplier;
|
||||
bool _userFacing;
|
||||
};
|
||||
|
||||
/// A simple attribute class that stores its values inline.
|
||||
|
@ -637,12 +646,14 @@ typedef QExplicitlySharedDataPointer<VoxelColorData> VoxelColorDataPointer;
|
|||
class VoxelColorData : public DataBlock {
|
||||
public:
|
||||
|
||||
VoxelColorData(const QVector<QRgb>& contents);
|
||||
VoxelColorData(const QVector<QRgb>& contents, int size);
|
||||
VoxelColorData(Bitstream& in, int bytes);
|
||||
VoxelColorData(Bitstream& in, int bytes, const VoxelColorDataPointer& reference);
|
||||
|
||||
const QVector<QRgb>& getContents() const { return _contents; }
|
||||
|
||||
int getSize() const { return _size; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const VoxelColorDataPointer& reference);
|
||||
|
||||
|
@ -651,6 +662,24 @@ private:
|
|||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QVector<QRgb> _contents;
|
||||
int _size;
|
||||
};
|
||||
|
||||
/// An attribute that stores voxel colors.
|
||||
class VoxelColorAttribute : public InlineAttribute<VoxelColorDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE VoxelColorAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<VoxelMaterialData> VoxelMaterialDataPointer;
|
||||
|
|
|
@ -642,3 +642,23 @@ void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedOb
|
|||
PaintHeightfieldMaterialEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelColorBoxEdit::VoxelColorBoxEdit(const Box& region, float granularity, const QColor& color) :
|
||||
region(region),
|
||||
granularity(granularity),
|
||||
color(color) {
|
||||
}
|
||||
|
||||
void VoxelColorBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
}
|
||||
|
||||
VoxelMaterialBoxEdit::VoxelMaterialBoxEdit(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
region(region),
|
||||
granularity(granularity),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
}
|
||||
|
|
|
@ -260,4 +260,40 @@ public:
|
|||
|
||||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit)
|
||||
|
||||
/// An edit that sets the color of voxels within a box to a value.
|
||||
class VoxelColorBoxEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM Box region;
|
||||
STREAM float granularity;
|
||||
STREAM QColor color;
|
||||
|
||||
VoxelColorBoxEdit(const Box& region = Box(), float granularity = 0.0f, const QColor& color = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelColorBoxEdit)
|
||||
|
||||
/// An edit that sets the materials of voxels within a box to a value.
|
||||
class VoxelMaterialBoxEdit : public MetavoxelEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM Box region;
|
||||
STREAM float granularity;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
VoxelMaterialBoxEdit(const Box& region = Box(), float granularity = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
||||
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(VoxelMaterialBoxEdit)
|
||||
|
||||
#endif // hifi_MetavoxelMessages_h
|
||||
|
|
Loading…
Reference in a new issue