mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-16 20:39:04 +02:00
Merge pull request #3159 from ey6es/metavoxels
Basic placeholder metavoxel save/load, added some stats on server and client, tie metavoxel LOD to avatars', spanner streaming fix.
This commit is contained in:
commit
a7b6879bea
13 changed files with 267 additions and 7 deletions
|
@ -10,6 +10,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QSaveFile>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
||||||
|
@ -44,6 +47,18 @@ void MetavoxelServer::run() {
|
||||||
|
|
||||||
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
||||||
_sendTimer.start(SEND_INTERVAL);
|
_sendTimer.start(SEND_INTERVAL);
|
||||||
|
|
||||||
|
// initialize Bitstream before using it in multiple threads
|
||||||
|
Bitstream::preThreadingInit();
|
||||||
|
|
||||||
|
// create the persister and start it in its own thread
|
||||||
|
_persister = new MetavoxelPersister(this);
|
||||||
|
QThread* persistenceThread = new QThread(this);
|
||||||
|
_persister->moveToThread(persistenceThread);
|
||||||
|
persistenceThread->start();
|
||||||
|
|
||||||
|
// queue up the load
|
||||||
|
QMetaObject::invokeMethod(_persister, "load");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelServer::readPendingDatagrams() {
|
void MetavoxelServer::readPendingDatagrams() {
|
||||||
|
@ -67,6 +82,12 @@ void MetavoxelServer::readPendingDatagrams() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetavoxelServer::aboutToFinish() {
|
||||||
|
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _data));
|
||||||
|
_persister->thread()->quit();
|
||||||
|
_persister->thread()->wait();
|
||||||
|
}
|
||||||
|
|
||||||
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
||||||
if (node->getType() == NodeType::Agent) {
|
if (node->getType() == NodeType::Agent) {
|
||||||
QMutexLocker locker(&node->getMutex());
|
QMutexLocker locker(&node->getMutex());
|
||||||
|
@ -193,3 +214,44 @@ void MetavoxelSession::sendPacketGroup(int alreadySent) {
|
||||||
_sequencer.endPacket();
|
_sequencer.endPacket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelPersister::MetavoxelPersister(MetavoxelServer* server) :
|
||||||
|
_server(server) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* SAVE_FILE = "metavoxels.dat";
|
||||||
|
|
||||||
|
void MetavoxelPersister::load() {
|
||||||
|
QFile file(SAVE_FILE);
|
||||||
|
if (!file.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MetavoxelData data;
|
||||||
|
{
|
||||||
|
QDebug debug = qDebug() << "Reading from" << SAVE_FILE << "...";
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QDataStream inStream(&file);
|
||||||
|
Bitstream in(inStream);
|
||||||
|
try {
|
||||||
|
in >> data;
|
||||||
|
} catch (const BitstreamException& e) {
|
||||||
|
debug << "failed, " << e.getDescription();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(_server, "setData", Q_ARG(const MetavoxelData&, data));
|
||||||
|
debug << "done.";
|
||||||
|
}
|
||||||
|
data.dumpStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelPersister::save(const MetavoxelData& data) {
|
||||||
|
QDebug debug = qDebug() << "Writing to" << SAVE_FILE << "...";
|
||||||
|
QSaveFile file(SAVE_FILE);
|
||||||
|
file.open(QIODevice::WriteOnly);
|
||||||
|
QDataStream outStream(&file);
|
||||||
|
Bitstream out(outStream);
|
||||||
|
out << data;
|
||||||
|
out.flush();
|
||||||
|
file.commit();
|
||||||
|
debug << "done.";
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <Endpoint.h>
|
#include <Endpoint.h>
|
||||||
|
|
||||||
class MetavoxelEditMessage;
|
class MetavoxelEditMessage;
|
||||||
|
class MetavoxelPersister;
|
||||||
class MetavoxelSession;
|
class MetavoxelSession;
|
||||||
|
|
||||||
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
||||||
|
@ -33,11 +34,15 @@ public:
|
||||||
void applyEdit(const MetavoxelEditMessage& edit);
|
void applyEdit(const MetavoxelEditMessage& edit);
|
||||||
|
|
||||||
const MetavoxelData& getData() const { return _data; }
|
const MetavoxelData& getData() const { return _data; }
|
||||||
|
|
||||||
|
Q_INVOKABLE void setData(const MetavoxelData& data) { _data = data; }
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
virtual void readPendingDatagrams();
|
virtual void readPendingDatagrams();
|
||||||
|
|
||||||
|
virtual void aboutToFinish();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void maybeAttachSession(const SharedNodePointer& node);
|
void maybeAttachSession(const SharedNodePointer& node);
|
||||||
|
@ -45,6 +50,8 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
MetavoxelPersister* _persister;
|
||||||
|
|
||||||
QTimer _sendTimer;
|
QTimer _sendTimer;
|
||||||
qint64 _lastSend;
|
qint64 _lastSend;
|
||||||
|
|
||||||
|
@ -88,4 +95,20 @@ private:
|
||||||
int _reliableDeltaID;
|
int _reliableDeltaID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Handles persistence in a separate thread.
|
||||||
|
class MetavoxelPersister : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MetavoxelPersister(MetavoxelServer* server);
|
||||||
|
|
||||||
|
Q_INVOKABLE void load();
|
||||||
|
Q_INVOKABLE void save(const MetavoxelData& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MetavoxelServer* _server;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_MetavoxelServer_h
|
#endif // hifi_MetavoxelServer_h
|
||||||
|
|
|
@ -48,8 +48,10 @@ void MetavoxelSystem::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelLOD MetavoxelSystem::getLOD() const {
|
MetavoxelLOD MetavoxelSystem::getLOD() const {
|
||||||
const float FIXED_LOD_THRESHOLD = 0.01f;
|
// the LOD threshold is temporarily tied to the avatar LOD parameter
|
||||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
|
const float BASE_LOD_THRESHOLD = 0.01f;
|
||||||
|
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(),
|
||||||
|
BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSystem::simulate(float deltaTime) {
|
void MetavoxelSystem::simulate(float deltaTime) {
|
||||||
|
|
|
@ -435,7 +435,7 @@ void Stats::display(
|
||||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||||
|
|
||||||
lines = _expanded ? 5 : 3;
|
lines = _expanded ? 8 : 3;
|
||||||
|
|
||||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||||
horizontalOffset += 5;
|
horizontalOffset += 5;
|
||||||
|
@ -477,6 +477,41 @@ void Stats::display(
|
||||||
|
|
||||||
verticalOffset += STATS_PELS_PER_LINE;
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
||||||
|
|
||||||
|
int internal = 0, leaves = 0;
|
||||||
|
int sendProgress = 0, sendTotal = 0;
|
||||||
|
int receiveProgress = 0, receiveTotal = 0;
|
||||||
|
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
|
if (node->getType() == NodeType::MetavoxelServer) {
|
||||||
|
QMutexLocker locker(&node->getMutex());
|
||||||
|
MetavoxelClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||||
|
if (client) {
|
||||||
|
client->getData().countNodes(internal, leaves, Application::getInstance()->getMetavoxels()->getLOD());
|
||||||
|
client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringstream nodes;
|
||||||
|
nodes << "Metavoxels: " << (internal + leaves);
|
||||||
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodes.str().c_str(), color);
|
||||||
|
|
||||||
|
stringstream nodeTypes;
|
||||||
|
nodeTypes << "Internal: " << internal << " Leaves: " << leaves;
|
||||||
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodeTypes.str().c_str(), color);
|
||||||
|
|
||||||
|
if (sendTotal > 0 || receiveTotal > 0) {
|
||||||
|
stringstream reliableStats;
|
||||||
|
if (sendTotal > 0) {
|
||||||
|
reliableStats << "Upload: " << (sendProgress * 100 / sendTotal) << "% ";
|
||||||
|
}
|
||||||
|
if (receiveTotal > 0) {
|
||||||
|
reliableStats << "Download: " << (receiveProgress * 100 / receiveTotal) << "%";
|
||||||
|
}
|
||||||
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reliableStats.str().c_str(), color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verticalOffset = 0;
|
verticalOffset = 0;
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QReadLocker>
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
|
#include <QWriteLocker>
|
||||||
|
|
||||||
#include "AttributeRegistry.h"
|
#include "AttributeRegistry.h"
|
||||||
#include "MetavoxelData.h"
|
#include "MetavoxelData.h"
|
||||||
|
@ -69,6 +71,7 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
return attribute;
|
return attribute;
|
||||||
}
|
}
|
||||||
|
QWriteLocker locker(&_attributesLock);
|
||||||
AttributePointer& pointer = _attributes[attribute->getName()];
|
AttributePointer& pointer = _attributes[attribute->getName()];
|
||||||
if (!pointer) {
|
if (!pointer) {
|
||||||
pointer = attribute;
|
pointer = attribute;
|
||||||
|
@ -77,9 +80,15 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeRegistry::deregisterAttribute(const QString& name) {
|
void AttributeRegistry::deregisterAttribute(const QString& name) {
|
||||||
|
QWriteLocker locker(&_attributesLock);
|
||||||
_attributes.remove(name);
|
_attributes.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttributePointer AttributeRegistry::getAttribute(const QString& name) {
|
||||||
|
QReadLocker locker(&_attributesLock);
|
||||||
|
return _attributes.value(name);
|
||||||
|
}
|
||||||
|
|
||||||
QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) {
|
||||||
return engine->newQObject(getInstance()->getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership,
|
return engine->newQObject(getInstance()->getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership,
|
||||||
QScriptEngine::PreferExistingWrapperObject);
|
QScriptEngine::PreferExistingWrapperObject);
|
||||||
|
@ -559,6 +568,10 @@ void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStream
|
||||||
}
|
}
|
||||||
data.insert(state.attribute, object);
|
data.insert(state.attribute, object);
|
||||||
}
|
}
|
||||||
|
// even if the root is empty, it should still exist
|
||||||
|
if (!data.getRoot(state.attribute)) {
|
||||||
|
data.createRoot(state.attribute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
|
||||||
|
@ -577,6 +590,10 @@ void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data,
|
||||||
}
|
}
|
||||||
data.toggle(state.attribute, object);
|
data.toggle(state.attribute, object);
|
||||||
}
|
}
|
||||||
|
// even if the root is empty, it should still exist
|
||||||
|
if (!data.getRoot(state.attribute)) {
|
||||||
|
data.createRoot(state.attribute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root,
|
void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root,
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QReadWriteLock>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
@ -61,11 +62,14 @@ public:
|
||||||
void deregisterAttribute(const QString& name);
|
void deregisterAttribute(const QString& name);
|
||||||
|
|
||||||
/// Retrieves an attribute by name.
|
/// Retrieves an attribute by name.
|
||||||
AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); }
|
AttributePointer getAttribute(const QString& name);
|
||||||
|
|
||||||
/// Returns a reference to the attribute hash.
|
/// Returns a reference to the attribute hash.
|
||||||
const QHash<QString, AttributePointer>& getAttributes() const { return _attributes; }
|
const QHash<QString, AttributePointer>& getAttributes() const { return _attributes; }
|
||||||
|
|
||||||
|
/// Returns a reference to the attributes lock.
|
||||||
|
QReadWriteLock& getAttributesLock() { return _attributesLock; }
|
||||||
|
|
||||||
/// Returns a reference to the standard SharedObjectPointer "guide" attribute.
|
/// Returns a reference to the standard SharedObjectPointer "guide" attribute.
|
||||||
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
|
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
|
||||||
|
|
||||||
|
@ -92,6 +96,8 @@ private:
|
||||||
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
|
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
|
||||||
QHash<QString, AttributePointer> _attributes;
|
QHash<QString, AttributePointer> _attributes;
|
||||||
|
QReadWriteLock _attributesLock;
|
||||||
|
|
||||||
AttributePointer _guideAttribute;
|
AttributePointer _guideAttribute;
|
||||||
AttributePointer _spannersAttribute;
|
AttributePointer _spannersAttribute;
|
||||||
AttributePointer _colorAttribute;
|
AttributePointer _colorAttribute;
|
||||||
|
|
|
@ -87,6 +87,12 @@ IDStreamer& IDStreamer::operator>>(int& value) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bitstream::preThreadingInit() {
|
||||||
|
getObjectStreamers();
|
||||||
|
getEnumStreamers();
|
||||||
|
getEnumStreamersByName();
|
||||||
|
}
|
||||||
|
|
||||||
int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) {
|
int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) {
|
||||||
getMetaObjects().insert(className, metaObject);
|
getMetaObjects().insert(className, metaObject);
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,11 @@ public:
|
||||||
QHash<int, SharedObjectPointer> sharedObjectValues;
|
QHash<int, SharedObjectPointer> sharedObjectValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Performs all of the various lazily initializations (of object streamers, etc.) If multiple threads need to use
|
||||||
|
/// Bitstream instances, call this beforehand to prevent errors from occurring when multiple threads attempt lazy
|
||||||
|
/// initialization simultaneously.
|
||||||
|
static void preThreadingInit();
|
||||||
|
|
||||||
/// Registers a metaobject under its name so that instances of it can be streamed. Consider using the REGISTER_META_OBJECT
|
/// Registers a metaobject under its name so that instances of it can be streamed. Consider using the REGISTER_META_OBJECT
|
||||||
/// at the top level of the source file associated with the class rather than calling this function directly.
|
/// at the top level of the source file associated with the class rather than calling this function directly.
|
||||||
/// \return zero; the function only returns a value so that it can be used in static initialization
|
/// \return zero; the function only returns a value so that it can be used in static initialization
|
||||||
|
|
|
@ -79,6 +79,24 @@ ReliableChannel* DatagramSequencer::getReliableInputChannel(int index) {
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatagramSequencer::addReliableChannelStats(int& sendProgress, int& sendTotal,
|
||||||
|
int& receiveProgress, int& receiveTotal) const {
|
||||||
|
foreach (ReliableChannel* channel, _reliableOutputChannels) {
|
||||||
|
int sent, total;
|
||||||
|
if (channel->getMessageSendProgress(sent, total)) {
|
||||||
|
sendProgress += sent;
|
||||||
|
sendTotal += total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (ReliableChannel* channel, _reliableInputChannels) {
|
||||||
|
int received, total;
|
||||||
|
if (channel->getMessageReceiveProgress(received, total)) {
|
||||||
|
receiveProgress += received;
|
||||||
|
receiveTotal += total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DatagramSequencer::notePacketGroup(int desiredPackets) {
|
int DatagramSequencer::notePacketGroup(int desiredPackets) {
|
||||||
// figure out how much data we have enqueued and increase the number of packets desired
|
// figure out how much data we have enqueued and increase the number of packets desired
|
||||||
int totalAvailable = 0;
|
int totalAvailable = 0;
|
||||||
|
@ -684,6 +702,8 @@ void ReliableChannel::endMessage() {
|
||||||
|
|
||||||
quint32 length = _buffer.pos() - _messageLengthPlaceholder;
|
quint32 length = _buffer.pos() - _messageLengthPlaceholder;
|
||||||
_buffer.writeBytes(_messageLengthPlaceholder, sizeof(quint32), (const char*)&length);
|
_buffer.writeBytes(_messageLengthPlaceholder, sizeof(quint32), (const char*)&length);
|
||||||
|
_messageReceivedOffset = getBytesWritten();
|
||||||
|
_messageSize = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReliableChannel::sendMessage(const QVariant& message) {
|
void ReliableChannel::sendMessage(const QVariant& message) {
|
||||||
|
@ -692,6 +712,26 @@ void ReliableChannel::sendMessage(const QVariant& message) {
|
||||||
endMessage();
|
endMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReliableChannel::getMessageSendProgress(int& sent, int& total) const {
|
||||||
|
if (!_messagesEnabled || _offset >= _messageReceivedOffset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sent = qMax(0, _messageSize - (_messageReceivedOffset - _offset));
|
||||||
|
total = _messageSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReliableChannel::getMessageReceiveProgress(int& received, int& total) const {
|
||||||
|
if (!_messagesEnabled || _buffer.bytesAvailable() < (int)sizeof(quint32)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
quint32 length;
|
||||||
|
_buffer.readBytes(_buffer.pos(), sizeof(quint32), (char*)&length);
|
||||||
|
total = length;
|
||||||
|
received = _buffer.bytesAvailable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ReliableChannel::sendClearSharedObjectMessage(int id) {
|
void ReliableChannel::sendClearSharedObjectMessage(int id) {
|
||||||
ClearSharedObjectMessage message = { id };
|
ClearSharedObjectMessage message = { id };
|
||||||
sendMessage(QVariant::fromValue(message));
|
sendMessage(QVariant::fromValue(message));
|
||||||
|
@ -717,7 +757,8 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o
|
||||||
_offset(0),
|
_offset(0),
|
||||||
_writePosition(0),
|
_writePosition(0),
|
||||||
_writePositionResetPacketNumber(0),
|
_writePositionResetPacketNumber(0),
|
||||||
_messagesEnabled(true) {
|
_messagesEnabled(true),
|
||||||
|
_messageReceivedOffset(0) {
|
||||||
|
|
||||||
_buffer.open(output ? QIODevice::WriteOnly : QIODevice::ReadOnly);
|
_buffer.open(output ? QIODevice::WriteOnly : QIODevice::ReadOnly);
|
||||||
_dataStream.setByteOrder(QDataStream::LittleEndian);
|
_dataStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
|
@ -108,6 +108,9 @@ public:
|
||||||
/// Returns the intput channel at the specified index, creating it if necessary.
|
/// Returns the intput channel at the specified index, creating it if necessary.
|
||||||
ReliableChannel* getReliableInputChannel(int index = 0);
|
ReliableChannel* getReliableInputChannel(int index = 0);
|
||||||
|
|
||||||
|
/// Adds stats for all reliable channels to the referenced variables.
|
||||||
|
void addReliableChannelStats(int& sendProgress, int& sendTotal, int& receiveProgress, int& receiveTotal) const;
|
||||||
|
|
||||||
/// Notes that we're sending a group of packets.
|
/// Notes that we're sending a group of packets.
|
||||||
/// \param desiredPackets the number of packets we'd like to write in the group
|
/// \param desiredPackets the number of packets we'd like to write in the group
|
||||||
/// \return the number of packets to write in the group
|
/// \return the number of packets to write in the group
|
||||||
|
@ -376,6 +379,14 @@ public:
|
||||||
/// writes the message to the bitstream, then calls endMessage).
|
/// writes the message to the bitstream, then calls endMessage).
|
||||||
void sendMessage(const QVariant& message);
|
void sendMessage(const QVariant& message);
|
||||||
|
|
||||||
|
/// Determines the number of bytes uploaded towards the currently pending message.
|
||||||
|
/// \return true if there is a message pending, in which case the sent and total arguments will be set
|
||||||
|
bool getMessageSendProgress(int& sent, int& total) const;
|
||||||
|
|
||||||
|
/// Determines the number of bytes downloaded towards the currently pending message.
|
||||||
|
/// \return true if there is a message pending, in which case the received and total arguments will be set
|
||||||
|
bool getMessageReceiveProgress(int& received, int& total) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/// Fired when a framed message has been received on this channel.
|
/// Fired when a framed message has been received on this channel.
|
||||||
|
@ -416,6 +427,8 @@ private:
|
||||||
SpanList _acknowledged;
|
SpanList _acknowledged;
|
||||||
bool _messagesEnabled;
|
bool _messagesEnabled;
|
||||||
int _messageLengthPlaceholder;
|
int _messageLengthPlaceholder;
|
||||||
|
int _messageReceivedOffset;
|
||||||
|
int _messageSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DatagramSequencer_h
|
#endif // hifi_DatagramSequencer_h
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
PacketRecord* baselineReceiveRecord = NULL);
|
PacketRecord* baselineReceiveRecord = NULL);
|
||||||
virtual ~Endpoint();
|
virtual ~Endpoint();
|
||||||
|
|
||||||
|
const DatagramSequencer& getSequencer() const { return _sequencer; }
|
||||||
|
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
|
||||||
virtual int parseData(const QByteArray& packet);
|
virtual int parseData(const QByteArray& packet);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QDebugStateSaver>
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
|
@ -627,6 +628,33 @@ bool MetavoxelData::deepEquals(const MetavoxelData& other, const MetavoxelLOD& l
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetavoxelData::countNodes(int& internal, int& leaves, const MetavoxelLOD& lod) const {
|
||||||
|
glm::vec3 minimum = getMinimum();
|
||||||
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
|
it.value()->countNodes(it.key(), minimum, _size, lod, internal, leaves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelData::dumpStats(QDebug debug) const {
|
||||||
|
QDebugStateSaver saver(debug);
|
||||||
|
debug.nospace() << "[size=" << _size << ", roots=[";
|
||||||
|
int totalInternal = 0, totalLeaves = 0;
|
||||||
|
glm::vec3 minimum = getMinimum();
|
||||||
|
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||||
|
if (it != _roots.constBegin()) {
|
||||||
|
debug << ", ";
|
||||||
|
}
|
||||||
|
debug << it.key()->getName() << " (" << it.key()->metaObject()->className() << "): ";
|
||||||
|
int internal = 0, leaves = 0;
|
||||||
|
it.value()->countNodes(it.key(), minimum, _size, MetavoxelLOD(), internal, leaves);
|
||||||
|
debug << internal << " internal, " << leaves << " leaves, " << (internal + leaves) << " total";
|
||||||
|
totalInternal += internal;
|
||||||
|
totalLeaves += leaves;
|
||||||
|
}
|
||||||
|
debug << "], totalInternal=" << totalInternal << ", totalLeaves=" << totalLeaves <<
|
||||||
|
", grandTotal=" << (totalInternal + totalLeaves) << "]";
|
||||||
|
}
|
||||||
|
|
||||||
bool MetavoxelData::operator==(const MetavoxelData& other) const {
|
bool MetavoxelData::operator==(const MetavoxelData& other) const {
|
||||||
return _size == other._size && _roots == other._roots;
|
return _size == other._size && _roots == other._roots;
|
||||||
}
|
}
|
||||||
|
@ -1056,8 +1084,20 @@ void MetavoxelNode::getSpanners(const AttributePointer& attribute, const glm::ve
|
||||||
}
|
}
|
||||||
float nextSize = size * 0.5f;
|
float nextSize = size * 0.5f;
|
||||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
glm::vec3 nextMinimum = getNextMinimum(minimum, nextSize, i);
|
_children[i]->getSpanners(attribute, getNextMinimum(minimum, nextSize, i), nextSize, lod, results);
|
||||||
_children[i]->getSpanners(attribute, nextMinimum, nextSize, lod, results);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetavoxelNode::countNodes(const AttributePointer& attribute, const glm::vec3& minimum,
|
||||||
|
float size, const MetavoxelLOD& lod, int& internal, int& leaves) const {
|
||||||
|
if (isLeaf() || !lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier())) {
|
||||||
|
leaves++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
internal++;
|
||||||
|
float nextSize = size * 0.5f;
|
||||||
|
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||||
|
_children[i]->countNodes(attribute, getNextMinimum(minimum, nextSize, i), nextSize, lod, internal, leaves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,11 @@ public:
|
||||||
/// shallow comparison).
|
/// shallow comparison).
|
||||||
bool deepEquals(const MetavoxelData& other, const MetavoxelLOD& lod = MetavoxelLOD()) const;
|
bool deepEquals(const MetavoxelData& other, const MetavoxelLOD& lod = MetavoxelLOD()) const;
|
||||||
|
|
||||||
|
/// Counts the nodes in the data.
|
||||||
|
void countNodes(int& internalNodes, int& leaves, const MetavoxelLOD& lod = MetavoxelLOD()) const;
|
||||||
|
|
||||||
|
void dumpStats(QDebug debug = QDebug(QtDebugMsg)) const;
|
||||||
|
|
||||||
bool operator==(const MetavoxelData& other) const;
|
bool operator==(const MetavoxelData& other) const;
|
||||||
bool operator!=(const MetavoxelData& other) const;
|
bool operator!=(const MetavoxelData& other) const;
|
||||||
|
|
||||||
|
@ -221,6 +226,9 @@ public:
|
||||||
void getSpanners(const AttributePointer& attribute, const glm::vec3& minimum,
|
void getSpanners(const AttributePointer& attribute, const glm::vec3& minimum,
|
||||||
float size, const MetavoxelLOD& lod, SharedObjectSet& results) const;
|
float size, const MetavoxelLOD& lod, SharedObjectSet& results) const;
|
||||||
|
|
||||||
|
void countNodes(const AttributePointer& attribute, const glm::vec3& minimum,
|
||||||
|
float size, const MetavoxelLOD& lod, int& internalNodes, int& leaves) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(MetavoxelNode)
|
Q_DISABLE_COPY(MetavoxelNode)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue