//// MetavoxelSystem.cpp// interface/src//// Created by Andrzej Kapolka on 12/10/13.// Copyright 2013 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <QMutexLocker>#include <QReadLocker>#include <QWriteLocker>#include <QtDebug> #include <glm/gtx/transform.hpp> #include <SharedUtil.h> #include <MetavoxelUtil.h>#include <ScriptCache.h> #include "Application.h"#include "MetavoxelSystem.h"#include "renderer/Model.h" REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation)REGISTER_META_OBJECT(SphereRenderer)REGISTER_META_OBJECT(StaticModelRenderer) static int texturePointerMetaTypeId = qRegisterMetaType<TexturePointer>();static int bufferPointVectorMetaTypeId = qRegisterMetaType<BufferPointVector>(); void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("heightfieldBuffer"));} MetavoxelLOD MetavoxelSystem::getLOD() { QReadLocker locker(&_lodLock); return _lod;} class SimulateVisitor : public MetavoxelVisitor {public: SimulateVisitor(float deltaTime, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); private: float _deltaTime;}; SimulateVisitor::SimulateVisitor(float deltaTime, const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod), _deltaTime(deltaTime) {} int SimulateVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->simulate(*_data, _deltaTime, info, _lod); return STOP_RECURSION;} void MetavoxelSystem::simulate(float deltaTime) { // update the lod { // the LOD threshold is temporarily tied to the avatar LOD parameter QWriteLocker locker(&_lodLock); const float BASE_LOD_THRESHOLD = 0.01f; _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); } SimulateVisitor simulateVisitor(deltaTime, getLOD()); guideToAugmented(simulateVisitor);} class RenderVisitor : public MetavoxelVisitor {public: RenderVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info);}; RenderVisitor::RenderVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod) {} int RenderVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->render(*_data, info, _lod); return STOP_RECURSION;} void MetavoxelSystem::render() { RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor);} void MetavoxelSystem::deleteTextures(const TexturePointer& height, const TexturePointer& color) { delete height; delete color;} MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater);} void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor) { foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData()); if (client) { client->getAugmentedData().guide(visitor); } } }} MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : MetavoxelClient(node, updater) {} void MetavoxelSystemClient::setAugmentedData(const MetavoxelData& data) { QWriteLocker locker(&_augmentedDataLock); _augmentedData = data;} MetavoxelData MetavoxelSystemClient::getAugmentedData() { QReadLocker locker(&_augmentedDataLock); return _augmentedData;} int MetavoxelSystemClient::parseData(const QByteArray& packet) { // process through sequencer QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size()); return packet.size();} class AugmentVisitor : public MetavoxelVisitor {public: AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData); virtual int visit(MetavoxelInfo& info); private: const MetavoxelData& _previousData;}; AugmentVisitor::AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod), _previousData(previousData) {} int AugmentVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->augment(*_data, _previousData, info, _lod); return STOP_RECURSION;} class Augmenter : public QRunnable {public: Augmenter(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelData& previousData, const MetavoxelLOD& lod); virtual void run(); private: QWeakPointer<Node> _node; MetavoxelData _data; MetavoxelData _previousData; MetavoxelLOD _lod;}; Augmenter::Augmenter(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelData& previousData, const MetavoxelLOD& lod) : _node(node), _data(data), _previousData(previousData), _lod(lod) {} void Augmenter::run() { SharedNodePointer node = _node; if (!node) { return; } AugmentVisitor visitor(_lod, _previousData); _data.guide(visitor); QMutexLocker locker(&node->getMutex()); QMetaObject::invokeMethod(node->getLinkedData(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data));} void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD));} void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { NodeList::getInstance()->writeDatagram(data, _node); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());} BufferData::~BufferData() {} PointBuffer::PointBuffer(const BufferPointVector& points) : _points(points) {} void PointBuffer::render() { // initialize buffer, etc. on first render if (!_buffer.isCreated()) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); _buffer.create(); _buffer.bind(); _pointCount = _points.size(); _buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint)); _points.clear(); _buffer.release(); } if (_pointCount == 0) { return; } _buffer.bind(); BufferPoint* point = 0; glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); glDrawArrays(GL_POINTS, 0, _pointCount); _buffer.release();} HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, bool clearAfterLoading) : _translation(translation), _scale(scale), _height(height), _color(color), _clearAfterLoading(clearAfterLoading), _heightTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)), _colorTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) {} HeightfieldBuffer::~HeightfieldBuffer() { // the textures have to be deleted on the main thread (for its opengl context) if (QThread::currentThread() != Application::getInstance()->thread()) { QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", Q_ARG(const TexturePointer&, _heightTexture), Q_ARG(const TexturePointer&, _colorTexture)); } else { delete _heightTexture; delete _colorTexture; }} class HeightfieldPoint {public: glm::vec2 textureCoord; glm::vec3 vertex;}; void HeightfieldBuffer::render() { // initialize textures, etc. on first render if (!_heightTexture->isCreated()) { int heightSize = glm::sqrt(_height.size()); _heightTexture->setSize(heightSize, heightSize); _heightTexture->setAutoMipMapGenerationEnabled(false); _heightTexture->setMinificationFilter(QOpenGLTexture::Linear); _heightTexture->setWrapMode(QOpenGLTexture::ClampToEdge); _heightTexture->setFormat(QOpenGLTexture::LuminanceFormat); _heightTexture->allocateStorage(); _heightTexture->setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); if (_clearAfterLoading) { _height.clear(); } if (!_color.isEmpty()) { int colorSize = glm::sqrt(_color.size() / 3); _colorTexture->setSize(colorSize, colorSize); } _colorTexture->setAutoMipMapGenerationEnabled(false); _colorTexture->setMinificationFilter(QOpenGLTexture::Linear); _colorTexture->setWrapMode(QOpenGLTexture::ClampToEdge); _colorTexture->setFormat(QOpenGLTexture::RGBFormat); _colorTexture->allocateStorage(); if (!_color.isEmpty()) { _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); if (_clearAfterLoading) { _color.clear(); } } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast<quint8*>(WHITE_COLOR)); } } // create the buffer objects lazily int size = _heightTexture->width(); int sizeWithSkirt = size + 2; int vertexCount = sizeWithSkirt * sizeWithSkirt; int rows = sizeWithSkirt - 1; int indexCount = rows * rows * 4; BufferPair& bufferPair = _bufferPairs[size]; if (!bufferPair.first.isCreated()) { QVector<HeightfieldPoint> vertices(vertexCount); HeightfieldPoint* point = vertices.data(); float step = 1.0f / (size - 1); float z = -step; for (int i = 0; i < sizeWithSkirt; i++, z += step) { float x = -step; const float SKIRT_LENGTH = 0.25f; float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); point->textureCoord = glm::vec2(x, z); } } bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw); bufferPair.first.create(); bufferPair.first.bind(); bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint)); QVector<int> indices(indexCount); int* index = indices.data(); for (int i = 0; i < rows; i++) { int lineIndex = i * sizeWithSkirt; int nextLineIndex = (i + 1) * sizeWithSkirt; for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; *index++ = lineIndex + j + 1; *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j; } } bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); bufferPair.second.create(); bufferPair.second.bind(); bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int)); } else { bufferPair.first.bind(); bufferPair.second.bind(); } HeightfieldPoint* point = 0; glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex); glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord); glPushMatrix(); glTranslatef(_translation.x, _translation.y, _translation.z); glScalef(_scale, _scale, _scale); _heightTexture->bind(0); _colorTexture->bind(1); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); _colorTexture->release(1); _heightTexture->release(0); glPopMatrix(); bufferPair.first.release(); bufferPair.second.release();} QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); DefaultMetavoxelRendererImplementation::getHeightfieldProgram().bind(); glPushMatrix(); glTranslatef(translation.x, translation.y, translation.z); glScalef(scale, scale, scale); foreach (const BufferDataPointer& buffer, _buffers) { buffer->render(); } glPopMatrix(); DefaultMetavoxelRendererImplementation::getHeightfieldProgram().release(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND);} BufferDataAttribute::BufferDataAttribute(const QString& name) : InlineAttribute<BufferDataPointer>(name) {} bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { BufferDataPointer firstChild = decodeInline<BufferDataPointer>(children[0]); for (int i = 1; i < MERGE_COUNT; i++) { if (firstChild != decodeInline<BufferDataPointer>(children[i])) { *(BufferDataPointer*)&parent = _defaultValue; return false; } } *(BufferDataPointer*)&parent = firstChild; return true;} void DefaultMetavoxelRendererImplementation::init() { if (!_pointProgram.isLinked()) { _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); _pointProgram.link(); _pointProgram.bind(); _pointScaleLocation = _pointProgram.uniformLocation("pointScale"); _pointProgram.release(); _heightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield.vert"); _heightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_heightfield.frag"); _heightfieldProgram.link(); _heightfieldProgram.bind(); _heightfieldProgram.setUniformValue("heightMap", 0); _heightfieldProgram.setUniformValue("diffuseMap", 1); _heightfieldProgram.release(); }} DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() {} class PointAugmentVisitor : public MetavoxelVisitor {public: PointAugmentVisitor(const MetavoxelLOD& lod); virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: BufferPointVector _points; float _pointLeafSize;}; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) {} const int ALPHA_RENDER_THRESHOLD = 0; void PointAugmentVisitor::prepare(MetavoxelData* data) { MetavoxelVisitor::prepare(data); const float MAX_POINT_LEAF_SIZE = 64.0f; _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE);} int PointAugmentVisitor::visit(MetavoxelInfo& info) {Lines 1–500 of 866. Load more
// // MetavoxelSystem.cpp // interface/src // // Created by Andrzej Kapolka on 12/10/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include <QMutexLocker> #include <QReadLocker> #include <QWriteLocker> #include <QtDebug> #include <glm/gtx/transform.hpp> #include <SharedUtil.h> #include <MetavoxelUtil.h> #include <ScriptCache.h> #include "Application.h" #include "MetavoxelSystem.h" #include "renderer/Model.h" REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(StaticModelRenderer) static int texturePointerMetaTypeId = qRegisterMetaType<TexturePointer>(); static int bufferPointVectorMetaTypeId = qRegisterMetaType<BufferPointVector>(); void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("heightfieldBuffer")); } MetavoxelLOD MetavoxelSystem::getLOD() { QReadLocker locker(&_lodLock); return _lod; } class SimulateVisitor : public MetavoxelVisitor { public: SimulateVisitor(float deltaTime, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); private: float _deltaTime; }; SimulateVisitor::SimulateVisitor(float deltaTime, const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod), _deltaTime(deltaTime) { } int SimulateVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->simulate(*_data, _deltaTime, info, _lod); return STOP_RECURSION; } void MetavoxelSystem::simulate(float deltaTime) { // update the lod { // the LOD threshold is temporarily tied to the avatar LOD parameter QWriteLocker locker(&_lodLock); const float BASE_LOD_THRESHOLD = 0.01f; _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); } SimulateVisitor simulateVisitor(deltaTime, getLOD()); guideToAugmented(simulateVisitor); } class RenderVisitor : public MetavoxelVisitor { public: RenderVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); }; RenderVisitor::RenderVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod) { } int RenderVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->render(*_data, info, _lod); return STOP_RECURSION; } void MetavoxelSystem::render() { RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor); } void MetavoxelSystem::deleteTextures(const TexturePointer& height, const TexturePointer& color) { delete height; delete color; } MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor) { foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData()); if (client) { client->getAugmentedData().guide(visitor); } } } } MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : MetavoxelClient(node, updater) { } void MetavoxelSystemClient::setAugmentedData(const MetavoxelData& data) { QWriteLocker locker(&_augmentedDataLock); _augmentedData = data; } MetavoxelData MetavoxelSystemClient::getAugmentedData() { QReadLocker locker(&_augmentedDataLock); return _augmentedData; } int MetavoxelSystemClient::parseData(const QByteArray& packet) { // process through sequencer QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size()); return packet.size(); } class AugmentVisitor : public MetavoxelVisitor { public: AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData); virtual int visit(MetavoxelInfo& info); private: const MetavoxelData& _previousData; }; AugmentVisitor::AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(), QVector<AttributePointer>(), lod), _previousData(previousData) { } int AugmentVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; } static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue< SharedObjectPointer>().data())->getImplementation()->augment(*_data, _previousData, info, _lod); return STOP_RECURSION; } class Augmenter : public QRunnable { public: Augmenter(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelData& previousData, const MetavoxelLOD& lod); virtual void run(); private: QWeakPointer<Node> _node; MetavoxelData _data; MetavoxelData _previousData; MetavoxelLOD _lod; }; Augmenter::Augmenter(const SharedNodePointer& node, const MetavoxelData& data, const MetavoxelData& previousData, const MetavoxelLOD& lod) : _node(node), _data(data), _previousData(previousData), _lod(lod) { } void Augmenter::run() { SharedNodePointer node = _node; if (!node) { return; } AugmentVisitor visitor(_lod, _previousData); _data.guide(visitor); QMutexLocker locker(&node->getMutex()); QMetaObject::invokeMethod(node->getLinkedData(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data)); } void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD)); } void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { NodeList::getInstance()->writeDatagram(data, _node); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } BufferData::~BufferData() { } PointBuffer::PointBuffer(const BufferPointVector& points) : _points(points) { } void PointBuffer::render() { // initialize buffer, etc. on first render if (!_buffer.isCreated()) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); _buffer.create(); _buffer.bind(); _pointCount = _points.size(); _buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint)); _points.clear(); _buffer.release(); } if (_pointCount == 0) { return; } _buffer.bind(); BufferPoint* point = 0; glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); glDrawArrays(GL_POINTS, 0, _pointCount); _buffer.release(); } HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, bool clearAfterLoading) : _translation(translation), _scale(scale), _height(height), _color(color), _clearAfterLoading(clearAfterLoading), _heightTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)), _colorTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) { } HeightfieldBuffer::~HeightfieldBuffer() { // the textures have to be deleted on the main thread (for its opengl context) if (QThread::currentThread() != Application::getInstance()->thread()) { QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", Q_ARG(const TexturePointer&, _heightTexture), Q_ARG(const TexturePointer&, _colorTexture)); } else { delete _heightTexture; delete _colorTexture; } } class HeightfieldPoint { public: glm::vec2 textureCoord; glm::vec3 vertex; }; void HeightfieldBuffer::render() { // initialize textures, etc. on first render if (!_heightTexture->isCreated()) { int heightSize = glm::sqrt(_height.size()); _heightTexture->setSize(heightSize, heightSize); _heightTexture->setAutoMipMapGenerationEnabled(false); _heightTexture->setMinificationFilter(QOpenGLTexture::Linear); _heightTexture->setWrapMode(QOpenGLTexture::ClampToEdge); _heightTexture->setFormat(QOpenGLTexture::LuminanceFormat); _heightTexture->allocateStorage(); _heightTexture->setData(QOpenGLTexture::Luminance, QOpenGLTexture::UInt8, _height.data()); if (_clearAfterLoading) { _height.clear(); } if (!_color.isEmpty()) { int colorSize = glm::sqrt(_color.size() / 3); _colorTexture->setSize(colorSize, colorSize); } _colorTexture->setAutoMipMapGenerationEnabled(false); _colorTexture->setMinificationFilter(QOpenGLTexture::Linear); _colorTexture->setWrapMode(QOpenGLTexture::ClampToEdge); _colorTexture->setFormat(QOpenGLTexture::RGBFormat); _colorTexture->allocateStorage(); if (!_color.isEmpty()) { _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, _color.data()); if (_clearAfterLoading) { _color.clear(); } } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; _colorTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, const_cast<quint8*>(WHITE_COLOR)); } } // create the buffer objects lazily int size = _heightTexture->width(); int sizeWithSkirt = size + 2; int vertexCount = sizeWithSkirt * sizeWithSkirt; int rows = sizeWithSkirt - 1; int indexCount = rows * rows * 4; BufferPair& bufferPair = _bufferPairs[size]; if (!bufferPair.first.isCreated()) { QVector<HeightfieldPoint> vertices(vertexCount); HeightfieldPoint* point = vertices.data(); float step = 1.0f / (size - 1); float z = -step; for (int i = 0; i < sizeWithSkirt; i++, z += step) { float x = -step; const float SKIRT_LENGTH = 0.25f; float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); point->textureCoord = glm::vec2(x, z); } } bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw); bufferPair.first.create(); bufferPair.first.bind(); bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint)); QVector<int> indices(indexCount); int* index = indices.data(); for (int i = 0; i < rows; i++) { int lineIndex = i * sizeWithSkirt; int nextLineIndex = (i + 1) * sizeWithSkirt; for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; *index++ = lineIndex + j + 1; *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j; } } bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); bufferPair.second.create(); bufferPair.second.bind(); bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int)); } else { bufferPair.first.bind(); bufferPair.second.bind(); } HeightfieldPoint* point = 0; glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex); glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord); glPushMatrix(); glTranslatef(_translation.x, _translation.y, _translation.z); glScalef(_scale, _scale, _scale); _heightTexture->bind(0); _colorTexture->bind(1); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); _colorTexture->release(1); _heightTexture->release(0); glPopMatrix(); bufferPair.first.release(); bufferPair.second.release(); } QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); DefaultMetavoxelRendererImplementation::getHeightfieldProgram().bind(); glPushMatrix(); glTranslatef(translation.x, translation.y, translation.z); glScalef(scale, scale, scale); foreach (const BufferDataPointer& buffer, _buffers) { buffer->render(); } glPopMatrix(); DefaultMetavoxelRendererImplementation::getHeightfieldProgram().release(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); } BufferDataAttribute::BufferDataAttribute(const QString& name) : InlineAttribute<BufferDataPointer>(name) { } bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { BufferDataPointer firstChild = decodeInline<BufferDataPointer>(children[0]); for (int i = 1; i < MERGE_COUNT; i++) { if (firstChild != decodeInline<BufferDataPointer>(children[i])) { *(BufferDataPointer*)&parent = _defaultValue; return false; } } *(BufferDataPointer*)&parent = firstChild; return true; } void DefaultMetavoxelRendererImplementation::init() { if (!_pointProgram.isLinked()) { _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); _pointProgram.link(); _pointProgram.bind(); _pointScaleLocation = _pointProgram.uniformLocation("pointScale"); _pointProgram.release(); _heightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield.vert"); _heightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_heightfield.frag"); _heightfieldProgram.link(); _heightfieldProgram.bind(); _heightfieldProgram.setUniformValue("heightMap", 0); _heightfieldProgram.setUniformValue("diffuseMap", 1); _heightfieldProgram.release(); } } DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() { } class PointAugmentVisitor : public MetavoxelVisitor { public: PointAugmentVisitor(const MetavoxelLOD& lod); virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: BufferPointVector _points; float _pointLeafSize; }; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { } const int ALPHA_RENDER_THRESHOLD = 0; void PointAugmentVisitor::prepare(MetavoxelData* data) { MetavoxelVisitor::prepare(data); const float MAX_POINT_LEAF_SIZE = 64.0f; _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE); } int PointAugmentVisitor::visit(MetavoxelInfo& info) {