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)); } deleteLater();} int MetavoxelSystemClient::parseData(const QByteArray& packet) { // process through sequencer MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation(); if (randFloat() < simulation.dropRate) { return packet.size(); } int count = (randFloat() < simulation.repeatRate) ? 2 : 1; for (int i = 0; i < count; i++) { if (simulation.bandwidthLimit > 0) { _receiveThrottle.setLimit(simulation.bandwidthLimit); if (_receiveThrottle.shouldThrottle(packet.size())) { continue; } } int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay); if (delay > 0) { ReceiveDelayer* delayer = new ReceiveDelayer(_node, packet); delayer->startTimer(delay); } else { 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::refreshVoxelData() { // make it look as if all the colors have changed MetavoxelData oldData = getAugmentedData(); oldData.touch(AttributeRegistry::getInstance()->getVoxelColorAttribute()); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, oldData, _remoteDataLOD));} void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD));} class SendDelayer : public QObject {public: SendDelayer(const SharedNodePointer& node, const QByteArray& data); virtual void timerEvent(QTimerEvent* event); private: SharedNodePointer _node; QByteArray _data;}; SendDelayer::SendDelayer(const SharedNodePointer& node, const QByteArray& data) : _node(node), _data(data.constData(), data.size()) {} void SendDelayer::timerEvent(QTimerEvent* event) { NodeList::getInstance()->writeDatagram(_data, _node); deleteLater();} void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation(); if (randFloat() < simulation.dropRate) { return; } int count = (randFloat() < simulation.repeatRate) ? 2 : 1; for (int i = 0; i < count; i++) { if (simulation.bandwidthLimit > 0) { _sendThrottle.setLimit(simulation.bandwidthLimit); if (_sendThrottle.shouldThrottle(data.size())) { continue; } } int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay); if (delay > 0) { SendDelayer* delayer = new SendDelayer(_node, data); delayer->startTimer(delay); } else { 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();} const int HeightfieldBuffer::HEIGHT_BORDER = 1;const int HeightfieldBuffer::SHARED_EDGE = 1;const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE; HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, const QByteArray& material, const QVector<SharedObjectPointer>& materials) : _translation(translation), _scale(scale), _heightBounds(translation, translation + glm::vec3(scale, scale, scale)), _colorBounds(_heightBounds), _materialBounds(_heightBounds), _height(height), _color(color), _material(material), _materials(materials), _heightTextureID(0), _colorTextureID(0), _materialTextureID(0), _heightSize(glm::sqrt((float)height.size())), _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)), _colorSize(glm::sqrt((float)color.size() / DataBlock::COLOR_BYTES)), _colorIncrement(scale / (_colorSize - SHARED_EDGE)), _materialSize(glm::sqrt((float)material.size())), _materialIncrement(scale / (_materialSize - SHARED_EDGE)) { _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER; _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER; _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE; _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE; _materialBounds.maximum.x += _materialIncrement * SHARED_EDGE; _materialBounds.maximum.z += _materialIncrement * SHARED_EDGE;} 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), Q_ARG(int, _materialTextureID)); } else { glDeleteTextures(1, &_heightTextureID); glDeleteTextures(1, &_colorTextureID); glDeleteTextures(1, &_materialTextureID); }Lines 501–1000 of 3173. Previous lines Load more
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)); } deleteLater(); } int MetavoxelSystemClient::parseData(const QByteArray& packet) { // process through sequencer MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation(); if (randFloat() < simulation.dropRate) { return packet.size(); } int count = (randFloat() < simulation.repeatRate) ? 2 : 1; for (int i = 0; i < count; i++) { if (simulation.bandwidthLimit > 0) { _receiveThrottle.setLimit(simulation.bandwidthLimit); if (_receiveThrottle.shouldThrottle(packet.size())) { continue; } } int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay); if (delay > 0) { ReceiveDelayer* delayer = new ReceiveDelayer(_node, packet); delayer->startTimer(delay); } else { 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::refreshVoxelData() { // make it look as if all the colors have changed MetavoxelData oldData = getAugmentedData(); oldData.touch(AttributeRegistry::getInstance()->getVoxelColorAttribute()); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, oldData, _remoteDataLOD)); } void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) { MetavoxelClient::dataChanged(oldData); QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD)); } class SendDelayer : public QObject { public: SendDelayer(const SharedNodePointer& node, const QByteArray& data); virtual void timerEvent(QTimerEvent* event); private: SharedNodePointer _node; QByteArray _data; }; SendDelayer::SendDelayer(const SharedNodePointer& node, const QByteArray& data) : _node(node), _data(data.constData(), data.size()) { } void SendDelayer::timerEvent(QTimerEvent* event) { NodeList::getInstance()->writeDatagram(_data, _node); deleteLater(); } void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation(); if (randFloat() < simulation.dropRate) { return; } int count = (randFloat() < simulation.repeatRate) ? 2 : 1; for (int i = 0; i < count; i++) { if (simulation.bandwidthLimit > 0) { _sendThrottle.setLimit(simulation.bandwidthLimit); if (_sendThrottle.shouldThrottle(data.size())) { continue; } } int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay); if (delay > 0) { SendDelayer* delayer = new SendDelayer(_node, data); delayer->startTimer(delay); } else { 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(); } const int HeightfieldBuffer::HEIGHT_BORDER = 1; const int HeightfieldBuffer::SHARED_EDGE = 1; const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE; HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, const QByteArray& material, const QVector<SharedObjectPointer>& materials) : _translation(translation), _scale(scale), _heightBounds(translation, translation + glm::vec3(scale, scale, scale)), _colorBounds(_heightBounds), _materialBounds(_heightBounds), _height(height), _color(color), _material(material), _materials(materials), _heightTextureID(0), _colorTextureID(0), _materialTextureID(0), _heightSize(glm::sqrt((float)height.size())), _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)), _colorSize(glm::sqrt((float)color.size() / DataBlock::COLOR_BYTES)), _colorIncrement(scale / (_colorSize - SHARED_EDGE)), _materialSize(glm::sqrt((float)material.size())), _materialIncrement(scale / (_materialSize - SHARED_EDGE)) { _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER; _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER; _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE; _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE; _materialBounds.maximum.x += _materialIncrement * SHARED_EDGE; _materialBounds.maximum.z += _materialIncrement * SHARED_EDGE; } 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), Q_ARG(int, _materialTextureID)); } else { glDeleteTextures(1, &_heightTextureID); glDeleteTextures(1, &_colorTextureID); glDeleteTextures(1, &_materialTextureID); }