//// 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 this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL#include "InterfaceConfig.h" #include <QMutexLocker>#include <QOpenGLFramebufferObject>#include <QReadLocker>#include <QWriteLocker>#include <QThreadPool>#include <QtDebug> #include <glm/gtx/transform.hpp> #include <SharedUtil.h> #include <MetavoxelMessages.h>#include <MetavoxelUtil.h>#include <ScriptCache.h> #include "Application.h"#include "MetavoxelSystem.h"#include "renderer/Model.h"#include "renderer/RenderUtil.h" REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation)REGISTER_META_OBJECT(SphereRenderer)REGISTER_META_OBJECT(CuboidRenderer)REGISTER_META_OBJECT(StaticModelRenderer)REGISTER_META_OBJECT(HeightfieldRenderer) MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repeatRate, int minimumDelay, int maximumDelay, int bandwidthLimit) : dropRate(dropRate), repeatRate(repeatRate), minimumDelay(minimumDelay), maximumDelay(maximumDelay), bandwidthLimit(bandwidthLimit) {} MetavoxelSystem::~MetavoxelSystem() { // kill the updater before we delete our network simulation objects _updater->thread()->quit(); _updater->thread()->wait(); _updater = NULL;} void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("heightfieldBuffer")); _heightfieldBufferAttribute->setLODThresholdMultiplier( AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier()); _voxelBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("voxelBuffer")); _voxelBufferAttribute->setLODThresholdMultiplier( AttributeRegistry::getInstance()->getVoxelColorAttribute()->getLODThresholdMultiplier());} MetavoxelLOD MetavoxelSystem::getLOD() { QReadLocker locker(&_lodLock); return _lod;} void MetavoxelSystem::setNetworkSimulation(const NetworkSimulation& simulation) { QWriteLocker locker(&_networkSimulationLock); _networkSimulation = simulation;} MetavoxelSystem::NetworkSimulation MetavoxelSystem::getNetworkSimulation() { QReadLocker locker(&_networkSimulationLock); return _networkSimulation;} 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 { QWriteLocker locker(&_lodLock); const float DEFAULT_LOD_THRESHOLD = 0.01f; _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), DEFAULT_LOD_THRESHOLD); } 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() { // update the frustum ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor, true); // give external parties a chance to join in emit rendering();} void MetavoxelSystem::refreshVoxelData() { 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) { QMetaObject::invokeMethod(client, "refreshVoxelData"); } } }} class RayVoxelIntersectionVisitor : public RayIntersectionVisitor {public: float intersectionDistance; RayVoxelIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info, float distance);}; RayVoxelIntersectionVisitor::RayVoxelIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod) : RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), QVector<AttributePointer>(), lod), intersectionDistance(FLT_MAX) {} int RayVoxelIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { if (!info.isLeaf) { return _order; } const VoxelBuffer* buffer = static_cast<VoxelBuffer*>( info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); if (!buffer) { return STOP_RECURSION; } glm::vec3 entry = ((_origin + distance * _direction) - info.minimum) / info.size; if (buffer->findFirstRayIntersection(entry, _origin, _direction, intersectionDistance)) { return SHORT_CIRCUIT; } return STOP_RECURSION;} bool MetavoxelSystem::findFirstRayVoxelIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) { RayVoxelIntersectionVisitor visitor(origin, direction, getLOD()); guideToAugmented(visitor); if (visitor.intersectionDistance == FLT_MAX) { return false; } distance = visitor.intersectionDistance; return true;} void MetavoxelSystem::paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, SharedObjectPointer(), color)) }; applyEdit(edit, true);} void MetavoxelSystem::paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, material)) }; applyMaterialEdit(edit, true);} void MetavoxelSystem::paintVoxelColor(const glm::vec3& position, float radius, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, SharedObjectPointer(), color)) }; applyEdit(edit, true);} void MetavoxelSystem::paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, material)) }; applyMaterialEdit(edit, true);} void MetavoxelSystem::setVoxelColor(const SharedObjectPointer& spanner, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, SharedObjectPointer(), color)) }; applyEdit(edit, true);} void MetavoxelSystem::setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material)) }; applyMaterialEdit(edit, true);} class SpannerCursorRenderVisitor : public SpannerVisitor {public: SpannerCursorRenderVisitor(const Box& bounds); virtual bool visit(Spanner* spanner); virtual int visit(MetavoxelInfo& info); private: Box _bounds;}; SpannerCursorRenderVisitor::SpannerCursorRenderVisitor(const Box& bounds) : SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()), _bounds(bounds) {} bool SpannerCursorRenderVisitor::visit(Spanner* spanner) { if (spanner->isHeightfield()) { spanner->getRenderer()->render(true); } return true;} int SpannerCursorRenderVisitor::visit(MetavoxelInfo& info) { return info.getBounds().intersects(_bounds) ? SpannerVisitor::visit(info) : STOP_RECURSION;} void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind(); glActiveTexture(GL_TEXTURE4); float scale = 1.0f / radius; glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); glm::vec4 tCoefficients(0.0f, 0.0f, scale, -scale * position.z); glm::vec4 rCoefficients(0.0f, 0.0f, 0.0f, 0.0f); glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&rCoefficients); glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); SpannerCursorRenderVisitor visitor(Box(position - extents, position + extents)); guide(visitor); DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS);} class BufferCursorRenderVisitor : public MetavoxelVisitor {public: BufferCursorRenderVisitor(const AttributePointer& attribute, const Box& bounds); virtual int visit(MetavoxelInfo& info); private: Box _bounds;}; BufferCursorRenderVisitor::BufferCursorRenderVisitor(const AttributePointer& attribute, const Box& bounds) : MetavoxelVisitor(QVector<AttributePointer>() << attribute), _bounds(bounds) {} int BufferCursorRenderVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_bounds)) { return STOP_RECURSION; } BufferData* buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>().data(); if (buffer) { buffer->render(true); } return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER;} void MetavoxelSystem::renderVoxelCursor(const glm::vec3& position, float radius) { glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().bind(); glActiveTexture(GL_TEXTURE4); float scale = 1.0f / radius; glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); glm::vec4 tCoefficients(0.0f, scale, 0.0f, -scale * position.y); glm::vec4 rCoefficients(0.0f, 0.0f, scale, -scale * position.z); glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&rCoefficients); glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); Box bounds(position - extents, position + extents); BufferCursorRenderVisitor voxelVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), bounds); guideToAugmented(voxelVisitor); DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().release(); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS);} void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) { glDeleteTextures(1, (GLuint*)&heightID); glDeleteTextures(1, (GLuint*)&colorID); glDeleteTextures(1, (GLuint*)&textureID);} class MaterialEditApplier : public SignalHandler {public: MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture); virtual void handle(); protected: MetavoxelEditMessage _message; QSharedPointer<NetworkTexture> _texture;}; MaterialEditApplier::MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture) : _message(message), _texture(texture) {} void MaterialEditApplier::handle() { static_cast<MaterialEdit*>(_message.edit.data())->averageColor = _texture->getAverageColor(); Application::getInstance()->getMetavoxels()->applyEdit(_message, true); deleteLater();} void MetavoxelSystem::applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable) { const MaterialEdit* edit = static_cast<const MaterialEdit*>(message.edit.constData()); MaterialObject* material = static_cast<MaterialObject*>(edit->material.data()); if (material && material->getDiffuse().isValid()) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "applyMaterialEdit", Q_ARG(const MetavoxelEditMessage&, message), Q_ARG(bool, reliable)); return; } QSharedPointer<NetworkTexture> texture = Application::getInstance()->getTextureCache()->getTexture( material->getDiffuse(), SPLAT_TEXTURE); if (texture->isLoaded()) { MetavoxelEditMessage newMessage = message; static_cast<MaterialEdit*>(newMessage.edit.data())->averageColor = texture->getAverageColor(); applyEdit(newMessage, true); } else { MaterialEditApplier* applier = new MaterialEditApplier(message, texture); connect(texture.data(), &Resource::loaded, applier, &SignalHandler::handle); } } else { applyEdit(message, true); }} MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater);} void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) { 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) { MetavoxelData data = client->getAugmentedData(); data.guide(visitor); if (render) { // save the rendered augmented data so that its cached texture references, etc., don't // get collected when we replace it with more recent versions client->setRenderedAugmentedData(data); } } } }} Throttle::Throttle() : _limit(INT_MAX), _total(0) {} bool Throttle::shouldThrottle(int bytes) { // clear expired buckets qint64 now = QDateTime::currentMSecsSinceEpoch(); while (!_buckets.isEmpty() && now >= _buckets.first().first) { _total -= _buckets.takeFirst().second; } // if possible, add the new bucket if (_total + bytes > _limit) { return true; } const int BUCKET_DURATION = 1000; _buckets.append(Bucket(now + BUCKET_DURATION, bytes)); _total += bytes; return false;} 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;} class ReceiveDelayer : public QObject {public: ReceiveDelayer(const SharedNodePointer& node, const QByteArray& packet); protected: virtual void timerEvent(QTimerEvent* event); private:Lines 1–500 of 3028. 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 this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include "InterfaceConfig.h" #include <QMutexLocker> #include <QOpenGLFramebufferObject> #include <QReadLocker> #include <QWriteLocker> #include <QThreadPool> #include <QtDebug> #include <glm/gtx/transform.hpp> #include <SharedUtil.h> #include <MetavoxelMessages.h> #include <MetavoxelUtil.h> #include <ScriptCache.h> #include "Application.h" #include "MetavoxelSystem.h" #include "renderer/Model.h" #include "renderer/RenderUtil.h" REGISTER_META_OBJECT(DefaultMetavoxelRendererImplementation) REGISTER_META_OBJECT(SphereRenderer) REGISTER_META_OBJECT(CuboidRenderer) REGISTER_META_OBJECT(StaticModelRenderer) REGISTER_META_OBJECT(HeightfieldRenderer) MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repeatRate, int minimumDelay, int maximumDelay, int bandwidthLimit) : dropRate(dropRate), repeatRate(repeatRate), minimumDelay(minimumDelay), maximumDelay(maximumDelay), bandwidthLimit(bandwidthLimit) { } MetavoxelSystem::~MetavoxelSystem() { // kill the updater before we delete our network simulation objects _updater->thread()->quit(); _updater->thread()->wait(); _updater = NULL; } void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("heightfieldBuffer")); _heightfieldBufferAttribute->setLODThresholdMultiplier( AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier()); _voxelBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( new BufferDataAttribute("voxelBuffer")); _voxelBufferAttribute->setLODThresholdMultiplier( AttributeRegistry::getInstance()->getVoxelColorAttribute()->getLODThresholdMultiplier()); } MetavoxelLOD MetavoxelSystem::getLOD() { QReadLocker locker(&_lodLock); return _lod; } void MetavoxelSystem::setNetworkSimulation(const NetworkSimulation& simulation) { QWriteLocker locker(&_networkSimulationLock); _networkSimulation = simulation; } MetavoxelSystem::NetworkSimulation MetavoxelSystem::getNetworkSimulation() { QReadLocker locker(&_networkSimulationLock); return _networkSimulation; } 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 { QWriteLocker locker(&_lodLock); const float DEFAULT_LOD_THRESHOLD = 0.01f; _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), DEFAULT_LOD_THRESHOLD); } 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() { // update the frustum ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); RenderVisitor renderVisitor(getLOD()); guideToAugmented(renderVisitor, true); // give external parties a chance to join in emit rendering(); } void MetavoxelSystem::refreshVoxelData() { 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) { QMetaObject::invokeMethod(client, "refreshVoxelData"); } } } } class RayVoxelIntersectionVisitor : public RayIntersectionVisitor { public: float intersectionDistance; RayVoxelIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info, float distance); }; RayVoxelIntersectionVisitor::RayVoxelIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod) : RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), QVector<AttributePointer>(), lod), intersectionDistance(FLT_MAX) { } int RayVoxelIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { if (!info.isLeaf) { return _order; } const VoxelBuffer* buffer = static_cast<VoxelBuffer*>( info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); if (!buffer) { return STOP_RECURSION; } glm::vec3 entry = ((_origin + distance * _direction) - info.minimum) / info.size; if (buffer->findFirstRayIntersection(entry, _origin, _direction, intersectionDistance)) { return SHORT_CIRCUIT; } return STOP_RECURSION; } bool MetavoxelSystem::findFirstRayVoxelIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) { RayVoxelIntersectionVisitor visitor(origin, direction, getLOD()); guideToAugmented(visitor); if (visitor.intersectionDistance == FLT_MAX) { return false; } distance = visitor.intersectionDistance; return true; } void MetavoxelSystem::paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, SharedObjectPointer(), color)) }; applyEdit(edit, true); } void MetavoxelSystem::paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, material)) }; applyMaterialEdit(edit, true); } void MetavoxelSystem::paintVoxelColor(const glm::vec3& position, float radius, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, SharedObjectPointer(), color)) }; applyEdit(edit, true); } void MetavoxelSystem::paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, material)) }; applyMaterialEdit(edit, true); } void MetavoxelSystem::setVoxelColor(const SharedObjectPointer& spanner, const QColor& color) { MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, SharedObjectPointer(), color)) }; applyEdit(edit, true); } void MetavoxelSystem::setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material) { MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material)) }; applyMaterialEdit(edit, true); } class SpannerCursorRenderVisitor : public SpannerVisitor { public: SpannerCursorRenderVisitor(const Box& bounds); virtual bool visit(Spanner* spanner); virtual int visit(MetavoxelInfo& info); private: Box _bounds; }; SpannerCursorRenderVisitor::SpannerCursorRenderVisitor(const Box& bounds) : SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()), _bounds(bounds) { } bool SpannerCursorRenderVisitor::visit(Spanner* spanner) { if (spanner->isHeightfield()) { spanner->getRenderer()->render(true); } return true; } int SpannerCursorRenderVisitor::visit(MetavoxelInfo& info) { return info.getBounds().intersects(_bounds) ? SpannerVisitor::visit(info) : STOP_RECURSION; } void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind(); glActiveTexture(GL_TEXTURE4); float scale = 1.0f / radius; glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); glm::vec4 tCoefficients(0.0f, 0.0f, scale, -scale * position.z); glm::vec4 rCoefficients(0.0f, 0.0f, 0.0f, 0.0f); glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&rCoefficients); glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); SpannerCursorRenderVisitor visitor(Box(position - extents, position + extents)); guide(visitor); DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS); } class BufferCursorRenderVisitor : public MetavoxelVisitor { public: BufferCursorRenderVisitor(const AttributePointer& attribute, const Box& bounds); virtual int visit(MetavoxelInfo& info); private: Box _bounds; }; BufferCursorRenderVisitor::BufferCursorRenderVisitor(const AttributePointer& attribute, const Box& bounds) : MetavoxelVisitor(QVector<AttributePointer>() << attribute), _bounds(bounds) { } int BufferCursorRenderVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_bounds)) { return STOP_RECURSION; } BufferData* buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>().data(); if (buffer) { buffer->render(true); } return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; } void MetavoxelSystem::renderVoxelCursor(const glm::vec3& position, float radius) { glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().bind(); glActiveTexture(GL_TEXTURE4); float scale = 1.0f / radius; glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); glm::vec4 tCoefficients(0.0f, scale, 0.0f, -scale * position.y); glm::vec4 rCoefficients(0.0f, 0.0f, scale, -scale * position.z); glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&rCoefficients); glActiveTexture(GL_TEXTURE0); glm::vec3 extents(radius, radius, radius); Box bounds(position - extents, position + extents); BufferCursorRenderVisitor voxelVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), bounds); guideToAugmented(voxelVisitor); DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().release(); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS); } void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) { glDeleteTextures(1, (GLuint*)&heightID); glDeleteTextures(1, (GLuint*)&colorID); glDeleteTextures(1, (GLuint*)&textureID); } class MaterialEditApplier : public SignalHandler { public: MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture); virtual void handle(); protected: MetavoxelEditMessage _message; QSharedPointer<NetworkTexture> _texture; }; MaterialEditApplier::MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture) : _message(message), _texture(texture) { } void MaterialEditApplier::handle() { static_cast<MaterialEdit*>(_message.edit.data())->averageColor = _texture->getAverageColor(); Application::getInstance()->getMetavoxels()->applyEdit(_message, true); deleteLater(); } void MetavoxelSystem::applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable) { const MaterialEdit* edit = static_cast<const MaterialEdit*>(message.edit.constData()); MaterialObject* material = static_cast<MaterialObject*>(edit->material.data()); if (material && material->getDiffuse().isValid()) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "applyMaterialEdit", Q_ARG(const MetavoxelEditMessage&, message), Q_ARG(bool, reliable)); return; } QSharedPointer<NetworkTexture> texture = Application::getInstance()->getTextureCache()->getTexture( material->getDiffuse(), SPLAT_TEXTURE); if (texture->isLoaded()) { MetavoxelEditMessage newMessage = message; static_cast<MaterialEdit*>(newMessage.edit.data())->averageColor = texture->getAverageColor(); applyEdit(newMessage, true); } else { MaterialEditApplier* applier = new MaterialEditApplier(message, texture); connect(texture.data(), &Resource::loaded, applier, &SignalHandler::handle); } } else { applyEdit(message, true); } } MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) { 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) { MetavoxelData data = client->getAugmentedData(); data.guide(visitor); if (render) { // save the rendered augmented data so that its cached texture references, etc., don't // get collected when we replace it with more recent versions client->setRenderedAugmentedData(data); } } } } } Throttle::Throttle() : _limit(INT_MAX), _total(0) { } bool Throttle::shouldThrottle(int bytes) { // clear expired buckets qint64 now = QDateTime::currentMSecsSinceEpoch(); while (!_buckets.isEmpty() && now >= _buckets.first().first) { _total -= _buckets.takeFirst().second; } // if possible, add the new bucket if (_total + bytes > _limit) { return true; } const int BUCKET_DURATION = 1000; _buckets.append(Bucket(now + BUCKET_DURATION, bytes)); _total += bytes; return false; } 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; } class ReceiveDelayer : public QObject { public: ReceiveDelayer(const SharedNodePointer& node, const QByteArray& packet); protected: virtual void timerEvent(QTimerEvent* event); private: