mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
Finally at the point of actually getting spanners to turn into voxels.
This commit is contained in:
parent
78896d6af9
commit
176d8f746e
6 changed files with 153 additions and 55 deletions
|
@ -188,7 +188,7 @@ int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
|
|||
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
|
||||
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
|
||||
quint8 alpha = qAlpha(color);
|
||||
if (info.inputValues.at(4).getAttribute()) {
|
||||
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 },
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
REGISTER_META_OBJECT(QRgbAttribute)
|
||||
REGISTER_META_OBJECT(PackedNormalAttribute)
|
||||
REGISTER_META_OBJECT(SpannerQRgbAttribute)
|
||||
REGISTER_META_OBJECT(SpannerPackedNormalAttribute)
|
||||
REGISTER_META_OBJECT(SharedObjectAttribute)
|
||||
REGISTER_META_OBJECT(SharedObjectSetAttribute)
|
||||
REGISTER_META_OBJECT(SpannerSetAttribute)
|
||||
|
@ -35,7 +37,7 @@ AttributeRegistry::AttributeRegistry() :
|
|||
_spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))) {
|
||||
|
||||
// our baseline LOD threshold is for voxels; spanners are a different story
|
||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 4.0f;
|
||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
||||
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
||||
}
|
||||
|
||||
|
@ -168,6 +170,10 @@ Attribute::Attribute(const QString& name) :
|
|||
Attribute::~Attribute() {
|
||||
}
|
||||
|
||||
MetavoxelNode* Attribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const {
|
||||
return new MetavoxelNode(value);
|
||||
}
|
||||
|
||||
void Attribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) {
|
||||
data.createRoot(state.attribute)->read(state);
|
||||
}
|
||||
|
@ -257,7 +263,7 @@ PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultVa
|
|||
|
||||
bool PackedNormalAttribute::merge(void*& parent, void* children[]) const {
|
||||
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||
glm::vec3 total = unpackNormal(firstValue);
|
||||
glm::vec3 total = unpackNormal(firstValue) * (float)qAlpha(firstValue);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
QRgb value = decodeInline<QRgb>(children[i]);
|
||||
|
@ -290,46 +296,62 @@ SpannerQRgbAttribute::SpannerQRgbAttribute(const QString& name, QRgb defaultValu
|
|||
QRgbAttribute(name, defaultValue) {
|
||||
}
|
||||
|
||||
void SpannerQRgbAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
value = getDefaultValue();
|
||||
in.read(&value, 32);
|
||||
}
|
||||
|
||||
void SpannerQRgbAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
out.write(&value, 32);
|
||||
}
|
||||
|
||||
MetavoxelNode* SpannerQRgbAttribute::createMetavoxelNode(
|
||||
const AttributeValue& value, const MetavoxelNode* original) const {
|
||||
return new MetavoxelNode(value, original);
|
||||
}
|
||||
|
||||
bool SpannerQRgbAttribute::merge(void*& parent, void* children[]) const {
|
||||
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||
int totalAlpha = qAlpha(firstValue);
|
||||
int totalRed = qRed(firstValue) * totalAlpha;
|
||||
int totalGreen = qGreen(firstValue) * totalAlpha;
|
||||
int totalBlue = qBlue(firstValue) * totalAlpha;
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
QRgb value = decodeInline<QRgb>(children[i]);
|
||||
int alpha = qAlpha(value);
|
||||
totalRed += qRed(value) * alpha;
|
||||
totalGreen += qGreen(value) * alpha;
|
||||
totalBlue += qBlue(value) * alpha;
|
||||
totalAlpha += alpha;
|
||||
allChildrenEqual &= (firstValue == value);
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (totalAlpha == 0) {
|
||||
parent = encodeInline(QRgb());
|
||||
} else {
|
||||
parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha,
|
||||
totalBlue / totalAlpha, totalAlpha / MERGE_COUNT));
|
||||
}
|
||||
return allChildrenEqual;
|
||||
return true;
|
||||
}
|
||||
|
||||
AttributeValue SpannerQRgbAttribute::inherit(const AttributeValue& parentValue) const {
|
||||
return AttributeValue(parentValue.getAttribute());
|
||||
}
|
||||
|
||||
SpannerPackedNormalAttribute::SpannerPackedNormalAttribute(const QString& name, QRgb defaultValue) :
|
||||
PackedNormalAttribute(name, defaultValue) {
|
||||
}
|
||||
|
||||
void SpannerPackedNormalAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
value = getDefaultValue();
|
||||
in.read(&value, 32);
|
||||
}
|
||||
|
||||
void SpannerPackedNormalAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
out.write(&value, 32);
|
||||
}
|
||||
|
||||
MetavoxelNode* SpannerPackedNormalAttribute::createMetavoxelNode(
|
||||
const AttributeValue& value, const MetavoxelNode* original) const {
|
||||
return new MetavoxelNode(value, original);
|
||||
}
|
||||
|
||||
bool SpannerPackedNormalAttribute::merge(void*& parent, void* children[]) const {
|
||||
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||
glm::vec3 total = unpackNormal(firstValue);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
QRgb value = decodeInline<QRgb>(children[i]);
|
||||
total += unpackNormal(value) * (float)qAlpha(value);
|
||||
allChildrenEqual &= (firstValue == value);
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
parent = encodeInline(packNormal(glm::normalize(total)));
|
||||
return allChildrenEqual;
|
||||
return true;
|
||||
}
|
||||
|
||||
AttributeValue SpannerPackedNormalAttribute::inherit(const AttributeValue& parentValue) const {
|
||||
return AttributeValue(parentValue.getAttribute());
|
||||
}
|
||||
|
||||
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
||||
|
@ -386,6 +408,11 @@ void SharedObjectSetAttribute::write(Bitstream& out, void* value, bool isLeaf) c
|
|||
out << decodeInline<SharedObjectSet>(value);
|
||||
}
|
||||
|
||||
MetavoxelNode* SharedObjectSetAttribute::createMetavoxelNode(
|
||||
const AttributeValue& value, const MetavoxelNode* original) const {
|
||||
return new MetavoxelNode(value, original);
|
||||
}
|
||||
|
||||
bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const {
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
if (!decodeInline<SharedObjectSet>(children[i]).isEmpty()) {
|
||||
|
@ -395,6 +422,10 @@ bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
AttributeValue SharedObjectSetAttribute::inherit(const AttributeValue& parentValue) const {
|
||||
return AttributeValue(parentValue.getAttribute());
|
||||
}
|
||||
|
||||
QWidget* SharedObjectSetAttribute::createEditor(QWidget* parent) const {
|
||||
return new SharedObjectEditor(_metaObject, parent);
|
||||
}
|
||||
|
|
|
@ -191,6 +191,8 @@ public:
|
|||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); }
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); }
|
||||
|
||||
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
|
||||
|
||||
virtual void readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state);
|
||||
virtual void writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state);
|
||||
|
||||
|
@ -206,6 +208,9 @@ public:
|
|||
/// \return whether or not the children and parent values are all equal
|
||||
virtual bool merge(void*& parent, void* children[]) const = 0;
|
||||
|
||||
/// Given the parent value, returns the value that children should inherit (either the parent value or the default).
|
||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const { return parentValue; }
|
||||
|
||||
/// Mixes the first and the second, returning a new value with the result.
|
||||
virtual void* mix(void* first, void* second, float alpha) const = 0;
|
||||
|
||||
|
@ -307,7 +312,14 @@ public:
|
|||
|
||||
Q_INVOKABLE SpannerQRgbAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
|
||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
};
|
||||
|
||||
/// Packed normals for voxelized spanners.
|
||||
|
@ -318,7 +330,14 @@ public:
|
|||
|
||||
Q_INVOKABLE SpannerPackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
|
||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
};
|
||||
|
||||
/// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject).
|
||||
|
@ -361,8 +380,12 @@ public:
|
|||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
|
||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||
|
||||
virtual QWidget* createEditor(QWidget* parent = NULL) const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -485,14 +485,26 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
|
|||
minimum = getNextMinimum(lastMinimum, size, index);
|
||||
}
|
||||
|
||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) {
|
||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) :
|
||||
_referenceCount(1) {
|
||||
|
||||
_attributeValue = attributeValue.copy();
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
_children[i] = NULL;
|
||||
if (copyChildren) {
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if ((_children[i] = copyChildren->_children[i])) {
|
||||
_children[i]->incrementReferenceCount();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
_children[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelNode::MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy) : _referenceCount(1) {
|
||||
MetavoxelNode::MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy) :
|
||||
_referenceCount(1) {
|
||||
|
||||
_attributeValue = attribute->create(copy->_attributeValue);
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if ((_children[i] = copy->_children[i])) {
|
||||
|
@ -969,7 +981,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
|||
// "set" to same value; disregard
|
||||
value = AttributeValue();
|
||||
} else {
|
||||
node = new MetavoxelNode(value);
|
||||
node = value.getAttribute()->createMetavoxelNode(value, node);
|
||||
}
|
||||
}
|
||||
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
|
||||
|
@ -991,7 +1003,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
|||
MetavoxelNode* child = (node && (visitation.info.size >= lodBase *
|
||||
parentValue.getAttribute()->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
|
||||
nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ?
|
||||
child->getAttributeValue(parentValue.getAttribute()) : parentValue;
|
||||
child->getAttributeValue(parentValue.getAttribute()) : parentValue.getAttribute()->inherit(parentValue);
|
||||
}
|
||||
for (int j = 0; j < visitation.outputNodes.size(); j++) {
|
||||
MetavoxelNode* node = visitation.outputNodes.at(j);
|
||||
|
@ -1019,7 +1031,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
|||
node = new MetavoxelNode(value.getAttribute(), node);
|
||||
} else {
|
||||
// create leaf with inherited value
|
||||
node = new MetavoxelNode(visitation.getInheritedOutputValue(j));
|
||||
node = new MetavoxelNode(value.getAttribute()->inherit(visitation.getInheritedOutputValue(j)));
|
||||
}
|
||||
}
|
||||
MetavoxelNode* node = visitation.outputNodes.at(j);
|
||||
|
@ -1028,7 +1040,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
|||
child->decrementReferenceCount(value.getAttribute());
|
||||
} else {
|
||||
// it's a leaf; we need to split it up
|
||||
AttributeValue nodeValue = node->getAttributeValue(value.getAttribute());
|
||||
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));
|
||||
}
|
||||
|
@ -1234,7 +1246,7 @@ bool Spanner::getAttributeValues(MetavoxelInfo& info) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Spanner::blendAttributeValues(MetavoxelInfo& info) const {
|
||||
bool Spanner::blendAttributeValues(MetavoxelInfo& info, bool force) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1369,10 +1381,10 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Sphere::blendAttributeValues(MetavoxelInfo& info) const {
|
||||
bool Sphere::blendAttributeValues(MetavoxelInfo& info, bool force) const {
|
||||
// bounds check
|
||||
Box bounds = info.getBounds();
|
||||
if (!getBounds().intersects(bounds)) {
|
||||
if (!(force || getBounds().intersects(bounds))) {
|
||||
return false;
|
||||
}
|
||||
// count the points inside the sphere
|
||||
|
@ -1388,7 +1400,7 @@ bool Sphere::blendAttributeValues(MetavoxelInfo& info) const {
|
|||
info.outputValues[1] = getNormal(info);
|
||||
return false;
|
||||
}
|
||||
if (info.size <= getVoxelizationGranularity()) {
|
||||
if (force || info.size <= getVoxelizationGranularity()) {
|
||||
// best guess
|
||||
if (pointsWithin > 0) {
|
||||
int oldAlpha = qAlpha(info.inputValues.at(0).getInlineValue<QRgb>());
|
||||
|
|
|
@ -132,7 +132,7 @@ public:
|
|||
|
||||
static const int CHILD_COUNT = 8;
|
||||
|
||||
MetavoxelNode(const AttributeValue& attributeValue);
|
||||
MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL);
|
||||
MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy);
|
||||
|
||||
void setAttributeValue(const AttributeValue& attributeValue);
|
||||
|
@ -439,8 +439,9 @@ public:
|
|||
virtual bool getAttributeValues(MetavoxelInfo& info) const;
|
||||
|
||||
/// Blends the attribute values associated with this spanner into the supplied info.
|
||||
/// \param force if true, blend even if we would normally subdivide
|
||||
/// \return true to recurse, false to stop
|
||||
virtual bool blendAttributeValues(MetavoxelInfo& info) const;
|
||||
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
|
||||
|
||||
/// 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.
|
||||
|
@ -536,7 +537,7 @@ public:
|
|||
virtual const QVector<AttributePointer>& getAttributes() const;
|
||||
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
|
||||
virtual bool getAttributeValues(MetavoxelInfo& info) const;
|
||||
virtual bool blendAttributeValues(MetavoxelInfo& info) const;
|
||||
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
signals:
|
||||
|
|
|
@ -104,32 +104,42 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
|
|||
spanner(spanner) {
|
||||
}
|
||||
|
||||
class SetSpannerEditVisitor : public MetavoxelVisitor {
|
||||
class InsertSpannerEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
|
||||
InsertSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
Spanner* _spanner;
|
||||
float _longestSide;
|
||||
};
|
||||
|
||||
SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
|
||||
InsertSpannerEditVisitor::InsertSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
|
||||
MetavoxelVisitor(attributes, attributes),
|
||||
_spanner(spanner) {
|
||||
_spanner(spanner),
|
||||
_longestSide(qMax(spanner->getBounds().getLongestSide(), spanner->getPlacementGranularity()) * 2.0f /
|
||||
AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()) {
|
||||
}
|
||||
|
||||
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
||||
return _spanner->blendAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION;
|
||||
int InsertSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_spanner->getBounds())) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (info.size > _longestSide) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
_spanner->blendAttributeValues(info, true);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
data.insert(attribute, this->spanner);
|
||||
|
||||
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
|
||||
SetSpannerEditVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
|
||||
InsertSpannerEditVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
|
@ -159,6 +169,27 @@ SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) :
|
|||
spanner(spanner) {
|
||||
}
|
||||
|
||||
class SetSpannerEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
Spanner* _spanner;
|
||||
};
|
||||
|
||||
SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
|
||||
MetavoxelVisitor(attributes, attributes),
|
||||
_spanner(spanner) {
|
||||
}
|
||||
|
||||
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
||||
return _spanner->blendAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION;
|
||||
}
|
||||
|
||||
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
|
||||
|
||||
|
|
Loading…
Reference in a new issue