1047 lines · 37.3 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 <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 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() {    // update the frustum    ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum();    _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(),        viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(),        viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight());        RenderVisitor renderVisitor(getLOD());    guideToAugmented(renderVisitor);} class HeightfieldCursorRenderVisitor : public MetavoxelVisitor {public:        HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds);        virtual int visit(MetavoxelInfo& info); private:        Box _bounds;}; HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds) :    MetavoxelVisitor(QVector<AttributePointer>() <<        Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),    _bounds(bounds) {} int HeightfieldCursorRenderVisitor::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);    glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients);    glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients);    glActiveTexture(GL_TEXTURE0);        glm::vec3 extents(radius, radius, radius);    HeightfieldCursorRenderVisitor visitor(getLOD(), 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::deleteTextures(int heightID, int colorID) {    glDeleteTextures(1, (GLuint*)&heightID);    glDeleteTextures(1, (GLuint*)&colorID);} 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(bool cursor) {    // 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),    _heightTextureID(0),    _colorTextureID(0),    _heightSize(glm::sqrt(height.size())) {} 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(int, _heightTextureID), Q_ARG(int, _colorTextureID));    } else {        glDeleteTextures(1, &_heightTextureID);        glDeleteTextures(1, &_colorTextureID);    }} class HeightfieldPoint {public:    glm::vec2 textureCoord;    glm::vec3 vertex;}; void HeightfieldBuffer::render(bool cursor) {    // initialize textures, etc. on first render    if (_heightTextureID == 0) {        glGenTextures(1, &_heightTextureID);        glBindTexture(GL_TEXTURE_2D, _heightTextureID);        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0,            GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData());        if (_clearAfterLoading) {            _height.clear();        }                glGenTextures(1, &_colorTextureID);        glBindTexture(GL_TEXTURE_2D, _colorTextureID);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);        if (_color.isEmpty()) {            const quint8 WHITE_COLOR[] = { 255, 255, 255 };            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);                       } else {            int colorSize = glm::sqrt(_color.size() / 3);                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());            if (_clearAfterLoading) {                _color.clear();            }        }    }    // create the buffer objects lazily    int innerSize = _heightSize - 2;    int vertexCount = _heightSize * _heightSize;    int rows = _heightSize - 1;    int indexCount = rows * rows * 4;    BufferPair& bufferPair = _bufferPairs[_heightSize];    if (!bufferPair.first.isCreated()) {        QVector<HeightfieldPoint> vertices(vertexCount);        HeightfieldPoint* point = vertices.data();                float vertexStep = 1.0f / (innerSize - 1);        float z = -vertexStep;        float textureStep = 1.0f / _heightSize;        float t = textureStep / 2.0f;        for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) {            float x = -vertexStep;            float s = textureStep / 2.0f;            const float SKIRT_LENGTH = 0.25f;            float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f;            for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) {                point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z);                point->textureCoord = glm::vec2(s, t);            }        }                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 * _heightSize;            int nextLineIndex = (i + 1) * _heightSize;            for (int j = 0; j < rows; j++) {                *index++ = lineIndex + j;                *index++ = nextLineIndex + j;                *index++ = nextLineIndex + j + 1;                *index++ = lineIndex + j + 1;            }        }                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);        glBindTexture(GL_TEXTURE_2D, _heightTextureID);        if (!cursor) {        DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize);        DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getColorScaleLocation(), (float)_heightSize / innerSize);        glActiveTexture(GL_TEXTURE1);        glBindTexture(GL_TEXTURE_2D, _colorTextureID);    }        glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);        if (!cursor) {        glBindTexture(GL_TEXTURE_2D, 0);        glActiveTexture(GL_TEXTURE0);     }        glBindTexture(GL_TEXTURE_2D, 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_CULL_FACE);    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);

Lines 1–500 of 1047.