mirror of
https://github.com/lubosz/overte.git
synced 2025-04-25 01:23:57 +02:00
Merge pull request #3093 from ey6es/metavoxels
Factored out the common endpoint/metavoxel client code from the metavoxel client, server, and tests.
This commit is contained in:
commit
daef739dee
17 changed files with 661 additions and 437 deletions
|
@ -69,7 +69,7 @@ void MetavoxelServer::readPendingDatagrams() {
|
|||
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
node->setLinkedData(new MetavoxelSession(this, NodeList::getInstance()->nodeWithUUID(node->getUUID())));
|
||||
node->setLinkedData(new MetavoxelSession(node, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ void MetavoxelServer::sendDeltas() {
|
|||
// send deltas for all sessions
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
static_cast<MetavoxelSession*>(node->getLinkedData())->sendDelta();
|
||||
static_cast<MetavoxelSession*>(node->getLinkedData())->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,59 +89,34 @@ void MetavoxelServer::sendDeltas() {
|
|||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - elapsed));
|
||||
}
|
||||
|
||||
MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const SharedNodePointer& node) :
|
||||
_server(server),
|
||||
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)),
|
||||
_node(node) {
|
||||
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) :
|
||||
Endpoint(node, new PacketRecord(), NULL),
|
||||
_server(server) {
|
||||
|
||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||
connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&)));
|
||||
connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)),
|
||||
SLOT(handleMessage(const QVariant&)));
|
||||
|
||||
// insert the baseline send record
|
||||
SendRecord record = { 0 };
|
||||
_sendRecords.append(record);
|
||||
}
|
||||
|
||||
MetavoxelSession::~MetavoxelSession() {
|
||||
}
|
||||
|
||||
int MetavoxelSession::parseData(const QByteArray& packet) {
|
||||
// process through sequencer
|
||||
_sequencer.receivedDatagram(packet);
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
void MetavoxelSession::sendDelta() {
|
||||
void MetavoxelSession::update() {
|
||||
// wait until we have a valid lod
|
||||
if (!_lod.isValid()) {
|
||||
return;
|
||||
if (_lod.isValid()) {
|
||||
Endpoint::update();
|
||||
}
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
}
|
||||
|
||||
void MetavoxelSession::writeUpdateMessage(Bitstream& out) {
|
||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||
_server->getData().writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData(), _lod };
|
||||
_sendRecords.append(record);
|
||||
PacketRecord* sendRecord = getLastAcknowledgedSendRecord();
|
||||
_server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
|
||||
}
|
||||
|
||||
void MetavoxelSession::sendData(const QByteArray& data) {
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
}
|
||||
|
||||
void MetavoxelSession::readPacket(Bitstream& in) {
|
||||
QVariant message;
|
||||
in >> message;
|
||||
void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
handleMessage(message);
|
||||
}
|
||||
|
||||
void MetavoxelSession::clearSendRecordsBefore(int index) {
|
||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||
PacketRecord* MetavoxelSession::maybeCreateSendRecord() const {
|
||||
return new PacketRecord(_lod, _server->getData());
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
|
||||
#include <ThreadedAssignment.h>
|
||||
|
||||
#include <DatagramSequencer.h>
|
||||
#include <MetavoxelData.h>
|
||||
#include <Endpoint.h>
|
||||
|
||||
class MetavoxelEditMessage;
|
||||
class MetavoxelSession;
|
||||
|
@ -53,46 +52,31 @@ private:
|
|||
};
|
||||
|
||||
/// Contains the state of a single client session.
|
||||
class MetavoxelSession : public NodeData {
|
||||
class MetavoxelSession : public Endpoint {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSession(MetavoxelServer* server, const SharedNodePointer& node);
|
||||
virtual ~MetavoxelSession();
|
||||
MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server);
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
virtual void update();
|
||||
|
||||
void sendDelta();
|
||||
protected:
|
||||
|
||||
virtual void writeUpdateMessage(Bitstream& out);
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void sendData(const QByteArray& data);
|
||||
|
||||
void readPacket(Bitstream& in);
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
|
||||
void handleMessage(const QVariant& message);
|
||||
|
||||
private:
|
||||
|
||||
class SendRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
MetavoxelServer* _server;
|
||||
|
||||
DatagramSequencer _sequencer;
|
||||
|
||||
SharedNodePointer _node;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
|
||||
QList<SendRecord> _sendRecords;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelServer_h
|
||||
|
|
|
@ -35,6 +35,8 @@ MetavoxelSystem::MetavoxelSystem() :
|
|||
}
|
||||
|
||||
void MetavoxelSystem::init() {
|
||||
MetavoxelClientManager::init();
|
||||
|
||||
if (!_program.isLinked()) {
|
||||
_program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
|
||||
_program.link();
|
||||
|
@ -43,62 +45,19 @@ void MetavoxelSystem::init() {
|
|||
}
|
||||
_buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||
_buffer.create();
|
||||
|
||||
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
|
||||
}
|
||||
|
||||
SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection(
|
||||
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance) {
|
||||
SharedObjectPointer closestSpanner;
|
||||
float closestDistance = FLT_MAX;
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
float clientDistance;
|
||||
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
||||
origin, direction, attribute, clientDistance);
|
||||
if (clientSpanner && clientDistance < closestDistance) {
|
||||
closestSpanner = clientSpanner;
|
||||
closestDistance = clientDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closestSpanner) {
|
||||
distance = closestDistance;
|
||||
}
|
||||
return closestSpanner;
|
||||
}
|
||||
|
||||
void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->applyEdit(edit, reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
MetavoxelLOD MetavoxelSystem::getLOD() const {
|
||||
const float FIXED_LOD_THRESHOLD = 0.01f;
|
||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
||||
}
|
||||
|
||||
void MetavoxelSystem::simulate(float deltaTime) {
|
||||
// simulate the clients
|
||||
// update the clients
|
||||
_points.clear();
|
||||
_simulateVisitor.setDeltaTime(deltaTime);
|
||||
_simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection());
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->simulate(deltaTime);
|
||||
client->guide(_simulateVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
update();
|
||||
|
||||
_buffer.bind();
|
||||
int bytes = _points.size() * sizeof(Point);
|
||||
|
@ -153,7 +112,7 @@ void MetavoxelSystem::render() {
|
|||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->guide(_renderVisitor);
|
||||
}
|
||||
|
@ -161,11 +120,13 @@ void MetavoxelSystem::render() {
|
|||
}
|
||||
}
|
||||
|
||||
void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
node->setLinkedData(new MetavoxelClient(NodeList::getInstance()->nodeWithUUID(node->getUUID())));
|
||||
}
|
||||
MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
|
||||
return new MetavoxelSystemClient(node, this);
|
||||
}
|
||||
|
||||
void MetavoxelSystem::updateClient(MetavoxelClient* client) {
|
||||
MetavoxelClientManager::updateClient(client);
|
||||
client->guide(_simulateVisitor);
|
||||
}
|
||||
|
||||
MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
|
||||
|
@ -235,115 +196,22 @@ bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& cl
|
|||
return true;
|
||||
}
|
||||
|
||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
||||
_node(node),
|
||||
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) {
|
||||
|
||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
|
||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||
connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
|
||||
|
||||
// insert the baseline send record
|
||||
SendRecord sendRecord = { 0 };
|
||||
_sendRecords.append(sendRecord);
|
||||
|
||||
// insert the baseline receive record
|
||||
ReceiveRecord receiveRecord = { 0, _data };
|
||||
_receiveRecords.append(receiveRecord);
|
||||
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) :
|
||||
MetavoxelClient(node, system) {
|
||||
}
|
||||
|
||||
MetavoxelClient::~MetavoxelClient() {
|
||||
// close the session
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
out << QVariant::fromValue(CloseSessionMessage());
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
|
||||
static MetavoxelLOD getLOD() {
|
||||
const float FIXED_LOD_THRESHOLD = 0.01f;
|
||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
||||
}
|
||||
|
||||
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
|
||||
visitor.setLOD(getLOD());
|
||||
_data.guide(visitor);
|
||||
}
|
||||
|
||||
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
if (reliable) {
|
||||
_sequencer.getReliableOutputChannel()->sendMessage(QVariant::fromValue(edit));
|
||||
|
||||
} else {
|
||||
// apply immediately to local tree
|
||||
edit.apply(_data, _sequencer.getWeakSharedObjectHash());
|
||||
|
||||
// start sending it out
|
||||
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClient::simulate(float deltaTime) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
|
||||
ClientStateMessage state = { getLOD() };
|
||||
out << QVariant::fromValue(state);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer.getOutgoingPacketNumber(), state.lod };
|
||||
_sendRecords.append(record);
|
||||
}
|
||||
|
||||
int MetavoxelClient::parseData(const QByteArray& packet) {
|
||||
int MetavoxelSystemClient::parseData(const QByteArray& packet) {
|
||||
// process through sequencer
|
||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
void MetavoxelClient::sendData(const QByteArray& data) {
|
||||
void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
||||
}
|
||||
|
||||
void MetavoxelClient::readPacket(Bitstream& in) {
|
||||
QVariant message;
|
||||
in >> message;
|
||||
handleMessage(message, in);
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data, _sendRecords.first().lod };
|
||||
_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, _sequencer.getWeakSharedObjectHash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearSendRecordsBefore(int index) {
|
||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
||||
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||
}
|
||||
|
||||
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
int userType = message.userType();
|
||||
if (userType == MetavoxelDeltaMessage::Type) {
|
||||
_data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
|
||||
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
|
||||
GLdouble coefficients[] = { x, y, z, w };
|
||||
glClipPlane(plane, coefficients);
|
||||
|
|
|
@ -18,37 +18,31 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
#include <DatagramSequencer.h>
|
||||
#include <MetavoxelData.h>
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelClientManager.h>
|
||||
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
class Model;
|
||||
|
||||
/// Renders a metavoxel tree.
|
||||
class MetavoxelSystem : public QObject {
|
||||
class MetavoxelSystem : public MetavoxelClientManager {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSystem();
|
||||
|
||||
void init();
|
||||
|
||||
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const AttributePointer& attribute, float& distance);
|
||||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
virtual void init();
|
||||
|
||||
virtual MetavoxelLOD getLOD() const;
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
private slots:
|
||||
|
||||
void maybeAttachClient(const SharedNodePointer& node);
|
||||
protected:
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
virtual void updateClient(MetavoxelClient* client);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -89,59 +83,18 @@ private:
|
|||
};
|
||||
|
||||
/// A client session associated with a single server.
|
||||
class MetavoxelClient : public NodeData {
|
||||
class MetavoxelSystemClient : public MetavoxelClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelClient(const SharedNodePointer& node);
|
||||
virtual ~MetavoxelClient();
|
||||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
|
||||
void simulate(float deltaTime);
|
||||
|
||||
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system);
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
private slots:
|
||||
protected:
|
||||
|
||||
void sendData(const QByteArray& data);
|
||||
|
||||
void readPacket(Bitstream& in);
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
|
||||
void clearReceiveRecordsBefore(int index);
|
||||
|
||||
private:
|
||||
|
||||
void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
class SendRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
class ReceiveRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
SharedNodePointer _node;
|
||||
|
||||
DatagramSequencer _sequencer;
|
||||
|
||||
MetavoxelData _data;
|
||||
|
||||
QList<SendRecord> _sendRecords;
|
||||
QList<ReceiveRecord> _receiveRecords;
|
||||
virtual void sendDatagram(const QByteArray& data);
|
||||
};
|
||||
|
||||
/// Base class for spanner renderers; provides clipping.
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <QVBoxLayout>
|
||||
|
||||
#include <AttributeRegistry.h>
|
||||
#include <MetavoxelMessages.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MetavoxelEditor.h"
|
||||
|
|
|
@ -1414,8 +1414,10 @@ Bitstream& Bitstream::operator<(const SharedObjectPointer& object) {
|
|||
*this << object->getOriginID();
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(object->getOriginID());
|
||||
if (reference) {
|
||||
*this << true;
|
||||
writeRawDelta((const QObject*)object.data(), (const QObject*)reference.data());
|
||||
} else {
|
||||
*this << false;
|
||||
*this << (QObject*)object.data();
|
||||
}
|
||||
return *this;
|
||||
|
@ -1430,19 +1432,27 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
}
|
||||
int originID;
|
||||
*this >> originID;
|
||||
bool delta;
|
||||
*this >> delta;
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(originID);
|
||||
QPointer<SharedObject>& pointer = _weakSharedObjectHash[id];
|
||||
if (pointer) {
|
||||
ObjectStreamerPointer objectStreamer;
|
||||
_objectStreamerStreamer >> objectStreamer;
|
||||
if (reference) {
|
||||
if (delta) {
|
||||
if (!reference) {
|
||||
qWarning() << "Delta without reference" << id << originID;
|
||||
}
|
||||
objectStreamer->readRawDelta(*this, reference.data(), pointer.data());
|
||||
} else {
|
||||
objectStreamer->read(*this, pointer.data());
|
||||
}
|
||||
} else {
|
||||
QObject* rawObject;
|
||||
if (reference) {
|
||||
if (delta) {
|
||||
if (!reference) {
|
||||
qWarning() << "Delta without reference" << id << originID;
|
||||
}
|
||||
readRawDelta(rawObject, (const QObject*)reference.data());
|
||||
} else {
|
||||
*this >> rawObject;
|
||||
|
|
|
@ -140,6 +140,12 @@ void DatagramSequencer::endPacket() {
|
|||
_outgoingPacketStream.device()->seek(0);
|
||||
}
|
||||
|
||||
void DatagramSequencer::cancelPacket() {
|
||||
_outputStream.reset();
|
||||
_outputStream.getAndResetWriteMappings();
|
||||
_outgoingPacketStream.device()->seek(0);
|
||||
}
|
||||
|
||||
/// Simple RAII-style object to keep a device open when in scope.
|
||||
class QIODeviceOpener {
|
||||
public:
|
||||
|
|
|
@ -111,6 +111,9 @@ public:
|
|||
/// Sends the packet currently being written.
|
||||
void endPacket();
|
||||
|
||||
/// Cancels the packet currently being written.
|
||||
void cancelPacket();
|
||||
|
||||
/// Processes a datagram received from the other party, emitting readyToRead when the entire packet
|
||||
/// has been successfully assembled.
|
||||
Q_INVOKABLE void receivedDatagram(const QByteArray& datagram);
|
||||
|
|
109
libraries/metavoxels/src/Endpoint.cpp
Normal file
109
libraries/metavoxels/src/Endpoint.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// Endpoint.cpp
|
||||
// libraries/metavoxels/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 6/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include "Endpoint.h"
|
||||
|
||||
Endpoint::Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendRecord, PacketRecord* baselineReceiveRecord) :
|
||||
_node(node),
|
||||
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) {
|
||||
|
||||
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&)));
|
||||
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||
connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
|
||||
|
||||
// insert the baseline send and receive records
|
||||
_sendRecords.append(baselineSendRecord);
|
||||
_receiveRecords.append(baselineReceiveRecord);
|
||||
}
|
||||
|
||||
Endpoint::~Endpoint() {
|
||||
foreach (PacketRecord* record, _sendRecords) {
|
||||
delete record;
|
||||
}
|
||||
foreach (PacketRecord* record, _receiveRecords) {
|
||||
delete record;
|
||||
}
|
||||
}
|
||||
|
||||
void Endpoint::update() {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
writeUpdateMessage(out);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
_sendRecords.append(maybeCreateSendRecord());
|
||||
}
|
||||
|
||||
int Endpoint::parseData(const QByteArray& packet) {
|
||||
// process through sequencer
|
||||
_sequencer.receivedDatagram(packet);
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
void Endpoint::sendDatagram(const QByteArray& data) {
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
}
|
||||
|
||||
void Endpoint::readMessage(Bitstream& in) {
|
||||
QVariant message;
|
||||
in >> message;
|
||||
handleMessage(message, in);
|
||||
|
||||
// record the receipt
|
||||
_receiveRecords.append(maybeCreateReceiveRecord());
|
||||
}
|
||||
|
||||
void Endpoint::clearSendRecordsBefore(int index) {
|
||||
QList<PacketRecord*>::iterator end = _sendRecords.begin() + index + 1;
|
||||
for (QList<PacketRecord*>::const_iterator it = _sendRecords.begin(); it != end; it++) {
|
||||
delete *it;
|
||||
}
|
||||
_sendRecords.erase(_sendRecords.begin(), end);
|
||||
}
|
||||
|
||||
void Endpoint::clearReceiveRecordsBefore(int index) {
|
||||
QList<PacketRecord*>::iterator end = _receiveRecords.begin() + index + 1;
|
||||
for (QList<PacketRecord*>::const_iterator it = _receiveRecords.begin(); it != end; it++) {
|
||||
delete *it;
|
||||
}
|
||||
_receiveRecords.erase(_receiveRecords.begin(), end);
|
||||
}
|
||||
|
||||
void Endpoint::writeUpdateMessage(Bitstream& out) {
|
||||
out << QVariant();
|
||||
}
|
||||
|
||||
void Endpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
if (message.userType() == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PacketRecord* Endpoint::maybeCreateSendRecord() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PacketRecord* Endpoint::maybeCreateReceiveRecord() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PacketRecord::PacketRecord(const MetavoxelLOD& lod, const MetavoxelData& data) :
|
||||
_lod(lod),
|
||||
_data(data) {
|
||||
}
|
||||
|
||||
PacketRecord::~PacketRecord() {
|
||||
}
|
78
libraries/metavoxels/src/Endpoint.h
Normal file
78
libraries/metavoxels/src/Endpoint.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// Endpoint.h
|
||||
// libraries/metavoxels/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 6/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Endpoint_h
|
||||
#define hifi_Endpoint_h
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "DatagramSequencer.h"
|
||||
#include "MetavoxelData.h"
|
||||
|
||||
class PacketRecord;
|
||||
|
||||
/// Base class for communication endpoints: clients and server sessions.
|
||||
class Endpoint : public NodeData {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendRecord = NULL,
|
||||
PacketRecord* baselineReceiveRecord = NULL);
|
||||
virtual ~Endpoint();
|
||||
|
||||
virtual void update();
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void sendDatagram(const QByteArray& data);
|
||||
virtual void readMessage(Bitstream& in);
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
void clearReceiveRecordsBefore(int index);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void writeUpdateMessage(Bitstream& out);
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
virtual PacketRecord* maybeCreateReceiveRecord() const;
|
||||
|
||||
PacketRecord* getLastAcknowledgedSendRecord() const { return _sendRecords.first(); }
|
||||
PacketRecord* getLastAcknowledgedReceiveRecord() const { return _receiveRecords.first(); }
|
||||
|
||||
SharedNodePointer _node;
|
||||
DatagramSequencer _sequencer;
|
||||
|
||||
QList<PacketRecord*> _sendRecords;
|
||||
QList<PacketRecord*> _receiveRecords;
|
||||
};
|
||||
|
||||
/// Base class for packet records.
|
||||
class PacketRecord {
|
||||
public:
|
||||
|
||||
PacketRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData());
|
||||
virtual ~PacketRecord();
|
||||
|
||||
const MetavoxelLOD& getLOD() const { return _lod; }
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
MetavoxelData _data;
|
||||
};
|
||||
|
||||
#endif // hifi_Endpoint_h
|
142
libraries/metavoxels/src/MetavoxelClientManager.cpp
Normal file
142
libraries/metavoxels/src/MetavoxelClientManager.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// MetavoxelClientManager.cpp
|
||||
// libraries/metavoxels/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 6/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MetavoxelClientManager.h"
|
||||
#include "MetavoxelMessages.h"
|
||||
|
||||
void MetavoxelClientManager::init() {
|
||||
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::update() {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
updateClient(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(const glm::vec3& origin,
|
||||
const glm::vec3& direction, const AttributePointer& attribute, float& distance) {
|
||||
SharedObjectPointer closestSpanner;
|
||||
float closestDistance = FLT_MAX;
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
float clientDistance;
|
||||
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
||||
origin, direction, attribute, clientDistance);
|
||||
if (clientSpanner && clientDistance < closestDistance) {
|
||||
closestSpanner = clientSpanner;
|
||||
closestDistance = clientDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closestSpanner) {
|
||||
distance = closestDistance;
|
||||
}
|
||||
return closestSpanner;
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->applyEdit(edit, reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelLOD MetavoxelClientManager::getLOD() const {
|
||||
return MetavoxelLOD();
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::maybeAttachClient(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
node->setLinkedData(createClient(node));
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelClient* MetavoxelClientManager::createClient(const SharedNodePointer& node) {
|
||||
return new MetavoxelClient(node, this);
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::updateClient(MetavoxelClient* client) {
|
||||
client->update();
|
||||
}
|
||||
|
||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) :
|
||||
Endpoint(node, new PacketRecord(), new PacketRecord()),
|
||||
_manager(manager) {
|
||||
}
|
||||
|
||||
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
|
||||
visitor.setLOD(_manager->getLOD());
|
||||
_data.guide(visitor);
|
||||
}
|
||||
|
||||
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
if (reliable) {
|
||||
_sequencer.getReliableOutputChannel()->sendMessage(QVariant::fromValue(edit));
|
||||
|
||||
} else {
|
||||
// apply immediately to local tree
|
||||
edit.apply(_data, _sequencer.getWeakSharedObjectHash());
|
||||
|
||||
// start sending it out
|
||||
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClient::writeUpdateMessage(Bitstream& out) {
|
||||
ClientStateMessage state = { _manager->getLOD() };
|
||||
out << QVariant::fromValue(state);
|
||||
}
|
||||
|
||||
void MetavoxelClient::readMessage(Bitstream& in) {
|
||||
Endpoint::readMessage(in);
|
||||
|
||||
// reapply local edits
|
||||
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
|
||||
if (message.data.userType() == MetavoxelEditMessage::Type) {
|
||||
message.data.value<MetavoxelEditMessage>().apply(_data, _sequencer.getWeakSharedObjectHash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
if (message.userType() == MetavoxelDeltaMessage::Type) {
|
||||
PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord();
|
||||
_data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD());
|
||||
|
||||
} else {
|
||||
Endpoint::handleMessage(message, in);
|
||||
}
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateSendRecord() const {
|
||||
return new PacketRecord(_manager->getLOD());
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const {
|
||||
return new PacketRecord(getLastAcknowledgedSendRecord()->getLOD(), _data);
|
||||
}
|
75
libraries/metavoxels/src/MetavoxelClientManager.h
Normal file
75
libraries/metavoxels/src/MetavoxelClientManager.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// MetavoxelClientManager.h
|
||||
// libraries/metavoxels/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 6/26/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MetavoxelClientManager_h
|
||||
#define hifi_MetavoxelClientManager_h
|
||||
|
||||
#include "Endpoint.h"
|
||||
|
||||
class MetavoxelClient;
|
||||
class MetavoxelEditMessage;
|
||||
|
||||
/// Manages the set of connected metavoxel clients.
|
||||
class MetavoxelClientManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
virtual void init();
|
||||
void update();
|
||||
|
||||
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const AttributePointer& attribute, float& distance);
|
||||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
|
||||
virtual MetavoxelLOD getLOD() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void maybeAttachClient(const SharedNodePointer& node);
|
||||
|
||||
protected:
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
virtual void updateClient(MetavoxelClient* client);
|
||||
};
|
||||
|
||||
/// Base class for metavoxel clients.
|
||||
class MetavoxelClient : public Endpoint {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager);
|
||||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void writeUpdateMessage(Bitstream& out);
|
||||
virtual void readMessage(Bitstream& in);
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
virtual PacketRecord* maybeCreateReceiveRecord() const;
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelClientManager* _manager;
|
||||
MetavoxelData _data;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelClientManager_h
|
|
@ -27,6 +27,7 @@ include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
|||
# link in the shared libraries
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
IF (WIN32)
|
||||
|
|
|
@ -440,6 +440,8 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
|
|||
}
|
||||
|
||||
bool MetavoxelTests::run() {
|
||||
LimitedNodeList::createInstance();
|
||||
|
||||
// seed the random number generator so that our tests are reproducible
|
||||
srand(0xBAAAAABE);
|
||||
|
||||
|
@ -456,14 +458,13 @@ bool MetavoxelTests::run() {
|
|||
}
|
||||
}
|
||||
|
||||
QByteArray datagramHeader("testheader");
|
||||
const int SIMULATION_ITERATIONS = 10000;
|
||||
if (test == 0 || test == 2) {
|
||||
qDebug() << "Running transmission test...";
|
||||
qDebug();
|
||||
|
||||
// create two endpoints with the same header
|
||||
Endpoint alice(datagramHeader), bob(datagramHeader);
|
||||
TestEndpoint alice, bob;
|
||||
|
||||
alice.setOther(&bob);
|
||||
bob.setOther(&alice);
|
||||
|
@ -497,7 +498,7 @@ bool MetavoxelTests::run() {
|
|||
datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
||||
|
||||
// create two endpoints with the same header
|
||||
Endpoint alice(datagramHeader, Endpoint::CONGESTION_MODE), bob(datagramHeader, Endpoint::CONGESTION_MODE);
|
||||
TestEndpoint alice(TestEndpoint::CONGESTION_MODE), bob(TestEndpoint::CONGESTION_MODE);
|
||||
|
||||
alice.setOther(&bob);
|
||||
bob.setOther(&alice);
|
||||
|
@ -537,8 +538,8 @@ bool MetavoxelTests::run() {
|
|||
datagramsSent = bytesSent = datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
||||
|
||||
// create client and server endpoints
|
||||
Endpoint client(datagramHeader, Endpoint::METAVOXEL_CLIENT_MODE);
|
||||
Endpoint server(datagramHeader, Endpoint::METAVOXEL_SERVER_MODE);
|
||||
TestEndpoint client(TestEndpoint::METAVOXEL_CLIENT_MODE);
|
||||
TestEndpoint server(TestEndpoint::METAVOXEL_SERVER_MODE);
|
||||
|
||||
client.setOther(&server);
|
||||
server.setOther(&client);
|
||||
|
@ -599,28 +600,57 @@ int RandomVisitor::visit(MetavoxelInfo& info) {
|
|||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) :
|
||||
class TestSendRecord : public PacketRecord {
|
||||
public:
|
||||
|
||||
TestSendRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData(),
|
||||
const SharedObjectPointer& localState = SharedObjectPointer(), int packetNumber = 0);
|
||||
|
||||
const SharedObjectPointer& getLocalState() const { return _localState; }
|
||||
int getPacketNumber() const { return _packetNumber; }
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectPointer _localState;
|
||||
int _packetNumber;
|
||||
|
||||
};
|
||||
|
||||
TestSendRecord::TestSendRecord(const MetavoxelLOD& lod, const MetavoxelData& data,
|
||||
const SharedObjectPointer& localState, int packetNumber) :
|
||||
PacketRecord(lod, data),
|
||||
_localState(localState),
|
||||
_packetNumber(packetNumber) {
|
||||
}
|
||||
|
||||
class TestReceiveRecord : public PacketRecord {
|
||||
public:
|
||||
|
||||
TestReceiveRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData(),
|
||||
const SharedObjectPointer& remoteState = SharedObjectPointer());
|
||||
|
||||
const SharedObjectPointer& getRemoteState() const { return _remoteState; }
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectPointer _remoteState;
|
||||
};
|
||||
|
||||
TestReceiveRecord::TestReceiveRecord(const MetavoxelLOD& lod,
|
||||
const MetavoxelData& data, const SharedObjectPointer& remoteState) :
|
||||
PacketRecord(lod, data),
|
||||
_remoteState(remoteState) {
|
||||
}
|
||||
|
||||
TestEndpoint::TestEndpoint(Mode mode) :
|
||||
Endpoint(SharedNodePointer(), new TestSendRecord(), new TestReceiveRecord()),
|
||||
_mode(mode),
|
||||
_sequencer(new DatagramSequencer(datagramHeader, this)),
|
||||
_highPriorityMessagesToSend(0.0f),
|
||||
_reliableMessagesToSend(0.0f) {
|
||||
|
||||
connect(_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&)));
|
||||
connect(_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&)));
|
||||
connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)),
|
||||
connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)),
|
||||
SLOT(handleHighPriorityMessage(const QVariant&)));
|
||||
|
||||
connect(_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||
connect(_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
|
||||
|
||||
// insert the baseline send record
|
||||
SendRecord sendRecord = { 0 };
|
||||
_sendRecords.append(sendRecord);
|
||||
|
||||
// insert the baseline receive record
|
||||
ReceiveRecord receiveRecord = { 0 };
|
||||
_receiveRecords.append(receiveRecord);
|
||||
|
||||
if (mode == METAVOXEL_CLIENT_MODE) {
|
||||
_lod = MetavoxelLOD(glm::vec3(), 0.01f);
|
||||
return;
|
||||
|
@ -643,15 +673,15 @@ Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) :
|
|||
// create the object that represents out delta-encoded state
|
||||
_localState = new TestSharedObjectA();
|
||||
|
||||
connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)),
|
||||
connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)),
|
||||
SLOT(handleReliableMessage(const QVariant&)));
|
||||
|
||||
ReliableChannel* secondInput = _sequencer->getReliableInputChannel(1);
|
||||
ReliableChannel* secondInput = _sequencer.getReliableInputChannel(1);
|
||||
secondInput->setMessagesEnabled(false);
|
||||
connect(&secondInput->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel()));
|
||||
|
||||
// enqueue a large amount of data in a low-priority channel
|
||||
ReliableChannel* output = _sequencer->getReliableOutputChannel(1);
|
||||
ReliableChannel* output = _sequencer.getReliableOutputChannel(1);
|
||||
output->setPriority(0.25f);
|
||||
output->setMessagesEnabled(false);
|
||||
QByteArray bytes;
|
||||
|
@ -800,11 +830,11 @@ int MutateVisitor::visit(MetavoxelInfo& info) {
|
|||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
bool Endpoint::simulate(int iterationNumber) {
|
||||
bool TestEndpoint::simulate(int iterationNumber) {
|
||||
// update/send our delayed datagrams
|
||||
for (QList<ByteArrayIntPair>::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) {
|
||||
if (it->second-- == 1) {
|
||||
_other->receiveDatagram(it->first);
|
||||
_other->parseData(it->first);
|
||||
it = _delayedDatagrams.erase(it);
|
||||
|
||||
} else {
|
||||
|
@ -819,41 +849,39 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
ByteArrayVector datagrams = _pipeline.takeLast();
|
||||
_pipeline.prepend(ByteArrayVector());
|
||||
foreach (const QByteArray& datagram, datagrams) {
|
||||
_sequencer->receivedDatagram(datagram);
|
||||
_sequencer.receivedDatagram(datagram);
|
||||
datagramsReceived++;
|
||||
bytesReceived += datagram.size();
|
||||
_remainingPipelineCapacity += datagram.size();
|
||||
}
|
||||
int packetCount = _sequencer->startPacketGroup();
|
||||
int packetCount = _sequencer.startPacketGroup();
|
||||
groupsSent++;
|
||||
maxPacketsPerGroup = qMax(maxPacketsPerGroup, packetCount);
|
||||
for (int i = 0; i < packetCount; i++) {
|
||||
oldDatagramsSent = datagramsSent;
|
||||
oldBytesSent = bytesSent;
|
||||
|
||||
Bitstream& out = _sequencer->startPacket();
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
out << QVariant();
|
||||
_sequencer->endPacket();
|
||||
_sequencer.endPacket();
|
||||
|
||||
maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent);
|
||||
maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent);
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer->getOutgoingPacketNumber() };
|
||||
_sendRecords.append(record);
|
||||
_sendRecords.append(maybeCreateSendRecord());
|
||||
}
|
||||
return false;
|
||||
|
||||
} else if (_mode == METAVOXEL_CLIENT_MODE) {
|
||||
Bitstream& out = _sequencer->startPacket();
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
|
||||
ClientStateMessage state = { _lod };
|
||||
out << QVariant::fromValue(state);
|
||||
_sequencer->endPacket();
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer->getOutgoingPacketNumber(), SharedObjectPointer(), MetavoxelData(), _lod };
|
||||
_sendRecords.append(record);
|
||||
_sendRecords.append(maybeCreateSendRecord());
|
||||
|
||||
} else if (_mode == METAVOXEL_SERVER_MODE) {
|
||||
// make a random change
|
||||
|
@ -879,16 +907,15 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
if (!_lod.isValid()) {
|
||||
return false;
|
||||
}
|
||||
Bitstream& out = _sequencer->startPacket();
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||
_data.writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod);
|
||||
|
||||
PacketRecord* sendRecord = getLastAcknowledgedSendRecord();
|
||||
_data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
|
||||
_sequencer.endPacket();
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer->getOutgoingPacketNumber() + 1, SharedObjectPointer(), _data, _lod };
|
||||
_sendRecords.append(record);
|
||||
|
||||
_sequencer->endPacket();
|
||||
|
||||
_sendRecords.append(maybeCreateSendRecord());
|
||||
|
||||
} else {
|
||||
// enqueue some number of high priority messages
|
||||
const float MIN_HIGH_PRIORITY_MESSAGES = 0.0f;
|
||||
|
@ -897,7 +924,7 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
while (_highPriorityMessagesToSend >= 1.0f) {
|
||||
QVariant message = createRandomMessage();
|
||||
_highPriorityMessagesSent.append(message);
|
||||
_sequencer->sendHighPriorityMessage(message);
|
||||
_sequencer.sendHighPriorityMessage(message);
|
||||
highPriorityMessagesSent++;
|
||||
_highPriorityMessagesToSend -= 1.0f;
|
||||
}
|
||||
|
@ -909,7 +936,7 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
while (_reliableMessagesToSend >= 1.0f) {
|
||||
QVariant message = createRandomMessage();
|
||||
_reliableMessagesSent.append(message);
|
||||
_sequencer->getReliableOutputChannel()->sendMessage(message);
|
||||
_sequencer.getReliableOutputChannel()->sendMessage(message);
|
||||
reliableMessagesSent++;
|
||||
_reliableMessagesToSend -= 1.0f;
|
||||
}
|
||||
|
@ -919,12 +946,12 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
|
||||
// send a packet
|
||||
try {
|
||||
Bitstream& out = _sequencer->startPacket();
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState };
|
||||
_unreliableMessagesSent.append(message);
|
||||
unreliableMessagesSent++;
|
||||
out << message;
|
||||
_sequencer->endPacket();
|
||||
_sequencer.endPacket();
|
||||
|
||||
} catch (const QString& message) {
|
||||
qDebug() << message;
|
||||
|
@ -932,15 +959,29 @@ bool Endpoint::simulate(int iterationNumber) {
|
|||
}
|
||||
|
||||
// record the send
|
||||
SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState };
|
||||
_sendRecords.append(record);
|
||||
_sendRecords.append(maybeCreateSendRecord());
|
||||
}
|
||||
maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent);
|
||||
maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Endpoint::sendDatagram(const QByteArray& datagram) {
|
||||
int TestEndpoint::parseData(const QByteArray& packet) {
|
||||
if (_mode == CONGESTION_MODE) {
|
||||
if (packet.size() <= _remainingPipelineCapacity) {
|
||||
// have to copy the datagram; the one we're passed is a reference to a shared buffer
|
||||
_pipeline[0].append(QByteArray(packet.constData(), packet.size()));
|
||||
_remainingPipelineCapacity -= packet.size();
|
||||
}
|
||||
} else {
|
||||
_sequencer.receivedDatagram(packet);
|
||||
datagramsReceived++;
|
||||
bytesReceived += packet.size();
|
||||
}
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
void TestEndpoint::sendDatagram(const QByteArray& datagram) {
|
||||
datagramsSent++;
|
||||
bytesSent += datagram.size();
|
||||
|
||||
|
@ -967,31 +1008,16 @@ void Endpoint::sendDatagram(const QByteArray& datagram) {
|
|||
}
|
||||
}
|
||||
|
||||
_other->receiveDatagram(datagram);
|
||||
_other->parseData(datagram);
|
||||
}
|
||||
|
||||
void Endpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||
if (message.userType() == ClearSharedObjectMessage::Type) {
|
||||
return;
|
||||
}
|
||||
if (_other->_highPriorityMessagesSent.isEmpty()) {
|
||||
throw QString("Received unsent/already sent high priority message.");
|
||||
}
|
||||
QVariant sentMessage = _other->_highPriorityMessagesSent.takeFirst();
|
||||
if (!messagesEqual(message, sentMessage)) {
|
||||
throw QString("Sent/received high priority message mismatch.");
|
||||
}
|
||||
highPriorityMessagesReceived++;
|
||||
}
|
||||
|
||||
void Endpoint::readMessage(Bitstream& in) {
|
||||
void TestEndpoint::readMessage(Bitstream& in) {
|
||||
if (_mode == CONGESTION_MODE) {
|
||||
QVariant message;
|
||||
in >> message;
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _sequencer->getIncomingPacketNumber() };
|
||||
_receiveRecords.append(record);
|
||||
_receiveRecords.append(maybeCreateReceiveRecord());
|
||||
return;
|
||||
}
|
||||
if (_mode == METAVOXEL_CLIENT_MODE) {
|
||||
|
@ -1000,10 +1026,11 @@ void Endpoint::readMessage(Bitstream& in) {
|
|||
handleMessage(message, in);
|
||||
|
||||
// deep-compare data to sent version
|
||||
int packetNumber = _sequencer->getIncomingPacketNumber();
|
||||
foreach (const SendRecord& sendRecord, _other->_sendRecords) {
|
||||
if (sendRecord.packetNumber == packetNumber) {
|
||||
if (!sendRecord.data.deepEquals(_data, _sendRecords.first().lod)) {
|
||||
int packetNumber = _sequencer.getIncomingPacketNumber();
|
||||
foreach (PacketRecord* record, _other->_sendRecords) {
|
||||
TestSendRecord* sendRecord = static_cast<TestSendRecord*>(record);
|
||||
if (sendRecord->getPacketNumber() == packetNumber) {
|
||||
if (!sendRecord->getData().deepEquals(_data, getLastAcknowledgedSendRecord()->getLOD())) {
|
||||
qDebug() << "Sent/received metavoxel data mismatch.";
|
||||
exit(true);
|
||||
}
|
||||
|
@ -1012,8 +1039,7 @@ void Endpoint::readMessage(Bitstream& in) {
|
|||
}
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { packetNumber, SharedObjectPointer(), _data, _sendRecords.first().lod };
|
||||
_receiveRecords.append(record);
|
||||
_receiveRecords.append(maybeCreateReceiveRecord());
|
||||
return;
|
||||
}
|
||||
if (_mode == METAVOXEL_SERVER_MODE) {
|
||||
|
@ -1022,8 +1048,7 @@ void Endpoint::readMessage(Bitstream& in) {
|
|||
handleMessage(message, in);
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _sequencer->getIncomingPacketNumber() };
|
||||
_receiveRecords.append(record);
|
||||
_receiveRecords.append(maybeCreateReceiveRecord());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1033,8 +1058,7 @@ void Endpoint::readMessage(Bitstream& in) {
|
|||
_remoteState = message.state;
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state };
|
||||
_receiveRecords.append(record);
|
||||
_receiveRecords.append(maybeCreateReceiveRecord());
|
||||
|
||||
for (QList<SequencedTestMessage>::iterator it = _other->_unreliableMessagesSent.begin();
|
||||
it != _other->_unreliableMessagesSent.end(); it++) {
|
||||
|
@ -1056,7 +1080,48 @@ void Endpoint::readMessage(Bitstream& in) {
|
|||
exit(true);
|
||||
}
|
||||
|
||||
void Endpoint::handleReliableMessage(const QVariant& message) {
|
||||
void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
int userType = message.userType();
|
||||
if (userType == ClientStateMessage::Type) {
|
||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||
_lod = state.lod;
|
||||
|
||||
} else if (userType == MetavoxelDeltaMessage::Type) {
|
||||
PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord();
|
||||
_data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD());
|
||||
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PacketRecord* TestEndpoint::maybeCreateSendRecord() const {
|
||||
return new TestSendRecord(_lod, (_mode == METAVOXEL_CLIENT_MODE) ? MetavoxelData() : _data,
|
||||
_localState, _sequencer.getOutgoingPacketNumber());
|
||||
}
|
||||
|
||||
PacketRecord* TestEndpoint::maybeCreateReceiveRecord() const {
|
||||
return new TestReceiveRecord(getLastAcknowledgedSendRecord()->getLOD(),
|
||||
(_mode == METAVOXEL_SERVER_MODE) ? MetavoxelData() : _data, _remoteState);
|
||||
}
|
||||
|
||||
void TestEndpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||
if (message.userType() == ClearSharedObjectMessage::Type) {
|
||||
return;
|
||||
}
|
||||
if (_other->_highPriorityMessagesSent.isEmpty()) {
|
||||
throw QString("Received unsent/already sent high priority message.");
|
||||
}
|
||||
QVariant sentMessage = _other->_highPriorityMessagesSent.takeFirst();
|
||||
if (!messagesEqual(message, sentMessage)) {
|
||||
throw QString("Sent/received high priority message mismatch.");
|
||||
}
|
||||
highPriorityMessagesReceived++;
|
||||
}
|
||||
|
||||
void TestEndpoint::handleReliableMessage(const QVariant& message) {
|
||||
if (message.userType() == ClearSharedObjectMessage::Type ||
|
||||
message.userType() == ClearMainChannelSharedObjectMessage::Type) {
|
||||
return;
|
||||
|
@ -1071,8 +1136,8 @@ void Endpoint::handleReliableMessage(const QVariant& message) {
|
|||
reliableMessagesReceived++;
|
||||
}
|
||||
|
||||
void Endpoint::readReliableChannel() {
|
||||
CircularBuffer& buffer = _sequencer->getReliableInputChannel(1)->getBuffer();
|
||||
void TestEndpoint::readReliableChannel() {
|
||||
CircularBuffer& buffer = _sequencer.getReliableInputChannel(1)->getBuffer();
|
||||
QByteArray bytes = buffer.read(buffer.bytesAvailable());
|
||||
if (_other->_dataStreamed.size() < bytes.size()) {
|
||||
throw QString("Received unsent/already sent streamed data.");
|
||||
|
@ -1085,44 +1150,6 @@ void Endpoint::readReliableChannel() {
|
|||
streamedBytesReceived += bytes.size();
|
||||
}
|
||||
|
||||
void Endpoint::clearSendRecordsBefore(int index) {
|
||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||
}
|
||||
|
||||
void Endpoint::clearReceiveRecordsBefore(int index) {
|
||||
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||
}
|
||||
|
||||
void Endpoint::receiveDatagram(const QByteArray& datagram) {
|
||||
if (_mode == CONGESTION_MODE) {
|
||||
if (datagram.size() <= _remainingPipelineCapacity) {
|
||||
// have to copy the datagram; the one we're passed is a reference to a shared buffer
|
||||
_pipeline[0].append(QByteArray(datagram.constData(), datagram.size()));
|
||||
_remainingPipelineCapacity -= datagram.size();
|
||||
}
|
||||
} else {
|
||||
_sequencer->receivedDatagram(datagram);
|
||||
datagramsReceived++;
|
||||
bytesReceived += datagram.size();
|
||||
}
|
||||
}
|
||||
|
||||
void Endpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
int userType = message.userType();
|
||||
if (userType == ClientStateMessage::Type) {
|
||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||
_lod = state.lod;
|
||||
|
||||
} else if (userType == MetavoxelDeltaMessage::Type) {
|
||||
_data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
|
||||
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) :
|
||||
_foo(foo),
|
||||
_baz(baz),
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QVariantList>
|
||||
|
||||
#include <DatagramSequencer.h>
|
||||
#include <MetavoxelData.h>
|
||||
#include <Endpoint.h>
|
||||
#include <ScriptCache.h>
|
||||
|
||||
class SequencedTestMessage;
|
||||
|
@ -35,60 +34,43 @@ public:
|
|||
};
|
||||
|
||||
/// Represents a simulated endpoint.
|
||||
class Endpoint : public QObject {
|
||||
class TestEndpoint : public Endpoint {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum Mode { BASIC_PEER_MODE, CONGESTION_MODE, METAVOXEL_SERVER_MODE, METAVOXEL_CLIENT_MODE };
|
||||
|
||||
Endpoint(const QByteArray& datagramHeader, Mode mode = BASIC_PEER_MODE);
|
||||
TestEndpoint(Mode mode = BASIC_PEER_MODE);
|
||||
|
||||
void setOther(Endpoint* other) { _other = other; }
|
||||
void setOther(TestEndpoint* other) { _other = other; }
|
||||
|
||||
/// Perform a simulation step.
|
||||
/// \return true if failure was detected
|
||||
bool simulate(int iterationNumber);
|
||||
|
||||
private slots:
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
protected:
|
||||
|
||||
void sendDatagram(const QByteArray& datagram);
|
||||
virtual void sendDatagram(const QByteArray& data);
|
||||
virtual void readMessage(Bitstream& in);
|
||||
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
virtual PacketRecord* maybeCreateReceiveRecord() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void handleHighPriorityMessage(const QVariant& message);
|
||||
void readMessage(Bitstream& in);
|
||||
void handleReliableMessage(const QVariant& message);
|
||||
void readReliableChannel();
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
void clearReceiveRecordsBefore(int index);
|
||||
|
||||
private:
|
||||
|
||||
void receiveDatagram(const QByteArray& datagram);
|
||||
|
||||
void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
class SendRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
SharedObjectPointer localState;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
class ReceiveRecord {
|
||||
public:
|
||||
int packetNumber;
|
||||
SharedObjectPointer remoteState;
|
||||
MetavoxelData data;
|
||||
MetavoxelLOD lod;
|
||||
};
|
||||
|
||||
Mode _mode;
|
||||
|
||||
DatagramSequencer* _sequencer;
|
||||
QList<SendRecord> _sendRecords;
|
||||
QList<ReceiveRecord> _receiveRecords;
|
||||
|
||||
SharedObjectPointer _localState;
|
||||
SharedObjectPointer _remoteState;
|
||||
|
||||
|
@ -97,7 +79,7 @@ private:
|
|||
|
||||
SharedObjectPointer _sphere;
|
||||
|
||||
Endpoint* _other;
|
||||
TestEndpoint* _other;
|
||||
|
||||
typedef QPair<QByteArray, int> ByteArrayIntPair;
|
||||
QList<ByteArrayIntPair> _delayedDatagrams;
|
||||
|
|
|
@ -18,9 +18,14 @@ include(${MACRO_DIR}/SetupHifiProject.cmake)
|
|||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
|
||||
|
|
|
@ -18,9 +18,14 @@ include(${MACRO_DIR}/SetupHifiProject.cmake)
|
|||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
|
||||
ENDIF(WIN32)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
|
||||
|
|
Loading…
Reference in a new issue