Merge branch 'master' into add_cara_face_tracker

This commit is contained in:
Zu 2014-07-30 08:45:44 +08:00
commit dcd7b81426
25 changed files with 1490 additions and 490 deletions

View file

@ -21,18 +21,21 @@
#include "MetavoxelServer.h"
const int SEND_INTERVAL = 50;
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
ThreadedAssignment(packet),
_sendTimer(this) {
_sendTimer.setSingleShot(true);
connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas()));
_nextSender(0) {
}
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
edit.apply(_data, SharedObject::getWeakHash());
MetavoxelData data = _data;
edit.apply(data, SharedObject::getWeakHash());
setData(data);
}
void MetavoxelServer::setData(const MetavoxelData& data) {
if (_data != data) {
emit dataChanged(_data = data);
}
}
const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
@ -43,19 +46,34 @@ void MetavoxelServer::run() {
NodeList* nodeList = NodeList::getInstance();
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&)));
_lastSend = QDateTime::currentMSecsSinceEpoch();
_sendTimer.start(SEND_INTERVAL);
connect(nodeList, &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
connect(nodeList, &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
// initialize Bitstream before using it in multiple threads
Bitstream::preThreadingInit();
// create the senders, each with its own thread
int threadCount = QThread::idealThreadCount();
if (threadCount == -1) {
const int DEFAULT_THREAD_COUNT = 4;
threadCount = DEFAULT_THREAD_COUNT;
}
qDebug() << "Creating" << threadCount << "sender threads";
for (int i = 0; i < threadCount; i++) {
QThread* thread = new QThread(this);
MetavoxelSender* sender = new MetavoxelSender(this);
sender->moveToThread(thread);
connect(thread, &QThread::finished, sender, &QObject::deleteLater);
thread->start();
QMetaObject::invokeMethod(sender, "start");
_senders.append(sender);
}
// create the persister and start it in its own thread
_persister = new MetavoxelPersister(this);
QThread* persistenceThread = new QThread(this);
_persister->moveToThread(persistenceThread);
_persister->connect(persistenceThread, SIGNAL(finished()), SLOT(deleteLater()));
connect(persistenceThread, &QThread::finished, _persister, &QObject::deleteLater);
persistenceThread->start();
// queue up the load
@ -85,6 +103,11 @@ void MetavoxelServer::readPendingDatagrams() {
void MetavoxelServer::aboutToFinish() {
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _data));
foreach (MetavoxelSender* sender, _senders) {
sender->thread()->quit();
sender->thread()->wait();
}
_persister->thread()->quit();
_persister->thread()->wait();
}
@ -92,17 +115,53 @@ void MetavoxelServer::aboutToFinish() {
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
if (node->getType() == NodeType::Agent) {
QMutexLocker locker(&node->getMutex());
node->setLinkedData(new MetavoxelSession(node, this));
MetavoxelSender* sender = _senders.at(_nextSender);
_nextSender = (_nextSender + 1) % _senders.size();
MetavoxelSession* session = new MetavoxelSession(node, sender);
session->moveToThread(sender->thread());
QMetaObject::invokeMethod(sender, "addSession", Q_ARG(QObject*, session));
node->setLinkedData(session);
}
}
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())->update();
void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) {
if (node->getType() == NodeType::Agent) {
// we assume the node is already locked
MetavoxelSession* session = static_cast<MetavoxelSession*>(node->getLinkedData());
if (session) {
node->setLinkedData(NULL);
session->deleteLater();
}
}
}
MetavoxelSender::MetavoxelSender(MetavoxelServer* server) :
_server(server),
_sendTimer(this) {
_sendTimer.setSingleShot(true);
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelSender::sendDeltas);
connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData);
}
const int SEND_INTERVAL = 50;
void MetavoxelSender::start() {
_lastSend = QDateTime::currentMSecsSinceEpoch();
_sendTimer.start(SEND_INTERVAL);
}
void MetavoxelSender::addSession(QObject* session) {
_sessions.insert(static_cast<MetavoxelSession*>(session));
connect(session, &QObject::destroyed, this, &MetavoxelSender::removeSession);
}
void MetavoxelSender::sendDeltas() {
// send deltas for all sessions associated with our thread
foreach (MetavoxelSession* session, _sessions) {
session->update();
}
// restart the send timer
qint64 now = QDateTime::currentMSecsSinceEpoch();
@ -112,9 +171,13 @@ void MetavoxelServer::sendDeltas() {
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
}
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) :
void MetavoxelSender::removeSession(QObject* session) {
_sessions.remove(static_cast<MetavoxelSession*>(session));
}
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) :
Endpoint(node, new PacketRecord(), NULL),
_server(server),
_sender(sender),
_reliableDeltaChannel(NULL),
_reliableDeltaID(0) {
@ -138,7 +201,7 @@ void MetavoxelSession::update() {
int start = _sequencer.getOutputStream().getUnderlying().device()->pos();
out << QVariant::fromValue(MetavoxelDeltaMessage());
PacketRecord* sendRecord = getLastAcknowledgedSendRecord();
_server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
_sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
out.flush();
int end = _sequencer.getOutputStream().getUnderlying().device()->pos();
if (end > _sequencer.getMaxPacketSize()) {
@ -150,7 +213,7 @@ void MetavoxelSession::update() {
_reliableDeltaWriteMappings = out.getAndResetWriteMappings();
_reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten();
_reliableDeltaData = _server->getData();
_reliableDeltaData = _sender->getData();
_reliableDeltaLOD = _lod;
// go back to the beginning with the current packet and note that there's a delta pending
@ -173,7 +236,7 @@ void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
PacketRecord* MetavoxelSession::maybeCreateSendRecord() const {
return _reliableDeltaChannel ? new PacketRecord(_reliableDeltaLOD, _reliableDeltaData) :
new PacketRecord(_lod, _server->getData());
new PacketRecord(_lod, _sender->getData());
}
void MetavoxelSession::handleMessage(const QVariant& message) {
@ -183,7 +246,8 @@ void MetavoxelSession::handleMessage(const QVariant& message) {
_lod = state.lod;
} else if (userType == MetavoxelEditMessage::Type) {
_server->applyEdit(message.value<MetavoxelEditMessage>());
QMetaObject::invokeMethod(_sender->getServer(), "applyEdit", Q_ARG(const MetavoxelEditMessage&,
message.value<MetavoxelEditMessage>()));
} else if (userType == QMetaType::QVariantList) {
foreach (const QVariant& element, message.toList()) {

View file

@ -21,6 +21,7 @@
class MetavoxelEditMessage;
class MetavoxelPersister;
class MetavoxelSender;
class MetavoxelSession;
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
@ -31,27 +32,64 @@ public:
MetavoxelServer(const QByteArray& packet);
void applyEdit(const MetavoxelEditMessage& edit);
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit);
const MetavoxelData& getData() const { return _data; }
Q_INVOKABLE void setData(const MetavoxelData& data) { _data = data; }
Q_INVOKABLE void setData(const MetavoxelData& data);
virtual void run();
virtual void readPendingDatagrams();
virtual void aboutToFinish();
signals:
void dataChanged(const MetavoxelData& data);
private slots:
void maybeAttachSession(const SharedNodePointer& node);
void sendDeltas();
void maybeDeleteSession(const SharedNodePointer& node);
private:
QVector<MetavoxelSender*> _senders;
int _nextSender;
MetavoxelPersister* _persister;
MetavoxelData _data;
};
/// Handles update sending for one thread.
class MetavoxelSender : public QObject {
Q_OBJECT
public:
MetavoxelSender(MetavoxelServer* server);
MetavoxelServer* getServer() const { return _server; }
const MetavoxelData& getData() const { return _data; }
Q_INVOKABLE void start();
Q_INVOKABLE void addSession(QObject* session);
private slots:
void setData(const MetavoxelData& data) { _data = data; }
void sendDeltas();
void removeSession(QObject* session);
private:
MetavoxelServer* _server;
QSet<MetavoxelSession*> _sessions;
QTimer _sendTimer;
qint64 _lastSend;
@ -64,8 +102,8 @@ class MetavoxelSession : public Endpoint {
public:
MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server);
MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender);
virtual void update();
protected:
@ -83,7 +121,7 @@ private:
void sendPacketGroup(int alreadySent = 0);
MetavoxelServer* _server;
MetavoxelSender* _sender;
MetavoxelLOD _lod;

View file

@ -255,13 +255,24 @@ function update(deltaTime){
}
frame++;
}
var locationChanged = false;
if (location.hostname != oldHost) {
print("Changed domain");
for (model in models) {
removeIndicators(models[model]);
}
oldHost = location.hostname;
locationChanged = true;
}
if (MyAvatar.position.x != avatarOldPosition.x &&
MyAvatar.position.y != avatarOldPosition.y &&
MyAvatar.position.z != avatarOldPosition.z) {
if (MyAvatar.position.x != avatarOldPosition.x ||
MyAvatar.position.y != avatarOldPosition.y ||
MyAvatar.position.z != avatarOldPosition.z ||
locationChanged) {
avatarOldPosition = MyAvatar.position;
var SEARCH_RADIUS = 10;
var SEARCH_RADIUS = 50;
var foundModels = Models.findModels(MyAvatar.position, SEARCH_RADIUS);
// Let's remove indicator that got out of radius
for (model in models) {
@ -274,7 +285,10 @@ function update(deltaTime){
for (var i = 0; i < foundModels.length; ++i) {
var model = foundModels[i];
if (typeof(models[model.id]) == "undefined") {
addIndicators(model);
model.properties = Models.getModelProperties(model);
if (Vec3.distance(model.properties.position, MyAvatar.position) < SEARCH_RADIUS) {
addIndicators(model);
}
}
}
@ -283,9 +297,9 @@ function update(deltaTime){
}
}
}
var oldHost = location.hostname;
function addIndicators(modelID) {
modelID.properties = Models.getModelProperties(modelID);
if (modelID.properties.sittingPoints.length > 0) {
for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) {
modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i);

View file

@ -18,7 +18,7 @@ void main(void) {
// standard diffuse lighting
gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb +
gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))),
gl_Color.a);
0.0);
// extract the first three components of the vertex for position
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);

View file

@ -10,6 +10,8 @@
//
#include <QMutexLocker>
#include <QReadLocker>
#include <QWriteLocker>
#include <QtDebug>
#include <glm/gtx/transform.hpp>
@ -23,183 +25,139 @@
#include "MetavoxelSystem.h"
#include "renderer/Model.h"
REGISTER_META_OBJECT(PointMetavoxelRendererImplementation)
REGISTER_META_OBJECT(SphereRenderer)
REGISTER_META_OBJECT(StaticModelRenderer)
ProgramObject MetavoxelSystem::_program;
int MetavoxelSystem::_pointScaleLocation;
MetavoxelSystem::MetavoxelSystem() :
_simulateVisitor(_points),
_buffer(QOpenGLBuffer::VertexBuffer) {
}
static int bufferPointVectorMetaTypeId = qRegisterMetaType<BufferPointVector>();
void MetavoxelSystem::init() {
MetavoxelClientManager::init();
if (!_program.isLinked()) {
_program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
_program.link();
_pointScaleLocation = _program.uniformLocation("pointScale");
}
_buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
_buffer.create();
PointMetavoxelRendererImplementation::init();
_pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute());
}
MetavoxelLOD MetavoxelSystem::getLOD() const {
// the LOD threshold is temporarily tied to the avatar LOD parameter
const float BASE_LOD_THRESHOLD = 0.01f;
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(),
BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier());
MetavoxelLOD MetavoxelSystem::getLOD() {
QReadLocker locker(&_lodLock);
return _lod;
}
class SpannerSimulateVisitor : public SpannerVisitor {
public:
SpannerSimulateVisitor(float deltaTime);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
private:
float _deltaTime;
};
SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(),
Application::getInstance()->getMetavoxels()->getLOD()),
_deltaTime(deltaTime) {
}
bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->simulate(_deltaTime);
return true;
}
void MetavoxelSystem::simulate(float deltaTime) {
// update the clients
_points.clear();
_simulateVisitor.setDeltaTime(deltaTime);
_simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection());
update();
_buffer.bind();
int bytes = _points.size() * sizeof(Point);
if (_buffer.size() < bytes) {
_buffer.allocate(_points.constData(), bytes);
} else {
_buffer.write(0, _points.constData(), bytes);
// update the lod
{
// the LOD threshold is temporarily tied to the avatar LOD parameter
QWriteLocker locker(&_lodLock);
const float BASE_LOD_THRESHOLD = 0.01f;
_lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(),
BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier());
}
_buffer.release();
SpannerSimulateVisitor spannerSimulateVisitor(deltaTime);
guide(spannerSimulateVisitor);
}
class SpannerRenderVisitor : public SpannerVisitor {
public:
SpannerRenderVisitor();
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
};
SpannerRenderVisitor::SpannerRenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(),
Application::getInstance()->getMetavoxels()->getLOD(),
encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) {
}
bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize);
return true;
}
class RenderVisitor : public MetavoxelVisitor {
public:
RenderVisitor(const MetavoxelLOD& lod);
virtual int visit(MetavoxelInfo& info);
};
RenderVisitor::RenderVisitor(const MetavoxelLOD& lod) :
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(),
QVector<AttributePointer>(), lod) {
}
int RenderVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue<
SharedObjectPointer>().data())->getImplementation()->render(*_data, info, _lod);
return STOP_RECURSION;
}
void MetavoxelSystem::render() {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
const int VIEWPORT_WIDTH_INDEX = 2;
const int VIEWPORT_HEIGHT_INDEX = 3;
float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];
float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];
float viewportDiagonal = sqrtf(viewportWidth*viewportWidth + viewportHeight*viewportHeight);
float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(),
Application::getInstance()->getViewFrustum()->getNearTopRight());
_program.bind();
_program.setUniformValue(_pointScaleLocation, viewportDiagonal *
Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal);
_buffer.bind();
Point* pt = 0;
glVertexPointer(4, GL_FLOAT, sizeof(Point), &pt->vertex);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Point), &pt->color);
glNormalPointer(GL_BYTE, sizeof(Point), &pt->normal);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDrawArrays(GL_POINTS, 0, _points.size());
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
_buffer.release();
_program.release();
RenderVisitor renderVisitor(getLOD());
guideToAugmented(renderVisitor);
SpannerRenderVisitor spannerRenderVisitor;
guide(spannerRenderVisitor);
}
MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
return new MetavoxelSystemClient(node, _updater);
}
void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor) {
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex());
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
if (client) {
client->guide(_renderVisitor);
client->getAugmentedData().guide(visitor);
}
}
}
}
MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
return new MetavoxelSystemClient(node, this);
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
MetavoxelClient(node, updater) {
}
void MetavoxelSystem::updateClient(MetavoxelClient* client) {
MetavoxelClientManager::updateClient(client);
client->guide(_simulateVisitor);
void MetavoxelSystemClient::setAugmentedData(const MetavoxelData& data) {
QWriteLocker locker(&_augmentedDataLock);
_augmentedData = data;
}
MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
AttributeRegistry::getInstance()->getNormalAttribute() <<
AttributeRegistry::getInstance()->getSpannerColorAttribute() <<
AttributeRegistry::getInstance()->getSpannerNormalAttribute()),
_points(points) {
}
bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->simulate(_deltaTime);
return true;
}
int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
SpannerVisitor::visit(info);
if (!info.isLeaf) {
return _order;
}
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
quint8 alpha = qAlpha(color);
if (!info.isLODLeaf) {
if (alpha > 0) {
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
_points.append(point);
}
} else {
QRgb spannerColor = info.inputValues.at(2).getInlineValue<QRgb>();
QRgb spannerNormal = info.inputValues.at(3).getInlineValue<QRgb>();
quint8 spannerAlpha = qAlpha(spannerColor);
if (spannerAlpha > 0) {
if (alpha > 0) {
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha },
{ quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } };
_points.append(point);
} else {
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha },
{ quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } };
_points.append(point);
}
} else if (alpha > 0) {
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
_points.append(point);
}
}
return STOP_RECURSION;
}
MetavoxelSystem::RenderVisitor::RenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannerMaskAttribute()) {
}
bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize);
return true;
}
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) :
MetavoxelClient(node, system) {
MetavoxelData MetavoxelSystemClient::getAugmentedData() {
QReadLocker locker(&_augmentedDataLock);
return _augmentedData;
}
int MetavoxelSystemClient::parseData(const QByteArray& packet) {
@ -209,11 +167,284 @@ int MetavoxelSystemClient::parseData(const QByteArray& packet) {
return packet.size();
}
class AugmentVisitor : public MetavoxelVisitor {
public:
AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData);
virtual int visit(MetavoxelInfo& info);
private:
const MetavoxelData& _previousData;
};
AugmentVisitor::AugmentVisitor(const MetavoxelLOD& lod, const MetavoxelData& previousData) :
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getRendererAttribute(),
QVector<AttributePointer>(), lod),
_previousData(previousData) {
}
int AugmentVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
static_cast<MetavoxelRenderer*>(info.inputValues.at(0).getInlineValue<
SharedObjectPointer>().data())->getImplementation()->augment(*_data, _previousData, info, _lod);
return STOP_RECURSION;
}
class Augmenter : public QRunnable {
public:
Augmenter(const SharedNodePointer& node, const MetavoxelData& data,
const MetavoxelData& previousData, const MetavoxelLOD& lod);
virtual void run();
private:
QWeakPointer<Node> _node;
MetavoxelData _data;
MetavoxelData _previousData;
MetavoxelLOD _lod;
};
Augmenter::Augmenter(const SharedNodePointer& node, const MetavoxelData& data,
const MetavoxelData& previousData, const MetavoxelLOD& lod) :
_node(node),
_data(data),
_previousData(previousData),
_lod(lod) {
}
void Augmenter::run() {
SharedNodePointer node = _node;
if (!node) {
return;
}
AugmentVisitor visitor(_lod, _previousData);
_data.guide(visitor);
QMutexLocker locker(&node->getMutex());
QMetaObject::invokeMethod(node->getLinkedData(), "setAugmentedData", Q_ARG(const MetavoxelData&, _data));
}
void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) {
MetavoxelClient::dataChanged(oldData);
QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD));
}
void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
NodeList::getInstance()->writeDatagram(data, _node);
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
}
PointBuffer::PointBuffer(const BufferPointVector& points) :
_points(points) {
}
void PointBuffer::render() {
// initialize buffer, etc. on first render
if (!_buffer.isCreated()) {
_buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
_buffer.create();
_buffer.bind();
_pointCount = _points.size();
_buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint));
_points.clear();
_buffer.release();
}
if (_pointCount == 0) {
return;
}
_buffer.bind();
BufferPoint* point = 0;
glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex);
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color);
glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal);
glDrawArrays(GL_POINTS, 0, _pointCount);
_buffer.release();
}
PointBufferAttribute::PointBufferAttribute() :
InlineAttribute<PointBufferPointer>("pointBuffer") {
}
bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const {
PointBufferPointer firstChild = decodeInline<PointBufferPointer>(children[0]);
for (int i = 1; i < MERGE_COUNT; i++) {
if (firstChild != decodeInline<PointBufferPointer>(children[i])) {
*(PointBufferPointer*)&parent = _defaultValue;
return false;
}
}
*(PointBufferPointer*)&parent = firstChild;
return true;
}
void PointMetavoxelRendererImplementation::init() {
if (!_program.isLinked()) {
_program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
_program.link();
_program.bind();
_pointScaleLocation = _program.uniformLocation("pointScale");
_program.release();
}
}
PointMetavoxelRendererImplementation::PointMetavoxelRendererImplementation() {
}
class PointAugmentVisitor : public MetavoxelVisitor {
public:
PointAugmentVisitor(const MetavoxelLOD& lod);
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info);
virtual bool postVisit(MetavoxelInfo& info);
private:
BufferPointVector _points;
float _pointLeafSize;
};
PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) :
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() <<
Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) {
}
const int ALPHA_RENDER_THRESHOLD = 0;
void PointAugmentVisitor::prepare(MetavoxelData* data) {
MetavoxelVisitor::prepare(data);
const float MAX_POINT_LEAF_SIZE = 64.0f;
_pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE);
}
int PointAugmentVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST);
}
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
quint8 alpha = qAlpha(color);
if (alpha > ALPHA_RENDER_THRESHOLD) {
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
_points.append(point);
}
if (info.size >= _pointLeafSize) {
BufferPointVector swapPoints;
_points.swap(swapPoints);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer(
new PointBuffer(swapPoints))));
}
return STOP_RECURSION;
}
bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) {
if (info.size != _pointLeafSize) {
return false;
}
BufferPointVector swapPoints;
_points.swap(swapPoints);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer(
new PointBuffer(swapPoints))));
return true;
}
void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
MetavoxelInfo& info, const MetavoxelLOD& lod) {
// copy the previous buffers
MetavoxelData expandedPrevious = previous;
while (expandedPrevious.getSize() < data.getSize()) {
expandedPrevious.expand();
}
const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute();
MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute);
if (root) {
data.setRoot(pointBufferAttribute, root);
root->incrementReferenceCount();
}
PointAugmentVisitor visitor(lod);
data.guideToDifferent(expandedPrevious, visitor);
}
class PointRenderVisitor : public MetavoxelVisitor {
public:
PointRenderVisitor(const MetavoxelLOD& lod);
virtual int visit(MetavoxelInfo& info);
private:
int _order;
};
PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) :
MetavoxelVisitor(QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(),
QVector<AttributePointer>(), lod),
_order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) {
}
int PointRenderVisitor::visit(MetavoxelInfo& info) {
PointBufferPointer buffer = info.inputValues.at(0).getInlineValue<PointBufferPointer>();
if (buffer) {
buffer->render();
}
return info.isLeaf ? STOP_RECURSION : _order;
}
void PointMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
const int VIEWPORT_WIDTH_INDEX = 2;
const int VIEWPORT_HEIGHT_INDEX = 3;
float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];
float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];
float viewportDiagonal = sqrtf(viewportWidth * viewportWidth + viewportHeight * viewportHeight);
float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(),
Application::getInstance()->getViewFrustum()->getNearTopRight());
_program.bind();
_program.setUniformValue(_pointScaleLocation, viewportDiagonal *
Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDisable(GL_BLEND);
PointRenderVisitor visitor(lod);
data.guide(visitor);
glEnable(GL_BLEND);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
_program.release();
}
ProgramObject PointMetavoxelRendererImplementation::_program;
int PointMetavoxelRendererImplementation::_pointScaleLocation;
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };
glClipPlane(plane, coefficients);
@ -251,7 +482,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum
return;
}
// slight performance optimization: don't render if clip bounds are entirely within sphere
Sphere* sphere = static_cast<Sphere*>(parent());
Sphere* sphere = static_cast<Sphere*>(_spanner);
Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize));
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
const float CLIP_PROPORTION = 0.95f;
@ -263,7 +494,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum
}
void SphereRenderer::renderUnclipped(float alpha, Mode mode) {
Sphere* sphere = static_cast<Sphere*>(parent());
Sphere* sphere = static_cast<Sphere*>(_spanner);
const QColor& color = sphere->getColor();
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha);
@ -284,6 +515,8 @@ StaticModelRenderer::StaticModelRenderer() :
}
void StaticModelRenderer::init(Spanner* spanner) {
SpannerRenderer::init(spanner);
_model->init();
StaticModel* staticModel = static_cast<StaticModel*>(spanner);
@ -305,7 +538,7 @@ void StaticModelRenderer::simulate(float deltaTime) {
const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents;
bounds = Box(extents.minimum, extents.maximum);
}
static_cast<StaticModel*>(parent())->setBounds(glm::translate(_model->getTranslation()) *
static_cast<StaticModel*>(_spanner)->setBounds(glm::translate(_model->getTranslation()) *
glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds);
_model->simulate(deltaTime);
}

View file

@ -14,6 +14,7 @@
#include <QList>
#include <QOpenGLBuffer>
#include <QReadWriteLock>
#include <QVector>
#include <glm/glm.hpp>
@ -30,11 +31,11 @@ class MetavoxelSystem : public MetavoxelClientManager {
public:
MetavoxelSystem();
virtual void init();
virtual MetavoxelLOD getLOD() const;
virtual MetavoxelLOD getLOD();
const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; }
void simulate(float deltaTime);
void render();
@ -42,59 +43,100 @@ public:
protected:
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
virtual void updateClient(MetavoxelClient* client);
private:
class Point {
public:
glm::vec4 vertex;
quint8 color[4];
quint8 normal[3];
};
void guideToAugmented(MetavoxelVisitor& visitor);
class SimulateVisitor : public SpannerVisitor {
public:
SimulateVisitor(QVector<Point>& points);
void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; }
void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); }
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
virtual int visit(MetavoxelInfo& info);
AttributePointer _pointBufferAttribute;
private:
QVector<Point>& _points;
float _deltaTime;
int _order;
};
class RenderVisitor : public SpannerVisitor {
public:
RenderVisitor();
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
};
static ProgramObject _program;
static int _pointScaleLocation;
QVector<Point> _points;
SimulateVisitor _simulateVisitor;
RenderVisitor _renderVisitor;
QOpenGLBuffer _buffer;
MetavoxelLOD _lod;
QReadWriteLock _lodLock;
};
/// Describes contents of a point in a point buffer.
class BufferPoint {
public:
glm::vec4 vertex;
quint8 color[3];
quint8 normal[3];
};
typedef QVector<BufferPoint> BufferPointVector;
Q_DECLARE_METATYPE(BufferPointVector)
/// A client session associated with a single server.
class MetavoxelSystemClient : public MetavoxelClient {
Q_OBJECT
public:
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system);
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
Q_INVOKABLE void setAugmentedData(const MetavoxelData& data);
/// Returns a copy of the augmented data. This function is thread-safe.
MetavoxelData getAugmentedData();
virtual int parseData(const QByteArray& packet);
protected:
virtual void dataChanged(const MetavoxelData& oldData);
virtual void sendDatagram(const QByteArray& data);
private:
MetavoxelData _augmentedData;
QReadWriteLock _augmentedDataLock;
};
/// Contains the information necessary to render a group of points.
class PointBuffer : public QSharedData {
public:
PointBuffer(const BufferPointVector& points);
void render();
private:
BufferPointVector _points;
QOpenGLBuffer _buffer;
int _pointCount;
};
typedef QExplicitlySharedDataPointer<PointBuffer> PointBufferPointer;
/// A client-side attribute that stores point buffers.
class PointBufferAttribute : public InlineAttribute<PointBufferPointer> {
Q_OBJECT
public:
Q_INVOKABLE PointBufferAttribute();
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
};
/// Renders metavoxels as points.
class PointMetavoxelRendererImplementation : public MetavoxelRendererImplementation {
Q_OBJECT
public:
static void init();
Q_INVOKABLE PointMetavoxelRendererImplementation();
virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod);
private:
static ProgramObject _program;
static int _pointScaleLocation;
};
/// Base class for spanner renderers; provides clipping.

View file

@ -48,7 +48,13 @@ Stats::Stats():
_pingStatsWidth(STATS_PING_MIN_WIDTH),
_geoStatsWidth(STATS_GEO_MIN_WIDTH),
_voxelStatsWidth(STATS_VOXEL_MIN_WIDTH),
_lastHorizontalOffset(0)
_lastHorizontalOffset(0),
_metavoxelInternal(0),
_metavoxelLeaves(0),
_metavoxelSendProgress(0),
_metavoxelSendTotal(0),
_metavoxelReceiveProgress(0),
_metavoxelReceiveTotal(0)
{
QGLWidget* glWidget = Application::getInstance()->getGLWidget();
resetWidth(glWidget->width(), 0);
@ -364,36 +370,26 @@ void Stats::display(
verticalOffset += STATS_PELS_PER_LINE;
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);
}
}
}
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels()->getUpdater(), "getStats",
Q_ARG(QObject*, this), Q_ARG(const QByteArray&, "setMetavoxelStats"));
stringstream nodes;
nodes << "Metavoxels: " << (internal + leaves);
nodes << "Metavoxels: " << (_metavoxelInternal + _metavoxelLeaves);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodes.str().c_str(), color);
stringstream nodeTypes;
nodeTypes << "Internal: " << internal << " Leaves: " << leaves;
nodeTypes << "Internal: " << _metavoxelInternal << " Leaves: " << _metavoxelLeaves;
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodeTypes.str().c_str(), color);
if (sendTotal > 0 || receiveTotal > 0) {
if (_metavoxelSendTotal > 0 || _metavoxelReceiveTotal > 0) {
stringstream reliableStats;
if (sendTotal > 0) {
reliableStats << "Upload: " << (sendProgress * 100 / sendTotal) << "% ";
if (_metavoxelSendTotal > 0) {
reliableStats << "Upload: " << (_metavoxelSendProgress * 100 / _metavoxelSendTotal) << "% ";
}
if (receiveTotal > 0) {
reliableStats << "Download: " << (receiveProgress * 100 / receiveTotal) << "%";
if (_metavoxelReceiveTotal > 0) {
reliableStats << "Download: " << (_metavoxelReceiveProgress * 100 / _metavoxelReceiveTotal) << "%";
}
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reliableStats.str().c_str(), color);
@ -726,3 +722,13 @@ void Stats::display(
}
void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress,
int sendTotal, int receiveProgress, int receiveTotal) {
_metavoxelInternal = internal;
_metavoxelLeaves = leaves;
_metavoxelSendProgress = sendProgress;
_metavoxelSendTotal = sendTotal;
_metavoxelReceiveProgress = receiveProgress;
_metavoxelReceiveTotal = receiveTotal;
}

View file

@ -31,6 +31,10 @@ public:
void resetWidth(int width, int horizontalOffset);
void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess);
bool includeTimingRecord(const QString& name);
Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress,
int sendTotal, int receiveProgress, int receiveTotal);
private:
static Stats* _sharedInstance;
@ -45,6 +49,13 @@ private:
int _voxelStatsWidth;
int _lastHorizontalOffset;
int _metavoxelInternal;
int _metavoxelLeaves;
int _metavoxelSendProgress;
int _metavoxelSendTotal;
int _metavoxelReceiveProgress;
int _metavoxelReceiveTotal;
};
#endif // hifi_Stats_h

View file

@ -17,10 +17,11 @@ BillboardOverlay::BillboardOverlay()
: _fromImage(-1,-1,-1,-1),
_scale(1.0f),
_isFacingAvatar(true) {
_isLoaded = false;
}
void BillboardOverlay::render() {
if (!_visible) {
if (!_visible || !_isLoaded) {
return;
}
@ -85,16 +86,7 @@ void BillboardOverlay::render() {
((float)_fromImage.y() + (float)_fromImage.height()) / (float)_size.height());
glVertex2f(-x, y);
} glEnd();
} else {
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
glBegin(GL_QUADS); {
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
} glEnd();
}
} glPopMatrix();
glDisable(GL_TEXTURE_2D);
@ -167,6 +159,7 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
}
void BillboardOverlay::setBillboardURL(const QUrl url) {
_isLoaded = false;
QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished);
}
@ -175,4 +168,5 @@ void BillboardOverlay::replyFinished() {
// replace our byte array with the downloaded data
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
_billboard = reply->readAll();
_isLoaded = true;
}

View file

@ -24,6 +24,7 @@ ImageOverlay::ImageOverlay() :
_textureBound(false),
_wantClipFromImage(false)
{
_isLoaded = false;
}
ImageOverlay::~ImageOverlay() {
@ -35,6 +36,7 @@ ImageOverlay::~ImageOverlay() {
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
void ImageOverlay::setImageURL(const QUrl& url) {
_isLoaded = false;
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished);
@ -47,10 +49,11 @@ void ImageOverlay::replyFinished() {
QByteArray rawData = reply->readAll();
_textureImage.loadFromData(rawData);
_renderImage = true;
_isLoaded = true;
}
void ImageOverlay::render() {
if (!_visible) {
if (!_visible || !_isLoaded) {
return; // do nothing if we're not visible
}
if (_renderImage && !_textureBound) {

View file

@ -15,8 +15,10 @@
ModelOverlay::ModelOverlay()
: _model(),
_scale(1.0f),
_updateModel(false) {
_updateModel(false)
{
_model.init();
_isLoaded = false;
}
void ModelOverlay::update(float deltatime) {
@ -32,6 +34,7 @@ void ModelOverlay::update(float deltatime) {
} else {
_model.simulate(deltatime);
}
_isLoaded = _model.isActive();
}
void ModelOverlay::render() {
@ -90,6 +93,7 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
if (urlValue.isValid()) {
_url = urlValue.toVariant().toString();
_updateModel = true;
_isLoaded = false;
}
QScriptValue scaleValue = properties.property("scale");

View file

@ -21,6 +21,7 @@
Overlay::Overlay() :
_parent(NULL),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_color(DEFAULT_OVERLAY_COLOR),
_visible(true),

View file

@ -40,6 +40,7 @@ public:
virtual void render() = 0;
// getters
bool isLoaded() { return _isLoaded; }
bool getVisible() const { return _visible; }
const xColor& getColor() const { return _color; }
float getAlpha() const { return _alpha; }
@ -55,6 +56,7 @@ public:
protected:
QGLWidget* _parent;
bool _isLoaded;
float _alpha;
xColor _color;
bool _visible; // should the overlay be drawn at all

View file

@ -227,11 +227,23 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
i.previous();
unsigned int thisID = i.key();
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value());
if (thisOverlay->getVisible() && thisOverlay->getBounds().contains(point.x, point.y, false)) {
if (thisOverlay->getVisible() && thisOverlay->isLoaded() && thisOverlay->getBounds().contains(point.x, point.y, false)) {
return thisID;
}
}
return 0; // not found
}
bool Overlays::isLoaded(unsigned int id) {
QReadLocker lock(&_lock);
Overlay* overlay = _overlays2D.value(id);
if (!overlay) {
_overlays3D.value(id);
}
if (!overlay) {
return false; // not found
}
return overlay->isLoaded();
}

View file

@ -38,6 +38,9 @@ public slots:
/// returns the top most overlay at the screen point, or 0 if not overlay at that point
unsigned int getOverlayAtPoint(const glm::vec2& point);
/// returns whether the overlay's assets are loaded or not
bool isLoaded(unsigned int id);
private:
QMap<unsigned int, Overlay*> _overlays2D;

View file

@ -35,7 +35,9 @@ AttributeRegistry* AttributeRegistry::getInstance() {
AttributeRegistry::AttributeRegistry() :
_guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject,
SharedObjectPointer(new DefaultMetavoxelGuide())))),
new DefaultMetavoxelGuide()))),
_rendererAttribute(registerAttribute(new SharedObjectAttribute("renderer", &MetavoxelRenderer::staticMetaObject,
new PointMetavoxelRenderer()))),
_spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))),
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))),
@ -197,7 +199,7 @@ MetavoxelNode* Attribute::createMetavoxelNode(const AttributeValue& value, const
}
void Attribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) {
data.createRoot(state.attribute)->read(state);
data.createRoot(state.base.attribute)->read(state);
}
void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
@ -205,7 +207,7 @@ void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamSta
}
void Attribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) {
data.createRoot(state.attribute)->readDelta(reference, state);
data.createRoot(state.base.attribute)->readDelta(reference, state);
}
void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) {
@ -214,10 +216,10 @@ void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNo
void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) {
// copy if changed
MetavoxelNode* oldRoot = data.getRoot(state.attribute);
MetavoxelNode* oldRoot = data.getRoot(state.base.attribute);
MetavoxelNode* newRoot = oldRoot->readSubdivision(state);
if (newRoot != oldRoot) {
data.setRoot(state.attribute, newRoot);
data.setRoot(state.base.attribute, newRoot);
}
}
@ -567,62 +569,62 @@ SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject*
void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) {
forever {
SharedObjectPointer object;
state.stream >> object;
state.base.stream >> object;
if (!object) {
break;
}
data.insert(state.attribute, object);
data.insert(state.base.attribute, object);
}
// even if the root is empty, it should still exist
if (!data.getRoot(state.attribute)) {
data.createRoot(state.attribute);
if (!data.getRoot(state.base.attribute)) {
data.createRoot(state.base.attribute);
}
}
void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) {
Spanner::incrementVisit();
state.base.visit = Spanner::getAndIncrementNextVisit();
root.writeSpanners(state);
state.stream << SharedObjectPointer();
state.base.stream << SharedObjectPointer();
}
void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data,
const MetavoxelNode& reference, MetavoxelStreamState& state) {
forever {
SharedObjectPointer object;
state.stream >> object;
state.base.stream >> object;
if (!object) {
break;
}
data.toggle(state.attribute, object);
data.toggle(state.base.attribute, object);
}
// even if the root is empty, it should still exist
if (!data.getRoot(state.attribute)) {
data.createRoot(state.attribute);
if (!data.getRoot(state.base.attribute)) {
data.createRoot(state.base.attribute);
}
}
void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root,
const MetavoxelNode& reference, MetavoxelStreamState& state) {
Spanner::incrementVisit();
state.base.visit = Spanner::getAndIncrementNextVisit();
root.writeSpannerDelta(reference, state);
state.stream << SharedObjectPointer();
state.base.stream << SharedObjectPointer();
}
void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) {
forever {
SharedObjectPointer object;
state.stream >> object;
state.base.stream >> object;
if (!object) {
break;
}
data.insert(state.attribute, object);
data.insert(state.base.attribute, object);
}
}
void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) {
Spanner::incrementVisit();
state.base.visit = Spanner::getAndIncrementNextVisit();
root.writeSpannerSubdivision(state);
state.stream << SharedObjectPointer();
state.base.stream << SharedObjectPointer();
}
bool SpannerSetAttribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot,

View file

@ -73,6 +73,9 @@ public:
/// Returns a reference to the standard SharedObjectPointer "guide" attribute.
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
/// Returns a reference to the standard SharedObjectPointer "renderer" attribute.
const AttributePointer& getRendererAttribute() const { return _rendererAttribute; }
/// Returns a reference to the standard SharedObjectSet "spanners" attribute.
const AttributePointer& getSpannersAttribute() const { return _spannersAttribute; }
@ -99,6 +102,7 @@ private:
QReadWriteLock _attributesLock;
AttributePointer _guideAttribute;
AttributePointer _rendererAttribute;
AttributePointer _spannersAttribute;
AttributePointer _colorAttribute;
AttributePointer _normalAttribute;

View file

@ -29,7 +29,7 @@ const float DEFAULT_SLOW_START_THRESHOLD = 1000.0f;
DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* parent) :
QObject(parent),
_outgoingPacketStream(&_outgoingPacketData, QIODevice::WriteOnly),
_outputStream(_outgoingPacketStream),
_outputStream(_outgoingPacketStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this),
_incomingDatagramStream(&_incomingDatagramBuffer),
_datagramHeaderSize(datagramHeader.size()),
_outgoingPacketNumber(0),
@ -38,7 +38,7 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject*
_outgoingDatagramStream(&_outgoingDatagramBuffer),
_incomingPacketNumber(0),
_incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly),
_inputStream(_incomingPacketStream),
_inputStream(_incomingPacketStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this),
_receivedHighPriorityMessages(0),
_maxPacketSize(DEFAULT_MAX_PACKET_SIZE),
_packetsPerGroup(1.0f),
@ -752,7 +752,7 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o
_index(index),
_output(output),
_dataStream(&_buffer),
_bitstream(_dataStream),
_bitstream(_dataStream, Bitstream::NO_METADATA, Bitstream::NO_GENERICS, this),
_priority(1.0f),
_offset(0),
_writePosition(0),

View file

@ -15,7 +15,7 @@
Endpoint::Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendRecord, PacketRecord* baselineReceiveRecord) :
_node(node),
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) {
_sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData), this) {
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&)));
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&)));
@ -49,7 +49,7 @@ void Endpoint::update() {
int Endpoint::parseData(const QByteArray& packet) {
// process through sequencer
_sequencer.receivedDatagram(packet);
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
return packet.size();
}

View file

@ -9,25 +9,31 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QDateTime>
#include <QReadLocker>
#include <QThread>
#include <QWriteLocker>
#include "MetavoxelClientManager.h"
#include "MetavoxelMessages.h"
void MetavoxelClientManager::init() {
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
MetavoxelClientManager::MetavoxelClientManager() :
_updater(new MetavoxelUpdater(this)) {
QThread* thread = new QThread(this);
_updater->moveToThread(thread);
connect(thread, &QThread::finished, _updater, &QObject::deleteLater);
thread->start();
QMetaObject::invokeMethod(_updater, "start");
}
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);
}
}
}
MetavoxelClientManager::~MetavoxelClientManager() {
_updater->thread()->quit();
_updater->thread()->wait();
}
void MetavoxelClientManager::init() {
connect(NodeList::getInstance(), &NodeList::nodeAdded, this, &MetavoxelClientManager::maybeAttachClient);
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &MetavoxelClientManager::maybeDeleteClient);
}
SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(const glm::vec3& origin,
@ -40,7 +46,7 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
if (client) {
float clientDistance;
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
SharedObjectPointer clientSpanner = client->getDataCopy().findFirstRaySpannerIntersection(
origin, direction, attribute, clientDistance);
if (clientSpanner && clientDistance < closestDistance) {
closestSpanner = clientSpanner;
@ -69,43 +75,113 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool
}
void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
return;
}
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);
}
}
}
QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
}
MetavoxelLOD MetavoxelClientManager::getLOD() const {
MetavoxelLOD MetavoxelClientManager::getLOD() {
return MetavoxelLOD();
}
void MetavoxelClientManager::maybeAttachClient(const SharedNodePointer& node) {
if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex());
node->setLinkedData(createClient(node));
MetavoxelClient* client = createClient(node);
client->moveToThread(_updater->thread());
QMetaObject::invokeMethod(_updater, "addClient", Q_ARG(QObject*, client));
node->setLinkedData(client);
}
}
void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) {
if (node->getType() == NodeType::MetavoxelServer) {
// we assume the node is already locked
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
if (client) {
node->setLinkedData(NULL);
client->deleteLater();
}
}
}
MetavoxelClient* MetavoxelClientManager::createClient(const SharedNodePointer& node) {
return new MetavoxelClient(node, this);
return new MetavoxelClient(node, _updater);
}
void MetavoxelClientManager::updateClient(MetavoxelClient* client) {
client->update();
void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) {
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->getDataCopy().guide(visitor);
}
}
}
}
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) :
MetavoxelUpdater::MetavoxelUpdater(MetavoxelClientManager* clientManager) :
_clientManager(clientManager),
_sendTimer(this) {
_sendTimer.setSingleShot(true);
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelUpdater::sendUpdates);
}
const int SEND_INTERVAL = 33;
void MetavoxelUpdater::start() {
_lastSend = QDateTime::currentMSecsSinceEpoch();
_sendTimer.start(SEND_INTERVAL);
}
void MetavoxelUpdater::addClient(QObject* client) {
_clients.insert(static_cast<MetavoxelClient*>(client));
connect(client, &QObject::destroyed, this, &MetavoxelUpdater::removeClient);
}
void MetavoxelUpdater::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
// apply to all clients
foreach (MetavoxelClient* client, _clients) {
client->applyEdit(edit, reliable);
}
}
void MetavoxelUpdater::getStats(QObject* receiver, const QByteArray& method) {
int internal = 0, leaves = 0;
int sendProgress = 0, sendTotal = 0;
int receiveProgress = 0, receiveTotal = 0;
foreach (MetavoxelClient* client, _clients) {
client->getData().countNodes(internal, leaves, _lod);
client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal);
}
QMetaObject::invokeMethod(receiver, method.constData(), Q_ARG(int, internal), Q_ARG(int, leaves), Q_ARG(int, sendProgress),
Q_ARG(int, sendTotal), Q_ARG(int, receiveProgress), Q_ARG(int, receiveTotal));
}
void MetavoxelUpdater::sendUpdates() {
// get the latest LOD from the client manager
_lod = _clientManager->getLOD();
// send updates for all clients
foreach (MetavoxelClient* client, _clients) {
client->update();
}
// restart the send timer
qint64 now = QDateTime::currentMSecsSinceEpoch();
int elapsed = now - _lastSend;
_lastSend = now;
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
}
void MetavoxelUpdater::removeClient(QObject* client) {
_clients.remove(static_cast<MetavoxelClient*>(client));
}
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
Endpoint(node, new PacketRecord(), new PacketRecord()),
_manager(manager),
_updater(updater),
_reliableDeltaChannel(NULL),
_reliableDeltaID(0) {
@ -113,9 +189,9 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientM
SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&)));
}
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
visitor.setLOD(_manager->getLOD());
_data.guide(visitor);
MetavoxelData MetavoxelClient::getDataCopy() {
QReadLocker locker(&_dataCopyLock);
return _dataCopy;
}
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
@ -124,15 +200,25 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable)
} else {
// apply immediately to local tree
MetavoxelData oldData = _data;
edit.apply(_data, _sequencer.getWeakSharedObjectHash());
if (_data != oldData) {
dataChanged(oldData);
}
// start sending it out
_sequencer.sendHighPriorityMessage(QVariant::fromValue(edit));
}
}
void MetavoxelClient::dataChanged(const MetavoxelData& oldData) {
// make thread-safe copy
QWriteLocker locker(&_dataCopyLock);
_dataCopy = _data;
}
void MetavoxelClient::writeUpdateMessage(Bitstream& out) {
ClientStateMessage state = { _manager->getLOD() };
ClientStateMessage state = { _updater->getLOD() };
out << QVariant::fromValue(state);
}
@ -152,12 +238,16 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
in.reset();
}
// copy to local and reapply local edits
MetavoxelData oldData = _data;
_data = _remoteData;
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
if (message.data.userType() == MetavoxelEditMessage::Type) {
message.data.value<MetavoxelEditMessage>().apply(_data, _sequencer.getWeakSharedObjectHash());
}
}
if (_data != oldData) {
dataChanged(oldData);
}
} else if (userType == MetavoxelDeltaPendingMessage::Type) {
// check the id to make sure this is not a delta we've already processed
int id = message.value<MetavoxelDeltaPendingMessage>().id;
@ -176,7 +266,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
}
PacketRecord* MetavoxelClient::maybeCreateSendRecord() const {
return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _manager->getLOD());
return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _updater->getLOD());
}
PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const {

View file

@ -12,10 +12,14 @@
#ifndef hifi_MetavoxelClientManager_h
#define hifi_MetavoxelClientManager_h
#include <QReadWriteLock>
#include <QTimer>
#include "Endpoint.h"
class MetavoxelClient;
class MetavoxelEditMessage;
class MetavoxelUpdater;
/// Manages the set of connected metavoxel clients.
class MetavoxelClientManager : public QObject {
@ -23,8 +27,12 @@ class MetavoxelClientManager : public QObject {
public:
MetavoxelClientManager();
virtual ~MetavoxelClientManager();
virtual void init();
void update();
MetavoxelUpdater* getUpdater() const { return _updater; }
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, float& distance);
@ -35,16 +43,57 @@ public:
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
virtual MetavoxelLOD getLOD() const;
/// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread.
virtual MetavoxelLOD getLOD();
private slots:
void maybeAttachClient(const SharedNodePointer& node);
void maybeDeleteClient(const SharedNodePointer& node);
protected:
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
virtual void updateClient(MetavoxelClient* client);
void guide(MetavoxelVisitor& visitor);
MetavoxelUpdater* _updater;
};
/// Handles updates in a dedicated thread.
class MetavoxelUpdater : public QObject {
Q_OBJECT
public:
MetavoxelUpdater(MetavoxelClientManager* clientManager);
const MetavoxelLOD& getLOD() const { return _lod; }
Q_INVOKABLE void start();
Q_INVOKABLE void addClient(QObject* client);
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable);
/// Requests a set of statistics. The receiving method should take six integer arguments: internal node count, leaf count,
/// send progress, send total, receive progress, receive total.
Q_INVOKABLE void getStats(QObject* receiver, const QByteArray& method);
private slots:
void sendUpdates();
void removeClient(QObject* client);
private:
MetavoxelClientManager* _clientManager;
QSet<MetavoxelClient*> _clients;
QTimer _sendTimer;
qint64 _lastSend;
MetavoxelLOD _lod;
};
/// Base class for metavoxel clients.
@ -53,25 +102,27 @@ class MetavoxelClient : public Endpoint {
public:
MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager);
MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
MetavoxelData& getData() { return _data; }
/// Returns a reference to the most recent data. This function is *not* thread-safe.
const MetavoxelData& getData() const { return _data; }
/// Returns a copy of the most recent data. This function *is* thread-safe.
MetavoxelData getDataCopy();
void guide(MetavoxelVisitor& visitor);
void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
protected:
virtual void dataChanged(const MetavoxelData& oldData);
virtual void writeUpdateMessage(Bitstream& out);
virtual void handleMessage(const QVariant& message, Bitstream& in);
virtual PacketRecord* maybeCreateSendRecord() const;
virtual PacketRecord* maybeCreateReceiveRecord() const;
private:
MetavoxelClientManager* _manager;
MetavoxelUpdater* _updater;
MetavoxelData _data;
MetavoxelData _remoteData;
MetavoxelLOD _remoteDataLOD;
@ -79,6 +130,9 @@ private:
ReliableChannel* _reliableDeltaChannel;
MetavoxelLOD _reliableDeltaLOD;
int _reliableDeltaID;
MetavoxelData _dataCopy;
QReadWriteLock _dataCopyLock;
};
#endif // hifi_MetavoxelClientManager_h

View file

@ -12,6 +12,7 @@
#include <QDateTime>
#include <QDebugStateSaver>
#include <QScriptEngine>
#include <QThread>
#include <QtDebug>
#include <GeometryUtil.h>
@ -24,6 +25,8 @@ REGISTER_META_OBJECT(MetavoxelGuide)
REGISTER_META_OBJECT(DefaultMetavoxelGuide)
REGISTER_META_OBJECT(ScriptedMetavoxelGuide)
REGISTER_META_OBJECT(ThrobbingMetavoxelGuide)
REGISTER_META_OBJECT(MetavoxelRenderer)
REGISTER_META_OBJECT(PointMetavoxelRenderer)
REGISTER_META_OBJECT(Spanner)
REGISTER_META_OBJECT(Sphere)
REGISTER_META_OBJECT(StaticModel)
@ -80,18 +83,19 @@ Box MetavoxelData::getBounds() const {
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
// let the visitor know we're about to begin a tour
visitor.prepare();
visitor.prepare(this);
// start with the root values/defaults (plus the guide attribute)
const QVector<AttributePointer>& inputs = visitor.getInputs();
const QVector<AttributePointer>& outputs = visitor.getOutputs();
MetavoxelVisitation firstVisitation = { NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
QVector<MetavoxelNode*>(outputs.size()), { NULL, getMinimum(), _size,
QVector<AttributeValue>(inputs.size() + 1), QVector<OwnedAttributeValue>(outputs.size()) } };
MetavoxelVisitation& firstVisitation = visitor.acquireVisitation();
firstVisitation.info.minimum = getMinimum();
firstVisitation.info.size = _size;
for (int i = 0; i < inputs.size(); i++) {
MetavoxelNode* node = _roots.value(inputs.at(i));
const AttributePointer& input = inputs.at(i);
MetavoxelNode* node = _roots.value(input);
firstVisitation.inputNodes[i] = node;
firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(inputs[i]) : inputs[i];
firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(input) : input;
}
AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute();
MetavoxelNode* node = _roots.value(guideAttribute);
@ -119,6 +123,80 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
node->decrementReferenceCount(value.getAttribute());
_roots.remove(value.getAttribute());
}
value = AttributeValue();
}
visitor.releaseVisitation();
}
void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) {
// if the other data is smaller, we need to expand it to compare
const MetavoxelData* expandedOther = &other;
if (_size > other._size) {
MetavoxelData* expanded = new MetavoxelData(other);
while (expanded->_size < _size) {
expanded->expand();
}
expandedOther = expanded;
}
// let the visitor know we're about to begin a tour
visitor.prepare(this);
// start with the root values/defaults (plus the guide attribute)
const QVector<AttributePointer>& inputs = visitor.getInputs();
const QVector<AttributePointer>& outputs = visitor.getOutputs();
MetavoxelVisitation& firstVisitation = visitor.acquireVisitation();
firstVisitation.compareNodes.resize(inputs.size() + 1);
firstVisitation.info.minimum = getMinimum();
firstVisitation.info.size = _size;
bool allNodesSame = true;
for (int i = 0; i < inputs.size(); i++) {
const AttributePointer& input = inputs.at(i);
MetavoxelNode* node = _roots.value(input);
firstVisitation.inputNodes[i] = node;
firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(input) : input;
MetavoxelNode* compareNode = expandedOther->_roots.value(input);
firstVisitation.compareNodes[i] = compareNode;
allNodesSame &= (node == compareNode);
}
AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute();
MetavoxelNode* node = _roots.value(guideAttribute);
firstVisitation.inputNodes.last() = node;
firstVisitation.info.inputValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute;
MetavoxelNode* compareNode = expandedOther->_roots.value(guideAttribute);
firstVisitation.compareNodes.last() = compareNode;
allNodesSame &= (node == compareNode);
if (!allNodesSame) {
for (int i = 0; i < outputs.size(); i++) {
MetavoxelNode* node = _roots.value(outputs.at(i));
firstVisitation.outputNodes[i] = node;
}
static_cast<MetavoxelGuide*>(firstVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guideToDifferent(firstVisitation);
for (int i = 0; i < outputs.size(); i++) {
OwnedAttributeValue& value = firstVisitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
// replace the old node with the new
MetavoxelNode*& node = _roots[value.getAttribute()];
if (node) {
node->decrementReferenceCount(value.getAttribute());
}
node = firstVisitation.outputNodes.at(i);
if (node->isLeaf() && value.isDefault()) {
// immediately remove the new node if redundant
node->decrementReferenceCount(value.getAttribute());
_roots.remove(value.getAttribute());
}
value = AttributeValue();
}
}
visitor.releaseVisitation();
// delete the expanded other if we had to expand
if (expandedOther != &other) {
delete expandedOther;
}
}
@ -467,7 +545,8 @@ void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) {
if (!attribute) {
break;
}
MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, lod };
MetavoxelStreamBase base = { attribute, in, lod, lod };
MetavoxelStreamState state = { base, getMinimum(), _size };
attribute->readMetavoxelRoot(*this, state);
}
}
@ -476,7 +555,8 @@ void MetavoxelData::write(Bitstream& out, const MetavoxelLOD& lod) const {
out << _size;
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
out << it.key();
MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, lod };
MetavoxelStreamBase base = { it.key(), out, lod, lod };
MetavoxelStreamState state = { base, getMinimum(), _size };
it.key()->writeMetavoxelRoot(*it.value(), state);
}
out << AttributePointer();
@ -509,7 +589,8 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD
if (!attribute) {
break;
}
MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD };
MetavoxelStreamBase base = { attribute, in, lod, referenceLOD };
MetavoxelStreamState state = { base, getMinimum(), _size };
MetavoxelNode* oldRoot = _roots.value(attribute);
if (oldRoot) {
bool changed;
@ -565,7 +646,8 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO
// write the added/changed/subdivided roots
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key());
MetavoxelStreamState state = { minimum, _size, it.key(), out, lod, referenceLOD };
MetavoxelStreamBase base = { it.key(), out, lod, referenceLOD };
MetavoxelStreamState state = { base, minimum, _size };
if (it.value() != referenceRoot || becameSubdivided) {
out << it.key();
if (referenceRoot) {
@ -695,15 +777,15 @@ template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData&
}
bool MetavoxelStreamState::shouldSubdivide() const {
return lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier());
return base.lod.shouldSubdivide(minimum, size, base.attribute->getLODThresholdMultiplier());
}
bool MetavoxelStreamState::shouldSubdivideReference() const {
return referenceLOD.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier());
return base.referenceLOD.shouldSubdivide(minimum, size, base.attribute->getLODThresholdMultiplier());
}
bool MetavoxelStreamState::becameSubdivided() const {
return lod.becameSubdivided(minimum, size, referenceLOD, attribute->getLODThresholdMultiplier());
return base.lod.becameSubdivided(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier());
}
void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
@ -777,38 +859,36 @@ bool MetavoxelNode::isLeaf() const {
}
void MetavoxelNode::read(MetavoxelStreamState& state) {
clearChildren(state.attribute);
clearChildren(state.base.attribute);
if (!state.shouldSubdivide()) {
state.attribute->read(state.stream, _attributeValue, true);
state.base.attribute->read(state.base.stream, _attributeValue, true);
return;
}
bool leaf;
state.stream >> leaf;
state.attribute->read(state.stream, _attributeValue, leaf);
state.base.stream >> leaf;
state.base.attribute->read(state.base.stream, _attributeValue, leaf);
if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i] = new MetavoxelNode(state.attribute);
_children[i] = new MetavoxelNode(state.base.attribute);
_children[i]->read(nextState);
}
mergeChildren(state.attribute, true);
mergeChildren(state.base.attribute, true);
}
}
void MetavoxelNode::write(MetavoxelStreamState& state) const {
if (!state.shouldSubdivide()) {
state.attribute->write(state.stream, _attributeValue, true);
state.base.attribute->write(state.base.stream, _attributeValue, true);
return;
}
bool leaf = isLeaf();
state.stream << leaf;
state.attribute->write(state.stream, _attributeValue, leaf);
state.base.stream << leaf;
state.base.attribute->write(state.base.stream, _attributeValue, leaf);
if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i]->write(nextState);
@ -817,31 +897,30 @@ void MetavoxelNode::write(MetavoxelStreamState& state) const {
}
void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) {
clearChildren(state.attribute);
clearChildren(state.base.attribute);
if (!state.shouldSubdivide()) {
state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, true);
state.base.attribute->readDelta(state.base.stream, _attributeValue, reference._attributeValue, true);
return;
}
bool leaf;
state.stream >> leaf;
state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, leaf);
state.base.stream >> leaf;
state.base.attribute->readDelta(state.base.stream, _attributeValue, reference._attributeValue, leaf);
if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i] = new MetavoxelNode(state.attribute);
_children[i] = new MetavoxelNode(state.base.attribute);
_children[i]->read(nextState);
}
} else {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
bool changed;
state.stream >> changed;
state.base.stream >> changed;
if (changed) {
_children[i] = new MetavoxelNode(state.attribute);
_children[i] = new MetavoxelNode(state.base.attribute);
_children[i]->readDelta(*reference._children[i], nextState);
} else {
if (nextState.becameSubdivided()) {
@ -856,21 +935,20 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta
}
}
}
mergeChildren(state.attribute, true);
mergeChildren(state.base.attribute, true);
}
}
void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const {
if (!state.shouldSubdivide()) {
state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true);
state.base.attribute->writeDelta(state.base.stream, _attributeValue, reference._attributeValue, true);
return;
}
bool leaf = isLeaf();
state.stream << leaf;
state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf);
state.base.stream << leaf;
state.base.attribute->writeDelta(state.base.stream, _attributeValue, reference._attributeValue, leaf);
if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
@ -880,12 +958,12 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
if (_children[i] == reference._children[i]) {
state.stream << false;
state.base.stream << false;
if (nextState.becameSubdivided()) {
_children[i]->writeSubdivision(nextState);
}
} else {
state.stream << true;
state.base.stream << true;
_children[i]->writeDelta(*reference._children[i], nextState);
}
}
@ -896,40 +974,38 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt
MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) {
if (!state.shouldSubdivideReference()) {
bool leaf;
state.stream >> leaf;
state.base.stream >> leaf;
if (leaf) {
return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.attribute));
return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute));
} else {
MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.attribute));
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute));
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
newNode->_children[i] = new MetavoxelNode(state.attribute);
newNode->_children[i] = new MetavoxelNode(state.base.attribute);
newNode->_children[i]->read(nextState);
}
return newNode;
}
} else if (!isLeaf()) {
MetavoxelNode* node = this;
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
if (nextState.becameSubdivided()) {
MetavoxelNode* child = _children[i]->readSubdivision(nextState);
if (child != _children[i]) {
if (node == this) {
node = new MetavoxelNode(state.attribute, this);
node = new MetavoxelNode(state.base.attribute, this);
}
node->_children[i] = child;
_children[i]->decrementReferenceCount(state.attribute);
_children[i]->decrementReferenceCount(state.base.attribute);
}
}
}
if (node != this) {
node->mergeChildren(state.attribute, true);
node->mergeChildren(state.base.attribute, true);
}
return node;
}
@ -939,18 +1015,16 @@ MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) {
void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const {
bool leaf = isLeaf();
if (!state.shouldSubdivideReference()) {
state.stream << leaf;
state.base.stream << leaf;
if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i]->write(nextState);
}
}
} else if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
if (nextState.becameSubdivided()) {
@ -962,15 +1036,14 @@ void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const {
void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const {
foreach (const SharedObjectPointer& object, decodeInline<SharedObjectSet>(_attributeValue)) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited()) {
state.stream << object;
if (static_cast<Spanner*>(object.data())->testAndSetVisited(state.base.visit)) {
state.base.stream << object;
}
}
if (!state.shouldSubdivide() || isLeaf()) {
return;
}
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i]->writeSpanners(nextState);
@ -981,19 +1054,18 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS
SharedObjectSet oldSet = decodeInline<SharedObjectSet>(reference.getAttributeValue());
SharedObjectSet newSet = decodeInline<SharedObjectSet>(_attributeValue);
foreach (const SharedObjectPointer& object, oldSet) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited() && !newSet.contains(object)) {
state.stream << object;
if (static_cast<Spanner*>(object.data())->testAndSetVisited(state.base.visit) && !newSet.contains(object)) {
state.base.stream << object;
}
}
foreach (const SharedObjectPointer& object, newSet) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited() && !oldSet.contains(object)) {
state.stream << object;
if (static_cast<Spanner*>(object.data())->testAndSetVisited(state.base.visit) && !oldSet.contains(object)) {
state.base.stream << object;
}
}
if (isLeaf() || !state.shouldSubdivide()) {
if (!reference.isLeaf() && state.shouldSubdivideReference()) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
reference._children[i]->writeSpanners(nextState);
@ -1001,8 +1073,7 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS
}
return;
}
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
@ -1023,8 +1094,7 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS
void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const {
if (!isLeaf()) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
if (!state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
@ -1042,7 +1112,7 @@ void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const {
}
void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) {
if (--_referenceCount == 0) {
if (!_referenceCount.deref()) {
destroy(attribute);
delete this;
}
@ -1119,6 +1189,15 @@ void MetavoxelNode::countNodes(const AttributePointer& attribute, const glm::vec
}
}
MetavoxelInfo::MetavoxelInfo(MetavoxelInfo* parentInfo, int inputValuesSize, int outputValuesSize) :
parentInfo(parentInfo),
inputValues(inputValuesSize),
outputValues(outputValuesSize) {
}
MetavoxelInfo::MetavoxelInfo() {
}
int MetavoxelVisitor::encodeOrder(int first, int second, int third, int fourth,
int fifth, int sixth, int seventh, int eighth) {
return first | (second << 3) | (third << 6) | (fourth << 9) |
@ -1169,13 +1248,16 @@ int MetavoxelVisitor::encodeRandomOrder() {
const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7);
const int MetavoxelVisitor::STOP_RECURSION = 0;
const int MetavoxelVisitor::SHORT_CIRCUIT = -1;
const int MetavoxelVisitor::ALL_NODES = 1 << 24;
const int MetavoxelVisitor::ALL_NODES_REST = 1 << 25;
MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
_inputs(inputs),
_outputs(outputs),
_lod(lod),
_minimumLODThresholdMultiplier(FLT_MAX) {
_minimumLODThresholdMultiplier(FLT_MAX),
_depth(-1) {
// find the minimum LOD threshold multiplier over all attributes
foreach (const AttributePointer& attribute, _inputs) {
@ -1189,33 +1271,48 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs,
MetavoxelVisitor::~MetavoxelVisitor() {
}
void MetavoxelVisitor::prepare() {
// nothing by default
void MetavoxelVisitor::prepare(MetavoxelData* data) {
_data = data;
}
bool MetavoxelVisitor::postVisit(MetavoxelInfo& info) {
return false;
}
MetavoxelVisitation& MetavoxelVisitor::acquireVisitation() {
if (++_depth >= _visitations.size()) {
_visitations.append(MetavoxelVisitation(_depth == 0 ? NULL : &_visitations[_depth - 1],
this, _inputs.size() + 1, _outputs.size()));
}
return _visitations[_depth];
}
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs,
const MetavoxelLOD& lod, int order) :
MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
_spannerMaskCount(spannerMasks.size()),
_order(order) {
}
void SpannerVisitor::prepare() {
Spanner::incrementVisit();
void SpannerVisitor::prepare(MetavoxelData* data) {
MetavoxelVisitor::prepare(data);
_visit = Spanner::getAndIncrementNextVisit();
}
int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited() &&
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit) &&
!visit(spanner, glm::vec3(), 0.0f)) {
return SHORT_CIRCUIT;
}
}
}
if (!info.isLeaf) {
return DEFAULT_ORDER;
return _order;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
@ -1259,8 +1356,9 @@ RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& or
_spannerMaskCount(spannerMasks.size()) {
}
void RaySpannerIntersectionVisitor::prepare() {
Spanner::incrementVisit();
void RaySpannerIntersectionVisitor::prepare(MetavoxelData* data) {
MetavoxelVisitor::prepare(data);
_visit = Spanner::getAndIncrementNextVisit();
}
class SpannerDistance {
@ -1278,7 +1376,7 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited()) {
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit)) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction, glm::vec3(), 0.0f, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
@ -1324,39 +1422,16 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
return STOP_RECURSION;
}
bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
return guide(visitation);
}
DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
}
bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor.getLOD().position, visitation.info.getCenter()) *
visitation.visitor.getLOD().threshold;
visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier());
visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor.visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = value.getAttribute()->createMetavoxelNode(value, node);
}
}
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor,
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
{ &visitation.info, glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
QVector<OwnedAttributeValue>(visitation.outputNodes.size()) } };
static inline bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) {
MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation();
nextVisitation.info.size = visitation.info.size * 0.5f;
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
// the encoded order tells us the child indices for each iteration
int index = encodedOrder & ORDER_ELEMENT_MASK;
@ -1372,12 +1447,13 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
for (int j = 0; j < visitation.outputNodes.size(); j++) {
MetavoxelNode* node = visitation.outputNodes.at(j);
MetavoxelNode* child = (node && (visitation.info.size >= lodBase *
visitation.visitor.getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
visitation.visitor->getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
nextVisitation.outputNodes[j] = child;
}
nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index);
if (!static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guide(nextVisitation)) {
visitation.visitor->releaseVisitation();
return false;
}
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
@ -1421,6 +1497,188 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
value = node->getAttributeValue(value.getAttribute());
}
}
visitation.visitor->releaseVisitation();
visitation.info.outputValues.swap(nextVisitation.info.outputValues);
bool changed = visitation.visitor->postVisit(visitation.info);
visitation.info.outputValues.swap(nextVisitation.info.outputValues);
if (changed) {
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& newValue = nextVisitation.info.outputValues[i];
if (!newValue.getAttribute()) {
continue;
}
OwnedAttributeValue& value = visitation.info.outputValues[i];
MetavoxelNode*& node = visitation.outputNodes[i];
if (value.getAttribute()) {
node->setAttributeValue(value = newValue);
} else if (!(node && node->isLeaf() && newValue.getAttribute()->equal(
newValue.getValue(), node->getAttributeValue()))) {
node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node);
}
newValue = AttributeValue();
}
}
return true;
}
bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) *
visitation.visitor->getLOD().threshold;
visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier());
visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor->visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = value.getAttribute()->createMetavoxelNode(value, node);
}
}
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
return (encodedOrder == MetavoxelVisitor::STOP_RECURSION || defaultGuideToChildren(visitation, lodBase, encodedOrder));
}
bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) *
visitation.visitor->getLOD().threshold;
visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier());
visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor->visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = value.getAttribute()->createMetavoxelNode(value, node);
}
}
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
if (encodedOrder & MetavoxelVisitor::ALL_NODES_REST) {
return defaultGuideToChildren(visitation, lodBase, encodedOrder);
}
bool onlyVisitDifferent = !(encodedOrder & MetavoxelVisitor::ALL_NODES);
MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation();
nextVisitation.compareNodes.resize(visitation.compareNodes.size());
nextVisitation.info.size = visitation.info.size * 0.5f;
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
// the encoded order tells us the child indices for each iteration
int index = encodedOrder & ORDER_ELEMENT_MASK;
encodedOrder >>= ORDER_ELEMENT_BITS;
bool allNodesSame = onlyVisitDifferent;
for (int j = 0; j < visitation.inputNodes.size(); j++) {
MetavoxelNode* node = visitation.inputNodes.at(j);
const AttributeValue& parentValue = visitation.info.inputValues.at(j);
bool expand = (visitation.info.size >= lodBase * parentValue.getAttribute()->getLODThresholdMultiplier());
MetavoxelNode* child = (node && expand) ? node->getChild(index) : NULL;
nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ?
child->getAttributeValue(parentValue.getAttribute()) : parentValue.getAttribute()->inherit(parentValue);
MetavoxelNode* compareNode = visitation.compareNodes.at(j);
MetavoxelNode* compareChild = (compareNode && expand) ? compareNode->getChild(index) : NULL;
nextVisitation.compareNodes[j] = compareChild;
allNodesSame &= (child == compareChild);
}
if (allNodesSame) {
continue;
}
for (int j = 0; j < visitation.outputNodes.size(); j++) {
MetavoxelNode* node = visitation.outputNodes.at(j);
MetavoxelNode* child = (node && (visitation.info.size >= lodBase *
visitation.visitor->getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
nextVisitation.outputNodes[j] = child;
}
nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index);
if (!static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guideToDifferent(nextVisitation)) {
visitation.visitor->releaseVisitation();
return false;
}
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
OwnedAttributeValue& value = nextVisitation.info.outputValues[j];
if (!value.getAttribute()) {
continue;
}
// replace the child
OwnedAttributeValue& parentValue = visitation.info.outputValues[j];
if (!parentValue.getAttribute()) {
// shallow-copy the parent node on first change
parentValue = value;
MetavoxelNode*& node = visitation.outputNodes[j];
if (node) {
node = new MetavoxelNode(value.getAttribute(), node);
} else {
// create leaf with inherited value
node = new MetavoxelNode(value.getAttribute()->inherit(visitation.getInheritedOutputValue(j)));
}
}
MetavoxelNode* node = visitation.outputNodes.at(j);
MetavoxelNode* child = node->getChild(index);
if (child) {
child->decrementReferenceCount(value.getAttribute());
} else {
// it's a leaf; we need to split it up
AttributeValue nodeValue = value.getAttribute()->inherit(node->getAttributeValue(value.getAttribute()));
for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) {
node->setChild((index + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue));
}
}
node->setChild(index, nextVisitation.outputNodes.at(j));
value = AttributeValue();
}
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (value.getAttribute()) {
MetavoxelNode* node = visitation.outputNodes.at(i);
node->mergeChildren(value.getAttribute());
value = node->getAttributeValue(value.getAttribute());
}
}
visitation.visitor->releaseVisitation();
visitation.info.outputValues.swap(nextVisitation.info.outputValues);
bool changed = visitation.visitor->postVisit(visitation.info);
visitation.info.outputValues.swap(nextVisitation.info.outputValues);
if (changed) {
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& newValue = nextVisitation.info.outputValues[i];
if (!newValue.getAttribute()) {
continue;
}
OwnedAttributeValue& value = visitation.info.outputValues[i];
MetavoxelNode*& node = visitation.outputNodes[i];
if (value.getAttribute()) {
node->setAttributeValue(value = newValue);
} else if (!(node && node->isLeaf() && newValue.getAttribute()->equal(
newValue.getValue(), node->getAttributeValue()))) {
node = newValue.getAttribute()->createMetavoxelNode(value = newValue, node);
}
newValue = AttributeValue();
}
}
return true;
}
@ -1456,12 +1714,12 @@ static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide*
QScriptValue ScriptedMetavoxelGuide::getInputs(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
return getAttributes(engine, guide, guide->_visitation->visitor.getInputs());
return getAttributes(engine, guide, guide->_visitation->visitor->getInputs());
}
QScriptValue ScriptedMetavoxelGuide::getOutputs(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
return getAttributes(engine, guide, guide->_visitation->visitor.getOutputs());
return getAttributes(engine, guide, guide->_visitation->visitor->getOutputs());
}
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
@ -1470,14 +1728,16 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
// start with the basics, including inherited attribute values
QScriptValue infoValue = context->argument(0);
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
MetavoxelInfo info = {
NULL, glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
(float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues,
guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() };
MetavoxelInfo info(NULL, 0, 0);
info.inputValues = guide->_visitation->info.inputValues;
info.outputValues = guide->_visitation->info.outputValues;
info.minimum = glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber());
info.size = (float)infoValue.property(guide->_sizeHandle).toNumber();
info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool();
// extract and convert the values provided by the script
QScriptValue inputValues = infoValue.property(guide->_inputValuesHandle);
const QVector<AttributePointer>& inputs = guide->_visitation->visitor.getInputs();
const QVector<AttributePointer>& inputs = guide->_visitation->visitor->getInputs();
for (int i = 0; i < inputs.size(); i++) {
QScriptValue attributeValue = inputValues.property(i);
if (attributeValue.isValid()) {
@ -1486,7 +1746,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
}
}
QScriptValue result = guide->_visitation->visitor.visit(info);
QScriptValue result = guide->_visitation->visitor->visit(info);
// destroy any created values
for (int i = 0; i < inputs.size(); i++) {
@ -1559,6 +1819,18 @@ void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) {
_minimumHandle = QScriptString();
}
MetavoxelVisitation::MetavoxelVisitation(MetavoxelVisitation* previous,
MetavoxelVisitor* visitor, int inputNodesSize, int outputNodesSize) :
previous(previous),
visitor(visitor),
inputNodes(inputNodesSize),
outputNodes(outputNodesSize),
info(previous ? &previous->info : NULL, inputNodesSize, outputNodesSize) {
}
MetavoxelVisitation::MetavoxelVisitation() {
}
bool MetavoxelVisitation::allInputNodesLeaves() const {
foreach (MetavoxelNode* node, inputNodes) {
if (node && !node->isLeaf()) {
@ -1572,10 +1844,55 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const {
for (const MetavoxelVisitation* visitation = previous; visitation; visitation = visitation->previous) {
MetavoxelNode* node = visitation->outputNodes.at(index);
if (node) {
return node->getAttributeValue(visitor.getOutputs().at(index));
return node->getAttributeValue(visitor->getOutputs().at(index));
}
}
return AttributeValue(visitor.getOutputs().at(index));
return AttributeValue(visitor->getOutputs().at(index));
}
MetavoxelRenderer::MetavoxelRenderer() :
_implementation(NULL) {
}
MetavoxelRendererImplementation* MetavoxelRenderer::getImplementation() {
QMutexLocker locker(&_implementationMutex);
if (!_implementation) {
QByteArray className = getImplementationClassName();
const QMetaObject* metaObject = Bitstream::getMetaObject(className);
if (!metaObject) {
qDebug() << "Unknown class name:" << className;
metaObject = &MetavoxelRendererImplementation::staticMetaObject;
}
_implementation = static_cast<MetavoxelRendererImplementation*>(metaObject->newInstance());
connect(this, &QObject::destroyed, _implementation, &QObject::deleteLater);
_implementation->init(this);
}
return _implementation;
}
MetavoxelRendererImplementation::MetavoxelRendererImplementation() {
}
void MetavoxelRendererImplementation::init(MetavoxelRenderer* renderer) {
_renderer = renderer;
}
void MetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
MetavoxelInfo& info, const MetavoxelLOD& lod) {
}
void MetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {
}
QByteArray MetavoxelRenderer::getImplementationClassName() const {
return "MetavoxelRendererImplementation";
}
PointMetavoxelRenderer::PointMetavoxelRenderer() {
}
QByteArray PointMetavoxelRenderer::getImplementationClassName() const {
return "PointMetavoxelRendererImplementation";
}
const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f;
@ -1585,8 +1902,7 @@ Spanner::Spanner() :
_renderer(NULL),
_placementGranularity(DEFAULT_PLACEMENT_GRANULARITY),
_voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY),
_masked(false),
_lastVisit(0) {
_masked(false) {
}
void Spanner::setBounds(const Box& bounds) {
@ -1615,11 +1931,13 @@ bool Spanner::blendAttributeValues(MetavoxelInfo& info, bool force) const {
return false;
}
bool Spanner::testAndSetVisited() {
if (_lastVisit == _visit) {
bool Spanner::testAndSetVisited(int visit) {
QMutexLocker locker(&_lastVisitsMutex);
int& lastVisit = _lastVisits[QThread::currentThread()];
if (lastVisit == visit) {
return false;
}
_lastVisit = _visit;
lastVisit = visit;
return true;
}
@ -1632,7 +1950,7 @@ SpannerRenderer* Spanner::getRenderer() {
metaObject = &SpannerRenderer::staticMetaObject;
}
_renderer = static_cast<SpannerRenderer*>(metaObject->newInstance());
_renderer->setParent(this);
connect(this, &QObject::destroyed, _renderer, &QObject::deleteLater);
_renderer->init(this);
}
return _renderer;
@ -1647,13 +1965,13 @@ QByteArray Spanner::getRendererClassName() const {
return "SpannerRendererer";
}
int Spanner::_visit = 0;
QAtomicInt Spanner::_nextVisit(1);
SpannerRenderer::SpannerRenderer() {
}
void SpannerRenderer::init(Spanner* spanner) {
// nothing by default
_spanner = spanner;
}
void SpannerRenderer::simulate(float deltaTime) {

View file

@ -14,6 +14,7 @@
#include <QBitArray>
#include <QHash>
#include <QMutex>
#include <QSharedData>
#include <QSharedPointer>
#include <QScriptString>
@ -27,7 +28,9 @@
class QScriptContext;
class MetavoxelInfo;
class MetavoxelNode;
class MetavoxelRendererImplementation;
class MetavoxelVisitation;
class MetavoxelVisitor;
class NetworkValue;
@ -80,6 +83,9 @@ public:
/// Applies the specified visitor to the contained voxels.
void guide(MetavoxelVisitor& visitor);
/// Guides the specified visitor to the voxels that differ from those of the specified other.
void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor);
/// Inserts a spanner into the specified attribute layer.
void insert(const AttributePointer& attribute, const SharedObjectPointer& object);
void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
@ -155,15 +161,22 @@ template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData&
Q_DECLARE_METATYPE(MetavoxelData)
/// Holds the state used in streaming metavoxel data.
class MetavoxelStreamState {
/// Holds the base state used in streaming metavoxel data.
class MetavoxelStreamBase {
public:
glm::vec3 minimum;
float size;
const AttributePointer& attribute;
Bitstream& stream;
const MetavoxelLOD& lod;
const MetavoxelLOD& referenceLOD;
int visit;
};
/// Holds the state used in streaming a metavoxel node.
class MetavoxelStreamState {
public:
MetavoxelStreamBase& base;
glm::vec3 minimum;
float size;
bool shouldSubdivide() const;
bool shouldSubdivideReference() const;
@ -209,7 +222,7 @@ public:
void writeSpannerSubdivision(MetavoxelStreamState& state) const;
/// Increments the node's reference count.
void incrementReferenceCount() { _referenceCount++; }
void incrementReferenceCount() { _referenceCount.ref(); }
/// Decrements the node's reference count. If the resulting reference count is zero, destroys the node
/// and calls delete this.
@ -235,7 +248,7 @@ private:
friend class MetavoxelVisitation;
int _referenceCount;
QAtomicInt _referenceCount;
void* _attributeValue;
MetavoxelNode* _children[CHILD_COUNT];
};
@ -252,6 +265,9 @@ public:
bool isLODLeaf;
bool isLeaf;
MetavoxelInfo(MetavoxelInfo* parentInfo, int inputValuesSize, int outputValuesSize);
MetavoxelInfo();
Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); }
glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; }
};
@ -278,6 +294,14 @@ public:
/// A special "order" that short-circuits the tour.
static const int SHORT_CIRCUIT;
/// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for
/// just this level.
static const int ALL_NODES;
/// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for
/// this level and all beneath it.
static const int ALL_NODES_REST;
MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
@ -297,19 +321,34 @@ public:
float getMinimumLODThresholdMultiplier() const { return _minimumLODThresholdMultiplier; }
/// Prepares for a new tour of the metavoxel data.
virtual void prepare();
virtual void prepare(MetavoxelData* data);
/// Visits a metavoxel.
/// \param info the metavoxel data
/// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour
/// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour.
/// If child traversal is requested, postVisit will be called after we return from traversing the children and have merged
/// their values
virtual int visit(MetavoxelInfo& info) = 0;
/// Called after we have visited all of a metavoxel's children.
/// \return whether or not any outputs were set in the info
virtual bool postVisit(MetavoxelInfo& info);
/// Acquires the next visitation, incrementing the depth.
MetavoxelVisitation& acquireVisitation();
/// Releases the current visitation, decrementing the depth.
void releaseVisitation() { _depth--; }
protected:
QVector<AttributePointer> _inputs;
QVector<AttributePointer> _outputs;
MetavoxelLOD _lod;
float _minimumLODThresholdMultiplier;
MetavoxelData* _data;
QList<MetavoxelVisitation> _visitations;
int _depth;
};
/// Base class for visitors to spanners.
@ -320,20 +359,23 @@ public:
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
const MetavoxelLOD& lod = MetavoxelLOD(),
int order = DEFAULT_ORDER);
/// Visits a spanner (or part thereof).
/// \param clipSize the size of the clip volume, or zero if unclipped
/// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) = 0;
virtual void prepare();
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info);
protected:
int _spannerInputCount;
int _spannerMaskCount;
int _order;
int _visit;
};
/// Base class for ray intersection visitors.
@ -372,13 +414,14 @@ public:
/// \return true to continue, false to short-circuit the tour
virtual bool visitSpanner(Spanner* spanner, float distance) = 0;
virtual void prepare();
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info, float distance);
protected:
int _spannerInputCount;
int _spannerMaskCount;
int _visit;
};
/// Interface for objects that guide metavoxel visitors.
@ -390,6 +433,10 @@ public:
/// Guides the specified visitor to the contained voxels.
/// \return true to keep going, false to short circuit the tour
virtual bool guide(MetavoxelVisitation& visitation) = 0;
/// Guides the specified visitor to the voxels that differ from a reference.
/// \return true to keep going, false to short circuit the tour
virtual bool guideToDifferent(MetavoxelVisitation& visitation);
};
/// Guides visitors through the explicit content of the system.
@ -401,6 +448,7 @@ public:
Q_INVOKABLE DefaultMetavoxelGuide();
virtual bool guide(MetavoxelVisitation& visitation);
virtual bool guideToDifferent(MetavoxelVisitation& visitation);
};
/// A temporary test guide that just makes the existing voxels throb with delight.
@ -464,15 +512,67 @@ class MetavoxelVisitation {
public:
MetavoxelVisitation* previous;
MetavoxelVisitor& visitor;
MetavoxelVisitor* visitor;
QVector<MetavoxelNode*> inputNodes;
QVector<MetavoxelNode*> outputNodes;
QVector<MetavoxelNode*> compareNodes;
MetavoxelInfo info;
MetavoxelVisitation(MetavoxelVisitation* previous, MetavoxelVisitor* visitor, int inputNodesSize, int outputNodesSize);
MetavoxelVisitation();
bool allInputNodesLeaves() const;
AttributeValue getInheritedOutputValue(int index) const;
};
/// Base class for objects that render metavoxels.
class MetavoxelRenderer : public SharedObject {
Q_OBJECT
public:
MetavoxelRenderer();
/// Returns a pointer to the implementation, creating it if necessary.
MetavoxelRendererImplementation* getImplementation();
protected:
MetavoxelRendererImplementation* _implementation;
QMutex _implementationMutex;
/// Returns the name of the class to instantiate for the implementation.
virtual QByteArray getImplementationClassName() const;
};
/// Base class for renderer implementations.
class MetavoxelRendererImplementation : public SharedObject {
Q_OBJECT
public:
Q_INVOKABLE MetavoxelRendererImplementation();
virtual void init(MetavoxelRenderer* renderer);
virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod);
protected:
MetavoxelRenderer* _renderer;
};
/// Renders metavoxels as points.
class PointMetavoxelRenderer : public MetavoxelRenderer {
Q_OBJECT
public:
Q_INVOKABLE PointMetavoxelRenderer();
virtual QByteArray getImplementationClassName() const;
};
/// An object that spans multiple octree cells.
class Spanner : public SharedObject {
Q_OBJECT
@ -483,8 +583,8 @@ class Spanner : public SharedObject {
public:
/// Increments the value of the global visit counter.
static void incrementVisit() { _visit++; }
/// Returns the value of the global visit counter and increments it.
static int getAndIncrementNextVisit() { return _nextVisit.fetchAndAddOrdered(1); }
Spanner();
@ -517,7 +617,7 @@ public:
/// Checks whether we've visited this object on the current traversal. If we have, returns false.
/// If we haven't, sets the last visit identifier and returns true.
bool testAndSetVisited();
bool testAndSetVisited(int visit);
/// Returns a pointer to the renderer, creating it if necessary.
SpannerRenderer* getRenderer();
@ -545,9 +645,10 @@ private:
float _placementGranularity;
float _voxelizationGranularity;
bool _masked;
int _lastVisit; ///< the identifier of the last visit
QHash<QThread*, int> _lastVisits; ///< last visit identifiers for each thread
QMutex _lastVisitsMutex;
static int _visit; ///< the global visit counter
static QAtomicInt _nextVisit; ///< the global visit counter
};
/// Base class for objects that can render spanners.
@ -565,6 +666,10 @@ public:
virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
protected:
Spanner* _spanner;
};
/// An object with a 3D transform.

View file

@ -23,7 +23,7 @@
REGISTER_META_OBJECT(SharedObject)
SharedObject::SharedObject() :
_id(++_lastID),
_id(_nextID.fetchAndAddOrdered(1)),
_originID(_id),
_remoteID(0),
_remoteOriginID(0) {
@ -131,7 +131,7 @@ void SharedObject::dump(QDebug debug) const {
}
}
int SharedObject::_lastID = 0;
QAtomicInt SharedObject::_nextID(1);
WeakSharedObjectHash SharedObject::_weakHash;
QReadWriteLock SharedObject::_weakHashLock;

View file

@ -87,7 +87,7 @@ private:
int _remoteOriginID;
QAtomicInt _referenceCount;
static int _lastID;
static QAtomicInt _nextID;
static WeakSharedObjectHash _weakHash;
static QReadWriteLock _weakHashLock;
};