Working on heightfield encoding.

This commit is contained in:
Andrzej Kapolka 2014-07-29 19:13:43 -07:00
parent 496f4a184e
commit 1ea9b0ccbc
6 changed files with 112 additions and 8 deletions

View file

@ -255,11 +255,12 @@ void PointBuffer::render() {
} }
HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
const QByteArray& height, const QByteArray& color) : const QByteArray& height, const QByteArray& color, bool clearAfterLoading) :
_translation(translation), _translation(translation),
_scale(scale), _scale(scale),
_height(height), _height(height),
_color(color), _color(color),
_clearAfterLoading(clearAfterLoading),
_heightTexture(QOpenGLTexture::Target2D), _heightTexture(QOpenGLTexture::Target2D),
_colorTexture(QOpenGLTexture::Target2D) { _colorTexture(QOpenGLTexture::Target2D) {
} }
@ -281,8 +282,9 @@ void HeightfieldBuffer::render() {
_heightTexture.setFormat(QOpenGLTexture::LuminanceFormat); _heightTexture.setFormat(QOpenGLTexture::LuminanceFormat);
_heightTexture.allocateStorage(); _heightTexture.allocateStorage();
_heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); _heightTexture.setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data());
_height.clear(); if (_clearAfterLoading) {
_height.clear();
}
if (!_color.isEmpty()) { if (!_color.isEmpty()) {
int colorSize = glm::sqrt(_color.size() / 3); int colorSize = glm::sqrt(_color.size() / 3);
_colorTexture.setSize(colorSize, colorSize); _colorTexture.setSize(colorSize, colorSize);
@ -294,8 +296,9 @@ void HeightfieldBuffer::render() {
_colorTexture.allocateStorage(); _colorTexture.allocateStorage();
if (!_color.isEmpty()) { if (!_color.isEmpty()) {
_colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data());
_color.clear(); if (_clearAfterLoading) {
_color.clear();
}
} else { } else {
const quint8 WHITE_COLOR[] = { 255, 255, 255 }; const quint8 WHITE_COLOR[] = { 255, 255, 255 };
_colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast<quint8*>(WHITE_COLOR)); _colorTexture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast<quint8*>(WHITE_COLOR));

View file

@ -125,7 +125,15 @@ private:
class HeightfieldBuffer : public BufferData { class HeightfieldBuffer : public BufferData {
public: public:
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); /// Creates a new heightfield buffer.
/// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color,
bool clearAfterLoading = true);
const glm::vec3& getTranslation() const { return _translation; }
const QByteArray& getHeight() const { return _height; }
const QByteArray& getColor() const { return _color; }
virtual void render(); virtual void render();
@ -135,6 +143,7 @@ private:
float _scale; float _scale;
QByteArray _height; QByteArray _height;
QByteArray _color; QByteArray _color;
bool _clearAfterLoading;
QOpenGLTexture _heightTexture; QOpenGLTexture _heightTexture;
QOpenGLTexture _colorTexture; QOpenGLTexture _colorTexture;
@ -147,6 +156,7 @@ class HeightfieldPreview {
public: public:
void setBuffers(const QVector<BufferDataPointer>& buffers) { _buffers = buffers; } void setBuffers(const QVector<BufferDataPointer>& buffers) { _buffers = buffers; }
const QVector<BufferDataPointer>& getBuffers() const { return _buffers; }
void render(const glm::vec3& translation, float scale) const; void render(const glm::vec3& translation, float scale) const;

View file

@ -908,11 +908,15 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
_scale->setMinimum(-FLT_MAX); _scale->setMinimum(-FLT_MAX);
_scale->setMaximum(FLT_MAX); _scale->setMaximum(FLT_MAX);
_scale->setPrefix("2^"); _scale->setPrefix("2^");
_scale->setValue(1.0); _scale->setValue(3.0);
form->addRow("Height:", _height = new QPushButton()); form->addRow("Height:", _height = new QPushButton());
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
form->addRow("Color:", _color = new QPushButton()); form->addRow("Color:", _color = new QPushButton());
connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile);
QPushButton* applyButton = new QPushButton("Apply");
layout()->addWidget(applyButton);
connect(applyButton, &QAbstractButton::clicked, this, &ImportHeightfieldTool::apply);
} }
bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const { bool ImportHeightfieldTool::appliesTo(const AttributePointer& attribute) const {
@ -955,6 +959,26 @@ void ImportHeightfieldTool::selectColorFile() {
updatePreview(); updatePreview();
} }
void ImportHeightfieldTool::apply() {
float scale = pow(2.0, _scale->value());
foreach (const BufferDataPointer& bufferData, _preview.getBuffers()) {
HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data());
MetavoxelData data;
data.setSize(scale);
HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight()));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer))));
if (!buffer->getColor().isEmpty()) {
HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor()));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
}
MetavoxelEditMessage message = { QVariant::fromValue(SetDataEdit(
_translation->getValue() + buffer->getTranslation() * scale, data)) };
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
}
}
const int BLOCK_SIZE = 32; const int BLOCK_SIZE = 32;
const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1;
@ -988,7 +1012,7 @@ void ImportHeightfieldTool::updatePreview() {
_colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR);
} }
} }
buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false)));
} }
} }
} }

View file

@ -241,6 +241,7 @@ private slots:
void selectHeightFile(); void selectHeightFile();
void selectColorFile(); void selectColorFile();
void apply();
private: private:

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QBuffer>
#include <QMutexLocker>
#include <QReadLocker> #include <QReadLocker>
#include <QScriptEngine> #include <QScriptEngine>
#include <QWriteLocker> #include <QWriteLocker>
@ -459,10 +461,49 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) :
_contents(contents) { _contents(contents) {
} }
void HeightfieldData::write(Bitstream& out, bool color) {
QMutexLocker locker(&_encodedMutex);
if (_encoded.isEmpty()) {
QImage image;
const int BYTES_PER_PIXEL = 3;
if (color) {
int size = glm::sqrt(_contents.size() / (double)BYTES_PER_PIXEL);
image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);
} else {
int size = glm::sqrt((double)_contents.size());
image = QImage(size, size, QImage::Format_RGB888);
uchar* dest = image.bits();
for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) {
*dest++ = *src;
*dest++ = *src;
*dest++ = *src;
}
}
QBuffer buffer(&_encoded);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");
}
}
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 {
if (isLeaf) {
}
}
void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
if (isLeaf) {
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
if (data) {
data->write(out, false);
}
}
}
bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const { bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const {
return false; return false;
} }
@ -471,6 +512,20 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) :
InlineAttribute<HeightfieldDataPointer>(name) { InlineAttribute<HeightfieldDataPointer>(name) {
} }
void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
if (isLeaf) {
}
}
void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
if (isLeaf) {
HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
if (data) {
data->write(out, true);
}
}
}
bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const { bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const {
return false; return false;
} }

View file

@ -13,6 +13,7 @@
#define hifi_AttributeRegistry_h #define hifi_AttributeRegistry_h
#include <QHash> #include <QHash>
#include <QMutex>
#include <QObject> #include <QObject>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QSharedPointer> #include <QSharedPointer>
@ -424,9 +425,13 @@ public:
const QByteArray& getContents() const { return _contents; } const QByteArray& getContents() const { return _contents; }
void write(Bitstream& out, bool color);
private: private:
QByteArray _contents; QByteArray _contents;
QByteArray _encoded;
QMutex _encodedMutex;
}; };
typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer; typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
@ -439,6 +444,9 @@ public:
Q_INVOKABLE HeightfieldAttribute(const QString& name = QString()); Q_INVOKABLE HeightfieldAttribute(const QString& name = QString());
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
virtual void write(Bitstream& out, void* value, 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;
}; };
@ -450,6 +458,9 @@ public:
Q_INVOKABLE HeightfieldColorAttribute(const QString& name = QString()); Q_INVOKABLE HeightfieldColorAttribute(const QString& name = QString());
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
virtual void write(Bitstream& out, void* value, 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;
}; };