mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 04:12:46 +02:00
Working on factoring out the common metavoxel endpoint/client code.
This commit is contained in:
parent
463ac9cc74
commit
4b2d122f3d
13 changed files with 453 additions and 38 deletions
|
@ -54,7 +54,7 @@ SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection(
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||||
if (client) {
|
if (client) {
|
||||||
float clientDistance;
|
float clientDistance;
|
||||||
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
||||||
|
@ -76,7 +76,7 @@ void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit, bool reliable)
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||||
if (client) {
|
if (client) {
|
||||||
client->applyEdit(edit, reliable);
|
client->applyEdit(edit, reliable);
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ void MetavoxelSystem::simulate(float deltaTime) {
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||||
if (client) {
|
if (client) {
|
||||||
client->simulate(deltaTime);
|
client->simulate(deltaTime);
|
||||||
client->guide(_simulateVisitor);
|
client->guide(_simulateVisitor);
|
||||||
|
@ -153,7 +153,7 @@ void MetavoxelSystem::render() {
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||||
if (client) {
|
if (client) {
|
||||||
client->guide(_renderVisitor);
|
client->guide(_renderVisitor);
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ void MetavoxelSystem::render() {
|
||||||
void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) {
|
void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) {
|
||||||
if (node->getType() == NodeType::MetavoxelServer) {
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
node->setLinkedData(new MetavoxelClient(NodeList::getInstance()->nodeWithUUID(node->getUUID())));
|
node->setLinkedData(new MetavoxelSystemClient(NodeList::getInstance()->nodeWithUUID(node->getUUID())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& cl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node) :
|
||||||
_node(node),
|
_node(node),
|
||||||
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) {
|
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) {
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
|
||||||
_receiveRecords.append(receiveRecord);
|
_receiveRecords.append(receiveRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelClient::~MetavoxelClient() {
|
MetavoxelSystemClient::~MetavoxelSystemClient() {
|
||||||
// close the session
|
// close the session
|
||||||
Bitstream& out = _sequencer.startPacket();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
out << QVariant::fromValue(CloseSessionMessage());
|
out << QVariant::fromValue(CloseSessionMessage());
|
||||||
|
@ -265,12 +265,12 @@ static MetavoxelLOD getLOD() {
|
||||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
|
void MetavoxelSystemClient::guide(MetavoxelVisitor& visitor) {
|
||||||
visitor.setLOD(getLOD());
|
visitor.setLOD(getLOD());
|
||||||
_data.guide(visitor);
|
_data.guide(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
void MetavoxelSystemClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||||
if (reliable) {
|
if (reliable) {
|
||||||
_sequencer.getReliableOutputChannel()->sendMessage(QVariant::fromValue(edit));
|
_sequencer.getReliableOutputChannel()->sendMessage(QVariant::fromValue(edit));
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::simulate(float deltaTime) {
|
void MetavoxelSystemClient::simulate(float deltaTime) {
|
||||||
Bitstream& out = _sequencer.startPacket();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
|
|
||||||
ClientStateMessage state = { getLOD() };
|
ClientStateMessage state = { getLOD() };
|
||||||
|
@ -295,19 +295,19 @@ void MetavoxelClient::simulate(float deltaTime) {
|
||||||
_sendRecords.append(record);
|
_sendRecords.append(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MetavoxelClient::parseData(const QByteArray& packet) {
|
int MetavoxelSystemClient::parseData(const QByteArray& packet) {
|
||||||
// process through sequencer
|
// process through sequencer
|
||||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
||||||
return packet.size();
|
return packet.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::sendData(const QByteArray& data) {
|
void MetavoxelSystemClient::sendData(const QByteArray& data) {
|
||||||
NodeList::getInstance()->writeDatagram(data, _node);
|
NodeList::getInstance()->writeDatagram(data, _node);
|
||||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::readPacket(Bitstream& in) {
|
void MetavoxelSystemClient::readPacket(Bitstream& in) {
|
||||||
QVariant message;
|
QVariant message;
|
||||||
in >> message;
|
in >> message;
|
||||||
handleMessage(message, in);
|
handleMessage(message, in);
|
||||||
|
@ -324,15 +324,15 @@ void MetavoxelClient::readPacket(Bitstream& in) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::clearSendRecordsBefore(int index) {
|
void MetavoxelSystemClient::clearSendRecordsBefore(int index) {
|
||||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
void MetavoxelSystemClient::clearReceiveRecordsBefore(int index) {
|
||||||
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
void MetavoxelSystemClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||||
int userType = message.userType();
|
int userType = message.userType();
|
||||||
if (userType == MetavoxelDeltaMessage::Type) {
|
if (userType == MetavoxelDeltaMessage::Type) {
|
||||||
_data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
|
_data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
|
||||||
|
|
|
@ -89,13 +89,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A client session associated with a single server.
|
/// A client session associated with a single server.
|
||||||
class MetavoxelClient : public NodeData {
|
class MetavoxelSystemClient : public NodeData {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MetavoxelClient(const SharedNodePointer& node);
|
MetavoxelSystemClient(const SharedNodePointer& node);
|
||||||
virtual ~MetavoxelClient();
|
virtual ~MetavoxelSystemClient();
|
||||||
|
|
||||||
MetavoxelData& getData() { return _data; }
|
MetavoxelData& getData() { return _data; }
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,12 @@ void DatagramSequencer::endPacket() {
|
||||||
_outgoingPacketStream.device()->seek(0);
|
_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.
|
/// Simple RAII-style object to keep a device open when in scope.
|
||||||
class QIODeviceOpener {
|
class QIODeviceOpener {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -111,6 +111,9 @@ public:
|
||||||
/// Sends the packet currently being written.
|
/// Sends the packet currently being written.
|
||||||
void endPacket();
|
void endPacket();
|
||||||
|
|
||||||
|
/// Cancels the packet currently being written.
|
||||||
|
void cancelPacket();
|
||||||
|
|
||||||
/// Processes a datagram received from the other party, emitting readyToRead when the entire packet
|
/// Processes a datagram received from the other party, emitting readyToRead when the entire packet
|
||||||
/// has been successfully assembled.
|
/// has been successfully assembled.
|
||||||
Q_INVOKABLE void receivedDatagram(const QByteArray& datagram);
|
Q_INVOKABLE void receivedDatagram(const QByteArray& datagram);
|
||||||
|
|
108
libraries/metavoxels/src/Endpoint.cpp
Normal file
108
libraries/metavoxels/src/Endpoint.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
//
|
||||||
|
// 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) :
|
||||||
|
_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(maybeCreateSendRecord(true));
|
||||||
|
_receiveRecords.append(maybeCreateReceiveRecord(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint::~Endpoint() {
|
||||||
|
foreach (PacketRecord* record, _sendRecords) {
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
foreach (PacketRecord* record, _receiveRecords) {
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::update() {
|
||||||
|
Bitstream& out = _sequencer.startPacket();
|
||||||
|
out << QVariant();
|
||||||
|
_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(bool baseline) const {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketRecord* Endpoint::maybeCreateReceiveRecord(bool baseline) const {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketRecord::PacketRecord(const MetavoxelLOD& lod) :
|
||||||
|
_lod(lod) {
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketRecord::~PacketRecord() {
|
||||||
|
}
|
75
libraries/metavoxels/src/Endpoint.h
Normal file
75
libraries/metavoxels/src/Endpoint.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// 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 or servers.
|
||||||
|
class Endpoint : public NodeData {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Endpoint(const SharedNodePointer& node);
|
||||||
|
virtual ~Endpoint();
|
||||||
|
|
||||||
|
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(bool baseline = false) const;
|
||||||
|
virtual PacketRecord* maybeCreateReceiveRecord(bool baseline = false) 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());
|
||||||
|
virtual ~PacketRecord();
|
||||||
|
|
||||||
|
const MetavoxelLOD& getLOD() const { return _lod; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MetavoxelLOD _lod;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_Endpoint_h
|
151
libraries/metavoxels/src/MetavoxelClientManager.cpp
Normal file
151
libraries/metavoxels/src/MetavoxelClientManager.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
client->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(new MetavoxelClient(node, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) :
|
||||||
|
Endpoint(node),
|
||||||
|
_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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReceiveRecord : public PacketRecord {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ReceiveRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData());
|
||||||
|
|
||||||
|
const MetavoxelData& getData() const { return _data; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MetavoxelData _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
ReceiveRecord::ReceiveRecord(const MetavoxelLOD& lod, const MetavoxelData& data) :
|
||||||
|
PacketRecord(lod),
|
||||||
|
_data(data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
||||||
|
if (message.userType() == MetavoxelDeltaMessage::Type) {
|
||||||
|
ReceiveRecord* receiveRecord = static_cast<ReceiveRecord*>(getLastAcknowledgedReceiveRecord());
|
||||||
|
_data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Endpoint::handleMessage(message, in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketRecord* MetavoxelClient::maybeCreateSendRecord(bool baseline) const {
|
||||||
|
return baseline ? new PacketRecord() : new PacketRecord(_manager->getLOD());
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketRecord* MetavoxelClient::maybeCreateReceiveRecord(bool baseline) const {
|
||||||
|
return baseline ? new ReceiveRecord() : new ReceiveRecord(getLastAcknowledgedSendRecord()->getLOD(), _data);
|
||||||
|
}
|
69
libraries/metavoxels/src/MetavoxelClientManager.h
Normal file
69
libraries/metavoxels/src/MetavoxelClientManager.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// 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 MetavoxelEditMessage;
|
||||||
|
|
||||||
|
/// Manages the set of connected metavoxel clients.
|
||||||
|
class MetavoxelClientManager : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void init();
|
||||||
|
virtual 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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(bool baseline) const;
|
||||||
|
virtual PacketRecord* maybeCreateReceiveRecord(bool baseline) 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
|
# link in the shared libraries
|
||||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
|
||||||
IF (WIN32)
|
IF (WIN32)
|
||||||
|
|
|
@ -463,7 +463,7 @@ bool MetavoxelTests::run() {
|
||||||
qDebug();
|
qDebug();
|
||||||
|
|
||||||
// create two endpoints with the same header
|
// create two endpoints with the same header
|
||||||
Endpoint alice(datagramHeader), bob(datagramHeader);
|
TestEndpoint alice(datagramHeader), bob(datagramHeader);
|
||||||
|
|
||||||
alice.setOther(&bob);
|
alice.setOther(&bob);
|
||||||
bob.setOther(&alice);
|
bob.setOther(&alice);
|
||||||
|
@ -497,7 +497,7 @@ bool MetavoxelTests::run() {
|
||||||
datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
||||||
|
|
||||||
// create two endpoints with the same header
|
// create two endpoints with the same header
|
||||||
Endpoint alice(datagramHeader, Endpoint::CONGESTION_MODE), bob(datagramHeader, Endpoint::CONGESTION_MODE);
|
TestEndpoint alice(datagramHeader, TestEndpoint::CONGESTION_MODE), bob(datagramHeader, TestEndpoint::CONGESTION_MODE);
|
||||||
|
|
||||||
alice.setOther(&bob);
|
alice.setOther(&bob);
|
||||||
bob.setOther(&alice);
|
bob.setOther(&alice);
|
||||||
|
@ -537,8 +537,8 @@ bool MetavoxelTests::run() {
|
||||||
datagramsSent = bytesSent = datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
datagramsSent = bytesSent = datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
|
||||||
|
|
||||||
// create client and server endpoints
|
// create client and server endpoints
|
||||||
Endpoint client(datagramHeader, Endpoint::METAVOXEL_CLIENT_MODE);
|
TestEndpoint client(datagramHeader, TestEndpoint::METAVOXEL_CLIENT_MODE);
|
||||||
Endpoint server(datagramHeader, Endpoint::METAVOXEL_SERVER_MODE);
|
TestEndpoint server(datagramHeader, TestEndpoint::METAVOXEL_SERVER_MODE);
|
||||||
|
|
||||||
client.setOther(&server);
|
client.setOther(&server);
|
||||||
server.setOther(&client);
|
server.setOther(&client);
|
||||||
|
@ -599,7 +599,7 @@ int RandomVisitor::visit(MetavoxelInfo& info) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) :
|
TestEndpoint::TestEndpoint(const QByteArray& datagramHeader, Mode mode) :
|
||||||
_mode(mode),
|
_mode(mode),
|
||||||
_sequencer(new DatagramSequencer(datagramHeader, this)),
|
_sequencer(new DatagramSequencer(datagramHeader, this)),
|
||||||
_highPriorityMessagesToSend(0.0f),
|
_highPriorityMessagesToSend(0.0f),
|
||||||
|
@ -800,7 +800,7 @@ int MutateVisitor::visit(MetavoxelInfo& info) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Endpoint::simulate(int iterationNumber) {
|
bool TestEndpoint::simulate(int iterationNumber) {
|
||||||
// update/send our delayed datagrams
|
// update/send our delayed datagrams
|
||||||
for (QList<ByteArrayIntPair>::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) {
|
for (QList<ByteArrayIntPair>::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) {
|
||||||
if (it->second-- == 1) {
|
if (it->second-- == 1) {
|
||||||
|
@ -940,7 +940,7 @@ bool Endpoint::simulate(int iterationNumber) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::sendDatagram(const QByteArray& datagram) {
|
void TestEndpoint::sendDatagram(const QByteArray& datagram) {
|
||||||
datagramsSent++;
|
datagramsSent++;
|
||||||
bytesSent += datagram.size();
|
bytesSent += datagram.size();
|
||||||
|
|
||||||
|
@ -970,7 +970,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) {
|
||||||
_other->receiveDatagram(datagram);
|
_other->receiveDatagram(datagram);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::handleHighPriorityMessage(const QVariant& message) {
|
void TestEndpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||||
if (message.userType() == ClearSharedObjectMessage::Type) {
|
if (message.userType() == ClearSharedObjectMessage::Type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -984,7 +984,7 @@ void Endpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||||
highPriorityMessagesReceived++;
|
highPriorityMessagesReceived++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::readMessage(Bitstream& in) {
|
void TestEndpoint::readMessage(Bitstream& in) {
|
||||||
if (_mode == CONGESTION_MODE) {
|
if (_mode == CONGESTION_MODE) {
|
||||||
QVariant message;
|
QVariant message;
|
||||||
in >> message;
|
in >> message;
|
||||||
|
@ -1056,7 +1056,7 @@ void Endpoint::readMessage(Bitstream& in) {
|
||||||
exit(true);
|
exit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::handleReliableMessage(const QVariant& message) {
|
void TestEndpoint::handleReliableMessage(const QVariant& message) {
|
||||||
if (message.userType() == ClearSharedObjectMessage::Type ||
|
if (message.userType() == ClearSharedObjectMessage::Type ||
|
||||||
message.userType() == ClearMainChannelSharedObjectMessage::Type) {
|
message.userType() == ClearMainChannelSharedObjectMessage::Type) {
|
||||||
return;
|
return;
|
||||||
|
@ -1071,7 +1071,7 @@ void Endpoint::handleReliableMessage(const QVariant& message) {
|
||||||
reliableMessagesReceived++;
|
reliableMessagesReceived++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::readReliableChannel() {
|
void TestEndpoint::readReliableChannel() {
|
||||||
CircularBuffer& buffer = _sequencer->getReliableInputChannel(1)->getBuffer();
|
CircularBuffer& buffer = _sequencer->getReliableInputChannel(1)->getBuffer();
|
||||||
QByteArray bytes = buffer.read(buffer.bytesAvailable());
|
QByteArray bytes = buffer.read(buffer.bytesAvailable());
|
||||||
if (_other->_dataStreamed.size() < bytes.size()) {
|
if (_other->_dataStreamed.size() < bytes.size()) {
|
||||||
|
@ -1085,15 +1085,15 @@ void Endpoint::readReliableChannel() {
|
||||||
streamedBytesReceived += bytes.size();
|
streamedBytesReceived += bytes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::clearSendRecordsBefore(int index) {
|
void TestEndpoint::clearSendRecordsBefore(int index) {
|
||||||
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::clearReceiveRecordsBefore(int index) {
|
void TestEndpoint::clearReceiveRecordsBefore(int index) {
|
||||||
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::receiveDatagram(const QByteArray& datagram) {
|
void TestEndpoint::receiveDatagram(const QByteArray& datagram) {
|
||||||
if (_mode == CONGESTION_MODE) {
|
if (_mode == CONGESTION_MODE) {
|
||||||
if (datagram.size() <= _remainingPipelineCapacity) {
|
if (datagram.size() <= _remainingPipelineCapacity) {
|
||||||
// have to copy the datagram; the one we're passed is a reference to a shared buffer
|
// have to copy the datagram; the one we're passed is a reference to a shared buffer
|
||||||
|
@ -1107,7 +1107,7 @@ void Endpoint::receiveDatagram(const QByteArray& datagram) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
||||||
int userType = message.userType();
|
int userType = message.userType();
|
||||||
if (userType == ClientStateMessage::Type) {
|
if (userType == ClientStateMessage::Type) {
|
||||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||||
|
|
|
@ -35,16 +35,16 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents a simulated endpoint.
|
/// Represents a simulated endpoint.
|
||||||
class Endpoint : public QObject {
|
class TestEndpoint : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Mode { BASIC_PEER_MODE, CONGESTION_MODE, METAVOXEL_SERVER_MODE, METAVOXEL_CLIENT_MODE };
|
enum Mode { BASIC_PEER_MODE, CONGESTION_MODE, METAVOXEL_SERVER_MODE, METAVOXEL_CLIENT_MODE };
|
||||||
|
|
||||||
Endpoint(const QByteArray& datagramHeader, Mode mode = BASIC_PEER_MODE);
|
TestEndpoint(const QByteArray& datagramHeader, Mode mode = BASIC_PEER_MODE);
|
||||||
|
|
||||||
void setOther(Endpoint* other) { _other = other; }
|
void setOther(TestEndpoint* other) { _other = other; }
|
||||||
|
|
||||||
/// Perform a simulation step.
|
/// Perform a simulation step.
|
||||||
/// \return true if failure was detected
|
/// \return true if failure was detected
|
||||||
|
@ -97,7 +97,7 @@ private:
|
||||||
|
|
||||||
SharedObjectPointer _sphere;
|
SharedObjectPointer _sphere;
|
||||||
|
|
||||||
Endpoint* _other;
|
TestEndpoint* _other;
|
||||||
|
|
||||||
typedef QPair<QByteArray, int> ByteArrayIntPair;
|
typedef QPair<QByteArray, int> ByteArrayIntPair;
|
||||||
QList<ByteArrayIntPair> _delayedDatagrams;
|
QList<ByteArrayIntPair> _delayedDatagrams;
|
||||||
|
|
|
@ -18,6 +18,7 @@ include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||||
|
|
||||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
|
|
@ -18,6 +18,7 @@ include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||||
|
|
||||||
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
|
||||||
|
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
|
Loading…
Reference in a new issue