3021 lines · 133.0 KB · C++
RawDownload
////  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 CursorRenderVisitor : public MetavoxelVisitor {public:        CursorRenderVisitor(const AttributePointer& attribute, const Box& bounds);        virtual int visit(MetavoxelInfo& info); private:        Box _bounds;}; CursorRenderVisitor::CursorRenderVisitor(const AttributePointer& attribute, const Box& bounds) :    MetavoxelVisitor(QVector<AttributePointer>() << attribute),    _bounds(bounds) {} int CursorRenderVisitor::visit(MetavoxelInfo& info) {    if (!info.getBounds().intersects(_bounds)) {        return STOP_RECURSION;    }    if (!info.isLeaf) {        return DEFAULT_ORDER;    }    BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();    if (buffer) {        buffer->render(true);    }    return 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);    CursorRenderVisitor visitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(),        Box(position - extents, position + extents));    guideToAugmented(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);} 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);    CursorRenderVisitor voxelVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), bounds);    guideToAugmented(voxelVisitor);        DefaultMetavoxelRendererImplementation::getVoxelCursorProgram().release();        glEnableClientState(GL_TEXTURE_COORD_ARRAY);        DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind();        CursorRenderVisitor heightfieldVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(),        bounds);    guideToAugmented(heightfieldVisitor);        DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release();        glDisableClientState(GL_TEXTURE_COORD_ARRAY);    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:        SharedNodePointer _node;    QByteArray _packet;}; ReceiveDelayer::ReceiveDelayer(const SharedNodePointer& node, const QByteArray& packet) :    _node(node),    _packet(packet) {} void ReceiveDelayer::timerEvent(QTimerEvent* event) {    QMutexLocker locker(&_node->getMutex());    MetavoxelClient* client = static_cast<MetavoxelClient*>(_node->getLinkedData());    if (client) {        QMetaObject::invokeMethod(&client->getSequencer(), "receivedDatagram", Q_ARG(const QByteArray&, _packet));

Lines 1–500 of 3021.