mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 07:23:00 +02:00
Deflated JPEG encoding for blocks above 16x16.
This commit is contained in:
parent
05d6b628fa
commit
67266b41df
1 changed files with 75 additions and 29 deletions
|
@ -55,7 +55,7 @@ AttributeRegistry::AttributeRegistry() :
|
||||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
||||||
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
||||||
|
|
||||||
const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 40.0f;
|
const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f;
|
||||||
_heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
_heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||||
_heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
_heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||||
}
|
}
|
||||||
|
@ -493,6 +493,49 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) {
|
||||||
read(in, bytes, color);
|
read(in, bytes, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE };
|
||||||
|
|
||||||
|
static QByteArray encodeHeightfieldImage(const QImage& image) {
|
||||||
|
if (image.isNull()) {
|
||||||
|
return QByteArray(1, NULL_HEIGHTFIELD_IMAGE);
|
||||||
|
}
|
||||||
|
QBuffer buffer;
|
||||||
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
const int JPEG_ENCODE_THRESHOLD = 16;
|
||||||
|
if (image.width() >= JPEG_ENCODE_THRESHOLD && image.height() >= JPEG_ENCODE_THRESHOLD) {
|
||||||
|
qint32 offsetX = image.offset().x(), offsetY = image.offset().y();
|
||||||
|
buffer.write((char*)&offsetX, sizeof(qint32));
|
||||||
|
buffer.write((char*)&offsetY, sizeof(qint32));
|
||||||
|
image.save(&buffer, "JPG");
|
||||||
|
return QByteArray(1, DEFLATED_HEIGHTFIELD_IMAGE) + qCompress(buffer.data());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
buffer.putChar(NORMAL_HEIGHTFIELD_IMAGE);
|
||||||
|
image.save(&buffer, "PNG");
|
||||||
|
return buffer.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QImage decodeHeightfieldImage(const QByteArray& data) {
|
||||||
|
switch (data.at(0)) {
|
||||||
|
case NULL_HEIGHTFIELD_IMAGE:
|
||||||
|
default:
|
||||||
|
return QImage();
|
||||||
|
|
||||||
|
case NORMAL_HEIGHTFIELD_IMAGE:
|
||||||
|
return QImage::fromData(QByteArray::fromRawData(data.constData() + 1, data.size() - 1));
|
||||||
|
|
||||||
|
case DEFLATED_HEIGHTFIELD_IMAGE: {
|
||||||
|
QByteArray inflated = qUncompress((const uchar*)data.constData() + 1, data.size() - 1);
|
||||||
|
const int OFFSET_SIZE = sizeof(qint32) * 2;
|
||||||
|
QImage image = QImage::fromData((const uchar*)inflated.constData() + OFFSET_SIZE, inflated.size() - OFFSET_SIZE);
|
||||||
|
const qint32* offsets = (const qint32*)inflated.constData();
|
||||||
|
image.setOffset(QPoint(offsets[0], offsets[1]));
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
|
HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
|
||||||
if (!reference) {
|
if (!reference) {
|
||||||
read(in, bytes, color);
|
read(in, bytes, color);
|
||||||
|
@ -502,7 +545,10 @@ HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldData
|
||||||
reference->_encodedDelta = in.readAligned(bytes);
|
reference->_encodedDelta = in.readAligned(bytes);
|
||||||
reference->_deltaData = this;
|
reference->_deltaData = this;
|
||||||
_contents = reference->_contents;
|
_contents = reference->_contents;
|
||||||
QImage image = QImage::fromData(reference->_encodedDelta);
|
QImage image = decodeHeightfieldImage(reference->_encodedDelta);
|
||||||
|
if (image.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QPoint offset = image.offset();
|
QPoint offset = image.offset();
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
image = image.convertToFormat(QImage::Format_RGB888);
|
||||||
if (offset.x() == 0) {
|
if (offset.x() == 0) {
|
||||||
|
@ -550,9 +596,7 @@ void HeightfieldData::write(Bitstream& out, bool color) {
|
||||||
*dest++ = *src;
|
*dest++ = *src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QBuffer buffer(&_encoded);
|
_encoded = encodeHeightfieldImage(image);
|
||||||
buffer.open(QIODevice::WriteOnly);
|
|
||||||
image.save(&buffer, "PNG");
|
|
||||||
}
|
}
|
||||||
out << _encoded.size();
|
out << _encoded.size();
|
||||||
out.writeAligned(_encoded);
|
out.writeAligned(_encoded);
|
||||||
|
@ -588,15 +632,17 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r
|
||||||
maxY = qMax(maxY, y);
|
maxY = qMax(maxY, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int width = qMax(maxX - minX + 1, 0);
|
if (maxX >= minX) {
|
||||||
int height = qMax(maxY - minY + 1, 0);
|
int width = maxX - minX + 1;
|
||||||
image = QImage(width, height, QImage::Format_RGB888);
|
int height = maxY - minY + 1;
|
||||||
src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
|
image = QImage(width, height, QImage::Format_RGB888);
|
||||||
int srcStride = size * COLOR_BYTES;
|
src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
|
||||||
int destStride = width * COLOR_BYTES;
|
int srcStride = size * COLOR_BYTES;
|
||||||
for (int y = 0; y < height; y++) {
|
int destStride = width * COLOR_BYTES;
|
||||||
memcpy(image.scanLine(y), src, destStride);
|
for (int y = 0; y < height; y++) {
|
||||||
src += srcStride;
|
memcpy(image.scanLine(y), src, destStride);
|
||||||
|
src += srcStride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int size = glm::sqrt((float)_contents.size());
|
int size = glm::sqrt((float)_contents.size());
|
||||||
|
@ -619,24 +665,24 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r
|
||||||
maxY = qMax(maxY, y);
|
maxY = qMax(maxY, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int width = qMax(maxX - minX + 1, 0);
|
if (maxX >= minX) {
|
||||||
int height = qMax(maxY - minY + 1, 0);
|
int width = qMax(maxX - minX + 1, 0);
|
||||||
image = QImage(width, height, QImage::Format_RGB888);
|
int height = qMax(maxY - minY + 1, 0);
|
||||||
const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
|
image = QImage(width, height, QImage::Format_RGB888);
|
||||||
for (int y = 0; y < height; y++) {
|
const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
|
||||||
uchar* dest = image.scanLine(y);
|
for (int y = 0; y < height; y++) {
|
||||||
for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
|
uchar* dest = image.scanLine(y);
|
||||||
*dest++ = *src;
|
for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
|
||||||
*dest++ = *src;
|
*dest++ = *src;
|
||||||
*dest++ = *src;
|
*dest++ = *src;
|
||||||
|
*dest++ = *src;
|
||||||
|
}
|
||||||
|
lineSrc += size;
|
||||||
}
|
}
|
||||||
lineSrc += size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QBuffer buffer(&reference->_encodedDelta);
|
|
||||||
buffer.open(QIODevice::WriteOnly);
|
|
||||||
image.setOffset(QPoint(minX + 1, minY + 1));
|
image.setOffset(QPoint(minX + 1, minY + 1));
|
||||||
image.save(&buffer, "PNG");
|
reference->_encodedDelta = encodeHeightfieldImage(image);
|
||||||
reference->_deltaData = this;
|
reference->_deltaData = this;
|
||||||
}
|
}
|
||||||
out << reference->_encodedDelta.size();
|
out << reference->_encodedDelta.size();
|
||||||
|
@ -644,7 +690,7 @@ void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& r
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
|
void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
|
||||||
set(QImage::fromData(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
|
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldData::set(const QImage& image, bool color) {
|
void HeightfieldData::set(const QImage& image, bool color) {
|
||||||
|
|
Loading…
Reference in a new issue