Ordered visitation bits.

This commit is contained in:
Andrzej Kapolka 2014-03-05 17:12:02 -08:00
parent c4f29005a0
commit 60b0281095
5 changed files with 162 additions and 63 deletions

View file

@ -61,13 +61,14 @@ void MetavoxelSystem::simulate(float deltaTime) {
// simulate the clients // simulate the clients
_points.clear(); _points.clear();
_simulateVisitor.setDeltaTime(deltaTime); _simulateVisitor.setDeltaTime(deltaTime);
_simulateVisitor.setOrder(-Application::getInstance()->getViewFrustum()->getDirection());
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
if (node->getType() == NodeType::MetavoxelServer) { if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex()); QMutexLocker locker(&node->getMutex());
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData()); MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
if (client) { if (client) {
client->simulate(deltaTime); client->simulate(deltaTime);
client->getData().guide(_simulateVisitor); client->guide(_simulateVisitor);
} }
} }
} }
@ -109,7 +110,7 @@ void MetavoxelSystem::render() {
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDrawArrays(GL_POINTS, 0, _points.size()); glDrawArrays(GL_POINTS, 0, _points.size());
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
@ -127,7 +128,7 @@ void MetavoxelSystem::render() {
QMutexLocker locker(&node->getMutex()); QMutexLocker locker(&node->getMutex());
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData()); MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
if (client) { if (client) {
client->getData().guide(_renderVisitor); client->guide(_renderVisitor);
} }
} }
} }
@ -147,15 +148,16 @@ MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
_points(points) { _points(points) {
} }
void MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) { bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) {
spanner->getRenderer()->simulate(_deltaTime); spanner->getRenderer()->simulate(_deltaTime);
return true;
} }
bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
SpannerVisitor::visit(info); SpannerVisitor::visit(info);
if (!info.isLeaf) { if (!info.isLeaf) {
return true; return _order;
} }
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>(); QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>(); QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
@ -165,15 +167,16 @@ bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
{ qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } }; { qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } };
_points.append(point); _points.append(point);
} }
return false; return STOP_RECURSION;
} }
MetavoxelSystem::RenderVisitor::RenderVisitor() : MetavoxelSystem::RenderVisitor::RenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()) { SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()) {
} }
void MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) {
spanner->getRenderer()->render(1.0f); spanner->getRenderer()->render(1.0f);
return true;
} }
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
@ -201,6 +204,16 @@ MetavoxelClient::~MetavoxelClient() {
_sequencer.endPacket(); _sequencer.endPacket();
} }
static MetavoxelLOD getLOD() {
const float FIXED_LOD_THRESHOLD = 0.01f;
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD);
}
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
visitor.setLOD(getLOD());
_data.guide(visitor);
}
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
// apply immediately to local tree // apply immediately to local tree
edit.apply(_data); edit.apply(_data);
@ -211,8 +224,8 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
void MetavoxelClient::simulate(float deltaTime) { void MetavoxelClient::simulate(float deltaTime) {
Bitstream& out = _sequencer.startPacket(); Bitstream& out = _sequencer.startPacket();
const float FIXED_LOD_THRESHOLD = 0.0001f;
ClientStateMessage state = { MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD) }; ClientStateMessage state = { getLOD() };
out << QVariant::fromValue(state); out << QVariant::fromValue(state);
_sequencer.endPacket(); _sequencer.endPacket();

View file

@ -57,18 +57,20 @@ private:
public: public:
SimulateVisitor(QVector<Point>& points); SimulateVisitor(QVector<Point>& points);
void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; } void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; }
virtual void visit(Spanner* spanner); void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); }
virtual bool visit(MetavoxelInfo& info); virtual bool visit(Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private: private:
QVector<Point>& _points; QVector<Point>& _points;
float _deltaTime; float _deltaTime;
int _order;
}; };
class RenderVisitor : public SpannerVisitor { class RenderVisitor : public SpannerVisitor {
public: public:
RenderVisitor(); RenderVisitor();
virtual void visit(Spanner* spanner); virtual bool visit(Spanner* spanner);
}; };
static ProgramObject _program; static ProgramObject _program;
@ -89,7 +91,7 @@ public:
MetavoxelClient(const SharedNodePointer& node); MetavoxelClient(const SharedNodePointer& node);
virtual ~MetavoxelClient(); virtual ~MetavoxelClient();
MetavoxelData& getData() { return _data; } void guide(MetavoxelVisitor& visitor);
void applyEdit(const MetavoxelEditMessage& edit); void applyEdit(const MetavoxelEditMessage& edit);

View file

@ -32,7 +32,19 @@ bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const {
} }
bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const { bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const {
return shouldSubdivide(minimum, size) && !reference.shouldSubdivide(minimum, size); if (position == reference.position && threshold >= reference.threshold) {
return false; // first off, nothing becomes subdivided if it doesn't change
}
if (!shouldSubdivide(minimum, size)) {
return false; // this one must be subdivided
}
// the general check is whether we've gotten closer (as multiplied by the threshold) to any point in the volume,
// which we approximate as a sphere for simplicity
float halfSize = size * 0.5f;
glm::vec3 center = minimum + glm::vec3(halfSize, halfSize, halfSize);
float radius = sqrtf(3 * halfSize * halfSize);
return qMax(0.0f, glm::distance(position, center) - radius) * threshold <=
qMax(0.0f, glm::distance(reference.position, center) - radius) * reference.threshold;
} }
MetavoxelData::MetavoxelData() : _size(1.0f) { MetavoxelData::MetavoxelData() : _size(1.0f) {
@ -128,7 +140,7 @@ public:
SpannerUpdateVisitor(const AttributePointer& attribute, const Box& bounds, SpannerUpdateVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object); float granularity, const SharedObjectPointer& object);
virtual bool visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
private: private:
@ -147,17 +159,17 @@ template<SpannerUpdateFunction F> SpannerUpdateVisitor<F>::SpannerUpdateVisitor(
_object(object) { _object(object) {
} }
template<SpannerUpdateFunction F> bool SpannerUpdateVisitor<F>::visit(MetavoxelInfo& info) { template<SpannerUpdateFunction F> int SpannerUpdateVisitor<F>::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) { if (!info.getBounds().intersects(_bounds)) {
return false; return STOP_RECURSION;
} }
if (info.size > _longestSide) { if (info.size > _longestSide) {
return true; return DEFAULT_ORDER;
} }
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>(); SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
F(set, _object); F(set, _object);
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return false; return STOP_RECURSION;
} }
void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) { void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) {
@ -737,9 +749,43 @@ void MetavoxelNode::clearChildren(const AttributePointer& attribute) {
} }
} }
MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs) : 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) |
(fifth << 12) | (sixth << 15) | (seventh << 18) | (eighth << 21);
}
class IndexDistance {
public:
int index;
float distance;
};
bool operator<(const IndexDistance& first, const IndexDistance& second) {
return first.distance < second.distance;
}
int MetavoxelVisitor::encodeOrder(const glm::vec3& direction) {
QList<IndexDistance> indexDistances;
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
IndexDistance indexDistance = { i, glm::dot(direction, getNextMinimum(glm::vec3(), 1.0f, i)) };
indexDistances.append(indexDistance);
}
qStableSort(indexDistances);
return encodeOrder(indexDistances.at(0).index, indexDistances.at(1).index, indexDistances.at(2).index,
indexDistances.at(3).index, indexDistances.at(4).index, indexDistances.at(5).index,
indexDistances.at(6).index, indexDistances.at(7).index);
}
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;
MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
_inputs(inputs), _inputs(inputs),
_outputs(outputs) { _outputs(outputs),
_lod(lod) {
} }
MetavoxelVisitor::~MetavoxelVisitor() { MetavoxelVisitor::~MetavoxelVisitor() {
@ -750,8 +796,8 @@ void MetavoxelVisitor::prepare() {
} }
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs, SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs) : const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
MetavoxelVisitor(inputs + spannerInputs, outputs), MetavoxelVisitor(inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()) { _spannerInputCount(spannerInputs.size()) {
} }
@ -759,24 +805,30 @@ void SpannerVisitor::prepare() {
Spanner::incrementVisit(); Spanner::incrementVisit();
} }
bool SpannerVisitor::visit(MetavoxelInfo& info) { int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data()); Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) { if (spanner->testAndSetVisited()) {
visit(spanner); if (!visit(spanner)) {
return SHORT_CIRCUIT;
}
} }
} }
} }
return !info.isLeaf; return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER;
} }
DefaultMetavoxelGuide::DefaultMetavoxelGuide() { DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
} }
void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
visitation.info.isLeaf = visitation.allInputNodesLeaves(); bool shouldSubdivide = visitation.visitor.getLOD().shouldSubdivide(visitation.info.minimum, visitation.info.size);
bool keepGoing = visitation.visitor.visit(visitation.info); visitation.info.isLeaf = !shouldSubdivide || 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++) { for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i]; OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) { if (!value.getAttribute()) {
@ -790,29 +842,35 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
node = new MetavoxelNode(value); node = new MetavoxelNode(value);
} }
} }
if (!keepGoing) { if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return; return true;
} }
MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor, MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor,
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()), QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()), { glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
QVector<OwnedAttributeValue>(visitation.outputNodes.size()) } }; QVector<OwnedAttributeValue>(visitation.outputNodes.size()) } };
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
const int ORDER_ELEMENT_BITS = 3;
const int ORDER_ELEMENT_MASK = (1 << ORDER_ELEMENT_BITS) - 1;
int index = encodedOrder & ORDER_ELEMENT_MASK;
encodedOrder >>= ORDER_ELEMENT_BITS;
for (int j = 0; j < visitation.inputNodes.size(); j++) { for (int j = 0; j < visitation.inputNodes.size(); j++) {
MetavoxelNode* node = visitation.inputNodes.at(j); MetavoxelNode* node = visitation.inputNodes.at(j);
MetavoxelNode* child = node ? node->getChild(i) : NULL; MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL;
nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ? nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ?
child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) : child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) :
visitation.info.inputValues[j]; visitation.info.inputValues[j];
} }
for (int j = 0; j < visitation.outputNodes.size(); j++) { for (int j = 0; j < visitation.outputNodes.size(); j++) {
MetavoxelNode* node = visitation.outputNodes.at(j); MetavoxelNode* node = visitation.outputNodes.at(j);
MetavoxelNode* child = node ? node->getChild(i) : NULL; MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL;
nextVisitation.outputNodes[j] = child; nextVisitation.outputNodes[j] = child;
} }
nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, i); nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index);
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue< if (!static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guide(nextVisitation); SharedObjectPointer>().data())->guide(nextVisitation)) {
return false;
}
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
OwnedAttributeValue& value = nextVisitation.info.outputValues[j]; OwnedAttributeValue& value = nextVisitation.info.outputValues[j];
if (!value.getAttribute()) { if (!value.getAttribute()) {
@ -839,10 +897,10 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
// it's a leaf; we need to split it up // it's a leaf; we need to split it up
AttributeValue nodeValue = node->getAttributeValue(value.getAttribute()); AttributeValue nodeValue = node->getAttributeValue(value.getAttribute());
for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) { for (int k = 1; k < MetavoxelNode::CHILD_COUNT; k++) {
node->setChild((i + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue)); node->setChild((index + k) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode(nodeValue));
} }
} }
node->setChild(i, nextVisitation.outputNodes.at(j)); node->setChild(index, nextVisitation.outputNodes.at(j));
value = AttributeValue(); value = AttributeValue();
} }
} }
@ -854,12 +912,13 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
value = node->getAttributeValue(value.getAttribute()); value = node->getAttributeValue(value.getAttribute());
} }
} }
return true;
} }
ThrobbingMetavoxelGuide::ThrobbingMetavoxelGuide() : _rate(10.0) { ThrobbingMetavoxelGuide::ThrobbingMetavoxelGuide() : _rate(10.0) {
} }
void ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) { bool ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
AttributePointer colorAttribute = AttributeRegistry::getInstance()->getColorAttribute(); AttributePointer colorAttribute = AttributeRegistry::getInstance()->getColorAttribute();
for (int i = 0; i < visitation.info.inputValues.size(); i++) { for (int i = 0; i < visitation.info.inputValues.size(); i++) {
AttributeValue& attributeValue = visitation.info.inputValues[i]; AttributeValue& attributeValue = visitation.info.inputValues[i];
@ -872,7 +931,7 @@ void ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
} }
} }
DefaultMetavoxelGuide::guide(visitation); return DefaultMetavoxelGuide::guide(visitation);
} }
static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* guide, static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* guide,
@ -933,7 +992,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
ScriptedMetavoxelGuide::ScriptedMetavoxelGuide() { ScriptedMetavoxelGuide::ScriptedMetavoxelGuide() {
} }
void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) { bool ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
QScriptValue guideFunction; QScriptValue guideFunction;
if (_guideFunction) { if (_guideFunction) {
guideFunction = _guideFunction->getValue(); guideFunction = _guideFunction->getValue();
@ -944,8 +1003,7 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
} }
if (!guideFunction.isValid()) { if (!guideFunction.isValid()) {
// before we load, just use the default behavior // before we load, just use the default behavior
DefaultMetavoxelGuide::guide(visitation); return DefaultMetavoxelGuide::guide(visitation);
return;
} }
QScriptEngine* engine = guideFunction.engine(); QScriptEngine* engine = guideFunction.engine();
if (!_minimumHandle.isValid()) { if (!_minimumHandle.isValid()) {
@ -983,6 +1041,7 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
if (engine->hasUncaughtException()) { if (engine->hasUncaughtException()) {
qDebug() << "Script error: " << engine->uncaughtException().toString(); qDebug() << "Script error: " << engine->uncaughtException().toString();
} }
return true;
} }
void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) { void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) {

View file

@ -194,8 +194,24 @@ public:
class MetavoxelVisitor { class MetavoxelVisitor {
public: public:
/// Encodes a visitation order sequence for the children of a metavoxel.
static int encodeOrder(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eighth);
/// Encodes a visitation order sequence that visits each child as sorted along the specified direction.
static int encodeOrder(const glm::vec3& direction);
/// The default visitation order.
static const int DEFAULT_ORDER;
/// A special "order" that instructs the guide to stop recursion.
static const int STOP_RECURSION;
/// A special "order" that short-circuits the tour.
static const int SHORT_CIRCUIT;
MetavoxelVisitor(const QVector<AttributePointer>& inputs, MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs = QVector<AttributePointer>()); const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
virtual ~MetavoxelVisitor(); virtual ~MetavoxelVisitor();
/// Returns a reference to the list of input attributes desired. /// Returns a reference to the list of input attributes desired.
@ -204,18 +220,24 @@ public:
/// Returns a reference to the list of output attributes provided. /// Returns a reference to the list of output attributes provided.
const QVector<AttributePointer>& getOutputs() const { return _outputs; } const QVector<AttributePointer>& getOutputs() const { return _outputs; }
/// Returns a reference to the level of detail that will determine subdivision levels.
const MetavoxelLOD& getLOD() const { return _lod; }
void setLOD(const MetavoxelLOD& lod) { _lod = lod; }
/// Prepares for a new tour of the metavoxel data. /// Prepares for a new tour of the metavoxel data.
virtual void prepare(); virtual void prepare();
/// Visits a metavoxel. /// Visits a metavoxel.
/// \param info the metavoxel data /// \param info the metavoxel data
/// \return if true, continue descending; if false, stop /// \return the encoded order in which to traverse the children, zero to stop recursion, or -1 to short-circuit the tour
virtual bool visit(MetavoxelInfo& info) = 0; virtual int visit(MetavoxelInfo& info) = 0;
protected: protected:
QVector<AttributePointer> _inputs; QVector<AttributePointer> _inputs;
QVector<AttributePointer> _outputs; QVector<AttributePointer> _outputs;
MetavoxelLOD _lod;
}; };
typedef QSharedPointer<MetavoxelVisitor> MetavoxelVisitorPointer; typedef QSharedPointer<MetavoxelVisitor> MetavoxelVisitorPointer;
@ -226,13 +248,15 @@ public:
SpannerVisitor(const QVector<AttributePointer>& spannerInputs, SpannerVisitor(const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(), const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>()); const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner. /// Visits a spanner.
virtual void visit(Spanner* spanner) = 0; /// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner) = 0;
virtual void prepare(); virtual void prepare();
virtual bool visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
protected: protected:
@ -246,7 +270,8 @@ class MetavoxelGuide : public SharedObject {
public: public:
/// Guides the specified visitor to the contained voxels. /// Guides the specified visitor to the contained voxels.
virtual void guide(MetavoxelVisitation& visitation) = 0; /// \return true to keep going, false to short circuit the tour
virtual bool guide(MetavoxelVisitation& visitation) = 0;
}; };
/// Guides visitors through the explicit content of the system. /// Guides visitors through the explicit content of the system.
@ -257,7 +282,7 @@ public:
Q_INVOKABLE DefaultMetavoxelGuide(); Q_INVOKABLE DefaultMetavoxelGuide();
virtual void guide(MetavoxelVisitation& visitation); virtual bool guide(MetavoxelVisitation& visitation);
}; };
/// A temporary test guide that just makes the existing voxels throb with delight. /// A temporary test guide that just makes the existing voxels throb with delight.
@ -269,7 +294,7 @@ public:
Q_INVOKABLE ThrobbingMetavoxelGuide(); Q_INVOKABLE ThrobbingMetavoxelGuide();
virtual void guide(MetavoxelVisitation& visitation); virtual bool guide(MetavoxelVisitation& visitation);
private: private:
@ -285,7 +310,7 @@ public:
Q_INVOKABLE ScriptedMetavoxelGuide(); Q_INVOKABLE ScriptedMetavoxelGuide();
virtual void guide(MetavoxelVisitation& visitation); virtual bool guide(MetavoxelVisitation& visitation);
public slots: public slots:

View file

@ -24,7 +24,7 @@ public:
BoxSetEditVisitor(const BoxSetEdit& edit); BoxSetEditVisitor(const BoxSetEdit& edit);
virtual bool visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
private: private:
@ -36,26 +36,26 @@ BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) :
_edit(edit) { _edit(edit) {
} }
bool BoxSetEditVisitor::visit(MetavoxelInfo& info) { int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
// find the intersection between volume and voxel // find the intersection between volume and voxel
glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum); glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum);
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum); glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum);
glm::vec3 size = maximum - minimum; glm::vec3 size = maximum - minimum;
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) { if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
return false; // disjoint return STOP_RECURSION; // disjoint
} }
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size); float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
if (volume >= 1.0f) { if (volume >= 1.0f) {
info.outputValues[0] = _edit.value; info.outputValues[0] = _edit.value;
return false; // entirely contained return STOP_RECURSION; // entirely contained
} }
if (info.size <= _edit.granularity) { if (info.size <= _edit.granularity) {
if (volume >= 0.5f) { if (volume >= 0.5f) {
info.outputValues[0] = _edit.value; info.outputValues[0] = _edit.value;
} }
return false; // reached granularity limit; take best guess return STOP_RECURSION; // reached granularity limit; take best guess
} }
return true; // subdivide return DEFAULT_ORDER; // subdivide
} }
void BoxSetEdit::apply(MetavoxelData& data) const { void BoxSetEdit::apply(MetavoxelData& data) const {
@ -77,7 +77,7 @@ public:
GlobalSetEditVisitor(const GlobalSetEdit& edit); GlobalSetEditVisitor(const GlobalSetEdit& edit);
virtual bool visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
private: private:
@ -89,9 +89,9 @@ GlobalSetEditVisitor::GlobalSetEditVisitor(const GlobalSetEdit& edit) :
_edit(edit) { _edit(edit) {
} }
bool GlobalSetEditVisitor::visit(MetavoxelInfo& info) { int GlobalSetEditVisitor::visit(MetavoxelInfo& info) {
info.outputValues[0] = _edit.value; info.outputValues[0] = _edit.value;
return false; // entirely contained return STOP_RECURSION; // entirely contained
} }
void GlobalSetEdit::apply(MetavoxelData& data) const { void GlobalSetEdit::apply(MetavoxelData& data) const {