mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 07:37:20 +02:00
Working on heightfield encoding.
This commit is contained in:
parent
496f4a184e
commit
1ea9b0ccbc
6 changed files with 112 additions and 8 deletions
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,6 +241,7 @@ private slots:
|
||||||
|
|
||||||
void selectHeightFile();
|
void selectHeightFile();
|
||||||
void selectColorFile();
|
void selectColorFile();
|
||||||
|
void apply();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue