mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 00:56:48 +02:00
Rather than using a boolean to indicate "colorness," use a different class.
More texture bits.
This commit is contained in:
parent
23a4c21ce1
commit
e854656a7f
9 changed files with 465 additions and 287 deletions
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue