mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 10:48:15 +02:00
Switch to PNG encoding, send only the changed portion of the image for deltas.
This commit is contained in:
parent
18256a657e
commit
8804fa3710
3 changed files with 268 additions and 53 deletions
|
@ -490,21 +490,52 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) :
|
||||||
}
|
}
|
||||||
|
|
||||||
const int BYTES_PER_PIXEL = 3;
|
const int BYTES_PER_PIXEL = 3;
|
||||||
|
const int ZERO_OFFSET = 128;
|
||||||
|
|
||||||
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) :
|
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) {
|
||||||
_encoded(in.readAligned(bytes)) {
|
read(in, bytes, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
|
||||||
|
if (!reference) {
|
||||||
|
read(in, bytes, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMutexLocker locker(&reference->_encodedDeltaMutex);
|
||||||
|
reference->_encodedDelta = in.readAligned(bytes);
|
||||||
|
reference->_deltaData = this;
|
||||||
|
_contents = reference->_contents;
|
||||||
|
|
||||||
QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888);
|
QBuffer buffer(&reference->_encodedDelta);
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
QImage image;
|
||||||
|
image.load(&buffer, "PNG");
|
||||||
|
QPoint offset = image.offset();
|
||||||
|
image = image.convertToFormat(QImage::Format_RGB888);
|
||||||
|
if (offset.x() == 0) {
|
||||||
|
set(image, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int minX = offset.x() - 1;
|
||||||
|
int minY = offset.y() - 1;
|
||||||
if (color) {
|
if (color) {
|
||||||
_contents.resize(image.width() * image.height() * BYTES_PER_PIXEL);
|
int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL);
|
||||||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
char* dest = _contents.data() + (minY * size + minX) * BYTES_PER_PIXEL;
|
||||||
|
int destStride = size * BYTES_PER_PIXEL;
|
||||||
|
int srcStride = image.width() * BYTES_PER_PIXEL;
|
||||||
|
for (int y = 0; y < image.height(); y++) {
|
||||||
|
memcpy(dest, image.constScanLine(y), srcStride);
|
||||||
|
dest += destStride;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_contents.resize(image.width() * image.height());
|
int size = glm::sqrt((float)_contents.size());
|
||||||
char* dest = _contents.data();
|
char* lineDest = _contents.data() + minY * size + minX;
|
||||||
for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL;
|
for (int y = 0; y < image.height(); y++) {
|
||||||
src != end; src += BYTES_PER_PIXEL) {
|
const uchar* src = image.constScanLine(y);
|
||||||
*dest++ = *src;
|
for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += BYTES_PER_PIXEL) {
|
||||||
|
*dest = *src;
|
||||||
|
}
|
||||||
|
lineDest += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,36 +559,168 @@ void HeightfieldData::write(Bitstream& out, bool color) {
|
||||||
}
|
}
|
||||||
QBuffer buffer(&_encoded);
|
QBuffer buffer(&_encoded);
|
||||||
buffer.open(QIODevice::WriteOnly);
|
buffer.open(QIODevice::WriteOnly);
|
||||||
image.save(&buffer, "JPG");
|
image.save(&buffer, "PNG");
|
||||||
}
|
}
|
||||||
out << _encoded.size();
|
out << _encoded.size();
|
||||||
out.writeAligned(_encoded);
|
out.writeAligned(_encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) {
|
||||||
|
if (!reference || reference->getContents().size() != _contents.size()) {
|
||||||
|
write(out, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMutexLocker locker(&reference->_encodedDeltaMutex);
|
||||||
|
if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) {
|
||||||
|
QImage image;
|
||||||
|
int minX, minY;
|
||||||
|
if (color) {
|
||||||
|
int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL);
|
||||||
|
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 += BYTES_PER_PIXEL, ref += BYTES_PER_PIXEL) {
|
||||||
|
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 width = qMax(maxX - minX + 1, 0);
|
||||||
|
int height = qMax(maxY - minY + 1, 0);
|
||||||
|
image = QImage(width, height, QImage::Format_RGB888);
|
||||||
|
src = _contents.constData() + (minY * size + minX) * BYTES_PER_PIXEL;
|
||||||
|
int srcStride = size * BYTES_PER_PIXEL;
|
||||||
|
int destStride = width * BYTES_PER_PIXEL;
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
memcpy(image.scanLine(y), src, destStride);
|
||||||
|
src += srcStride;
|
||||||
|
}
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QBuffer buffer(&reference->_encodedDelta);
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
image.setOffset(QPoint(minX + 1, minY + 1));
|
||||||
|
image.save(&buffer, "PNG");
|
||||||
|
reference->_deltaData = this;
|
||||||
|
}
|
||||||
|
out << reference->_encodedDelta.size();
|
||||||
|
out.writeAligned(reference->_encodedDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
|
||||||
|
set(QImage::fromData(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldData::set(const QImage& image, bool color) {
|
||||||
|
if (color) {
|
||||||
|
_contents.resize(image.width() * image.height() * BYTES_PER_PIXEL);
|
||||||
|
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() * BYTES_PER_PIXEL;
|
||||||
|
src != end; src += BYTES_PER_PIXEL) {
|
||||||
|
*dest++ = *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HeightfieldAttribute::HeightfieldAttribute(const QString& name) :
|
HeightfieldAttribute::HeightfieldAttribute(const QString& name) :
|
||||||
InlineAttribute<HeightfieldDataPointer>(name) {
|
InlineAttribute<HeightfieldDataPointer>(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||||
if (isLeaf) {
|
if (!isLeaf) {
|
||||||
int size;
|
return;
|
||||||
in >> size;
|
}
|
||||||
if (size == 0) {
|
int size;
|
||||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
in >> size;
|
||||||
} else {
|
if (size == 0) {
|
||||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||||
}
|
} else {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||||
if (isLeaf) {
|
if (!isLeaf) {
|
||||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
return;
|
||||||
if (data) {
|
}
|
||||||
data->write(out, false);
|
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||||
} else {
|
if (data) {
|
||||||
out << 0;
|
data->write(out, false);
|
||||||
}
|
} else {
|
||||||
|
out << 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||||
|
if (!isLeaf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int size;
|
||||||
|
in >> size;
|
||||||
|
if (size == 0) {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||||
|
} else {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
|
||||||
|
in, size, decodeInline<HeightfieldDataPointer>(reference), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||||
|
if (!isLeaf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||||
|
if (data) {
|
||||||
|
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), false);
|
||||||
|
} else {
|
||||||
|
out << 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,25 +798,53 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||||
if (isLeaf) {
|
if (!isLeaf) {
|
||||||
int size;
|
return;
|
||||||
in >> size;
|
}
|
||||||
if (size == 0) {
|
int size;
|
||||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
in >> size;
|
||||||
} else {
|
if (size == 0) {
|
||||||
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||||
}
|
} else {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||||
if (isLeaf) {
|
if (!isLeaf) {
|
||||||
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
return;
|
||||||
if (data) {
|
}
|
||||||
data->write(out, true);
|
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||||
} else {
|
if (data) {
|
||||||
out << 0;
|
data->write(out, true);
|
||||||
}
|
} else {
|
||||||
|
out << 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||||
|
if (!isLeaf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int size;
|
||||||
|
in >> size;
|
||||||
|
if (size == 0) {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
|
||||||
|
} else {
|
||||||
|
*(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
|
||||||
|
in, size, decodeInline<HeightfieldDataPointer>(reference), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||||
|
if (!isLeaf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
|
||||||
|
if (data) {
|
||||||
|
data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), true);
|
||||||
|
} else {
|
||||||
|
out << 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ class QScriptEngine;
|
||||||
class QScriptValue;
|
class QScriptValue;
|
||||||
|
|
||||||
class Attribute;
|
class Attribute;
|
||||||
|
class HeightfieldData;
|
||||||
class MetavoxelData;
|
class MetavoxelData;
|
||||||
class MetavoxelLOD;
|
class MetavoxelLOD;
|
||||||
class MetavoxelNode;
|
class MetavoxelNode;
|
||||||
|
@ -421,26 +422,35 @@ public:
|
||||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
|
||||||
|
|
||||||
/// Contains a block of heightfield data.
|
/// Contains a block of heightfield data.
|
||||||
class HeightfieldData : public QSharedData {
|
class HeightfieldData : public QSharedData {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HeightfieldData(const QByteArray& contents);
|
HeightfieldData(const QByteArray& contents);
|
||||||
HeightfieldData(Bitstream& in, int bytes, bool color);
|
HeightfieldData(Bitstream& in, int bytes, bool color);
|
||||||
|
HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color);
|
||||||
|
|
||||||
const QByteArray& getContents() const { return _contents; }
|
const QByteArray& getContents() const { return _contents; }
|
||||||
|
|
||||||
void write(Bitstream& out, bool color);
|
void write(Bitstream& out, bool color);
|
||||||
|
void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void read(Bitstream& in, int bytes, bool color);
|
||||||
|
void set(const QImage& image, bool color);
|
||||||
|
|
||||||
QByteArray _contents;
|
QByteArray _contents;
|
||||||
QByteArray _encoded;
|
QByteArray _encoded;
|
||||||
QMutex _encodedMutex;
|
QMutex _encodedMutex;
|
||||||
|
|
||||||
|
HeightfieldDataPointer _deltaData;
|
||||||
|
QByteArray _encodedDelta;
|
||||||
|
QMutex _encodedDeltaMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
|
|
||||||
|
|
||||||
/// An attribute that stores heightfield data.
|
/// An attribute that stores heightfield data.
|
||||||
class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {
|
class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -451,7 +461,10 @@ public:
|
||||||
|
|
||||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||||
|
|
||||||
|
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||||
|
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||||
|
|
||||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -466,6 +479,9 @@ public:
|
||||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||||
|
|
||||||
|
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||||
|
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||||
|
|
||||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -378,6 +378,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||||
|
bool changed = false;
|
||||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
uchar* dest = lineDest;
|
uchar* dest = lineDest;
|
||||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||||
|
@ -386,14 +387,18 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
if (distanceSquared <= squaredRadius) {
|
if (distanceSquared <= squaredRadius) {
|
||||||
// height falls off towards edges
|
// height falls off towards edges
|
||||||
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
|
||||||
*dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
|
if (value != *dest) {
|
||||||
|
*dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lineDest += size;
|
lineDest += size;
|
||||||
}
|
}
|
||||||
|
if (changed) {
|
||||||
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||||
|
}
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,6 +466,7 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
||||||
float squaredRadius = scaledRadius * scaledRadius;
|
float squaredRadius = scaledRadius * scaledRadius;
|
||||||
char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
|
char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
|
||||||
|
bool changed = false;
|
||||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
char* dest = lineDest;
|
char* dest = lineDest;
|
||||||
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
||||||
|
@ -469,13 +475,15 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
dest[0] = red;
|
dest[0] = red;
|
||||||
dest[1] = green;
|
dest[1] = green;
|
||||||
dest[2] = blue;
|
dest[2] = blue;
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lineDest += stride;
|
lineDest += stride;
|
||||||
}
|
}
|
||||||
|
if (changed) {
|
||||||
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
HeightfieldDataPointer newPointer(new HeightfieldData(contents));
|
||||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
|
||||||
|
}
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue