mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 02:27:48 +02:00
Fix for server saving, use Paeth filter before compressing heightfield data.
This commit is contained in:
parent
8a0ff4acf5
commit
dd87a45211
3 changed files with 117 additions and 11 deletions
|
@ -35,14 +35,16 @@ void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
|
||||||
setData(data);
|
setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelServer::setData(const MetavoxelData& data) {
|
void MetavoxelServer::setData(const MetavoxelData& data, bool loaded) {
|
||||||
if (_data == data) {
|
if (_data == data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit dataChanged(_data = data);
|
emit dataChanged(_data = data);
|
||||||
|
|
||||||
if (!_savedDataInitialized) {
|
if (loaded) {
|
||||||
_savedData = data;
|
_savedData = data;
|
||||||
|
|
||||||
|
} else if (!_savedDataInitialized) {
|
||||||
_savedDataInitialized = true;
|
_savedDataInitialized = true;
|
||||||
|
|
||||||
// start the save timer
|
// start the save timer
|
||||||
|
@ -340,7 +342,7 @@ void MetavoxelPersister::load() {
|
||||||
debug << "failed, " << e.getDescription();
|
debug << "failed, " << e.getDescription();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(_server, "setData", Q_ARG(const MetavoxelData&, data));
|
QMetaObject::invokeMethod(_server, "setData", Q_ARG(const MetavoxelData&, data), Q_ARG(bool, true));
|
||||||
debug << "done.";
|
debug << "done.";
|
||||||
}
|
}
|
||||||
data.dumpStats();
|
data.dumpStats();
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
|
|
||||||
const MetavoxelData& getData() const { return _data; }
|
const MetavoxelData& getData() const { return _data; }
|
||||||
|
|
||||||
Q_INVOKABLE void setData(const MetavoxelData& data);
|
Q_INVOKABLE void setData(const MetavoxelData& data, bool loaded = false);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
|
|
|
@ -613,7 +613,31 @@ static QByteArray encodeHeightfieldHeight(int offsetX, int offsetY, int width, i
|
||||||
*header++ = offsetY;
|
*header++ = offsetY;
|
||||||
*header++ = width;
|
*header++ = width;
|
||||||
*header++ = height;
|
*header++ = height;
|
||||||
inflated.append((const char*)contents.constData(), contents.size() * sizeof(quint16));
|
if (!contents.isEmpty()) {
|
||||||
|
// encode with Paeth filter (see http://en.wikipedia.org/wiki/Portable_Network_Graphics#Filtering)
|
||||||
|
QVector<quint16> filteredContents(contents.size());
|
||||||
|
const quint16* src = contents.constData();
|
||||||
|
quint16* dest = filteredContents.data();
|
||||||
|
*dest++ = *src++;
|
||||||
|
for (quint16* end = dest + width - 1; dest != end; dest++, src++) {
|
||||||
|
*dest = *src - src[-1];
|
||||||
|
}
|
||||||
|
for (int y = 1; y < height; y++) {
|
||||||
|
*dest++ = *src - src[-width];
|
||||||
|
src++;
|
||||||
|
for (quint16* end = dest + width - 1; dest != end; dest++, src++) {
|
||||||
|
int a = src[-1];
|
||||||
|
int b = src[-width];
|
||||||
|
int c = src[-width - 1];
|
||||||
|
int p = a + b - c;
|
||||||
|
int ad = abs(a - p);
|
||||||
|
int bd = abs(b - p);
|
||||||
|
int cd = abs(c - p);
|
||||||
|
*dest = *src - (ad < bd ? (ad < cd ? a : c) : (bd < cd ? b : c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inflated.append((const char*)filteredContents.constData(), filteredContents.size() * sizeof(quint16));
|
||||||
|
}
|
||||||
return qCompress(inflated);
|
return qCompress(inflated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,9 +650,30 @@ static QVector<quint16> decodeHeightfieldHeight(const QByteArray& encoded, int&
|
||||||
width = *header++;
|
width = *header++;
|
||||||
height = *header++;
|
height = *header++;
|
||||||
int payloadSize = inflated.size() - HEIGHTFIELD_DATA_HEADER_SIZE;
|
int payloadSize = inflated.size() - HEIGHTFIELD_DATA_HEADER_SIZE;
|
||||||
QVector<quint16> decoded(payloadSize / sizeof(quint16));
|
QVector<quint16> unfiltered(payloadSize / sizeof(quint16));
|
||||||
memcpy(decoded.data(), inflated.constData() + HEIGHTFIELD_DATA_HEADER_SIZE, payloadSize);
|
if (!unfiltered.isEmpty()) {
|
||||||
return decoded;
|
quint16* dest = unfiltered.data();
|
||||||
|
const quint16* src = (const quint16*)(inflated.constData() + HEIGHTFIELD_DATA_HEADER_SIZE);
|
||||||
|
*dest++ = *src++;
|
||||||
|
for (quint16* end = dest + width - 1; dest != end; dest++, src++) {
|
||||||
|
*dest = *src + dest[-1];
|
||||||
|
}
|
||||||
|
for (int y = 1; y < height; y++) {
|
||||||
|
*dest = (*src++) + dest[-width];
|
||||||
|
dest++;
|
||||||
|
for (quint16* end = dest + width - 1; dest != end; dest++, src++) {
|
||||||
|
int a = dest[-1];
|
||||||
|
int b = dest[-width];
|
||||||
|
int c = dest[-width - 1];
|
||||||
|
int p = a + b - c;
|
||||||
|
int ad = abs(a - p);
|
||||||
|
int bd = abs(b - p);
|
||||||
|
int cd = abs(c - p);
|
||||||
|
*dest = *src + (ad < bd ? (ad < cd ? a : c) : (bd < cd ? b : c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unfiltered;
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightfieldHeight::HeightfieldHeight(int width, const QVector<quint16>& contents) :
|
HeightfieldHeight::HeightfieldHeight(int width, const QVector<quint16>& contents) :
|
||||||
|
@ -861,13 +906,42 @@ void HeightfieldHeightEditor::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray encodeHeightfieldColor(int offsetX, int offsetY, int width, int height, const QByteArray& contents) {
|
static QByteArray encodeHeightfieldColor(int offsetX, int offsetY, int width, int height, const QByteArray& contents) {
|
||||||
QByteArray inflated(HEIGHTFIELD_DATA_HEADER_SIZE, 0);
|
QByteArray inflated(HEIGHTFIELD_DATA_HEADER_SIZE + contents.size(), 0);
|
||||||
qint32* header = (qint32*)inflated.data();
|
qint32* header = (qint32*)inflated.data();
|
||||||
*header++ = offsetX;
|
*header++ = offsetX;
|
||||||
*header++ = offsetY;
|
*header++ = offsetY;
|
||||||
*header++ = width;
|
*header++ = width;
|
||||||
*header++ = height;
|
*header++ = height;
|
||||||
inflated.append(contents);
|
if (!contents.isEmpty()) {
|
||||||
|
// encode with Paeth filter (see http://en.wikipedia.org/wiki/Portable_Network_Graphics#Filtering)
|
||||||
|
const uchar* src = (const uchar*)contents.constData();
|
||||||
|
uchar* dest = (uchar*)inflated.data() + HEIGHTFIELD_DATA_HEADER_SIZE;
|
||||||
|
*dest++ = *src++;
|
||||||
|
*dest++ = *src++;
|
||||||
|
*dest++ = *src++;
|
||||||
|
int stride = width * DataBlock::COLOR_BYTES;
|
||||||
|
for (uchar* end = dest + stride - DataBlock::COLOR_BYTES; dest != end; dest++, src++) {
|
||||||
|
*dest = *src - src[-DataBlock::COLOR_BYTES];
|
||||||
|
}
|
||||||
|
for (int y = 1; y < height; y++) {
|
||||||
|
*dest++ = *src - src[-stride];
|
||||||
|
src++;
|
||||||
|
*dest++ = *src - src[-stride];
|
||||||
|
src++;
|
||||||
|
*dest++ = *src - src[-stride];
|
||||||
|
src++;
|
||||||
|
for (uchar* end = dest + stride - DataBlock::COLOR_BYTES; dest != end; dest++, src++) {
|
||||||
|
int a = src[-DataBlock::COLOR_BYTES];
|
||||||
|
int b = src[-stride];
|
||||||
|
int c = src[-stride - DataBlock::COLOR_BYTES];
|
||||||
|
int p = a + b - c;
|
||||||
|
int ad = abs(a - p);
|
||||||
|
int bd = abs(b - p);
|
||||||
|
int cd = abs(c - p);
|
||||||
|
*dest = *src - (ad < bd ? (ad < cd ? a : c) : (bd < cd ? b : c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return qCompress(inflated);
|
return qCompress(inflated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,7 +952,37 @@ static QByteArray decodeHeightfieldColor(const QByteArray& encoded, int& offsetX
|
||||||
offsetY = *header++;
|
offsetY = *header++;
|
||||||
width = *header++;
|
width = *header++;
|
||||||
height = *header++;
|
height = *header++;
|
||||||
return inflated.mid(HEIGHTFIELD_DATA_HEADER_SIZE);
|
QByteArray contents(inflated.size() - HEIGHTFIELD_DATA_HEADER_SIZE, 0);
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
const uchar* src = (const uchar*)inflated.constData() + HEIGHTFIELD_DATA_HEADER_SIZE;
|
||||||
|
uchar* dest = (uchar*)contents.data();
|
||||||
|
*dest++ = *src++;
|
||||||
|
*dest++ = *src++;
|
||||||
|
*dest++ = *src++;
|
||||||
|
int stride = width * DataBlock::COLOR_BYTES;
|
||||||
|
for (uchar* end = dest + stride - DataBlock::COLOR_BYTES; dest != end; dest++, src++) {
|
||||||
|
*dest = *src + dest[-DataBlock::COLOR_BYTES];
|
||||||
|
}
|
||||||
|
for (int y = 1; y < height; y++) {
|
||||||
|
*dest = (*src++) + dest[-stride];
|
||||||
|
dest++;
|
||||||
|
*dest = (*src++) + dest[-stride];
|
||||||
|
dest++;
|
||||||
|
*dest = (*src++) + dest[-stride];
|
||||||
|
dest++;
|
||||||
|
for (uchar* end = dest + stride - DataBlock::COLOR_BYTES; dest != end; dest++, src++) {
|
||||||
|
int a = dest[-DataBlock::COLOR_BYTES];
|
||||||
|
int b = dest[-stride];
|
||||||
|
int c = dest[-stride - DataBlock::COLOR_BYTES];
|
||||||
|
int p = a + b - c;
|
||||||
|
int ad = abs(a - p);
|
||||||
|
int bd = abs(b - p);
|
||||||
|
int cd = abs(c - p);
|
||||||
|
*dest = *src + (ad < bd ? (ad < cd ? a : c) : (bd < cd ? b : c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightfieldColor::HeightfieldColor(int width, const QByteArray& contents) :
|
HeightfieldColor::HeightfieldColor(int width, const QByteArray& contents) :
|
||||||
|
|
Loading…
Reference in a new issue