mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 09:33:49 +02:00
Working on sending edits.
This commit is contained in:
parent
f73f16b0fb
commit
7f20750e80
10 changed files with 172 additions and 79 deletions
|
@ -9,10 +9,12 @@ macro(AUTO_MTC TARGET ROOT_DIR)
|
|||
${INCLUDE_FILES} DEPENDS mtc ${INCLUDE_FILES})
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Script REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
|
||||
add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp)
|
||||
|
||||
qt5_use_modules(${TARGET}_automtc Core)
|
||||
qt5_use_modules(${TARGET}_automtc Core Script Widgets)
|
||||
|
||||
target_link_libraries(${TARGET} ${TARGET}_automtc)
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -42,6 +41,12 @@ void MetavoxelSystem::init() {
|
|||
_buffer.create();
|
||||
}
|
||||
|
||||
void MetavoxelSystem::applyEdit(const MetavoxelEdit& edit) {
|
||||
foreach (MetavoxelClient* client, _clients) {
|
||||
client->applyEdit(edit);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelSystem::processData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||
QMetaObject::invokeMethod(this, "receivedData", Q_ARG(const QByteArray&, data), Q_ARG(const HifiSockAddr&, sender));
|
||||
}
|
||||
|
@ -187,6 +192,14 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
|
|||
_receiveRecords.append(record);
|
||||
}
|
||||
|
||||
void MetavoxelClient::applyEdit(const MetavoxelEdit& edit) {
|
||||
// apply immediately to local tree
|
||||
edit.apply(_data);
|
||||
|
||||
// start sending it out
|
||||
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
|
||||
}
|
||||
|
||||
void MetavoxelClient::simulate(float deltaTime, MetavoxelVisitor& visitor) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() };
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <DatagramSequencer.h>
|
||||
#include <MetavoxelData.h>
|
||||
#include <MetavoxelMessages.h>
|
||||
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
|
@ -34,7 +35,7 @@ public:
|
|||
|
||||
void init();
|
||||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
void applyEdit(const MetavoxelEdit& edit);
|
||||
|
||||
void processData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
|
||||
|
@ -90,6 +91,8 @@ public:
|
|||
|
||||
const QUuid& getSessionID() const { return _sessionID; }
|
||||
|
||||
void applyEdit(const MetavoxelEdit& edit);
|
||||
|
||||
void simulate(float deltaTime, MetavoxelVisitor& visitor);
|
||||
|
||||
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
|
|
|
@ -339,60 +339,14 @@ void MetavoxelEditor::resetState() {
|
|||
_height = 0.0f;
|
||||
}
|
||||
|
||||
class Applier : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value);
|
||||
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _minimum;
|
||||
glm::vec3 _maximum;
|
||||
float _granularity;
|
||||
AttributeValue _value;
|
||||
};
|
||||
|
||||
Applier::Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << value.getAttribute()),
|
||||
_minimum(minimum),
|
||||
_maximum(maximum),
|
||||
_granularity(granularity),
|
||||
_value(value) {
|
||||
}
|
||||
|
||||
bool Applier::visit(MetavoxelInfo& info) {
|
||||
// find the intersection between volume and voxel
|
||||
glm::vec3 minimum = glm::max(info.minimum, _minimum);
|
||||
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _maximum);
|
||||
glm::vec3 size = maximum - minimum;
|
||||
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
||||
return false; // disjoint
|
||||
}
|
||||
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
||||
if (volume >= 1.0f) {
|
||||
info.outputValues[0] = _value;
|
||||
return false; // entirely contained
|
||||
}
|
||||
if (info.size <= _granularity) {
|
||||
if (volume >= 0.5f) {
|
||||
info.outputValues[0] = _value;
|
||||
}
|
||||
return false; // reached granularity limit; take best guess
|
||||
}
|
||||
return true; // subdivide
|
||||
}
|
||||
|
||||
void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
return;
|
||||
}
|
||||
OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue()));
|
||||
|
||||
Applier applier(minimum, maximum, _gridSpacing->value(), value);
|
||||
Application::getInstance()->getMetavoxels()->getData().guide(applier);
|
||||
MetavoxelEdit edit = { minimum, maximum, _gridSpacing->value(), value };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(edit);
|
||||
}
|
||||
|
||||
QVariant MetavoxelEditor::getValue() const {
|
||||
|
|
|
@ -237,20 +237,25 @@ Bitstream& Bitstream::operator>>(QVariant& value) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const AttributeValue& value) {
|
||||
_attributeStreamer << value.getAttribute();
|
||||
if (value.getAttribute()) {
|
||||
value.getAttribute()->write(*this, value.getValue(), true);
|
||||
Bitstream& Bitstream::operator<<(const AttributeValue& attributeValue) {
|
||||
_attributeStreamer << attributeValue.getAttribute();
|
||||
if (attributeValue.getAttribute()) {
|
||||
attributeValue.getAttribute()->write(*this, attributeValue.getValue(), true);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(AttributeValue& value) {
|
||||
Bitstream& Bitstream::operator>>(OwnedAttributeValue& attributeValue) {
|
||||
AttributePointer attribute;
|
||||
_attributeStreamer >> attribute;
|
||||
if (attribute) {
|
||||
void* value;
|
||||
void* value = attribute->create();
|
||||
attribute->read(*this, value, true);
|
||||
attributeValue = AttributeValue(attribute, value);
|
||||
attribute->destroy(value);
|
||||
|
||||
} else {
|
||||
attributeValue = AttributeValue();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class QObject;
|
|||
class Attribute;
|
||||
class AttributeValue;
|
||||
class Bitstream;
|
||||
class OwnedAttributeValue;
|
||||
class TypeStreamer;
|
||||
|
||||
typedef QSharedPointer<Attribute> AttributePointer;
|
||||
|
@ -232,8 +233,8 @@ public:
|
|||
Bitstream& operator<<(const QVariant& value);
|
||||
Bitstream& operator>>(QVariant& value);
|
||||
|
||||
Bitstream& operator<<(const AttributeValue& value);
|
||||
Bitstream& operator>>(AttributeValue& value);
|
||||
Bitstream& operator<<(const AttributeValue& attributeValue);
|
||||
Bitstream& operator>>(OwnedAttributeValue& attributeValue);
|
||||
|
||||
template<class T> Bitstream& operator<<(const QList<T>& list);
|
||||
template<class T> Bitstream& operator>>(QList<T>& list);
|
||||
|
|
|
@ -25,7 +25,8 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader) :
|
|||
_outgoingDatagramStream(&_outgoingDatagramBuffer),
|
||||
_incomingPacketNumber(0),
|
||||
_incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly),
|
||||
_inputStream(_incomingPacketStream) {
|
||||
_inputStream(_incomingPacketStream),
|
||||
_receivedHighPriorityMessages(0) {
|
||||
|
||||
_outgoingPacketStream.setByteOrder(QDataStream::LittleEndian);
|
||||
_incomingDatagramStream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
@ -35,6 +36,34 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader) :
|
|||
memcpy(_outgoingDatagram.data(), datagramHeader.constData(), _datagramHeaderSize);
|
||||
}
|
||||
|
||||
void DatagramSequencer::sendHighPriorityMessage(const QVariant& data) {
|
||||
HighPriorityMessage message = { data, _outgoingPacketNumber + 1 };
|
||||
_highPriorityMessages.append(message);
|
||||
}
|
||||
|
||||
Bitstream& DatagramSequencer::startPacket() {
|
||||
// start with the list of acknowledgements
|
||||
_outgoingPacketStream << (quint32)_receiveRecords.size();
|
||||
foreach (const ReceiveRecord& record, _receiveRecords) {
|
||||
_outgoingPacketStream << (quint32)record.packetNumber;
|
||||
}
|
||||
|
||||
// write the high-priority messages
|
||||
_outgoingPacketStream << (quint32)_highPriorityMessages.size();
|
||||
foreach (const HighPriorityMessage& message, _highPriorityMessages) {
|
||||
_outputStream << message.data;
|
||||
}
|
||||
|
||||
// return the stream, allowing the caller to write the rest
|
||||
return _outputStream;
|
||||
}
|
||||
|
||||
void DatagramSequencer::endPacket() {
|
||||
_outputStream.flush();
|
||||
sendPacket(QByteArray::fromRawData(_outgoingPacketData.constData(), _outgoingPacketStream.device()->pos()));
|
||||
_outgoingPacketStream.device()->seek(0);
|
||||
}
|
||||
|
||||
/// Simple RAII-style object to keep a device open when in scope.
|
||||
class QIODeviceOpener {
|
||||
public:
|
||||
|
@ -47,21 +76,6 @@ private:
|
|||
QIODevice* _device;
|
||||
};
|
||||
|
||||
Bitstream& DatagramSequencer::startPacket() {
|
||||
// start with the list of acknowledgements
|
||||
_outgoingPacketStream << (quint32)_receiveRecords.size();
|
||||
foreach (const ReceiveRecord& record, _receiveRecords) {
|
||||
_outgoingPacketStream << (quint32)record.packetNumber;
|
||||
}
|
||||
return _outputStream;
|
||||
}
|
||||
|
||||
void DatagramSequencer::endPacket() {
|
||||
_outputStream.flush();
|
||||
sendPacket(QByteArray::fromRawData(_outgoingPacketData.constData(), _outgoingPacketStream.device()->pos()));
|
||||
_outgoingPacketStream.device()->seek(0);
|
||||
}
|
||||
|
||||
void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
|
||||
_incomingDatagramBuffer.setData(datagram.constData() + _datagramHeaderSize, datagram.size() - _datagramHeaderSize);
|
||||
QIODeviceOpener opener(&_incomingDatagramBuffer, QIODevice::ReadOnly);
|
||||
|
@ -123,12 +137,26 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
|
|||
_sendRecords.erase(_sendRecords.begin(), it + 1);
|
||||
}
|
||||
|
||||
// read and dispatch the high-priority messages
|
||||
quint32 highPriorityMessageCount;
|
||||
_incomingPacketStream >> highPriorityMessageCount;
|
||||
int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages;
|
||||
for (int i = 0; i < highPriorityMessageCount; i++) {
|
||||
QVariant data;
|
||||
_inputStream >> data;
|
||||
if (i >= _receivedHighPriorityMessages) {
|
||||
emit receivedHighPriorityMessage(data);
|
||||
}
|
||||
}
|
||||
_receivedHighPriorityMessages = highPriorityMessageCount;
|
||||
|
||||
// alert external parties so that they can read the rest
|
||||
emit readyToRead(_inputStream);
|
||||
_incomingPacketStream.device()->seek(0);
|
||||
_inputStream.reset();
|
||||
|
||||
// record the receipt
|
||||
ReceiveRecord record = { _incomingPacketNumber, _inputStream.getAndResetReadMappings() };
|
||||
ReceiveRecord record = { _incomingPacketNumber, _inputStream.getAndResetReadMappings(), newHighPriorityMessages };
|
||||
_receiveRecords.append(record);
|
||||
}
|
||||
|
||||
|
@ -138,10 +166,19 @@ void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) {
|
|||
QList<ReceiveRecord>::iterator it = qBinaryFind(_receiveRecords.begin(), _receiveRecords.end(), compare);
|
||||
if (it != _receiveRecords.end()) {
|
||||
_inputStream.persistReadMappings(it->mappings);
|
||||
_receivedHighPriorityMessages -= it->newHighPriorityMessages;
|
||||
emit receiveAcknowledged(it - _receiveRecords.begin());
|
||||
_receiveRecords.erase(_receiveRecords.begin(), it + 1);
|
||||
}
|
||||
_outputStream.persistWriteMappings(record.mappings);
|
||||
|
||||
// remove the received high priority messages
|
||||
for (int i = _highPriorityMessages.size() - 1; i >= 0; i--) {
|
||||
if (_highPriorityMessages.at(i).firstPacketNumber <= record.packetNumber) {
|
||||
_highPriorityMessages.erase(_highPriorityMessages.begin(), _highPriorityMessages.begin() + i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramSequencer::sendPacket(const QByteArray& packet) {
|
||||
|
|
|
@ -31,6 +31,12 @@ public:
|
|||
/// Returns the packet number of the last packet received (or the packet currently being assembled).
|
||||
int getIncomingPacketNumber() const { return _incomingPacketNumber; }
|
||||
|
||||
/// Returns the packet number of the sent packet at the specified index.
|
||||
int getSentPacketNumber(int index) const { return _sendRecords.at(index).packetNumber; }
|
||||
|
||||
/// Adds a message to the high priority queue. Will be sent with every outgoing packet until received.
|
||||
void sendHighPriorityMessage(const QVariant& data);
|
||||
|
||||
/// Starts a new packet for transmission.
|
||||
/// \return a reference to the Bitstream to use for writing to the packet
|
||||
Bitstream& startPacket();
|
||||
|
@ -50,6 +56,9 @@ signals:
|
|||
/// Emitted when a packet is available to read.
|
||||
void readyToRead(Bitstream& input);
|
||||
|
||||
/// Emitted when we've received a high-priority message
|
||||
void receivedHighPriorityMessage(const QVariant& data);
|
||||
|
||||
/// Emitted when a sent packet has been acknowledged by the remote side.
|
||||
/// \param index the index of the packet in our list of send records
|
||||
void sendAcknowledged(int index);
|
||||
|
@ -71,10 +80,17 @@ private:
|
|||
public:
|
||||
int packetNumber;
|
||||
Bitstream::ReadMappings mappings;
|
||||
int newHighPriorityMessages;
|
||||
|
||||
bool operator<(const ReceiveRecord& other) const { return packetNumber < other.packetNumber; }
|
||||
};
|
||||
|
||||
class HighPriorityMessage {
|
||||
public:
|
||||
QVariant data;
|
||||
int firstPacketNumber;
|
||||
};
|
||||
|
||||
/// Notes that the described send was acknowledged by the other party.
|
||||
void sendRecordAcknowledged(const SendRecord& record);
|
||||
|
||||
|
@ -104,6 +120,9 @@ private:
|
|||
Bitstream _inputStream;
|
||||
QSet<int> _offsetsReceived;
|
||||
int _remainingBytes;
|
||||
|
||||
QList<HighPriorityMessage> _highPriorityMessages;
|
||||
int _receivedHighPriorityMessages;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__DatagramSequencer__) */
|
||||
|
|
54
libraries/metavoxels/src/MetavoxelMessages.cpp
Normal file
54
libraries/metavoxels/src/MetavoxelMessages.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// MetavoxelMessages.cpp
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 1/24/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "MetavoxelMessages.h"
|
||||
|
||||
class EditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
EditVisitor(const MetavoxelEdit& edit);
|
||||
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
const MetavoxelEdit& _edit;
|
||||
};
|
||||
|
||||
EditVisitor::EditVisitor(const MetavoxelEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()),
|
||||
_edit(edit) {
|
||||
}
|
||||
|
||||
bool EditVisitor::visit(MetavoxelInfo& info) {
|
||||
// find the intersection between volume and voxel
|
||||
glm::vec3 minimum = glm::max(info.minimum, _edit.minimum);
|
||||
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.maximum);
|
||||
glm::vec3 size = maximum - minimum;
|
||||
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
||||
return false; // disjoint
|
||||
}
|
||||
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
||||
if (volume >= 1.0f) {
|
||||
info.outputValues[0] = _edit.value;
|
||||
return false; // entirely contained
|
||||
}
|
||||
if (info.size <= _edit.granularity) {
|
||||
if (volume >= 0.5f) {
|
||||
info.outputValues[0] = _edit.value;
|
||||
}
|
||||
return false; // reached granularity limit; take best guess
|
||||
}
|
||||
return true; // subdivide
|
||||
}
|
||||
|
||||
void MetavoxelEdit::apply(MetavoxelDataPointer& data) const {
|
||||
//data.detach();
|
||||
EditVisitor visitor(*this);
|
||||
data->guide(visitor);
|
||||
}
|
|
@ -9,7 +9,9 @@
|
|||
#ifndef __interface__MetavoxelMessages__
|
||||
#define __interface__MetavoxelMessages__
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
#include "Bitstream.h"
|
||||
#include "MetavoxelData.h"
|
||||
|
||||
/// A message containing the state of a client.
|
||||
class ClientStateMessage {
|
||||
|
@ -35,9 +37,12 @@ class MetavoxelEdit {
|
|||
|
||||
public:
|
||||
|
||||
glm::vec3 minimum;
|
||||
glm::vec3 maximum;
|
||||
float granularity;
|
||||
STREAM glm::vec3 minimum;
|
||||
STREAM glm::vec3 maximum;
|
||||
STREAM float granularity;
|
||||
STREAM OwnedAttributeValue value;
|
||||
|
||||
void apply(MetavoxelDataPointer& data) const;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(MetavoxelEdit)
|
||||
|
|
Loading…
Reference in a new issue