mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 04:57:23 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
e700a39c3c
27 changed files with 611 additions and 264 deletions
|
@ -18,15 +18,18 @@
|
||||||
const int SEND_INTERVAL = 50;
|
const int SEND_INTERVAL = 50;
|
||||||
|
|
||||||
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
||||||
ThreadedAssignment(packet),
|
ThreadedAssignment(packet) {
|
||||||
_data(new MetavoxelData()) {
|
|
||||||
|
|
||||||
_sendTimer.setSingleShot(true);
|
_sendTimer.setSingleShot(true);
|
||||||
connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas()));
|
connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
|
||||||
|
edit.apply(_data);
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelServer::removeSession(const QUuid& sessionId) {
|
void MetavoxelServer::removeSession(const QUuid& sessionId) {
|
||||||
delete _sessions.take(sessionId);
|
_sessions.take(sessionId)->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char METAVOXEL_SERVER_LOGGING_NAME[] = "metavoxel-server";
|
const char METAVOXEL_SERVER_LOGGING_NAME[] = "metavoxel-server";
|
||||||
|
@ -75,16 +78,18 @@ void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& se
|
||||||
// forward to session, creating if necessary
|
// forward to session, creating if necessary
|
||||||
MetavoxelSession*& session = _sessions[sessionID];
|
MetavoxelSession*& session = _sessions[sessionID];
|
||||||
if (!session) {
|
if (!session) {
|
||||||
session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize));
|
session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize), sender);
|
||||||
}
|
}
|
||||||
session->receivedData(data, sender);
|
session->receivedData(data, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader) :
|
MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
|
||||||
|
const QByteArray& datagramHeader, const HifiSockAddr& sender) :
|
||||||
QObject(server),
|
QObject(server),
|
||||||
_server(server),
|
_server(server),
|
||||||
_sessionId(sessionId),
|
_sessionId(sessionId),
|
||||||
_sequencer(datagramHeader) {
|
_sequencer(datagramHeader),
|
||||||
|
_sender(sender) {
|
||||||
|
|
||||||
const int TIMEOUT_INTERVAL = 30 * 1000;
|
const int TIMEOUT_INTERVAL = 30 * 1000;
|
||||||
_timeoutTimer.setInterval(TIMEOUT_INTERVAL);
|
_timeoutTimer.setInterval(TIMEOUT_INTERVAL);
|
||||||
|
@ -94,10 +99,13 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& session
|
||||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
||||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
||||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||||
|
connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&)));
|
||||||
|
|
||||||
// insert the baseline send record
|
// insert the baseline send record
|
||||||
SendRecord record = { 0, MetavoxelDataPointer(new MetavoxelData()) };
|
SendRecord record = { 0 };
|
||||||
_sendRecords.append(record);
|
_sendRecords.append(record);
|
||||||
|
|
||||||
|
qDebug() << "Opened session [sessionId=" << _sessionId << ", sender=" << _sender << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
|
void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||||
|
@ -114,7 +122,7 @@ void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr&
|
||||||
void MetavoxelSession::sendDelta() {
|
void MetavoxelSession::sendDelta() {
|
||||||
Bitstream& out = _sequencer.startPacket();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||||
writeDelta(_server->getData(), _sendRecords.first().data, out);
|
_server->getData().writeDelta(_sendRecords.first().data, out);
|
||||||
_sequencer.endPacket();
|
_sequencer.endPacket();
|
||||||
|
|
||||||
// record the send
|
// record the send
|
||||||
|
@ -134,25 +142,29 @@ void MetavoxelSession::sendData(const QByteArray& data) {
|
||||||
void MetavoxelSession::readPacket(Bitstream& in) {
|
void MetavoxelSession::readPacket(Bitstream& in) {
|
||||||
QVariant message;
|
QVariant message;
|
||||||
in >> message;
|
in >> message;
|
||||||
handleMessage(message, in);
|
handleMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSession::clearSendRecordsBefore(int index) {
|
void MetavoxelSession::clearSendRecordsBefore(int index) {
|
||||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
|
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||||
int userType = message.userType();
|
int userType = message.userType();
|
||||||
if (userType == ClientStateMessage::Type) {
|
if (userType == CloseSessionMessage::Type) {
|
||||||
|
qDebug() << "Session closed [sessionId=" << _sessionId << ", sender=" << _sender << "]";
|
||||||
|
_server->removeSession(_sessionId);
|
||||||
|
|
||||||
|
} else if (userType == ClientStateMessage::Type) {
|
||||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||||
_position = state.position;
|
_position = state.position;
|
||||||
|
|
||||||
} else if (userType == MetavoxelDeltaMessage::Type) {
|
} else if (userType == MetavoxelEditMessage::Type) {
|
||||||
|
_server->applyEdit(message.value<MetavoxelEditMessage>());
|
||||||
|
|
||||||
} else if (userType == QMetaType::QVariantList) {
|
} else if (userType == QMetaType::QVariantList) {
|
||||||
foreach (const QVariant& element, message.toList()) {
|
foreach (const QVariant& element, message.toList()) {
|
||||||
handleMessage(element, in);
|
handleMessage(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <DatagramSequencer.h>
|
#include <DatagramSequencer.h>
|
||||||
#include <MetavoxelData.h>
|
#include <MetavoxelData.h>
|
||||||
|
|
||||||
|
class MetavoxelEditMessage;
|
||||||
class MetavoxelSession;
|
class MetavoxelSession;
|
||||||
|
|
||||||
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
||||||
|
@ -30,7 +31,9 @@ public:
|
||||||
|
|
||||||
MetavoxelServer(const QByteArray& packet);
|
MetavoxelServer(const QByteArray& packet);
|
||||||
|
|
||||||
const MetavoxelDataPointer& getData() const { return _data; }
|
void applyEdit(const MetavoxelEditMessage& edit);
|
||||||
|
|
||||||
|
const MetavoxelData& getData() const { return _data; }
|
||||||
|
|
||||||
void removeSession(const QUuid& sessionId);
|
void removeSession(const QUuid& sessionId);
|
||||||
|
|
||||||
|
@ -51,7 +54,7 @@ private:
|
||||||
|
|
||||||
QHash<QUuid, MetavoxelSession*> _sessions;
|
QHash<QUuid, MetavoxelSession*> _sessions;
|
||||||
|
|
||||||
MetavoxelDataPointer _data;
|
MetavoxelData _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Contains the state of a single client session.
|
/// Contains the state of a single client session.
|
||||||
|
@ -60,7 +63,8 @@ class MetavoxelSession : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader);
|
MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
|
||||||
|
const QByteArray& datagramHeader, const HifiSockAddr& sender);
|
||||||
|
|
||||||
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
||||||
|
|
||||||
|
@ -76,14 +80,14 @@ private slots:
|
||||||
|
|
||||||
void clearSendRecordsBefore(int index);
|
void clearSendRecordsBefore(int index);
|
||||||
|
|
||||||
private:
|
void handleMessage(const QVariant& message);
|
||||||
|
|
||||||
void handleMessage(const QVariant& message, Bitstream& in);
|
private:
|
||||||
|
|
||||||
class SendRecord {
|
class SendRecord {
|
||||||
public:
|
public:
|
||||||
int packetNumber;
|
int packetNumber;
|
||||||
MetavoxelDataPointer data;
|
MetavoxelData data;
|
||||||
};
|
};
|
||||||
|
|
||||||
MetavoxelServer* _server;
|
MetavoxelServer* _server;
|
||||||
|
|
|
@ -9,10 +9,12 @@ macro(AUTO_MTC TARGET ROOT_DIR)
|
||||||
${INCLUDE_FILES} DEPENDS mtc ${INCLUDE_FILES})
|
${INCLUDE_FILES} DEPENDS mtc ${INCLUDE_FILES})
|
||||||
|
|
||||||
find_package(Qt5Core REQUIRED)
|
find_package(Qt5Core REQUIRED)
|
||||||
|
find_package(Qt5Script REQUIRED)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp)
|
add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp)
|
||||||
|
|
||||||
qt5_use_modules(${TARGET}_automtc Core)
|
qt5_use_modules(${TARGET}_automtc Core Script Widgets)
|
||||||
|
|
||||||
target_link_libraries(${TARGET} ${TARGET}_automtc)
|
target_link_libraries(${TARGET} ${TARGET}_automtc)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QMutexLocker>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include <MetavoxelMessages.h>
|
|
||||||
#include <MetavoxelUtil.h>
|
#include <MetavoxelUtil.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -24,6 +24,12 @@ MetavoxelSystem::MetavoxelSystem() :
|
||||||
_buffer(QOpenGLBuffer::VertexBuffer) {
|
_buffer(QOpenGLBuffer::VertexBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelSystem::~MetavoxelSystem() {
|
||||||
|
for (QHash<QUuid, MetavoxelClient*>::const_iterator it = _clients.begin(); it != _clients.end(); it++) {
|
||||||
|
delete it.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelSystem::init() {
|
void MetavoxelSystem::init() {
|
||||||
if (!_program.isLinked()) {
|
if (!_program.isLinked()) {
|
||||||
switchToResourcesParentIfRequired();
|
switchToResourcesParentIfRequired();
|
||||||
|
@ -42,18 +48,22 @@ void MetavoxelSystem::init() {
|
||||||
_buffer.create();
|
_buffer.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) {
|
||||||
|
foreach (MetavoxelClient* client, _clients) {
|
||||||
|
client->applyEdit(edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelSystem::processData(const QByteArray& data, const HifiSockAddr& sender) {
|
void MetavoxelSystem::processData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||||
QMetaObject::invokeMethod(this, "receivedData", Q_ARG(const QByteArray&, data), Q_ARG(const HifiSockAddr&, sender));
|
QMetaObject::invokeMethod(this, "receivedData", Q_ARG(const QByteArray&, data), Q_ARG(const HifiSockAddr&, sender));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSystem::simulate(float deltaTime) {
|
void MetavoxelSystem::simulate(float deltaTime) {
|
||||||
// simulate the clients
|
// simulate the clients
|
||||||
foreach (MetavoxelClient* client, _clients) {
|
|
||||||
client->simulate(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
_points.clear();
|
_points.clear();
|
||||||
_data.guide(_pointVisitor);
|
foreach (MetavoxelClient* client, _clients) {
|
||||||
|
client->simulate(deltaTime, _pointVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
_buffer.bind();
|
_buffer.bind();
|
||||||
int bytes = _points.size() * sizeof(Point);
|
int bytes = _points.size() * sizeof(Point);
|
||||||
|
@ -108,8 +118,7 @@ void MetavoxelSystem::render() {
|
||||||
|
|
||||||
void MetavoxelSystem::nodeAdded(SharedNodePointer node) {
|
void MetavoxelSystem::nodeAdded(SharedNodePointer node) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMetaObject::invokeMethod(this, "addClient", Q_ARG(const QUuid&, node->getUUID()),
|
QMetaObject::invokeMethod(this, "addClient", Q_ARG(const SharedNodePointer&, node));
|
||||||
Q_ARG(const HifiSockAddr&, node->getLocalSocket()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,9 +128,9 @@ void MetavoxelSystem::nodeKilled(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSystem::addClient(const QUuid& uuid, const HifiSockAddr& address) {
|
void MetavoxelSystem::addClient(const SharedNodePointer& node) {
|
||||||
MetavoxelClient* client = new MetavoxelClient(address);
|
MetavoxelClient* client = new MetavoxelClient(node);
|
||||||
_clients.insert(uuid, client);
|
_clients.insert(node->getUUID(), client);
|
||||||
_clientsBySessionID.insert(client->getSessionID(), client);
|
_clientsBySessionID.insert(client->getSessionID(), client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +148,7 @@ void MetavoxelSystem::receivedData(const QByteArray& data, const HifiSockAddr& s
|
||||||
}
|
}
|
||||||
MetavoxelClient* client = _clientsBySessionID.value(sessionID);
|
MetavoxelClient* client = _clientsBySessionID.value(sessionID);
|
||||||
if (client) {
|
if (client) {
|
||||||
client->receivedData(data, sender);
|
client->receivedData(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +181,10 @@ static QByteArray createDatagramHeader(const QUuid& sessionID) {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
|
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
||||||
_address(address),
|
_node(node),
|
||||||
_sessionID(QUuid::createUuid()),
|
_sessionID(QUuid::createUuid()),
|
||||||
_sequencer(createDatagramHeader(_sessionID)),
|
_sequencer(createDatagramHeader(_sessionID)) {
|
||||||
_data(new MetavoxelData()) {
|
|
||||||
|
|
||||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
||||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
||||||
|
@ -187,23 +195,41 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
|
||||||
_receiveRecords.append(record);
|
_receiveRecords.append(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::simulate(float deltaTime) {
|
MetavoxelClient::~MetavoxelClient() {
|
||||||
|
// close the session
|
||||||
|
Bitstream& out = _sequencer.startPacket();
|
||||||
|
out << QVariant::fromValue(CloseSessionMessage());
|
||||||
|
_sequencer.endPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
|
||||||
|
// apply immediately to local tree
|
||||||
|
edit.apply(_data);
|
||||||
|
|
||||||
|
// start sending it out
|
||||||
|
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelClient::simulate(float deltaTime, MetavoxelVisitor& visitor) {
|
||||||
Bitstream& out = _sequencer.startPacket();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() };
|
ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() };
|
||||||
out << QVariant::fromValue(state);
|
out << QVariant::fromValue(state);
|
||||||
_sequencer.endPacket();
|
_sequencer.endPacket();
|
||||||
|
|
||||||
|
_data.guide(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
|
void MetavoxelClient::receivedData(const QByteArray& data) {
|
||||||
// save the most recent sender
|
|
||||||
_address = sender;
|
|
||||||
|
|
||||||
// process through sequencer
|
// process through sequencer
|
||||||
_sequencer.receivedDatagram(data);
|
_sequencer.receivedDatagram(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::sendData(const QByteArray& data) {
|
void MetavoxelClient::sendData(const QByteArray& data) {
|
||||||
NodeList::getInstance()->getNodeSocket().writeDatagram(data, _address.getAddress(), _address.getPort());
|
QMutexLocker locker(&_node->getMutex());
|
||||||
|
const HifiSockAddr* address = _node->getActiveSocket();
|
||||||
|
if (address) {
|
||||||
|
NodeList::getInstance()->getNodeSocket().writeDatagram(data, address->getAddress(), address->getPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::readPacket(Bitstream& in) {
|
void MetavoxelClient::readPacket(Bitstream& in) {
|
||||||
|
@ -214,6 +240,13 @@ void MetavoxelClient::readPacket(Bitstream& in) {
|
||||||
// record the receipt
|
// record the receipt
|
||||||
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data };
|
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data };
|
||||||
_receiveRecords.append(record);
|
_receiveRecords.append(record);
|
||||||
|
|
||||||
|
// reapply local edits
|
||||||
|
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
|
||||||
|
if (message.data.userType() == MetavoxelEditMessage::Type) {
|
||||||
|
message.data.value<MetavoxelEditMessage>().apply(_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
||||||
|
@ -223,7 +256,7 @@ void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
||||||
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||||
int userType = message.userType();
|
int userType = message.userType();
|
||||||
if (userType == MetavoxelDeltaMessage::Type) {
|
if (userType == MetavoxelDeltaMessage::Type) {
|
||||||
readDelta(_data, _receiveRecords.first().data, in);
|
_data.readDelta(_receiveRecords.first().data, in);
|
||||||
|
|
||||||
} else if (userType == QMetaType::QVariantList) {
|
} else if (userType == QMetaType::QVariantList) {
|
||||||
foreach (const QVariant& element, message.toList()) {
|
foreach (const QVariant& element, message.toList()) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <DatagramSequencer.h>
|
#include <DatagramSequencer.h>
|
||||||
#include <MetavoxelData.h>
|
#include <MetavoxelData.h>
|
||||||
|
#include <MetavoxelMessages.h>
|
||||||
|
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
|
||||||
|
@ -31,10 +32,11 @@ class MetavoxelSystem : public QObject {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelSystem();
|
MetavoxelSystem();
|
||||||
|
~MetavoxelSystem();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
MetavoxelData& getData() { return _data; }
|
void applyEdit(const MetavoxelEditMessage& edit);
|
||||||
|
|
||||||
void processData(const QByteArray& data, const HifiSockAddr& sender);
|
void processData(const QByteArray& data, const HifiSockAddr& sender);
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Q_INVOKABLE void addClient(const QUuid& uuid, const HifiSockAddr& address);
|
Q_INVOKABLE void addClient(const SharedNodePointer& node);
|
||||||
Q_INVOKABLE void removeClient(const QUuid& uuid);
|
Q_INVOKABLE void removeClient(const QUuid& uuid);
|
||||||
Q_INVOKABLE void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
Q_INVOKABLE void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
||||||
|
|
||||||
|
@ -71,7 +73,6 @@ private:
|
||||||
static ProgramObject _program;
|
static ProgramObject _program;
|
||||||
static int _pointScaleLocation;
|
static int _pointScaleLocation;
|
||||||
|
|
||||||
MetavoxelData _data;
|
|
||||||
QVector<Point> _points;
|
QVector<Point> _points;
|
||||||
PointVisitor _pointVisitor;
|
PointVisitor _pointVisitor;
|
||||||
QOpenGLBuffer _buffer;
|
QOpenGLBuffer _buffer;
|
||||||
|
@ -86,13 +87,16 @@ class MetavoxelClient : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelClient(const HifiSockAddr& address);
|
MetavoxelClient(const SharedNodePointer& node);
|
||||||
|
virtual ~MetavoxelClient();
|
||||||
|
|
||||||
const QUuid& getSessionID() const { return _sessionID; }
|
const QUuid& getSessionID() const { return _sessionID; }
|
||||||
|
|
||||||
void simulate(float deltaTime);
|
void applyEdit(const MetavoxelEditMessage& edit);
|
||||||
|
|
||||||
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
void simulate(float deltaTime, MetavoxelVisitor& visitor);
|
||||||
|
|
||||||
|
void receivedData(const QByteArray& data);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
@ -109,15 +113,15 @@ private:
|
||||||
class ReceiveRecord {
|
class ReceiveRecord {
|
||||||
public:
|
public:
|
||||||
int packetNumber;
|
int packetNumber;
|
||||||
MetavoxelDataPointer data;
|
MetavoxelData data;
|
||||||
};
|
};
|
||||||
|
|
||||||
HifiSockAddr _address;
|
SharedNodePointer _node;
|
||||||
QUuid _sessionID;
|
QUuid _sessionID;
|
||||||
|
|
||||||
DatagramSequencer _sequencer;
|
DatagramSequencer _sequencer;
|
||||||
|
|
||||||
MetavoxelDataPointer _data;
|
MetavoxelData _data;
|
||||||
|
|
||||||
QList<ReceiveRecord> _receiveRecords;
|
QList<ReceiveRecord> _receiveRecords;
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,17 +58,20 @@ MetavoxelEditor::MetavoxelEditor() :
|
||||||
_gridPlane->addItem("X/Z");
|
_gridPlane->addItem("X/Z");
|
||||||
_gridPlane->addItem("Y/Z");
|
_gridPlane->addItem("Y/Z");
|
||||||
_gridPlane->setCurrentIndex(GRID_PLANE_XZ);
|
_gridPlane->setCurrentIndex(GRID_PLANE_XZ);
|
||||||
|
connect(_gridPlane, SIGNAL(currentIndexChanged(int)), SLOT(centerGridPosition()));
|
||||||
|
|
||||||
formLayout->addRow("Grid Spacing:", _gridSpacing = new QDoubleSpinBox());
|
formLayout->addRow("Grid Spacing:", _gridSpacing = new QDoubleSpinBox());
|
||||||
_gridSpacing->setValue(0.1);
|
_gridSpacing->setMinimum(-FLT_MAX);
|
||||||
_gridSpacing->setMaximum(FLT_MAX);
|
_gridSpacing->setMaximum(FLT_MAX);
|
||||||
_gridSpacing->setSingleStep(0.01);
|
_gridSpacing->setPrefix("2^");
|
||||||
connect(_gridSpacing, SIGNAL(valueChanged(double)), SLOT(updateGridPosition()));
|
_gridSpacing->setValue(-3.0);
|
||||||
|
connect(_gridSpacing, SIGNAL(valueChanged(double)), SLOT(alignGridPosition()));
|
||||||
|
|
||||||
formLayout->addRow("Grid Position:", _gridPosition = new QDoubleSpinBox());
|
formLayout->addRow("Grid Position:", _gridPosition = new QDoubleSpinBox());
|
||||||
_gridPosition->setSingleStep(0.1);
|
|
||||||
_gridPosition->setMinimum(-FLT_MAX);
|
_gridPosition->setMinimum(-FLT_MAX);
|
||||||
_gridPosition->setMaximum(FLT_MAX);
|
_gridPosition->setMaximum(FLT_MAX);
|
||||||
|
alignGridPosition();
|
||||||
|
centerGridPosition();
|
||||||
|
|
||||||
_value = new QGroupBox();
|
_value = new QGroupBox();
|
||||||
_value->setTitle("Value");
|
_value->setTitle("Value");
|
||||||
|
@ -119,7 +122,7 @@ bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) {
|
||||||
float top = base + _height;
|
float top = base + _height;
|
||||||
glm::quat rotation = getGridRotation();
|
glm::quat rotation = getGridRotation();
|
||||||
glm::vec3 start = rotation * glm::vec3(glm::min(_startPosition, _endPosition), glm::min(base, top));
|
glm::vec3 start = rotation * glm::vec3(glm::min(_startPosition, _endPosition), glm::min(base, top));
|
||||||
float spacing = _gridSpacing->value();
|
float spacing = getGridSpacing();
|
||||||
glm::vec3 end = rotation * glm::vec3(glm::max(_startPosition, _endPosition) +
|
glm::vec3 end = rotation * glm::vec3(glm::max(_startPosition, _endPosition) +
|
||||||
glm::vec2(spacing, spacing), glm::max(base, top));
|
glm::vec2(spacing, spacing), glm::max(base, top));
|
||||||
|
|
||||||
|
@ -181,13 +184,19 @@ void MetavoxelEditor::createNewAttribute() {
|
||||||
updateAttributes(nameText);
|
updateAttributes(nameText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelEditor::updateGridPosition() {
|
void MetavoxelEditor::centerGridPosition() {
|
||||||
|
const float CENTER_OFFSET = 0.625f;
|
||||||
|
float eyePosition = (glm::inverse(getGridRotation()) * Application::getInstance()->getCamera()->getPosition()).z -
|
||||||
|
Application::getInstance()->getAvatar()->getScale() * CENTER_OFFSET;
|
||||||
|
double step = getGridSpacing();
|
||||||
|
_gridPosition->setValue(step * floor(eyePosition / step));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelEditor::alignGridPosition() {
|
||||||
// make sure our grid position matches our grid spacing
|
// make sure our grid position matches our grid spacing
|
||||||
double step = _gridSpacing->value();
|
double step = getGridSpacing();
|
||||||
if (step > 0.0) {
|
|
||||||
_gridPosition->setSingleStep(step);
|
_gridPosition->setSingleStep(step);
|
||||||
_gridPosition->setValue(step * floor(_gridPosition->value() / step));
|
_gridPosition->setValue(step * floor(_gridPosition->value() / step));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelEditor::render() {
|
void MetavoxelEditor::render() {
|
||||||
|
@ -209,7 +218,7 @@ void MetavoxelEditor::render() {
|
||||||
glm::quat inverseRotation = glm::inverse(rotation);
|
glm::quat inverseRotation = glm::inverse(rotation);
|
||||||
glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin();
|
glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin();
|
||||||
glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection();
|
glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection();
|
||||||
float spacing = _gridSpacing->value();
|
float spacing = getGridSpacing();
|
||||||
float position = _gridPosition->value();
|
float position = _gridPosition->value();
|
||||||
if (_state == RAISING_STATE) {
|
if (_state == RAISING_STATE) {
|
||||||
// find the plane at the mouse position, orthogonal to the plane, facing the eye position
|
// find the plane at the mouse position, orthogonal to the plane, facing the eye position
|
||||||
|
@ -318,6 +327,10 @@ QString MetavoxelEditor::getSelectedAttribute() const {
|
||||||
return selectedItems.isEmpty() ? QString() : selectedItems.first()->text();
|
return selectedItems.isEmpty() ? QString() : selectedItems.first()->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double MetavoxelEditor::getGridSpacing() const {
|
||||||
|
return pow(2.0, _gridSpacing->value());
|
||||||
|
}
|
||||||
|
|
||||||
glm::quat MetavoxelEditor::getGridRotation() const {
|
glm::quat MetavoxelEditor::getGridRotation() const {
|
||||||
// for simplicity, we handle the other two planes by rotating them onto X/Y and performing computation there
|
// for simplicity, we handle the other two planes by rotating them onto X/Y and performing computation there
|
||||||
switch (_gridPlane->currentIndex()) {
|
switch (_gridPlane->currentIndex()) {
|
||||||
|
@ -339,60 +352,14 @@ void MetavoxelEditor::resetState() {
|
||||||
_height = 0.0f;
|
_height = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Applier : public MetavoxelVisitor {
|
|
||||||
public:
|
|
||||||
|
|
||||||
Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value);
|
|
||||||
|
|
||||||
virtual bool visit(MetavoxelInfo& info);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
glm::vec3 _minimum;
|
|
||||||
glm::vec3 _maximum;
|
|
||||||
float _granularity;
|
|
||||||
AttributeValue _value;
|
|
||||||
};
|
|
||||||
|
|
||||||
Applier::Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value) :
|
|
||||||
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << value.getAttribute()),
|
|
||||||
_minimum(minimum),
|
|
||||||
_maximum(maximum),
|
|
||||||
_granularity(granularity),
|
|
||||||
_value(value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Applier::visit(MetavoxelInfo& info) {
|
|
||||||
// find the intersection between volume and voxel
|
|
||||||
glm::vec3 minimum = glm::max(info.minimum, _minimum);
|
|
||||||
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _maximum);
|
|
||||||
glm::vec3 size = maximum - minimum;
|
|
||||||
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
|
||||||
return false; // disjoint
|
|
||||||
}
|
|
||||||
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
|
||||||
if (volume >= 1.0f) {
|
|
||||||
info.outputValues[0] = _value;
|
|
||||||
return false; // entirely contained
|
|
||||||
}
|
|
||||||
if (info.size <= _granularity) {
|
|
||||||
if (volume > 0.5f) {
|
|
||||||
info.outputValues[0] = _value;
|
|
||||||
}
|
|
||||||
return false; // reached granularity limit; take best guess
|
|
||||||
}
|
|
||||||
return true; // subdivide
|
|
||||||
}
|
|
||||||
|
|
||||||
void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(getSelectedAttribute());
|
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(getSelectedAttribute());
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue()));
|
OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue()));
|
||||||
|
MetavoxelEditMessage edit = { { minimum, maximum }, getGridSpacing(), value };
|
||||||
Applier applier(minimum, maximum, _gridSpacing->value(), value);
|
Application::getInstance()->getMetavoxels()->applyEdit(edit);
|
||||||
Application::getInstance()->getMetavoxels()->getData().guide(applier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant MetavoxelEditor::getValue() const {
|
QVariant MetavoxelEditor::getValue() const {
|
||||||
|
|
|
@ -32,7 +32,8 @@ private slots:
|
||||||
|
|
||||||
void updateValueEditor();
|
void updateValueEditor();
|
||||||
void createNewAttribute();
|
void createNewAttribute();
|
||||||
void updateGridPosition();
|
void centerGridPosition();
|
||||||
|
void alignGridPosition();
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ private:
|
||||||
|
|
||||||
void updateAttributes(const QString& select = QString());
|
void updateAttributes(const QString& select = QString());
|
||||||
QString getSelectedAttribute() const;
|
QString getSelectedAttribute() const;
|
||||||
|
double getGridSpacing() const;
|
||||||
glm::quat getGridRotation() const;
|
glm::quat getGridRotation() const;
|
||||||
void resetState();
|
void resetState();
|
||||||
void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
|
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include "HandData.h"
|
#include "HandData.h"
|
||||||
#include "AvatarData.h"
|
#include "AvatarData.h"
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
|
@ -237,6 +237,29 @@ Bitstream& Bitstream::operator>>(QVariant& value) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bitstream& Bitstream::operator<<(const AttributeValue& attributeValue) {
|
||||||
|
_attributeStreamer << attributeValue.getAttribute();
|
||||||
|
if (attributeValue.getAttribute()) {
|
||||||
|
attributeValue.getAttribute()->write(*this, attributeValue.getValue(), true);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitstream& Bitstream::operator>>(OwnedAttributeValue& attributeValue) {
|
||||||
|
AttributePointer attribute;
|
||||||
|
_attributeStreamer >> attribute;
|
||||||
|
if (attribute) {
|
||||||
|
void* value = attribute->create();
|
||||||
|
attribute->read(*this, value, true);
|
||||||
|
attributeValue = AttributeValue(attribute, value);
|
||||||
|
attribute->destroy(value);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
attributeValue = AttributeValue();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Bitstream& Bitstream::operator<<(const QObject* object) {
|
Bitstream& Bitstream::operator<<(const QObject* object) {
|
||||||
if (!object) {
|
if (!object) {
|
||||||
_metaObjectStreamer << NULL;
|
_metaObjectStreamer << NULL;
|
||||||
|
|
|
@ -23,7 +23,9 @@ struct QMetaObject;
|
||||||
class QObject;
|
class QObject;
|
||||||
|
|
||||||
class Attribute;
|
class Attribute;
|
||||||
|
class AttributeValue;
|
||||||
class Bitstream;
|
class Bitstream;
|
||||||
|
class OwnedAttributeValue;
|
||||||
class TypeStreamer;
|
class TypeStreamer;
|
||||||
|
|
||||||
typedef QSharedPointer<Attribute> AttributePointer;
|
typedef QSharedPointer<Attribute> AttributePointer;
|
||||||
|
@ -89,9 +91,11 @@ template<class T> inline QHash<T, int> RepeatedValueStreamer<T>::getAndResetTran
|
||||||
template<class T> inline void RepeatedValueStreamer<T>::persistTransientOffsets(const QHash<T, int>& transientOffsets) {
|
template<class T> inline void RepeatedValueStreamer<T>::persistTransientOffsets(const QHash<T, int>& transientOffsets) {
|
||||||
int oldLastPersistentID = _lastPersistentID;
|
int oldLastPersistentID = _lastPersistentID;
|
||||||
for (typename QHash<T, int>::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) {
|
for (typename QHash<T, int>::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) {
|
||||||
int id = oldLastPersistentID + it.value();
|
int& id = _persistentIDs[it.key()];
|
||||||
|
if (id == 0) {
|
||||||
|
id = oldLastPersistentID + it.value();
|
||||||
_lastPersistentID = qMax(_lastPersistentID, id);
|
_lastPersistentID = qMax(_lastPersistentID, id);
|
||||||
_persistentIDs.insert(it.key(), id);
|
}
|
||||||
}
|
}
|
||||||
_idStreamer.setBitsFromValue(_lastPersistentID);
|
_idStreamer.setBitsFromValue(_lastPersistentID);
|
||||||
}
|
}
|
||||||
|
@ -106,10 +110,13 @@ template<class T> inline QHash<int, T> RepeatedValueStreamer<T>::getAndResetTran
|
||||||
template<class T> inline void RepeatedValueStreamer<T>::persistTransientValues(const QHash<int, T>& transientValues) {
|
template<class T> inline void RepeatedValueStreamer<T>::persistTransientValues(const QHash<int, T>& transientValues) {
|
||||||
int oldLastPersistentID = _lastPersistentID;
|
int oldLastPersistentID = _lastPersistentID;
|
||||||
for (typename QHash<int, T>::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) {
|
for (typename QHash<int, T>::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) {
|
||||||
int id = oldLastPersistentID + it.key();
|
int& id = _persistentIDs[it.value()];
|
||||||
|
if (id == 0) {
|
||||||
|
id = oldLastPersistentID + it.key();
|
||||||
_lastPersistentID = qMax(_lastPersistentID, id);
|
_lastPersistentID = qMax(_lastPersistentID, id);
|
||||||
_persistentValues.insert(id, it.value());
|
_persistentValues.insert(id, it.value());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_idStreamer.setBitsFromValue(_lastPersistentID);
|
_idStreamer.setBitsFromValue(_lastPersistentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +238,9 @@ public:
|
||||||
Bitstream& operator<<(const QVariant& value);
|
Bitstream& operator<<(const QVariant& value);
|
||||||
Bitstream& operator>>(QVariant& value);
|
Bitstream& operator>>(QVariant& value);
|
||||||
|
|
||||||
|
Bitstream& operator<<(const AttributeValue& attributeValue);
|
||||||
|
Bitstream& operator>>(OwnedAttributeValue& attributeValue);
|
||||||
|
|
||||||
template<class T> Bitstream& operator<<(const QList<T>& list);
|
template<class T> Bitstream& operator<<(const QList<T>& list);
|
||||||
template<class T> Bitstream& operator>>(QList<T>& list);
|
template<class T> Bitstream& operator>>(QList<T>& list);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader) :
|
||||||
_outgoingDatagramStream(&_outgoingDatagramBuffer),
|
_outgoingDatagramStream(&_outgoingDatagramBuffer),
|
||||||
_incomingPacketNumber(0),
|
_incomingPacketNumber(0),
|
||||||
_incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly),
|
_incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly),
|
||||||
_inputStream(_incomingPacketStream) {
|
_inputStream(_incomingPacketStream),
|
||||||
|
_receivedHighPriorityMessages(0) {
|
||||||
|
|
||||||
_outgoingPacketStream.setByteOrder(QDataStream::LittleEndian);
|
_outgoingPacketStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
_incomingDatagramStream.setByteOrder(QDataStream::LittleEndian);
|
_incomingDatagramStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
@ -35,6 +36,34 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader) :
|
||||||
memcpy(_outgoingDatagram.data(), datagramHeader.constData(), _datagramHeaderSize);
|
memcpy(_outgoingDatagram.data(), datagramHeader.constData(), _datagramHeaderSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatagramSequencer::sendHighPriorityMessage(const QVariant& data) {
|
||||||
|
HighPriorityMessage message = { data, _outgoingPacketNumber + 1 };
|
||||||
|
_highPriorityMessages.append(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitstream& DatagramSequencer::startPacket() {
|
||||||
|
// start with the list of acknowledgements
|
||||||
|
_outgoingPacketStream << (quint32)_receiveRecords.size();
|
||||||
|
foreach (const ReceiveRecord& record, _receiveRecords) {
|
||||||
|
_outgoingPacketStream << (quint32)record.packetNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the high-priority messages
|
||||||
|
_outgoingPacketStream << (quint32)_highPriorityMessages.size();
|
||||||
|
foreach (const HighPriorityMessage& message, _highPriorityMessages) {
|
||||||
|
_outputStream << message.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the stream, allowing the caller to write the rest
|
||||||
|
return _outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatagramSequencer::endPacket() {
|
||||||
|
_outputStream.flush();
|
||||||
|
sendPacket(QByteArray::fromRawData(_outgoingPacketData.constData(), _outgoingPacketStream.device()->pos()));
|
||||||
|
_outgoingPacketStream.device()->seek(0);
|
||||||
|
}
|
||||||
|
|
||||||
/// Simple RAII-style object to keep a device open when in scope.
|
/// Simple RAII-style object to keep a device open when in scope.
|
||||||
class QIODeviceOpener {
|
class QIODeviceOpener {
|
||||||
public:
|
public:
|
||||||
|
@ -47,21 +76,6 @@ private:
|
||||||
QIODevice* _device;
|
QIODevice* _device;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitstream& DatagramSequencer::startPacket() {
|
|
||||||
// start with the list of acknowledgements
|
|
||||||
_outgoingPacketStream << (quint32)_receiveRecords.size();
|
|
||||||
foreach (const ReceiveRecord& record, _receiveRecords) {
|
|
||||||
_outgoingPacketStream << (quint32)record.packetNumber;
|
|
||||||
}
|
|
||||||
return _outputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSequencer::endPacket() {
|
|
||||||
_outputStream.flush();
|
|
||||||
sendPacket(QByteArray::fromRawData(_outgoingPacketData.constData(), _outgoingPacketStream.device()->pos()));
|
|
||||||
_outgoingPacketStream.device()->seek(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
|
void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
|
||||||
_incomingDatagramBuffer.setData(datagram.constData() + _datagramHeaderSize, datagram.size() - _datagramHeaderSize);
|
_incomingDatagramBuffer.setData(datagram.constData() + _datagramHeaderSize, datagram.size() - _datagramHeaderSize);
|
||||||
QIODeviceOpener opener(&_incomingDatagramBuffer, QIODevice::ReadOnly);
|
QIODeviceOpener opener(&_incomingDatagramBuffer, QIODevice::ReadOnly);
|
||||||
|
@ -123,25 +137,47 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
|
||||||
_sendRecords.erase(_sendRecords.begin(), it + 1);
|
_sendRecords.erase(_sendRecords.begin(), it + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read and dispatch the high-priority messages
|
||||||
|
quint32 highPriorityMessageCount;
|
||||||
|
_incomingPacketStream >> highPriorityMessageCount;
|
||||||
|
int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages;
|
||||||
|
for (int i = 0; i < highPriorityMessageCount; i++) {
|
||||||
|
QVariant data;
|
||||||
|
_inputStream >> data;
|
||||||
|
if (i >= _receivedHighPriorityMessages) {
|
||||||
|
emit receivedHighPriorityMessage(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_receivedHighPriorityMessages = highPriorityMessageCount;
|
||||||
|
|
||||||
|
// alert external parties so that they can read the rest
|
||||||
emit readyToRead(_inputStream);
|
emit readyToRead(_inputStream);
|
||||||
_incomingPacketStream.device()->seek(0);
|
_incomingPacketStream.device()->seek(0);
|
||||||
_inputStream.reset();
|
_inputStream.reset();
|
||||||
|
|
||||||
// record the receipt
|
// record the receipt
|
||||||
ReceiveRecord record = { _incomingPacketNumber, _inputStream.getAndResetReadMappings() };
|
ReceiveRecord record = { _incomingPacketNumber, _inputStream.getAndResetReadMappings(), newHighPriorityMessages };
|
||||||
_receiveRecords.append(record);
|
_receiveRecords.append(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) {
|
void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) {
|
||||||
// stop acknowledging the recorded packets (TODO: replace with interpolation search?)
|
// stop acknowledging the recorded packets
|
||||||
ReceiveRecord compare = { record.lastReceivedPacketNumber };
|
while (!_receiveRecords.isEmpty() && _receiveRecords.first().packetNumber <= record.lastReceivedPacketNumber) {
|
||||||
QList<ReceiveRecord>::iterator it = qBinaryFind(_receiveRecords.begin(), _receiveRecords.end(), compare);
|
const ReceiveRecord& received = _receiveRecords.first();
|
||||||
if (it != _receiveRecords.end()) {
|
_inputStream.persistReadMappings(received.mappings);
|
||||||
_inputStream.persistReadMappings(it->mappings);
|
_receivedHighPriorityMessages -= received.newHighPriorityMessages;
|
||||||
emit receiveAcknowledged(it - _receiveRecords.begin());
|
emit receiveAcknowledged(0);
|
||||||
_receiveRecords.erase(_receiveRecords.begin(), it + 1);
|
_receiveRecords.removeFirst();
|
||||||
}
|
}
|
||||||
_outputStream.persistWriteMappings(record.mappings);
|
_outputStream.persistWriteMappings(record.mappings);
|
||||||
|
|
||||||
|
// remove the received high priority messages
|
||||||
|
for (int i = _highPriorityMessages.size() - 1; i >= 0; i--) {
|
||||||
|
if (_highPriorityMessages.at(i).firstPacketNumber <= record.packetNumber) {
|
||||||
|
_highPriorityMessages.erase(_highPriorityMessages.begin(), _highPriorityMessages.begin() + i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSequencer::sendPacket(const QByteArray& packet) {
|
void DatagramSequencer::sendPacket(const QByteArray& packet) {
|
||||||
|
|
|
@ -23,6 +23,12 @@ class DatagramSequencer : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
class HighPriorityMessage {
|
||||||
|
public:
|
||||||
|
QVariant data;
|
||||||
|
int firstPacketNumber;
|
||||||
|
};
|
||||||
|
|
||||||
DatagramSequencer(const QByteArray& datagramHeader = QByteArray());
|
DatagramSequencer(const QByteArray& datagramHeader = QByteArray());
|
||||||
|
|
||||||
/// Returns the packet number of the last packet sent.
|
/// Returns the packet number of the last packet sent.
|
||||||
|
@ -31,6 +37,15 @@ public:
|
||||||
/// Returns the packet number of the last packet received (or the packet currently being assembled).
|
/// Returns the packet number of the last packet received (or the packet currently being assembled).
|
||||||
int getIncomingPacketNumber() const { return _incomingPacketNumber; }
|
int getIncomingPacketNumber() const { return _incomingPacketNumber; }
|
||||||
|
|
||||||
|
/// Returns the packet number of the sent packet at the specified index.
|
||||||
|
int getSentPacketNumber(int index) const { return _sendRecords.at(index).packetNumber; }
|
||||||
|
|
||||||
|
/// Adds a message to the high priority queue. Will be sent with every outgoing packet until received.
|
||||||
|
void sendHighPriorityMessage(const QVariant& data);
|
||||||
|
|
||||||
|
/// Returns a reference to the list of high priority messages not yet acknowledged.
|
||||||
|
const QList<HighPriorityMessage>& getHighPriorityMessages() const { return _highPriorityMessages; }
|
||||||
|
|
||||||
/// Starts a new packet for transmission.
|
/// Starts a new packet for transmission.
|
||||||
/// \return a reference to the Bitstream to use for writing to the packet
|
/// \return a reference to the Bitstream to use for writing to the packet
|
||||||
Bitstream& startPacket();
|
Bitstream& startPacket();
|
||||||
|
@ -50,6 +65,9 @@ signals:
|
||||||
/// Emitted when a packet is available to read.
|
/// Emitted when a packet is available to read.
|
||||||
void readyToRead(Bitstream& input);
|
void readyToRead(Bitstream& input);
|
||||||
|
|
||||||
|
/// Emitted when we've received a high-priority message
|
||||||
|
void receivedHighPriorityMessage(const QVariant& data);
|
||||||
|
|
||||||
/// Emitted when a sent packet has been acknowledged by the remote side.
|
/// Emitted when a sent packet has been acknowledged by the remote side.
|
||||||
/// \param index the index of the packet in our list of send records
|
/// \param index the index of the packet in our list of send records
|
||||||
void sendAcknowledged(int index);
|
void sendAcknowledged(int index);
|
||||||
|
@ -71,6 +89,7 @@ private:
|
||||||
public:
|
public:
|
||||||
int packetNumber;
|
int packetNumber;
|
||||||
Bitstream::ReadMappings mappings;
|
Bitstream::ReadMappings mappings;
|
||||||
|
int newHighPriorityMessages;
|
||||||
|
|
||||||
bool operator<(const ReceiveRecord& other) const { return packetNumber < other.packetNumber; }
|
bool operator<(const ReceiveRecord& other) const { return packetNumber < other.packetNumber; }
|
||||||
};
|
};
|
||||||
|
@ -104,6 +123,9 @@ private:
|
||||||
Bitstream _inputStream;
|
Bitstream _inputStream;
|
||||||
QSet<int> _offsetsReceived;
|
QSet<int> _offsetsReceived;
|
||||||
int _remainingBytes;
|
int _remainingBytes;
|
||||||
|
|
||||||
|
QList<HighPriorityMessage> _highPriorityMessages;
|
||||||
|
int _receivedHighPriorityMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__DatagramSequencer__) */
|
#endif /* defined(__interface__DatagramSequencer__) */
|
||||||
|
|
|
@ -10,11 +10,15 @@
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
#include "MetavoxelData.h"
|
#include "MetavoxelData.h"
|
||||||
|
#include "MetavoxelUtil.h"
|
||||||
|
|
||||||
MetavoxelData::MetavoxelData() {
|
MetavoxelData::MetavoxelData() : _size(1.0f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelData::MetavoxelData(const MetavoxelData& other) : _roots(other._roots) {
|
MetavoxelData::MetavoxelData(const MetavoxelData& other) :
|
||||||
|
_size(other._size),
|
||||||
|
_roots(other._roots) {
|
||||||
|
|
||||||
incrementRootReferenceCounts();
|
incrementRootReferenceCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,18 +28,24 @@ MetavoxelData::~MetavoxelData() {
|
||||||
|
|
||||||
MetavoxelData& MetavoxelData::operator=(const MetavoxelData& other) {
|
MetavoxelData& MetavoxelData::operator=(const MetavoxelData& other) {
|
||||||
decrementRootReferenceCounts();
|
decrementRootReferenceCounts();
|
||||||
|
_size = other._size;
|
||||||
_roots = other._roots;
|
_roots = other._roots;
|
||||||
incrementRootReferenceCounts();
|
incrementRootReferenceCounts();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Box MetavoxelData::getBounds() const {
|
||||||
|
float halfSize = _size * 0.5f;
|
||||||
|
Box bounds = { glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize) };
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
|
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
|
||||||
// start with the root values/defaults (plus the guide attribute)
|
// start with the root values/defaults (plus the guide attribute)
|
||||||
const float TOP_LEVEL_SIZE = 1.0f;
|
|
||||||
const QVector<AttributePointer>& inputs = visitor.getInputs();
|
const QVector<AttributePointer>& inputs = visitor.getInputs();
|
||||||
const QVector<AttributePointer>& outputs = visitor.getOutputs();
|
const QVector<AttributePointer>& outputs = visitor.getOutputs();
|
||||||
MetavoxelVisitation firstVisitation = { this, NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
|
MetavoxelVisitation firstVisitation = { NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
|
||||||
QVector<MetavoxelNode*>(outputs.size()), { glm::vec3(), TOP_LEVEL_SIZE,
|
QVector<MetavoxelNode*>(outputs.size()), { glm::vec3(_size, _size, _size) * -0.5f, _size,
|
||||||
QVector<AttributeValue>(inputs.size() + 1), QVector<AttributeValue>(outputs.size()) } };
|
QVector<AttributeValue>(inputs.size() + 1), QVector<AttributeValue>(outputs.size()) } };
|
||||||
for (int i = 0; i < inputs.size(); i++) {
|
for (int i = 0; i < inputs.size(); i++) {
|
||||||
MetavoxelNode* node = _roots.value(inputs.at(i));
|
MetavoxelNode* node = _roots.value(inputs.at(i));
|
||||||
|
@ -54,42 +64,80 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
|
||||||
PolymorphicDataPointer>().data())->guide(firstVisitation);
|
PolymorphicDataPointer>().data())->guide(firstVisitation);
|
||||||
for (int i = 0; i < outputs.size(); i++) {
|
for (int i = 0; i < outputs.size(); i++) {
|
||||||
AttributeValue& value = firstVisitation.info.outputValues[i];
|
AttributeValue& value = firstVisitation.info.outputValues[i];
|
||||||
if (value.getAttribute()) {
|
if (!value.getAttribute()) {
|
||||||
MetavoxelNode* node = firstVisitation.outputNodes.at(i);
|
continue;
|
||||||
|
}
|
||||||
|
// replace the old node with the new
|
||||||
|
MetavoxelNode*& node = _roots[value.getAttribute()];
|
||||||
|
if (node) {
|
||||||
|
node->decrementReferenceCount(value.getAttribute());
|
||||||
|
}
|
||||||
|
node = firstVisitation.outputNodes.at(i);
|
||||||
if (node->isLeaf() && value.isDefault()) {
|
if (node->isLeaf() && value.isDefault()) {
|
||||||
|
// immediately remove the new node if redundant
|
||||||
node->decrementReferenceCount(value.getAttribute());
|
node->decrementReferenceCount(value.getAttribute());
|
||||||
_roots.remove(value.getAttribute());
|
_roots.remove(value.getAttribute());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int X_MAXIMUM_FLAG = 1;
|
||||||
|
const int Y_MAXIMUM_FLAG = 2;
|
||||||
|
const int Z_MAXIMUM_FLAG = 4;
|
||||||
|
const int MAXIMUM_FLAG_MASK = X_MAXIMUM_FLAG | Y_MAXIMUM_FLAG | Z_MAXIMUM_FLAG;
|
||||||
|
|
||||||
|
static int getOppositeIndex(int index) {
|
||||||
|
return index ^ MAXIMUM_FLAG_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelData::expand() {
|
||||||
|
for (QHash<AttributePointer, MetavoxelNode*>::iterator it = _roots.begin(); it != _roots.end(); it++) {
|
||||||
|
MetavoxelNode* newParent = new MetavoxelNode(it.key());
|
||||||
|
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||||
|
MetavoxelNode* newChild = new MetavoxelNode(it.key());
|
||||||
|
newParent->setChild(i, newChild);
|
||||||
|
int index = getOppositeIndex(i);
|
||||||
|
if (it.value()->isLeaf()) {
|
||||||
|
newChild->setChild(index, new MetavoxelNode(it.value()->getAttributeValue(it.key())));
|
||||||
|
} else {
|
||||||
|
MetavoxelNode* grandchild = it.value()->getChild(i);
|
||||||
|
grandchild->incrementReferenceCount();
|
||||||
|
newChild->setChild(index, grandchild);
|
||||||
}
|
}
|
||||||
|
for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) {
|
||||||
|
MetavoxelNode* newGrandchild = new MetavoxelNode(it.key());
|
||||||
|
newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild);
|
||||||
|
}
|
||||||
|
newChild->mergeChildren(it.key());
|
||||||
|
}
|
||||||
|
newParent->mergeChildren(it.key());
|
||||||
|
it.value()->decrementReferenceCount(it.key());
|
||||||
|
it.value() = newParent;
|
||||||
|
}
|
||||||
|
_size *= 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelData::read(Bitstream& in) {
|
void MetavoxelData::read(Bitstream& in) {
|
||||||
// save the old roots and clear
|
// clear out any existing roots
|
||||||
QHash<AttributePointer, MetavoxelNode*> oldRoots = _roots;
|
decrementRootReferenceCounts();
|
||||||
_roots.clear();
|
_roots.clear();
|
||||||
|
|
||||||
// read in the new roots, reusing old ones where appropriate
|
in >> _size;
|
||||||
|
|
||||||
|
// read in the new roots
|
||||||
int rootCount;
|
int rootCount;
|
||||||
in >> rootCount;
|
in >> rootCount;
|
||||||
for (int i = 0; i < rootCount; i++) {
|
for (int i = 0; i < rootCount; i++) {
|
||||||
AttributePointer attribute;
|
AttributePointer attribute;
|
||||||
in.getAttributeStreamer() >> attribute;
|
in.getAttributeStreamer() >> attribute;
|
||||||
MetavoxelNode* root = oldRoots.take(attribute);
|
MetavoxelNode*& root = _roots[attribute];
|
||||||
if (!root) {
|
|
||||||
root = new MetavoxelNode(attribute);
|
root = new MetavoxelNode(attribute);
|
||||||
}
|
|
||||||
_roots.insert(attribute, root);
|
|
||||||
root->read(attribute, in);
|
root->read(attribute, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear out the remaining old roots
|
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = oldRoots.constBegin(); it != oldRoots.constEnd(); it++) {
|
|
||||||
it.value()->decrementReferenceCount(it.key());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelData::write(Bitstream& out) const {
|
void MetavoxelData::write(Bitstream& out) const {
|
||||||
|
out << _size;
|
||||||
out << _roots.size();
|
out << _roots.size();
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
out.getAttributeStreamer() << it.key();
|
out.getAttributeStreamer() << it.key();
|
||||||
|
@ -98,20 +146,39 @@ void MetavoxelData::write(Bitstream& out) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
|
void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
|
||||||
|
// shallow copy the reference
|
||||||
|
*this = reference;
|
||||||
|
|
||||||
|
bool changed;
|
||||||
|
in >> changed;
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sizeChanged;
|
||||||
|
in >> sizeChanged;
|
||||||
|
if (sizeChanged) {
|
||||||
|
float size;
|
||||||
|
in >> size;
|
||||||
|
while (_size < size) {
|
||||||
|
expand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int changedCount;
|
int changedCount;
|
||||||
in >> changedCount;
|
in >> changedCount;
|
||||||
for (int i = 0; i < changedCount; i++) {
|
for (int i = 0; i < changedCount; i++) {
|
||||||
AttributePointer attribute;
|
AttributePointer attribute;
|
||||||
in.getAttributeStreamer() >> attribute;
|
in.getAttributeStreamer() >> attribute;
|
||||||
MetavoxelNode*& root = _roots[attribute];
|
MetavoxelNode*& root = _roots[attribute];
|
||||||
if (!root) {
|
if (root) {
|
||||||
|
MetavoxelNode* oldRoot = root;
|
||||||
root = new MetavoxelNode(attribute);
|
root = new MetavoxelNode(attribute);
|
||||||
}
|
root->readDelta(attribute, *oldRoot, in);
|
||||||
MetavoxelNode* referenceRoot = reference._roots.value(attribute);
|
oldRoot->decrementReferenceCount(attribute);
|
||||||
if (referenceRoot) {
|
|
||||||
root->readDelta(attribute, *referenceRoot, in);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
root = new MetavoxelNode(attribute);
|
||||||
root->read(attribute, in);
|
root->read(attribute, in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,22 +188,44 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
|
||||||
for (int i = 0; i < removedCount; i++) {
|
for (int i = 0; i < removedCount; i++) {
|
||||||
AttributePointer attribute;
|
AttributePointer attribute;
|
||||||
in.getAttributeStreamer() >> attribute;
|
in.getAttributeStreamer() >> attribute;
|
||||||
|
_roots.take(attribute)->decrementReferenceCount(attribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) const {
|
void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) const {
|
||||||
|
// first things first: there might be no change whatsoever
|
||||||
|
if (_size == reference._size && _roots == reference._roots) {
|
||||||
|
out << false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out << true;
|
||||||
|
|
||||||
|
// compare the size; if changed (rare), we must compare to the expanded reference
|
||||||
|
const MetavoxelData* expandedReference = &reference;
|
||||||
|
if (_size == reference._size) {
|
||||||
|
out << false;
|
||||||
|
} else {
|
||||||
|
out << true;
|
||||||
|
out << _size;
|
||||||
|
|
||||||
|
MetavoxelData* expanded = new MetavoxelData(reference);
|
||||||
|
while (expanded->_size < _size) {
|
||||||
|
expanded->expand();
|
||||||
|
}
|
||||||
|
expandedReference = expanded;
|
||||||
|
}
|
||||||
|
|
||||||
// count the number of roots added/changed, then write
|
// count the number of roots added/changed, then write
|
||||||
int changedCount = 0;
|
int changedCount = 0;
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
MetavoxelNode* referenceRoot = reference._roots.value(it.key());
|
MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key());
|
||||||
if (it.value() != referenceRoot) {
|
if (it.value() != referenceRoot) {
|
||||||
changedCount++;
|
changedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << changedCount;
|
out << changedCount;
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
MetavoxelNode* referenceRoot = reference._roots.value(it.key());
|
MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key());
|
||||||
if (it.value() != referenceRoot) {
|
if (it.value() != referenceRoot) {
|
||||||
out.getAttributeStreamer() << it.key();
|
out.getAttributeStreamer() << it.key();
|
||||||
if (referenceRoot) {
|
if (referenceRoot) {
|
||||||
|
@ -149,19 +238,24 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c
|
||||||
|
|
||||||
// same with nodes removed
|
// same with nodes removed
|
||||||
int removedCount = 0;
|
int removedCount = 0;
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = reference._roots.constBegin();
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = expandedReference->_roots.constBegin();
|
||||||
it != reference._roots.constEnd(); it++) {
|
it != expandedReference->_roots.constEnd(); it++) {
|
||||||
if (!_roots.contains(it.key())) {
|
if (!_roots.contains(it.key())) {
|
||||||
removedCount++;
|
removedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << removedCount;
|
out << removedCount;
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = reference._roots.constBegin();
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = expandedReference->_roots.constBegin();
|
||||||
it != reference._roots.constEnd(); it++) {
|
it != expandedReference->_roots.constEnd(); it++) {
|
||||||
if (!_roots.contains(it.key())) {
|
if (!_roots.contains(it.key())) {
|
||||||
out.getAttributeStreamer() << it.key();
|
out.getAttributeStreamer() << it.key();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete the expanded reference if we had to expand
|
||||||
|
if (expandedReference != &reference) {
|
||||||
|
delete expandedReference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelData::incrementRootReferenceCounts() {
|
void MetavoxelData::incrementRootReferenceCounts() {
|
||||||
|
@ -176,28 +270,6 @@ void MetavoxelData::decrementRootReferenceCounts() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeDelta(const MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& out) {
|
|
||||||
if (data == reference) {
|
|
||||||
out << false;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
out << true;
|
|
||||||
data->writeDelta(*reference, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDelta(MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& in) {
|
|
||||||
bool changed;
|
|
||||||
in >> changed;
|
|
||||||
if (changed) {
|
|
||||||
data.detach();
|
|
||||||
data->readDelta(*reference, in);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
data = reference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) {
|
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) {
|
||||||
_attributeValue = attributeValue.copy();
|
_attributeValue = attributeValue.copy();
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
@ -205,6 +277,15 @@ MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelNode::MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy) : _referenceCount(1) {
|
||||||
|
_attributeValue = attribute->create(copy->_attributeValue);
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
if ((_children[i] = copy->_children[i])) {
|
||||||
|
_children[i]->incrementReferenceCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) {
|
void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) {
|
||||||
attributeValue.getAttribute()->destroy(_attributeValue);
|
attributeValue.getAttribute()->destroy(_attributeValue);
|
||||||
_attributeValue = attributeValue.copy();
|
_attributeValue = attributeValue.copy();
|
||||||
|
@ -237,22 +318,16 @@ bool MetavoxelNode::isLeaf() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) {
|
void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) {
|
||||||
|
clearChildren(attribute);
|
||||||
|
|
||||||
bool leaf;
|
bool leaf;
|
||||||
in >> leaf;
|
in >> leaf;
|
||||||
attribute->read(in, _attributeValue, leaf);
|
attribute->read(in, _attributeValue, leaf);
|
||||||
if (leaf) {
|
if (!leaf) {
|
||||||
clearChildren(attribute);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
void* childValues[CHILD_COUNT];
|
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
if (!_children[i]) {
|
|
||||||
_children[i] = new MetavoxelNode(attribute);
|
_children[i] = new MetavoxelNode(attribute);
|
||||||
}
|
|
||||||
_children[i]->read(attribute, in);
|
_children[i]->read(attribute, in);
|
||||||
childValues[i] = _children[i]->_attributeValue;
|
|
||||||
}
|
}
|
||||||
attribute->merge(_attributeValue, childValues);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,20 +343,28 @@ void MetavoxelNode::write(const AttributePointer& attribute, Bitstream& out) con
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) {
|
void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) {
|
||||||
|
clearChildren(attribute);
|
||||||
|
|
||||||
bool leaf;
|
bool leaf;
|
||||||
in >> leaf;
|
in >> leaf;
|
||||||
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf);
|
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf);
|
||||||
if (leaf) {
|
if (!leaf) {
|
||||||
clearChildren(attribute);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (reference.isLeaf()) {
|
if (reference.isLeaf()) {
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
_children[i] = new MetavoxelNode(attribute);
|
||||||
_children[i]->read(attribute, in);
|
_children[i]->read(attribute, in);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
bool changed;
|
||||||
|
in >> changed;
|
||||||
|
if (changed) {
|
||||||
|
_children[i] = new MetavoxelNode(attribute);
|
||||||
_children[i]->readDelta(attribute, *reference._children[i], in);
|
_children[i]->readDelta(attribute, *reference._children[i], in);
|
||||||
|
} else {
|
||||||
|
_children[i] = reference._children[i];
|
||||||
|
_children[i]->incrementReferenceCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,10 +381,15 @@ void MetavoxelNode::writeDelta(const AttributePointer& attribute, const Metavoxe
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
if (_children[i] == reference._children[i]) {
|
||||||
|
out << false;
|
||||||
|
} else {
|
||||||
|
out << true;
|
||||||
_children[i]->writeDelta(attribute, *reference._children[i], out);
|
_children[i]->writeDelta(attribute, *reference._children[i], out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) {
|
void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) {
|
||||||
|
@ -334,31 +422,33 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs, cons
|
||||||
_outputs(outputs) {
|
_outputs(outputs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelVisitor::~MetavoxelVisitor() {
|
||||||
|
}
|
||||||
|
|
||||||
PolymorphicData* DefaultMetavoxelGuide::clone() const {
|
PolymorphicData* DefaultMetavoxelGuide::clone() const {
|
||||||
return new DefaultMetavoxelGuide();
|
return new DefaultMetavoxelGuide();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int X_MAXIMUM_FLAG = 1;
|
|
||||||
const int Y_MAXIMUM_FLAG = 2;
|
|
||||||
const int Z_MAXIMUM_FLAG = 4;
|
|
||||||
|
|
||||||
void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||||
visitation.info.isLeaf = visitation.allInputNodesLeaves();
|
visitation.info.isLeaf = visitation.allInputNodesLeaves();
|
||||||
bool keepGoing = visitation.visitor.visit(visitation.info);
|
bool keepGoing = visitation.visitor.visit(visitation.info);
|
||||||
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
||||||
AttributeValue& value = visitation.info.outputValues[i];
|
AttributeValue& value = visitation.info.outputValues[i];
|
||||||
if (value.getAttribute()) {
|
if (!value.getAttribute()) {
|
||||||
MetavoxelNode*& node = visitation.outputNodes[i];
|
continue;
|
||||||
if (!node) {
|
|
||||||
node = visitation.createOutputNode(i);
|
|
||||||
}
|
}
|
||||||
node->setAttributeValue(value);
|
MetavoxelNode*& node = visitation.outputNodes[i];
|
||||||
|
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
|
||||||
|
// "set" to same value; disregard
|
||||||
|
value = AttributeValue();
|
||||||
|
} else {
|
||||||
|
node = new MetavoxelNode(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!keepGoing) {
|
if (!keepGoing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MetavoxelVisitation nextVisitation = { visitation.data, &visitation, visitation.visitor,
|
MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor,
|
||||||
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
|
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
|
||||||
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
|
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
|
||||||
QVector<AttributeValue>(visitation.outputNodes.size()) } };
|
QVector<AttributeValue>(visitation.outputNodes.size()) } };
|
||||||
|
@ -379,15 +469,39 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||||
(i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
(i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||||
(i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
(i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||||
(i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f);
|
(i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f);
|
||||||
nextVisitation.childIndex = i;
|
|
||||||
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
|
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
|
||||||
PolymorphicDataPointer>().data())->guide(nextVisitation);
|
PolymorphicDataPointer>().data())->guide(nextVisitation);
|
||||||
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
|
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
|
||||||
AttributeValue& value = nextVisitation.info.outputValues[j];
|
AttributeValue& value = nextVisitation.info.outputValues[j];
|
||||||
if (value.getAttribute()) {
|
if (!value.getAttribute()) {
|
||||||
visitation.info.outputValues[j] = value;
|
continue;
|
||||||
value = AttributeValue();
|
|
||||||
}
|
}
|
||||||
|
// replace the child
|
||||||
|
AttributeValue& parentValue = visitation.info.outputValues[j];
|
||||||
|
if (!parentValue.getAttribute()) {
|
||||||
|
// shallow-copy the parent node on first change
|
||||||
|
parentValue = value;
|
||||||
|
MetavoxelNode*& node = visitation.outputNodes[j];
|
||||||
|
if (node) {
|
||||||
|
node = new MetavoxelNode(value.getAttribute(), node);
|
||||||
|
} else {
|
||||||
|
// create leaf with inherited value
|
||||||
|
node = new MetavoxelNode(visitation.getInheritedOutputValue(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MetavoxelNode* node = visitation.outputNodes.at(j);
|
||||||
|
MetavoxelNode* child = node->getChild(i);
|
||||||
|
if (child) {
|
||||||
|
child->decrementReferenceCount(value.getAttribute());
|
||||||
|
} else {
|
||||||
|
// it's a leaf; we need to split it up
|
||||||
|
AttributeValue nodeValue = node->getAttributeValue(value.getAttribute());
|
||||||
|
for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) {
|
||||||
|
node->setChild((i + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node->setChild(i, nextVisitation.outputNodes.at(j));
|
||||||
|
value = AttributeValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
||||||
|
@ -507,20 +621,13 @@ bool MetavoxelVisitation::allInputNodesLeaves() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelNode* MetavoxelVisitation::createOutputNode(int index) {
|
AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const {
|
||||||
const AttributePointer& attribute = visitor.getOutputs().at(index);
|
for (const MetavoxelVisitation* visitation = previous; visitation != NULL; visitation = visitation->previous) {
|
||||||
if (previous) {
|
MetavoxelNode* node = visitation->outputNodes.at(index);
|
||||||
MetavoxelNode*& parent = previous->outputNodes[index];
|
if (node) {
|
||||||
if (!parent) {
|
return node->getAttributeValue(visitor.getOutputs().at(index));
|
||||||
parent = previous->createOutputNode(index);
|
|
||||||
}
|
}
|
||||||
AttributeValue value = parent->getAttributeValue(attribute);
|
|
||||||
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
|
||||||
parent->_children[i] = new MetavoxelNode(value);
|
|
||||||
}
|
|
||||||
return parent->_children[childIndex];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return data->_roots[attribute] = new MetavoxelNode(attribute);
|
|
||||||
}
|
}
|
||||||
|
return AttributeValue(visitor.getOutputs().at(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#define __interface__MetavoxelData__
|
#define __interface__MetavoxelData__
|
||||||
|
|
||||||
#include <QBitArray>
|
#include <QBitArray>
|
||||||
#include <QExplicitlySharedDataPointer>
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QSharedData>
|
#include <QSharedData>
|
||||||
#include <QScriptString>
|
#include <QScriptString>
|
||||||
|
@ -23,12 +22,13 @@
|
||||||
|
|
||||||
class QScriptContext;
|
class QScriptContext;
|
||||||
|
|
||||||
|
class Box;
|
||||||
class MetavoxelNode;
|
class MetavoxelNode;
|
||||||
class MetavoxelVisitation;
|
class MetavoxelVisitation;
|
||||||
class MetavoxelVisitor;
|
class MetavoxelVisitor;
|
||||||
|
|
||||||
/// The base metavoxel representation shared between server and client.
|
/// The base metavoxel representation shared between server and client.
|
||||||
class MetavoxelData : public QSharedData {
|
class MetavoxelData {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelData();
|
MetavoxelData();
|
||||||
|
@ -37,9 +37,16 @@ public:
|
||||||
|
|
||||||
MetavoxelData& operator=(const MetavoxelData& other);
|
MetavoxelData& operator=(const MetavoxelData& other);
|
||||||
|
|
||||||
|
float getSize() const { return _size; }
|
||||||
|
|
||||||
|
Box getBounds() const;
|
||||||
|
|
||||||
/// Applies the specified visitor to the contained voxels.
|
/// Applies the specified visitor to the contained voxels.
|
||||||
void guide(MetavoxelVisitor& visitor);
|
void guide(MetavoxelVisitor& visitor);
|
||||||
|
|
||||||
|
/// Expands the tree, increasing its capacity in all dimensions.
|
||||||
|
void expand();
|
||||||
|
|
||||||
void read(Bitstream& in);
|
void read(Bitstream& in);
|
||||||
void write(Bitstream& out) const;
|
void write(Bitstream& out) const;
|
||||||
|
|
||||||
|
@ -53,15 +60,10 @@ private:
|
||||||
void incrementRootReferenceCounts();
|
void incrementRootReferenceCounts();
|
||||||
void decrementRootReferenceCounts();
|
void decrementRootReferenceCounts();
|
||||||
|
|
||||||
|
float _size;
|
||||||
QHash<AttributePointer, MetavoxelNode*> _roots;
|
QHash<AttributePointer, MetavoxelNode*> _roots;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QExplicitlySharedDataPointer<MetavoxelData> MetavoxelDataPointer;
|
|
||||||
|
|
||||||
void writeDelta(const MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& out);
|
|
||||||
|
|
||||||
void readDelta(MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& in);
|
|
||||||
|
|
||||||
/// A single node within a metavoxel layer.
|
/// A single node within a metavoxel layer.
|
||||||
class MetavoxelNode {
|
class MetavoxelNode {
|
||||||
public:
|
public:
|
||||||
|
@ -69,10 +71,12 @@ public:
|
||||||
static const int CHILD_COUNT = 8;
|
static const int CHILD_COUNT = 8;
|
||||||
|
|
||||||
MetavoxelNode(const AttributeValue& attributeValue);
|
MetavoxelNode(const AttributeValue& attributeValue);
|
||||||
|
MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy);
|
||||||
|
|
||||||
void setAttributeValue(const AttributeValue& attributeValue);
|
void setAttributeValue(const AttributeValue& attributeValue);
|
||||||
|
|
||||||
AttributeValue getAttributeValue(const AttributePointer& attribute) const;
|
AttributeValue getAttributeValue(const AttributePointer& attribute) const;
|
||||||
|
void* getAttributeValue() const { return _attributeValue; }
|
||||||
|
|
||||||
void mergeChildren(const AttributePointer& attribute);
|
void mergeChildren(const AttributePointer& attribute);
|
||||||
|
|
||||||
|
@ -124,6 +128,7 @@ class MetavoxelVisitor {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelVisitor(const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs);
|
MetavoxelVisitor(const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs);
|
||||||
|
virtual ~MetavoxelVisitor();
|
||||||
|
|
||||||
/// Returns a reference to the list of input attributes desired.
|
/// Returns a reference to the list of input attributes desired.
|
||||||
const QVector<AttributePointer>& getInputs() const { return _inputs; }
|
const QVector<AttributePointer>& getInputs() const { return _inputs; }
|
||||||
|
@ -142,6 +147,8 @@ protected:
|
||||||
QVector<AttributePointer> _outputs;
|
QVector<AttributePointer> _outputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QSharedPointer<MetavoxelVisitor> MetavoxelVisitorPointer;
|
||||||
|
|
||||||
/// Interface for objects that guide metavoxel visitors.
|
/// Interface for objects that guide metavoxel visitors.
|
||||||
class MetavoxelGuide : public PolymorphicData {
|
class MetavoxelGuide : public PolymorphicData {
|
||||||
public:
|
public:
|
||||||
|
@ -195,16 +202,14 @@ private:
|
||||||
class MetavoxelVisitation {
|
class MetavoxelVisitation {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelData* data;
|
|
||||||
MetavoxelVisitation* previous;
|
MetavoxelVisitation* previous;
|
||||||
MetavoxelVisitor& visitor;
|
MetavoxelVisitor& visitor;
|
||||||
QVector<MetavoxelNode*> inputNodes;
|
QVector<MetavoxelNode*> inputNodes;
|
||||||
QVector<MetavoxelNode*> outputNodes;
|
QVector<MetavoxelNode*> outputNodes;
|
||||||
MetavoxelInfo info;
|
MetavoxelInfo info;
|
||||||
int childIndex;
|
|
||||||
|
|
||||||
bool allInputNodesLeaves() const;
|
bool allInputNodesLeaves() const;
|
||||||
MetavoxelNode* createOutputNode(int index);
|
AttributeValue getInheritedOutputValue(int index) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__MetavoxelData__) */
|
#endif /* defined(__interface__MetavoxelData__) */
|
||||||
|
|
59
libraries/metavoxels/src/MetavoxelMessages.cpp
Normal file
59
libraries/metavoxels/src/MetavoxelMessages.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// MetavoxelMessages.cpp
|
||||||
|
// metavoxels
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 1/24/14.
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MetavoxelData.h"
|
||||||
|
#include "MetavoxelMessages.h"
|
||||||
|
|
||||||
|
class EditVisitor : public MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
EditVisitor(const MetavoxelEditMessage& edit);
|
||||||
|
|
||||||
|
virtual bool visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const MetavoxelEditMessage& _edit;
|
||||||
|
};
|
||||||
|
|
||||||
|
EditVisitor::EditVisitor(const MetavoxelEditMessage& edit) :
|
||||||
|
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()),
|
||||||
|
_edit(edit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditVisitor::visit(MetavoxelInfo& info) {
|
||||||
|
// find the intersection between volume and voxel
|
||||||
|
glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum);
|
||||||
|
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum);
|
||||||
|
glm::vec3 size = maximum - minimum;
|
||||||
|
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
||||||
|
return false; // disjoint
|
||||||
|
}
|
||||||
|
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
||||||
|
if (volume >= 1.0f) {
|
||||||
|
info.outputValues[0] = _edit.value;
|
||||||
|
return false; // entirely contained
|
||||||
|
}
|
||||||
|
if (info.size <= _edit.granularity) {
|
||||||
|
if (volume >= 0.5f) {
|
||||||
|
info.outputValues[0] = _edit.value;
|
||||||
|
}
|
||||||
|
return false; // reached granularity limit; take best guess
|
||||||
|
}
|
||||||
|
return true; // subdivide
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelEditMessage::apply(MetavoxelData& data) const {
|
||||||
|
// expand to fit the entire edit
|
||||||
|
while (!data.getBounds().contains(region)) {
|
||||||
|
data.expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditVisitor visitor(*this);
|
||||||
|
data.guide(visitor);
|
||||||
|
}
|
|
@ -9,7 +9,17 @@
|
||||||
#ifndef __interface__MetavoxelMessages__
|
#ifndef __interface__MetavoxelMessages__
|
||||||
#define __interface__MetavoxelMessages__
|
#define __interface__MetavoxelMessages__
|
||||||
|
|
||||||
#include "Bitstream.h"
|
#include "AttributeRegistry.h"
|
||||||
|
#include "MetavoxelUtil.h"
|
||||||
|
|
||||||
|
class MetavoxelData;
|
||||||
|
|
||||||
|
/// Requests to close the session.
|
||||||
|
class CloseSessionMessage {
|
||||||
|
STREAMABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_STREAMABLE_METATYPE(CloseSessionMessage)
|
||||||
|
|
||||||
/// A message containing the state of a client.
|
/// A message containing the state of a client.
|
||||||
class ClientStateMessage {
|
class ClientStateMessage {
|
||||||
|
@ -29,4 +39,19 @@ class MetavoxelDeltaMessage {
|
||||||
|
|
||||||
DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage)
|
DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage)
|
||||||
|
|
||||||
|
/// A simple streamable edit.
|
||||||
|
class MetavoxelEditMessage {
|
||||||
|
STREAMABLE
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
STREAM Box region;
|
||||||
|
STREAM float granularity;
|
||||||
|
STREAM OwnedAttributeValue value;
|
||||||
|
|
||||||
|
void apply(MetavoxelData& data) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage)
|
||||||
|
|
||||||
#endif /* defined(__interface__MetavoxelMessages__) */
|
#endif /* defined(__interface__MetavoxelMessages__) */
|
||||||
|
|
|
@ -27,3 +27,9 @@ QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& hea
|
||||||
}
|
}
|
||||||
return QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES));
|
return QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Box::contains(const Box& other) const {
|
||||||
|
return other.minimum.x >= minimum.x && other.maximum.x <= maximum.x &&
|
||||||
|
other.minimum.y >= minimum.y && other.maximum.y <= maximum.y &&
|
||||||
|
other.minimum.z >= minimum.z && other.maximum.z <= maximum.z;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include "Bitstream.h"
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
|
|
||||||
class HifiSockAddr;
|
class HifiSockAddr;
|
||||||
|
@ -20,4 +22,18 @@ class HifiSockAddr;
|
||||||
/// \return the session ID, or a null ID if invalid (in which case a warning will be logged)
|
/// \return the session ID, or a null ID if invalid (in which case a warning will be logged)
|
||||||
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize);
|
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize);
|
||||||
|
|
||||||
|
/// A streamable axis-aligned bounding box.
|
||||||
|
class Box {
|
||||||
|
STREAMABLE
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
STREAM glm::vec3 minimum;
|
||||||
|
STREAM glm::vec3 maximum;
|
||||||
|
|
||||||
|
bool contains(const Box& other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_STREAMABLE_METATYPE(Box)
|
||||||
|
|
||||||
#endif /* defined(__interface__MetavoxelUtil__) */
|
#endif /* defined(__interface__MetavoxelUtil__) */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "HifiSockAddr.h"
|
#include "HifiSockAddr.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
#include <QtNetwork/QHostInfo>
|
#include <QtNetwork/QHostInfo>
|
||||||
#include <QtNetwork/QNetworkInterface>
|
#include <QtNetwork/QNetworkInterface>
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
const QString UNKNOWN_NodeType_t_NAME = "Unknown";
|
const QString UNKNOWN_NodeType_t_NAME = "Unknown";
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <QtCore/QDataStream>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtNetwork/QHostInfo>
|
#include <QtNetwork/QHostInfo>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue