From f8f9c25d381620ff1e2ed0a6d2fcb274ab960eb4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 14:59:28 -0800 Subject: [PATCH 1/6] Back to JPG compression for heightfield colors. --- .../src/metavoxels/MetavoxelServer.cpp | 2 +- libraries/metavoxels/src/Spanner.cpp | 76 +++++-------------- libraries/networking/src/PacketHeaders.cpp | 2 +- 3 files changed, 20 insertions(+), 60 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index f52cdf3e49..5c4591cf61 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -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; diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index e890821ec2..b550207ec0 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -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; } diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 5b9811a152..110892a106 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -78,7 +78,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeAudioStreamStats: return 1; case PacketTypeMetavoxelData: - return 11; + return 12; default: return 0; } From e5f3d48ffbbdac5fb58923caf9ccc2edf6513f18 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 16:33:41 -0800 Subject: [PATCH 2/6] Fix for splatted textures against empty regions. --- interface/resources/shaders/metavoxel_heightfield_splat.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_splat.frag b/interface/resources/shaders/metavoxel_heightfield_splat.frag index bb6b0d6536..180cb653ad 100644 --- a/interface/resources/shaders/metavoxel_heightfield_splat.frag +++ b/interface/resources/shaders/metavoxel_heightfield_splat.frag @@ -22,7 +22,7 @@ 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(0.5, gl_Color.a)) * (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); From dafa44570a448cffc50d04c828fa3e8bcf235584 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 17:15:58 -0800 Subject: [PATCH 3/6] That was not the shader change I wanted to check in. This was. --- interface/resources/shaders/metavoxel_heightfield_splat.frag | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_splat.frag b/interface/resources/shaders/metavoxel_heightfield_splat.frag index 180cb653ad..0754987fc3 100644 --- a/interface/resources/shaders/metavoxel_heightfield_splat.frag +++ b/interface/resources/shaders/metavoxel_heightfield_splat.frag @@ -22,7 +22,8 @@ varying vec4 alphaValues; void main(void) { // blend the splat textures - gl_FragColor = vec4(gl_Color.rgb, step(0.5, gl_Color.a)) * (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); From a16b54a34a9ff0e9a15e8591a30c9dde29ce8735 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 17:23:31 -0800 Subject: [PATCH 4/6] Let's try not using the "augmented" data, since we don't need it. --- interface/src/MetavoxelSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a566b18b7e..eb2933d113 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -154,7 +154,7 @@ void MetavoxelSystem::simulate(float deltaTime) { } SimulateVisitor simulateVisitor(deltaTime, getLOD()); - guideToAugmented(simulateVisitor); + guide(simulateVisitor); } class RenderVisitor : public MetavoxelVisitor { @@ -199,7 +199,7 @@ void MetavoxelSystem::render() { viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); RenderVisitor renderVisitor(getLOD()); - guideToAugmented(renderVisitor, true); + guide(renderVisitor); if (!_heightfieldBaseBatches.isEmpty() && Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) { glEnableClientState(GL_VERTEX_ARRAY); From 16de6a130bfdc81346f942072b248687fc12df3e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 17:29:43 -0800 Subject: [PATCH 5/6] Scratch that last change; it wasn't the problem. --- interface/src/MetavoxelSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index eb2933d113..a566b18b7e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -154,7 +154,7 @@ void MetavoxelSystem::simulate(float deltaTime) { } SimulateVisitor simulateVisitor(deltaTime, getLOD()); - guide(simulateVisitor); + guideToAugmented(simulateVisitor); } class RenderVisitor : public MetavoxelVisitor { @@ -199,7 +199,7 @@ void MetavoxelSystem::render() { viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); RenderVisitor renderVisitor(getLOD()); - guide(renderVisitor); + guideToAugmented(renderVisitor, true); if (!_heightfieldBaseBatches.isEmpty() && Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) { glEnableClientState(GL_VERTEX_ARRAY); From 35bd1cda8987edc5bf209bfbdfecac7769428869 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Jan 2015 21:52:56 -0800 Subject: [PATCH 6/6] I believe this should fix some problems with flickering/crashing on edits: don't reapply properties that we've already read (thus clearing cached data, stepping on other threads, etc.) --- libraries/metavoxels/src/Bitstream.cpp | 20 +++++++++----- libraries/metavoxels/src/SharedObject.cpp | 4 +-- libraries/metavoxels/src/SharedObject.h | 6 +++-- libraries/metavoxels/src/Spanner.cpp | 32 +++++++++++++++++------ libraries/metavoxels/src/Spanner.h | 4 +-- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index c3bd05d3c7..642562bfb5 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -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(result)->readExtra(in); + static_cast(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(result)->readExtraDelta(in, static_cast(reference)); + static_cast(result)->readExtraDelta(in, static_cast(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(object)->setValues(values); + if (!reread) { + static_cast(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(reference)->getValues().at(i) : QVariant()); values.append(value); } - static_cast(object)->setValues(values); + if (!reread) { + static_cast(object)->setValues(values); + } return object; } diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index dcfa9732b3..6369037e2a 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -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 } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index ebea322bf1..cd46ae9658 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -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. diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index b550207ec0..c771b8fb4a 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -3678,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; @@ -3692,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 { @@ -3716,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(in.getContext()); @@ -3726,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(reference)->getRoot()); bool changed; in >> changed; if (changed) { HeightfieldNodePointer root(new HeightfieldNode()); root->readDelta(static_cast(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(reference)->getRoot()); } } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 12d04edd14..653893c84d 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -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);