Rather than using a boolean to indicate "colorness," use a different class.

More texture bits.
This commit is contained in:
Andrzej Kapolka 2014-08-19 14:20:47 -07:00
parent 23a4c21ce1
commit e854656a7f
9 changed files with 465 additions and 287 deletions

View file

@ -1011,7 +1011,7 @@ int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf && info.size > _buffer->getScale()) {
return DEFAULT_ORDER;
}
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
if (!height) {
return STOP_RECURSION;
}
@ -1067,7 +1067,7 @@ int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
if (colorSize == 0) {
return STOP_RECURSION;
}
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
if (!color) {
return STOP_RECURSION;
}
@ -1149,14 +1149,14 @@ int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
return DEFAULT_ORDER;
}
HeightfieldBuffer* buffer = NULL;
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
if (height) {
const QByteArray& heightContents = height->getContents();
int size = glm::sqrt(heightContents.size());
int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION;
int heightContentsSize = extendedSize * extendedSize;
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
int colorContentsSize = 0;
if (color) {
const QByteArray& colorContents = color->getContents();

View file

@ -957,14 +957,28 @@ void ImportHeightfieldTool::apply() {
HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data());
MetavoxelData data;
data.setSize(scale);
HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getUnextendedHeight()));
QByteArray height = buffer->getUnextendedHeight();
HeightfieldHeightDataPointer heightPointer(new HeightfieldHeightData(height));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer))));
if (!buffer->getColor().isEmpty()) {
HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getUnextendedColor()));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
QByteArray color;
if (buffer->getColor().isEmpty()) {
const int WHITE_VALUE = 0xFF;
color = QByteArray(height.size() * HeightfieldData::COLOR_BYTES, WHITE_VALUE);
} else {
color = buffer->getUnextendedColor();
}
HeightfieldColorDataPointer colorPointer(new HeightfieldColorData(color));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
QByteArray texture(height.size(), 0);
HeightfieldDataPointer texturePointer(new HeightfieldData(texture));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), encodeInline(texturePointer))));
MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit(
_translation->getValue() + buffer->getTranslation() * scale, data)) };
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
@ -1165,20 +1179,20 @@ QVariant HeightfieldColorBrushTool::createEdit(bool alternate) {
HeightfieldTextureBrushTool::HeightfieldTextureBrushTool(MetavoxelEditor* editor) :
HeightfieldBrushTool(editor, "Texture Brush") {
_form->addRow("URL:", _url = new QUrlEditor(this));
_url->setURL(QUrl());
connect(_url, &QUrlEditor::urlChanged, this, &HeightfieldTextureBrushTool::updateTexture);
_form->addRow(_textureEditor = new SharedObjectEditor(&HeightfieldTexture::staticMetaObject, false));
connect(_textureEditor, &SharedObjectEditor::objectChanged, this, &HeightfieldTextureBrushTool::updateTexture);
}
QVariant HeightfieldTextureBrushTool::createEdit(bool alternate) {
if (alternate) {
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), QUrl(), QColor()));
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), SharedObjectPointer(), QColor()));
} else {
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), _url->getURL(),
return QVariant::fromValue(PaintHeightfieldTextureEdit(_position, _radius->value(), _textureEditor->getObject(),
_texture ? _texture->getAverageColor() : QColor()));
}
}
void HeightfieldTextureBrushTool::updateTexture() {
_texture = Application::getInstance()->getTextureCache()->getTexture(_url->getURL());
HeightfieldTexture* texture = static_cast<HeightfieldTexture*>(_textureEditor->getObject().data());
_texture = Application::getInstance()->getTextureCache()->getTexture(texture->getURL());
}

View file

@ -26,9 +26,9 @@ class QListWidget;
class QPushButton;
class QScrollArea;
class QSpinBox;
class QUrlEditor;
class MetavoxelTool;
class SharedObjectEditor;
class Vec3Editor;
/// Allows editing metavoxels.
@ -380,7 +380,7 @@ private slots:
private:
QUrlEditor* _url;
SharedObjectEditor* _textureEditor;
QSharedPointer<NetworkTexture> _texture;
};

View file

@ -23,6 +23,7 @@ REGISTER_META_OBJECT(QRgbAttribute)
REGISTER_META_OBJECT(PackedNormalAttribute)
REGISTER_META_OBJECT(SpannerQRgbAttribute)
REGISTER_META_OBJECT(SpannerPackedNormalAttribute)
REGISTER_META_OBJECT(HeightfieldTexture)
REGISTER_META_OBJECT(HeightfieldAttribute)
REGISTER_META_OBJECT(HeightfieldColorAttribute)
REGISTER_META_OBJECT(HeightfieldTextureAttribute)
@ -502,8 +503,7 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) :
_contents(contents) {
}
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) {
read(in, bytes, color);
HeightfieldData::~HeightfieldData() {
}
enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE };
@ -549,51 +549,48 @@ const QImage decodeHeightfieldImage(const QByteArray& data) {
}
}
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
HeightfieldHeightData::HeightfieldHeightData(const QByteArray& contents) :
HeightfieldData(contents) {
}
HeightfieldHeightData::HeightfieldHeightData(Bitstream& in, int bytes) {
read(in, bytes);
}
HeightfieldHeightData::HeightfieldHeightData(Bitstream& in, int bytes, const HeightfieldHeightDataPointer& reference) {
if (!reference) {
read(in, bytes, color);
read(in, bytes);
return;
}
QMutexLocker locker(&reference->_encodedDeltaMutex);
reference->_encodedDelta = in.readAligned(bytes);
reference->_deltaData = this;
_contents = reference->_contents;
QImage image = decodeHeightfieldImage(reference->_encodedDelta);
QMutexLocker locker(&reference->getEncodedDeltaMutex());
reference->setEncodedDelta(in.readAligned(bytes));
reference->setDeltaData(HeightfieldDataPointer(this));
_contents = reference->getContents();
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
if (image.isNull()) {
return;
}
QPoint offset = image.offset();
image = image.convertToFormat(QImage::Format_RGB888);
if (offset.x() == 0) {
set(image, color);
set(image);
return;
}
int minX = offset.x() - 1;
int minY = offset.y() - 1;
if (color) {
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES;
int destStride = size * COLOR_BYTES;
int srcStride = image.width() * COLOR_BYTES;
for (int y = 0; y < image.height(); y++) {
memcpy(dest, image.constScanLine(y), srcStride);
dest += destStride;
}
} else {
int size = glm::sqrt((float)_contents.size());
char* lineDest = _contents.data() + minY * size + minX;
for (int y = 0; y < image.height(); y++) {
const uchar* src = image.constScanLine(y);
for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) {
*dest = *src;
}
lineDest += size;
int size = glm::sqrt((float)_contents.size());
char* lineDest = _contents.data() + minY * size + minX;
for (int y = 0; y < image.height(); y++) {
const uchar* src = image.constScanLine(y);
for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) {
*dest = *src;
}
lineDest += size;
}
}
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& ancestor,
const glm::vec3& minimum, float size, bool color) {
HeightfieldHeightData::HeightfieldHeightData(Bitstream& in, int bytes, const HeightfieldHeightDataPointer& ancestor,
const glm::vec3& minimum, float size) {
QMutexLocker locker(&_encodedSubdivisionsMutex);
int index = (int)glm::round(glm::log(size) / glm::log(0.5f)) - 1;
if (_encodedSubdivisions.size() <= index) {
@ -610,61 +607,35 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData
int destSize = image.width();
const uchar* src = image.constBits();
const QByteArray& ancestorContents = ancestor->getContents();
if (color) {
int ancestorSize = glm::sqrt(ancestorContents.size() / (float)COLOR_BYTES);
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
int ancestorStride = ancestorSize * COLOR_BYTES;
_contents = QByteArray(destSize * destSize * COLOR_BYTES, 0);
char* dest = _contents.data();
int stride = image.width() * COLOR_BYTES;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorStride;
float ancestorX = minimum.x * ancestorSize;
for (char* end = dest + stride; dest != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX * COLOR_BYTES;
*dest++ = *ref++ + *src++;
*dest++ = *ref++ + *src++;
*dest++ = *ref++ + *src++;
}
}
} else {
int ancestorSize = glm::sqrt((float)ancestorContents.size());
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
_contents = QByteArray(destSize * destSize, 0);
char* dest = _contents.data();
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorSize;
float ancestorX = minimum.x * ancestorSize;
for (char* end = dest + destSize; dest != end; src += COLOR_BYTES, ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX;
*dest++ = *ref++ + *src;
}
int ancestorSize = glm::sqrt((float)ancestorContents.size());
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
_contents = QByteArray(destSize * destSize, 0);
char* dest = _contents.data();
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorSize;
float ancestorX = minimum.x * ancestorSize;
for (char* end = dest + destSize; dest != end; src += COLOR_BYTES, ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX;
*dest++ = *ref++ + *src;
}
}
}
void HeightfieldData::write(Bitstream& out, bool color) {
void HeightfieldHeightData::write(Bitstream& out) {
QMutexLocker locker(&_encodedMutex);
if (_encoded.isEmpty()) {
QImage image;
if (color) {
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);
} else {
int size = glm::sqrt((float)_contents.size());
image = QImage(size, size, QImage::Format_RGB888);
uchar* dest = image.bits();
for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
int size = glm::sqrt((float)_contents.size());
image = QImage(size, size, QImage::Format_RGB888);
uchar* dest = image.bits();
for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
_encoded = encodeHeightfieldImage(image);
}
@ -672,95 +643,58 @@ void HeightfieldData::write(Bitstream& out, bool color) {
out.writeAligned(_encoded);
}
void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) {
void HeightfieldHeightData::writeDelta(Bitstream& out, const HeightfieldHeightDataPointer& reference) {
if (!reference || reference->getContents().size() != _contents.size()) {
write(out, color);
write(out);
return;
}
QMutexLocker locker(&reference->_encodedDeltaMutex);
if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) {
QMutexLocker locker(&reference->getEncodedDeltaMutex());
if (reference->getEncodedDelta().isEmpty() || reference->getDeltaData() != this) {
QImage image;
int minX, minY;
if (color) {
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
minX = size;
minY = size;
int maxX = -1, maxY = -1;
const char* src = _contents.constData();
const char* ref = reference->_contents.constData();
for (int y = 0; y < size; y++) {
bool difference = false;
for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) {
if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) {
minX = qMin(minX, x);
maxX = qMax(maxX, x);
difference = true;
}
}
if (difference) {
minY = qMin(minY, y);
maxY = qMax(maxY, y);
int size = glm::sqrt((float)_contents.size());
int minX = size, minY = size;
int maxX = -1, maxY = -1;
const char* src = _contents.constData();
const char* ref = reference->getContents().constData();
for (int y = 0; y < size; y++) {
bool difference = false;
for (int x = 0; x < size; x++) {
if (*src++ != *ref++) {
minX = qMin(minX, x);
maxX = qMax(maxX, x);
difference = true;
}
}
if (maxX >= minX) {
int width = maxX - minX + 1;
int height = maxY - minY + 1;
image = QImage(width, height, QImage::Format_RGB888);
src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
int srcStride = size * COLOR_BYTES;
int destStride = width * COLOR_BYTES;
for (int y = 0; y < height; y++) {
memcpy(image.scanLine(y), src, destStride);
src += srcStride;
}
if (difference) {
minY = qMin(minY, y);
maxY = qMax(maxY, y);
}
} else {
int size = glm::sqrt((float)_contents.size());
minX = size;
minY = size;
int maxX = -1, maxY = -1;
const char* src = _contents.constData();
const char* ref = reference->_contents.constData();
for (int y = 0; y < size; y++) {
bool difference = false;
for (int x = 0; x < size; x++) {
if (*src++ != *ref++) {
minX = qMin(minX, x);
maxX = qMax(maxX, x);
difference = true;
}
}
if (difference) {
minY = qMin(minY, y);
maxY = qMax(maxY, y);
}
}
if (maxX >= minX) {
int width = qMax(maxX - minX + 1, 0);
int height = qMax(maxY - minY + 1, 0);
image = QImage(width, height, QImage::Format_RGB888);
const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
for (int y = 0; y < height; y++) {
uchar* dest = image.scanLine(y);
for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
lineSrc += size;
}
if (maxX >= minX) {
int width = qMax(maxX - minX + 1, 0);
int height = qMax(maxY - minY + 1, 0);
image = QImage(width, height, QImage::Format_RGB888);
const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
for (int y = 0; y < height; y++) {
uchar* dest = image.scanLine(y);
for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
lineSrc += size;
}
}
image.setOffset(QPoint(minX + 1, minY + 1));
reference->_encodedDelta = encodeHeightfieldImage(image);
reference->_deltaData = this;
reference->setEncodedDelta(encodeHeightfieldImage(image));
reference->setDeltaData(HeightfieldDataPointer(this));
}
out << reference->_encodedDelta.size();
out.writeAligned(reference->_encodedDelta);
out << reference->getEncodedDelta().size();
out.writeAligned(reference->getEncodedDelta());
}
void HeightfieldData::writeSubdivided(Bitstream& out, const HeightfieldDataPointer& ancestor,
const glm::vec3& minimum, float size, bool color) {
void HeightfieldHeightData::writeSubdivided(Bitstream& out, const HeightfieldHeightDataPointer& ancestor,
const glm::vec3& minimum, float size) {
QMutexLocker locker(&_encodedSubdivisionsMutex);
int index = (int)glm::round(glm::log(size) / glm::log(0.5f)) - 1;
if (_encodedSubdivisions.size() <= index) {
@ -771,48 +705,26 @@ void HeightfieldData::writeSubdivided(Bitstream& out, const HeightfieldDataPoint
QImage image;
const QByteArray& ancestorContents = ancestor->getContents();
const uchar* src = (const uchar*)_contents.constData();
if (color) {
int destSize = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
image = QImage(destSize, destSize, QImage::Format_RGB888);
uchar* dest = image.bits();
int stride = destSize * COLOR_BYTES;
int ancestorSize = glm::sqrt(ancestorContents.size() / (float)COLOR_BYTES);
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
int ancestorStride = ancestorSize * COLOR_BYTES;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorStride;
float ancestorX = minimum.x * ancestorSize;
for (const uchar* end = src + stride; src != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX * COLOR_BYTES;
*dest++ = *src++ - *ref++;
*dest++ = *src++ - *ref++;
*dest++ = *src++ - *ref++;
}
}
} else {
int destSize = glm::sqrt((float)_contents.size());
image = QImage(destSize, destSize, QImage::Format_RGB888);
uchar* dest = image.bits();
int ancestorSize = glm::sqrt((float)ancestorContents.size());
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorSize;
float ancestorX = minimum.x * ancestorSize;
for (const uchar* end = src + destSize; src != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX;
uchar difference = *src++ - *ref;
*dest++ = difference;
*dest++ = difference;
*dest++ = difference;
}
}
}
int destSize = glm::sqrt((float)_contents.size());
image = QImage(destSize, destSize, QImage::Format_RGB888);
uchar* dest = image.bits();
int ancestorSize = glm::sqrt((float)ancestorContents.size());
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorSize;
float ancestorX = minimum.x * ancestorSize;
for (const uchar* end = src + destSize; src != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX;
uchar difference = *src++ - *ref;
*dest++ = difference;
*dest++ = difference;
*dest++ = difference;
}
}
subdivision.data = encodeHeightfieldImage(image, true);
subdivision.ancestor = ancestor;
}
@ -820,27 +732,211 @@ void HeightfieldData::writeSubdivided(Bitstream& out, const HeightfieldDataPoint
out.writeAligned(subdivision.data);
}
void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
void HeightfieldHeightData::read(Bitstream& in, int bytes) {
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888));
}
void HeightfieldData::set(const QImage& image, bool color) {
if (color) {
_contents.resize(image.width() * image.height() * COLOR_BYTES);
memcpy(_contents.data(), image.constBits(), _contents.size());
} else {
_contents.resize(image.width() * image.height());
char* dest = _contents.data();
for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES;
src != end; src += COLOR_BYTES) {
*dest++ = *src;
void HeightfieldHeightData::set(const QImage& image) {
_contents.resize(image.width() * image.height());
char* dest = _contents.data();
for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES;
src != end; src += COLOR_BYTES) {
*dest++ = *src;
}
}
HeightfieldColorData::HeightfieldColorData(const QByteArray& contents) :
HeightfieldData(contents) {
}
HeightfieldColorData::HeightfieldColorData(Bitstream& in, int bytes) {
read(in, bytes);
}
HeightfieldColorData::HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& reference) {
if (!reference) {
read(in, bytes);
return;
}
QMutexLocker locker(&reference->getEncodedDeltaMutex());
reference->setEncodedDelta(in.readAligned(bytes));
reference->setDeltaData(HeightfieldDataPointer(this));
_contents = reference->getContents();
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
if (image.isNull()) {
return;
}
QPoint offset = image.offset();
image = image.convertToFormat(QImage::Format_RGB888);
if (offset.x() == 0) {
set(image);
return;
}
int minX = offset.x() - 1;
int minY = offset.y() - 1;
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES;
int destStride = size * COLOR_BYTES;
int srcStride = image.width() * COLOR_BYTES;
for (int y = 0; y < image.height(); y++) {
memcpy(dest, image.constScanLine(y), srcStride);
dest += destStride;
}
}
HeightfieldColorData::HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& ancestor,
const glm::vec3& minimum, float size) {
QMutexLocker locker(&_encodedSubdivisionsMutex);
int index = (int)glm::round(glm::log(size) / glm::log(0.5f)) - 1;
if (_encodedSubdivisions.size() <= index) {
_encodedSubdivisions.resize(index + 1);
}
EncodedSubdivision& subdivision = _encodedSubdivisions[index];
subdivision.data = in.readAligned(bytes);
subdivision.ancestor = ancestor;
QImage image = decodeHeightfieldImage(subdivision.data);
if (image.isNull()) {
return;
}
image = image.convertToFormat(QImage::Format_RGB888);
int destSize = image.width();
const uchar* src = image.constBits();
const QByteArray& ancestorContents = ancestor->getContents();
int ancestorSize = glm::sqrt(ancestorContents.size() / (float)COLOR_BYTES);
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
int ancestorStride = ancestorSize * COLOR_BYTES;
_contents = QByteArray(destSize * destSize * COLOR_BYTES, 0);
char* dest = _contents.data();
int stride = image.width() * COLOR_BYTES;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorStride;
float ancestorX = minimum.x * ancestorSize;
for (char* end = dest + stride; dest != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX * COLOR_BYTES;
*dest++ = *ref++ + *src++;
*dest++ = *ref++ + *src++;
*dest++ = *ref++ + *src++;
}
}
}
void HeightfieldColorData::write(Bitstream& out) {
QMutexLocker locker(&_encodedMutex);
if (_encoded.isEmpty()) {
QImage image;
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);
_encoded = encodeHeightfieldImage(image);
}
out << _encoded.size();
out.writeAligned(_encoded);
}
void HeightfieldColorData::writeDelta(Bitstream& out, const HeightfieldColorDataPointer& reference) {
if (!reference || reference->getContents().size() != _contents.size()) {
write(out);
return;
}
QMutexLocker locker(&reference->getEncodedDeltaMutex());
if (reference->getEncodedDelta().isEmpty() || reference->getDeltaData() != this) {
QImage image;
int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
int minX = size, minY = size;
int maxX = -1, maxY = -1;
const char* src = _contents.constData();
const char* ref = reference->getContents().constData();
for (int y = 0; y < size; y++) {
bool difference = false;
for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) {
if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) {
minX = qMin(minX, x);
maxX = qMax(maxX, x);
difference = true;
}
}
if (difference) {
minY = qMin(minY, y);
maxY = qMax(maxY, y);
}
}
if (maxX >= minX) {
int width = maxX - minX + 1;
int height = maxY - minY + 1;
image = QImage(width, height, QImage::Format_RGB888);
src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
int srcStride = size * COLOR_BYTES;
int destStride = width * COLOR_BYTES;
for (int y = 0; y < height; y++) {
memcpy(image.scanLine(y), src, destStride);
src += srcStride;
}
}
image.setOffset(QPoint(minX + 1, minY + 1));
reference->setEncodedDelta(encodeHeightfieldImage(image));
reference->setDeltaData(HeightfieldDataPointer(this));
}
out << reference->getEncodedDelta().size();
out.writeAligned(reference->getEncodedDelta());
}
void HeightfieldColorData::writeSubdivided(Bitstream& out, const HeightfieldColorDataPointer& ancestor,
const glm::vec3& minimum, float size) {
QMutexLocker locker(&_encodedSubdivisionsMutex);
int index = (int)glm::round(glm::log(size) / glm::log(0.5f)) - 1;
if (_encodedSubdivisions.size() <= index) {
_encodedSubdivisions.resize(index + 1);
}
EncodedSubdivision& subdivision = _encodedSubdivisions[index];
if (subdivision.data.isEmpty() || subdivision.ancestor != ancestor) {
QImage image;
const QByteArray& ancestorContents = ancestor->getContents();
const uchar* src = (const uchar*)_contents.constData();
int destSize = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
image = QImage(destSize, destSize, QImage::Format_RGB888);
uchar* dest = image.bits();
int stride = destSize * COLOR_BYTES;
int ancestorSize = glm::sqrt(ancestorContents.size() / (float)COLOR_BYTES);
float ancestorY = minimum.z * ancestorSize;
float ancestorIncrement = size * ancestorSize / destSize;
int ancestorStride = ancestorSize * COLOR_BYTES;
for (int y = 0; y < destSize; y++, ancestorY += ancestorIncrement) {
const uchar* lineRef = (const uchar*)ancestorContents.constData() + (int)ancestorY * ancestorStride;
float ancestorX = minimum.x * ancestorSize;
for (const uchar* end = src + stride; src != end; ancestorX += ancestorIncrement) {
const uchar* ref = lineRef + (int)ancestorX * COLOR_BYTES;
*dest++ = *src++ - *ref++;
*dest++ = *src++ - *ref++;
*dest++ = *src++ - *ref++;
}
}
subdivision.data = encodeHeightfieldImage(image, true);
subdivision.ancestor = ancestor;
}
out << subdivision.data.size();
out.writeAligned(subdivision.data);
}
void HeightfieldColorData::read(Bitstream& in, int bytes) {
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888));
}
void HeightfieldColorData::set(const QImage& image) {
_contents.resize(image.width() * image.height() * COLOR_BYTES);
memcpy(_contents.data(), image.constBits(), _contents.size());
}
HeightfieldTexture::HeightfieldTexture() {
}
HeightfieldAttribute::HeightfieldAttribute(const QString& name) :
InlineAttribute<HeightfieldDataPointer>(name) {
InlineAttribute<HeightfieldHeightDataPointer>(name) {
}
void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
@ -850,9 +946,9 @@ void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const
int size;
in >> size;
if (size == 0) {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
*(HeightfieldHeightDataPointer*)&value = HeightfieldHeightDataPointer();
} else {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
*(HeightfieldHeightDataPointer*)&value = HeightfieldHeightDataPointer(new HeightfieldHeightData(in, size));
}
}
@ -860,9 +956,9 @@ void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const
if (!isLeaf) {
return;
}
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
HeightfieldHeightDataPointer data = decodeInline<HeightfieldHeightDataPointer>(value);
if (data) {
data->write(out, false);
data->write(out);
} else {
out << 0;
}
@ -875,10 +971,10 @@ void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* referenc
int size;
in >> size;
if (size == 0) {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
*(HeightfieldHeightDataPointer*)&value = HeightfieldHeightDataPointer();
} else {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
in, size, decodeInline<HeightfieldDataPointer>(reference), false));
*(HeightfieldHeightDataPointer*)&value = HeightfieldHeightDataPointer(new HeightfieldHeightData(
in, size, decodeInline<HeightfieldHeightDataPointer>(reference)));
}
}
@ -886,9 +982,9 @@ void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* referen
if (!isLeaf) {
return;
}
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
HeightfieldHeightDataPointer data = decodeInline<HeightfieldHeightDataPointer>(value);
if (data) {
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), false);
data->writeDelta(out, decodeInline<HeightfieldHeightDataPointer>(reference));
} else {
out << 0;
}
@ -897,20 +993,20 @@ void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* referen
bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const {
int maxSize = 0;
for (int i = 0; i < MERGE_COUNT; i++) {
HeightfieldDataPointer pointer = decodeInline<HeightfieldDataPointer>(children[i]);
HeightfieldHeightDataPointer pointer = decodeInline<HeightfieldHeightDataPointer>(children[i]);
if (pointer) {
maxSize = qMax(maxSize, pointer->getContents().size());
}
}
if (maxSize == 0) {
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();
*(HeightfieldHeightDataPointer*)&parent = HeightfieldHeightDataPointer();
return true;
}
int size = glm::sqrt((float)maxSize);
QByteArray contents(size * size, 0);
int halfSize = size / 2;
for (int i = 0; i < MERGE_COUNT; i++) {
HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]);
HeightfieldHeightDataPointer child = decodeInline<HeightfieldHeightDataPointer>(children[i]);
if (!child) {
continue;
}
@ -920,7 +1016,7 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead)
int xIndex = i & INDEX_MASK;
const int Y_SHIFT = 1;
int yIndex = (i >> Y_SHIFT) & INDEX_MASK;
if (yIndex == 0 && decodeInline<HeightfieldDataPointer>(children[i | (1 << Y_SHIFT)])) {
if (yIndex == 0 && decodeInline<HeightfieldHeightDataPointer>(children[i | (1 << Y_SHIFT)])) {
continue; // bottom is overriden by top
}
const int HALF_RANGE = 128;
@ -959,12 +1055,12 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead)
}
}
}
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
*(HeightfieldHeightDataPointer*)&parent = HeightfieldHeightDataPointer(new HeightfieldHeightData(contents));
return false;
}
HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) :
InlineAttribute<HeightfieldDataPointer>(name) {
InlineAttribute<HeightfieldColorDataPointer>(name) {
}
void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
@ -974,9 +1070,9 @@ void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) c
int size;
in >> size;
if (size == 0) {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
*(HeightfieldColorDataPointer*)&value = HeightfieldColorDataPointer();
} else {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
*(HeightfieldColorDataPointer*)&value = HeightfieldColorDataPointer(new HeightfieldColorData(in, size));
}
}
@ -984,9 +1080,9 @@ void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf)
if (!isLeaf) {
return;
}
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
HeightfieldColorDataPointer data = decodeInline<HeightfieldColorDataPointer>(value);
if (data) {
data->write(out, true);
data->write(out);
} else {
out << 0;
}
@ -999,10 +1095,10 @@ void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* ref
int size;
in >> size;
if (size == 0) {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
*(HeightfieldColorDataPointer*)&value = HeightfieldColorDataPointer();
} else {
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
in, size, decodeInline<HeightfieldDataPointer>(reference), true));
*(HeightfieldColorDataPointer*)&value = HeightfieldColorDataPointer(new HeightfieldColorData(
in, size, decodeInline<HeightfieldColorDataPointer>(reference)));
}
}
@ -1010,9 +1106,9 @@ void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* re
if (!isLeaf) {
return;
}
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
HeightfieldColorDataPointer data = decodeInline<HeightfieldColorDataPointer>(value);
if (data) {
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), true);
data->writeDelta(out, decodeInline<HeightfieldColorDataPointer>(reference));
} else {
out << 0;
}
@ -1021,20 +1117,20 @@ void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* re
bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const {
int maxSize = 0;
for (int i = 0; i < MERGE_COUNT; i++) {
HeightfieldDataPointer pointer = decodeInline<HeightfieldDataPointer>(children[i]);
HeightfieldColorDataPointer pointer = decodeInline<HeightfieldColorDataPointer>(children[i]);
if (pointer) {
maxSize = qMax(maxSize, pointer->getContents().size());
}
}
if (maxSize == 0) {
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();
*(HeightfieldColorDataPointer*)&parent = HeightfieldColorDataPointer();
return true;
}
int size = glm::sqrt(maxSize / (float)HeightfieldData::COLOR_BYTES);
QByteArray contents(size * size * HeightfieldData::COLOR_BYTES, 0);
int halfSize = size / 2;
for (int i = 0; i < MERGE_COUNT; i++) {
HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]);
HeightfieldColorDataPointer child = decodeInline<HeightfieldColorDataPointer>(children[i]);
if (!child) {
continue;
}
@ -1044,7 +1140,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
int xIndex = i & INDEX_MASK;
const int Y_SHIFT = 1;
int yIndex = (i >> Y_SHIFT) & INDEX_MASK;
if (yIndex == 0 && decodeInline<HeightfieldDataPointer>(children[i | (1 << Y_SHIFT)])) {
if (yIndex == 0 && decodeInline<HeightfieldColorDataPointer>(children[i | (1 << Y_SHIFT)])) {
continue; // bottom is overriden by top
}
int Z_SHIFT = 2;
@ -1098,7 +1194,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
}
}
}
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
*(HeightfieldColorDataPointer*)&parent = HeightfieldColorDataPointer(new HeightfieldColorData(contents));
return false;
}

View file

@ -18,6 +18,7 @@
#include <QReadWriteLock>
#include <QSharedPointer>
#include <QString>
#include <QUrl>
#include <QWidget>
#include "Bitstream.h"
@ -28,7 +29,9 @@ class QScriptEngine;
class QScriptValue;
class Attribute;
class HeightfieldColorData;
class HeightfieldData;
class HeightfieldHeightData;
class MetavoxelData;
class MetavoxelLOD;
class MetavoxelNode;
@ -439,23 +442,20 @@ public:
static const int COLOR_BYTES = 3;
HeightfieldData(const QByteArray& contents);
HeightfieldData(Bitstream& in, int bytes, bool color);
HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color);
HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& ancestor,
const glm::vec3& minimum, float size, bool color);
HeightfieldData(const QByteArray& contents = QByteArray());
virtual ~HeightfieldData();
const QByteArray& getContents() const { return _contents; }
void write(Bitstream& out, bool color);
void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color);
void writeSubdivided(Bitstream& out, const HeightfieldDataPointer& ancestor,
const glm::vec3& minimum, float size, bool color);
private:
void setDeltaData(const HeightfieldDataPointer& deltaData) { _deltaData = deltaData; }
const HeightfieldDataPointer& getDeltaData() const { return _deltaData; }
void read(Bitstream& in, int bytes, bool color);
void set(const QImage& image, bool color);
void setEncodedDelta(const QByteArray& encodedDelta) { _encodedDelta = encodedDelta; }
const QByteArray& getEncodedDelta() const { return _encodedDelta; }
QMutex& getEncodedDeltaMutex() { return _encodedDeltaMutex; }
protected:
QByteArray _contents;
QByteArray _encoded;
@ -474,8 +474,70 @@ private:
QMutex _encodedSubdivisionsMutex;
};
typedef QExplicitlySharedDataPointer<HeightfieldHeightData> HeightfieldHeightDataPointer;
/// Contains a block of heightfield height data.
class HeightfieldHeightData : public HeightfieldData {
public:
HeightfieldHeightData(const QByteArray& contents);
HeightfieldHeightData(Bitstream& in, int bytes);
HeightfieldHeightData(Bitstream& in, int bytes, const HeightfieldHeightDataPointer& reference);
HeightfieldHeightData(Bitstream& in, int bytes, const HeightfieldHeightDataPointer& ancestor,
const glm::vec3& minimum, float size);
void write(Bitstream& out);
void writeDelta(Bitstream& out, const HeightfieldHeightDataPointer& reference);
void writeSubdivided(Bitstream& out, const HeightfieldHeightDataPointer& ancestor,
const glm::vec3& minimum, float size);
private:
void read(Bitstream& in, int bytes);
void set(const QImage& image);
};
typedef QExplicitlySharedDataPointer<HeightfieldColorData> HeightfieldColorDataPointer;
/// Contains a block of heightfield color data.
class HeightfieldColorData : public HeightfieldData {
public:
HeightfieldColorData(const QByteArray& contents);
HeightfieldColorData(Bitstream& in, int bytes);
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& reference);
HeightfieldColorData(Bitstream& in, int bytes, const HeightfieldColorDataPointer& ancestor,
const glm::vec3& minimum, float size);
void write(Bitstream& out);
void writeDelta(Bitstream& out, const HeightfieldColorDataPointer& reference);
void writeSubdivided(Bitstream& out, const HeightfieldColorDataPointer& ancestor,
const glm::vec3& minimum, float size);
private:
void read(Bitstream& in, int bytes);
void set(const QImage& image);
};
/// Contains the description of a heightfield texture.
class HeightfieldTexture : public SharedObject {
Q_OBJECT
Q_PROPERTY(QUrl url MEMBER _url)
public:
Q_INVOKABLE HeightfieldTexture();
const QUrl& getURL() const { return _url; }
private:
QUrl _url;
};
/// An attribute that stores heightfield data.
class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {
class HeightfieldAttribute : public InlineAttribute<HeightfieldHeightDataPointer> {
Q_OBJECT
public:
@ -492,7 +554,7 @@ public:
};
/// An attribute that stores heightfield colors.
class HeightfieldColorAttribute : public InlineAttribute<HeightfieldDataPointer> {
class HeightfieldColorAttribute : public InlineAttribute<HeightfieldColorDataPointer> {
Q_OBJECT
public:

View file

@ -354,7 +354,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
HeightfieldHeightDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
if (!pointer) {
return STOP_RECURSION;
}
@ -396,8 +396,8 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
lineDest += size;
}
if (changed) {
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
HeightfieldHeightDataPointer newPointer(new HeightfieldHeightData(contents));
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldHeightDataPointer>(newPointer));
}
return STOP_RECURSION;
}
@ -442,7 +442,7 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
HeightfieldColorDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldColorDataPointer>();
if (!pointer) {
return STOP_RECURSION;
}
@ -481,8 +481,8 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
lineDest += stride;
}
if (changed) {
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldColorDataPointer>(newPointer));
}
return STOP_RECURSION;
}
@ -493,10 +493,10 @@ void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjec
}
PaintHeightfieldTextureEdit::PaintHeightfieldTextureEdit(const glm::vec3& position, float radius,
const QUrl& url, const QColor& averageColor) :
const SharedObjectPointer& texture, const QColor& averageColor) :
position(position),
radius(radius),
url(url),
texture(texture),
averageColor(averageColor) {
}
@ -531,7 +531,7 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
HeightfieldDataPointer pointer = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
HeightfieldColorDataPointer pointer = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
if (!pointer) {
return STOP_RECURSION;
}
@ -570,8 +570,8 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
lineDest += stride;
}
if (changed) {
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldDataPointer>(newPointer));
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldColorDataPointer>(newPointer));
}
return STOP_RECURSION;
}

View file

@ -249,11 +249,11 @@ public:
STREAM glm::vec3 position;
STREAM float radius;
STREAM QUrl url;
STREAM SharedObjectPointer texture;
STREAM QColor averageColor;
PaintHeightfieldTextureEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QUrl& url = QUrl(),
const QColor& averageColor = QColor());
PaintHeightfieldTextureEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
const SharedObjectPointer& texture = SharedObjectPointer(), const QColor& averageColor = QColor());
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};

View file

@ -158,7 +158,7 @@ SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nulla
_type->addItem("(none)");
}
foreach (const QMetaObject* metaObject, Bitstream::getMetaObjectSubClasses(metaObject)) {
// add add constructable subclasses
// add constructable subclasses
if (metaObject->constructorCount() > 0) {
_type->addItem(metaObject->className(), QVariant::fromValue(metaObject));
}
@ -226,6 +226,7 @@ void SharedObjectEditor::updateType() {
const QMetaObject* metaObject = _type->itemData(_type->currentIndex()).value<const QMetaObject*>();
if (!metaObject) {
_object.reset();
emit objectChanged(_object);
return;
}
QObject* newObject = metaObject->newInstance();
@ -259,7 +260,7 @@ void SharedObjectEditor::updateType() {
}
}
}
_object = static_cast<SharedObject*>(newObject);
emit objectChanged(_object = static_cast<SharedObject*>(newObject));
}
void SharedObjectEditor::propertyChanged() {
@ -275,6 +276,7 @@ void SharedObjectEditor::propertyChanged() {
QByteArray valuePropertyName = QItemEditorFactory::defaultFactory()->valuePropertyName(property.userType());
property.write(object, widget->property(valuePropertyName));
}
emit objectChanged(_object);
}
void SharedObjectEditor::updateProperty() {

View file

@ -211,7 +211,7 @@ Q_DECLARE_METATYPE(SharedObjectSet)
/// Allows editing shared object instances.
class SharedObjectEditor : public QWidget {
Q_OBJECT
Q_PROPERTY(SharedObjectPointer object READ getObject WRITE setObject USER true)
Q_PROPERTY(SharedObjectPointer object READ getObject WRITE setObject NOTIFY objectChanged USER true)
public:
@ -222,6 +222,10 @@ public:
/// "Detaches" the object pointer, copying it if anyone else is holding a reference.
void detachObject();
signals:
void objectChanged(const SharedObjectPointer& object);
public slots:
void setObject(const SharedObjectPointer& object);