Merge pull request #4135 from ey6es/master

Back to JPG compression for heightfield colors.
This commit is contained in:
Andrew Meadows 2015-01-20 10:01:45 -08:00
commit 4112acc382
8 changed files with 68 additions and 81 deletions

View file

@ -311,7 +311,7 @@ MetavoxelPersister::MetavoxelPersister(MetavoxelServer* server) :
const char* SAVE_FILE = "/resources/metavoxels.dat";
const int FILE_MAGIC = 0xDADAFACE;
const int FILE_VERSION = 3;
const int FILE_VERSION = 4;
void MetavoxelPersister::load() {
QString path = QCoreApplication::applicationDirPath() + SAVE_FILE;

View file

@ -22,7 +22,8 @@ varying vec4 alphaValues;
void main(void) {
// blend the splat textures
gl_FragColor = gl_Color * (texture2D(diffuseMaps[0], gl_TexCoord[0].st) * alphaValues.x +
gl_FragColor = vec4(gl_Color.rgb, step(1.0, gl_Color.a + 1.0 / 512.0)) *
(texture2D(diffuseMaps[0], gl_TexCoord[0].st) * alphaValues.x +
texture2D(diffuseMaps[1], gl_TexCoord[1].st) * alphaValues.y +
texture2D(diffuseMaps[2], gl_TexCoord[2].st) * alphaValues.z +
texture2D(diffuseMaps[3], gl_TexCoord[3].st) * alphaValues.w);

View file

@ -2432,12 +2432,13 @@ void MappedObjectStreamer::writeRawDelta(Bitstream& out, const QObject* object,
}
QObject* MappedObjectStreamer::read(Bitstream& in, QObject* object) const {
bool reread = (object != NULL);
if (!object && _metaObject) {
object = _metaObject->newInstance();
}
foreach (const StreamerPropertyPair& property, _properties) {
QVariant value = property.first->read(in);
if (property.second.isValid() && object) {
if (property.second.isValid() && object && !reread) {
property.second.write(object, value);
}
}
@ -2445,6 +2446,7 @@ QObject* MappedObjectStreamer::read(Bitstream& in, QObject* object) const {
}
QObject* MappedObjectStreamer::readRawDelta(Bitstream& in, const QObject* reference, QObject* object) const {
bool reread = (object != NULL);
if (!object && _metaObject) {
object = _metaObject->newInstance();
}
@ -2452,7 +2454,7 @@ QObject* MappedObjectStreamer::readRawDelta(Bitstream& in, const QObject* refere
QVariant value;
property.first->readDelta(in, value, (property.second.isValid() && reference &&
reference->metaObject() == _metaObject) ? property.second.read(reference) : QVariant());
if (property.second.isValid() && object) {
if (property.second.isValid() && object && !reread) {
property.second.write(object, value);
}
}
@ -2475,13 +2477,13 @@ void SharedObjectStreamer::writeRawDelta(Bitstream& out, const QObject* object,
QObject* SharedObjectStreamer::read(Bitstream& in, QObject* object) const {
QObject* result = MappedObjectStreamer::read(in, object);
static_cast<SharedObject*>(result)->readExtra(in);
static_cast<SharedObject*>(result)->readExtra(in, object != NULL);
return result;
}
QObject* SharedObjectStreamer::readRawDelta(Bitstream& in, const QObject* reference, QObject* object) const {
QObject* result = MappedObjectStreamer::readRawDelta(in, reference, object);
static_cast<SharedObject*>(result)->readExtraDelta(in, static_cast<const SharedObject*>(reference));
static_cast<SharedObject*>(result)->readExtraDelta(in, static_cast<const SharedObject*>(reference), object != NULL);
return result;
}
@ -2592,6 +2594,7 @@ void GenericObjectStreamer::writeRawDelta(Bitstream& out, const QObject* object,
}
QObject* GenericObjectStreamer::read(Bitstream& in, QObject* object) const {
bool reread = (object != NULL);
if (!object) {
object = new GenericSharedObject(_weakSelf);
}
@ -2599,11 +2602,14 @@ QObject* GenericObjectStreamer::read(Bitstream& in, QObject* object) const {
foreach (const StreamerNamePair& property, _properties) {
values.append(property.first->read(in));
}
static_cast<GenericSharedObject*>(object)->setValues(values);
if (!reread) {
static_cast<GenericSharedObject*>(object)->setValues(values);
}
return object;
}
QObject* GenericObjectStreamer::readRawDelta(Bitstream& in, const QObject* reference, QObject* object) const {
bool reread = (object != NULL);
if (!object) {
object = new GenericSharedObject(_weakSelf);
}
@ -2615,7 +2621,9 @@ QObject* GenericObjectStreamer::readRawDelta(Bitstream& in, const QObject* refer
static_cast<const GenericSharedObject*>(reference)->getValues().at(i) : QVariant());
values.append(value);
}
static_cast<GenericSharedObject*>(object)->setValues(values);
if (!reread) {
static_cast<GenericSharedObject*>(object)->setValues(values);
}
return object;
}

View file

@ -135,7 +135,7 @@ void SharedObject::writeExtra(Bitstream& out) const {
// nothing by default
}
void SharedObject::readExtra(Bitstream& in) {
void SharedObject::readExtra(Bitstream& in, bool reread) {
// nothing by default
}
@ -143,7 +143,7 @@ void SharedObject::writeExtraDelta(Bitstream& out, const SharedObject* reference
// nothing by default
}
void SharedObject::readExtraDelta(Bitstream& in, const SharedObject* reference) {
void SharedObject::readExtraDelta(Bitstream& in, const SharedObject* reference, bool reread) {
// nothing by default
}

View file

@ -84,13 +84,15 @@ public:
virtual void writeExtra(Bitstream& out) const;
/// Reads the non-property contents of this object from the specified stream.
virtual void readExtra(Bitstream& in);
/// \param reread if true, reread the contents from the stream but don't reapply them
virtual void readExtra(Bitstream& in, bool reread = false);
/// Writes the delta-encoded non-property contents of this object to the specified stream.
virtual void writeExtraDelta(Bitstream& out, const SharedObject* reference) const;
/// Reads the delta-encoded non-property contents of this object from the specified stream.
virtual void readExtraDelta(Bitstream& in, const SharedObject* reference);
/// \param reread if true, reread the contents from the stream but don't reapply them
virtual void readExtraDelta(Bitstream& in, const SharedObject* reference, bool reread = false);
/// Writes the subdivision of the contents of this object (preceeded by a
/// reference to the object itself) to the specified stream if necessary.

View file

@ -681,41 +681,17 @@ void HeightfieldHeightEditor::clear() {
}
static QByteArray encodeHeightfieldColor(int offsetX, int offsetY, int width, int height, const QByteArray& contents) {
QByteArray inflated(HEIGHTFIELD_DATA_HEADER_SIZE + contents.size(), 0);
QByteArray inflated(HEIGHTFIELD_DATA_HEADER_SIZE, 0);
qint32* header = (qint32*)inflated.data();
*header++ = offsetX;
*header++ = offsetY;
*header++ = width;
*header++ = height;
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));
}
}
QBuffer buffer(&inflated);
buffer.open(QIODevice::WriteOnly | QIODevice::Append);
QImage((const uchar*)contents.constData(), width, height, width * DataBlock::COLOR_BYTES,
QImage::Format_RGB888).save(&buffer, "JPG");
}
return qCompress(inflated);
}
@ -727,35 +703,19 @@ static QByteArray decodeHeightfieldColor(const QByteArray& encoded, int& offsetX
offsetY = *header++;
width = *header++;
height = *header++;
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));
}
}
int payloadSize = inflated.size() - HEIGHTFIELD_DATA_HEADER_SIZE;
if (payloadSize == 0) {
return QByteArray();
}
QImage image = QImage::fromData((const uchar*)inflated.constData() + HEIGHTFIELD_DATA_HEADER_SIZE, payloadSize, "JPG");
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
}
QByteArray contents(width * height * DataBlock::COLOR_BYTES, 0);
char* dest = contents.data();
int stride = width * DataBlock::COLOR_BYTES;
for (int y = 0; y < height; y++, dest += stride) {
memcpy(dest, image.constScanLine(y), stride);
}
return contents;
}
@ -3718,9 +3678,18 @@ void Heightfield::writeExtra(Bitstream& out) const {
_root->write(state);
}
void Heightfield::readExtra(Bitstream& in) {
void Heightfield::readExtra(Bitstream& in, bool reread) {
if (getWillBeVoxelized()) {
in >> _height >> _color >> _material >> _stack;
if (reread) {
HeightfieldHeightPointer height;
HeightfieldColorPointer color;
HeightfieldMaterialPointer material;
HeightfieldStackPointer stack;
in >> height >> color >> material >> stack;
} else {
in >> _height >> _color >> _material >> _stack;
}
return;
}
MetavoxelLOD lod;
@ -3732,7 +3701,9 @@ void Heightfield::readExtra(Bitstream& in) {
HeightfieldNodePointer root(new HeightfieldNode());
root->read(state);
setRoot(root);
if (!reread) {
setRoot(root);
}
}
void Heightfield::writeExtraDelta(Bitstream& out, const SharedObject* reference) const {
@ -3756,7 +3727,7 @@ void Heightfield::writeExtraDelta(Bitstream& out, const SharedObject* reference)
}
}
void Heightfield::readExtraDelta(Bitstream& in, const SharedObject* reference) {
void Heightfield::readExtraDelta(Bitstream& in, const SharedObject* reference, bool reread) {
MetavoxelLOD lod, referenceLOD;
if (in.getContext()) {
MetavoxelStreamBase* base = static_cast<MetavoxelStreamBase*>(in.getContext());
@ -3766,16 +3737,21 @@ void Heightfield::readExtraDelta(Bitstream& in, const SharedObject* reference) {
HeightfieldStreamBase base = { in, lod, referenceLOD };
HeightfieldStreamState state = { base, glm::vec2(), 1.0f };
setRoot(static_cast<const Heightfield*>(reference)->getRoot());
bool changed;
in >> changed;
if (changed) {
HeightfieldNodePointer root(new HeightfieldNode());
root->readDelta(static_cast<const Heightfield*>(reference)->getRoot(), state);
setRoot(root);
if (!reread) {
setRoot(root);
}
} else if (state.becameSubdividedOrCollapsed()) {
setRoot(HeightfieldNodePointer(_root->readSubdivision(state)));
HeightfieldNodePointer root(_root->readSubdivision(state));
if (!reread) {
setRoot(root);
}
} else if (!reread) {
setRoot(static_cast<const Heightfield*>(reference)->getRoot());
}
}

View file

@ -820,9 +820,9 @@ public:
virtual bool intersects(const glm::vec3& start, const glm::vec3& end, float& distance, glm::vec3& normal);
virtual void writeExtra(Bitstream& out) const;
virtual void readExtra(Bitstream& in);
virtual void readExtra(Bitstream& in, bool reread);
virtual void writeExtraDelta(Bitstream& out, const SharedObject* reference) const;
virtual void readExtraDelta(Bitstream& in, const SharedObject* reference);
virtual void readExtraDelta(Bitstream& in, const SharedObject* reference, bool reread);
virtual void maybeWriteSubdivision(Bitstream& out);
virtual SharedObject* readSubdivision(Bitstream& in);

View file

@ -78,7 +78,7 @@ PacketVersion versionForPacketType(PacketType type) {
case PacketTypeAudioStreamStats:
return 1;
case PacketTypeMetavoxelData:
return 11;
return 12;
default:
return 0;
}