// // AttributeRegistry.cpp // libraries/metavoxels/src // // Created by Andrzej Kapolka on 12/6/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include #include #include #include #include #include "AttributeRegistry.h" #include "MetavoxelData.h" REGISTER_META_OBJECT(FloatAttribute) REGISTER_META_OBJECT(QRgbAttribute) REGISTER_META_OBJECT(PackedNormalAttribute) REGISTER_META_OBJECT(SpannerQRgbAttribute) REGISTER_META_OBJECT(SpannerPackedNormalAttribute) REGISTER_META_OBJECT(HeightfieldAttribute) REGISTER_META_OBJECT(HeightfieldColorAttribute) REGISTER_META_OBJECT(SharedObjectAttribute) REGISTER_META_OBJECT(SharedObjectSetAttribute) REGISTER_META_OBJECT(SpannerSetAttribute) static int attributePointerMetaTypeId = qRegisterMetaType(); static int ownedAttributeValueMetaTypeId = qRegisterMetaType(); AttributeRegistry* AttributeRegistry::getInstance() { static AttributeRegistry registry; return ®istry; } AttributeRegistry::AttributeRegistry() : _guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject, new DefaultMetavoxelGuide()))), _rendererAttribute(registerAttribute(new SharedObjectAttribute("renderer", &MetavoxelRenderer::staticMetaObject, new DefaultMetavoxelRenderer()))), _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))), _spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))), _spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))), _spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))), _heightfieldAttribute(registerAttribute(new HeightfieldAttribute("heightfield"))), _heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))) { // our baseline LOD threshold is for voxels; spanners and heightfields are a different story const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; _spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER); const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f; _heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); _heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER); } static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) { QDebug debug = qDebug(); for (int i = 0; i < context->argumentCount(); i++) { debug << context->argument(i).toString(); } return QScriptValue(); } void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) { QScriptValue registry = engine->newObject(); registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data())); registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data())); registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1)); engine->globalObject().setProperty("AttributeRegistry", registry); engine->globalObject().setProperty("qDebug", engine->newFunction(qDebugFunction, 1)); } AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { if (!attribute) { return attribute; } QWriteLocker locker(&_attributesLock); AttributePointer& pointer = _attributes[attribute->getName()]; if (!pointer) { pointer = attribute; } return pointer; } void AttributeRegistry::deregisterAttribute(const QString& name) { QWriteLocker locker(&_attributesLock); _attributes.remove(name); } AttributePointer AttributeRegistry::getAttribute(const QString& name) { QReadLocker locker(&_attributesLock); return _attributes.value(name); } QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) { return engine->newQObject(getInstance()->getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject); } AttributeValue::AttributeValue(const AttributePointer& attribute) : _attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) { } AttributeValue::AttributeValue(const AttributePointer& attribute, void* value) : _attribute(attribute), _value(value) { } void* AttributeValue::copy() const { return _attribute->create(_value); } bool AttributeValue::isDefault() const { return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue()); } bool AttributeValue::operator==(const AttributeValue& other) const { return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value)); } bool AttributeValue::operator==(void* other) const { return _attribute && _attribute->equal(_value, other); } bool AttributeValue::operator!=(const AttributeValue& other) const { return _attribute != other._attribute || (_attribute && !_attribute->equal(_value, other._value)); } bool AttributeValue::operator!=(void* other) const { return !_attribute || !_attribute->equal(_value, other); } OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute, void* value) : AttributeValue(attribute, value) { } OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute) : AttributeValue(attribute, attribute ? attribute->create() : NULL) { } OwnedAttributeValue::OwnedAttributeValue(const AttributeValue& other) : AttributeValue(other.getAttribute(), other.getAttribute() ? other.copy() : NULL) { } OwnedAttributeValue::OwnedAttributeValue(const OwnedAttributeValue& other) : AttributeValue(other.getAttribute(), other.getAttribute() ? other.copy() : NULL) { } OwnedAttributeValue::~OwnedAttributeValue() { if (_attribute) { _attribute->destroy(_value); } } void OwnedAttributeValue::mix(const AttributeValue& first, const AttributeValue& second, float alpha) { if (_attribute) { _attribute->destroy(_value); } _attribute = first.getAttribute(); _value = _attribute->mix(first.getValue(), second.getValue(), alpha); } void OwnedAttributeValue::blend(const AttributeValue& source, const AttributeValue& dest) { if (_attribute) { _attribute->destroy(_value); } _attribute = source.getAttribute(); _value = _attribute->blend(source.getValue(), dest.getValue()); } OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) { if (_attribute) { _attribute->destroy(_value); } if ((_attribute = other.getAttribute())) { _value = other.copy(); } return *this; } OwnedAttributeValue& OwnedAttributeValue::operator=(const OwnedAttributeValue& other) { if (_attribute) { _attribute->destroy(_value); } if ((_attribute = other.getAttribute())) { _value = other.copy(); } return *this; } Attribute::Attribute(const QString& name) : _lodThresholdMultiplier(1.0f) { setObjectName(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.base.attribute)->read(state); } void Attribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { root.write(state); } void Attribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { data.createRoot(state.base.attribute)->readDelta(reference, state); } void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { root.writeDelta(reference, state); } void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { // copy if changed MetavoxelNode* oldRoot = data.getRoot(state.base.attribute); MetavoxelNode* newRoot = oldRoot->readSubdivision(state); if (newRoot != oldRoot) { data.setRoot(state.base.attribute, newRoot); } } void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { root.writeSubdivision(state); } bool Attribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, const glm::vec3& minimum, float size, const MetavoxelLOD& lod) { return firstRoot.deepEquals(this, secondRoot, minimum, size, lod); } FloatAttribute::FloatAttribute(const QString& name, float defaultValue) : SimpleInlineAttribute(name, defaultValue) { } QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : InlineAttribute(name, defaultValue) { } bool QRgbAttribute::merge(void*& parent, void* children[], bool postRead) const { QRgb firstValue = decodeInline(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(children[i]); int alpha = qAlpha(value); totalRed += qRed(value) * alpha; totalGreen += qGreen(value) * alpha; totalBlue += qBlue(value) * alpha; totalAlpha += alpha; allChildrenEqual &= (firstValue == value); } if (totalAlpha == 0) { parent = encodeInline(QRgb()); } else { parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha, totalBlue / totalAlpha, totalAlpha / MERGE_COUNT)); } return allChildrenEqual; } void* QRgbAttribute::mix(void* first, void* second, float alpha) const { QRgb firstValue = decodeInline(first); QRgb secondValue = decodeInline(second); return encodeInline(qRgba( glm::mix((float)qRed(firstValue), (float)qRed(secondValue), alpha), glm::mix((float)qGreen(firstValue), (float)qGreen(secondValue), alpha), glm::mix((float)qBlue(firstValue), (float)qBlue(secondValue), alpha), glm::mix((float)qAlpha(firstValue), (float)qAlpha(secondValue), alpha))); } const float EIGHT_BIT_MAXIMUM = 255.0f; void* QRgbAttribute::blend(void* source, void* dest) const { QRgb sourceValue = decodeInline(source); QRgb destValue = decodeInline(dest); float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM; return encodeInline(qRgba( glm::mix((float)qRed(destValue), (float)qRed(sourceValue), alpha), glm::mix((float)qGreen(destValue), (float)qGreen(sourceValue), alpha), glm::mix((float)qBlue(destValue), (float)qBlue(sourceValue), alpha), glm::mix((float)qAlpha(destValue), (float)qAlpha(sourceValue), alpha))); } void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return encodeInline((QRgb)value.toUInt32()); } void* QRgbAttribute::createFromVariant(const QVariant& value) const { switch (value.userType()) { case QMetaType::QColor: return encodeInline(value.value().rgba()); default: return encodeInline((QRgb)value.toUInt()); } } QWidget* QRgbAttribute::createEditor(QWidget* parent) const { QColorEditor* editor = new QColorEditor(parent); editor->setColor(QColor::fromRgba(_defaultValue)); return editor; } PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultValue) : QRgbAttribute(name, defaultValue) { } bool PackedNormalAttribute::merge(void*& parent, void* children[], bool postRead) const { QRgb firstValue = decodeInline(children[0]); glm::vec3 total = unpackNormal(firstValue) * (float)qAlpha(firstValue); bool allChildrenEqual = true; for (int i = 1; i < Attribute::MERGE_COUNT; i++) { QRgb value = decodeInline(children[i]); total += unpackNormal(value) * (float)qAlpha(value); allChildrenEqual &= (firstValue == value); } float length = glm::length(total); parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length)); return allChildrenEqual; } void* PackedNormalAttribute::mix(void* first, void* second, float alpha) const { glm::vec3 firstNormal = unpackNormal(decodeInline(first)); glm::vec3 secondNormal = unpackNormal(decodeInline(second)); return encodeInline(packNormal(glm::normalize(glm::mix(firstNormal, secondNormal, alpha)))); } void* PackedNormalAttribute::blend(void* source, void* dest) const { QRgb sourceValue = decodeInline(source); QRgb destValue = decodeInline(dest); float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM; return encodeInline(packNormal(glm::normalize(glm::mix(unpackNormal(destValue), unpackNormal(sourceValue), alpha)))); } const float CHAR_SCALE = 127.0f; const float INVERSE_CHAR_SCALE = 1.0f / CHAR_SCALE; QRgb packNormal(const glm::vec3& normal) { return qRgb((char)(normal.x * CHAR_SCALE), (char)(normal.y * CHAR_SCALE), (char)(normal.z * CHAR_SCALE)); } glm::vec3 unpackNormal(QRgb value) { return glm::vec3((char)qRed(value) * INVERSE_CHAR_SCALE, (char)qGreen(value) * INVERSE_CHAR_SCALE, (char)qBlue(value) * INVERSE_CHAR_SCALE); } SpannerQRgbAttribute::SpannerQRgbAttribute(const QString& name, QRgb defaultValue) : 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[], bool postRead) const { if (postRead) { for (int i = 0; i < MERGE_COUNT; i++) { if (qAlpha(decodeInline(children[i])) != 0) { return false; } } return true; } QRgb parentValue = decodeInline(parent); int totalAlpha = qAlpha(parentValue) * Attribute::MERGE_COUNT; int totalRed = qRed(parentValue) * totalAlpha; int totalGreen = qGreen(parentValue) * totalAlpha; int totalBlue = qBlue(parentValue) * totalAlpha; bool allChildrenTransparent = true; for (int i = 0; i < Attribute::MERGE_COUNT; i++) { QRgb value = decodeInline(children[i]); int alpha = qAlpha(value); totalRed += qRed(value) * alpha; totalGreen += qGreen(value) * alpha; totalBlue += qBlue(value) * alpha; totalAlpha += alpha; allChildrenTransparent &= (alpha == 0); } if (totalAlpha == 0) { parent = encodeInline(QRgb()); } else { parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha, totalBlue / totalAlpha, totalAlpha / MERGE_COUNT)); } return allChildrenTransparent; } 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[], bool postRead) const { if (postRead) { for (int i = 0; i < MERGE_COUNT; i++) { if (qAlpha(decodeInline(children[i])) != 0) { return false; } } return true; } QRgb parentValue = decodeInline(parent); glm::vec3 total = unpackNormal(parentValue) * (float)(qAlpha(parentValue) * Attribute::MERGE_COUNT); bool allChildrenTransparent = true; for (int i = 0; i < Attribute::MERGE_COUNT; i++) { QRgb value = decodeInline(children[i]); int alpha = qAlpha(value); total += unpackNormal(value) * (float)alpha; allChildrenTransparent &= (alpha == 0); } float length = glm::length(total); parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length)); return allChildrenTransparent; } AttributeValue SpannerPackedNormalAttribute::inherit(const AttributeValue& parentValue) const { return AttributeValue(parentValue.getAttribute()); } HeightfieldData::HeightfieldData(const QByteArray& contents) : _contents(contents) { } const int BYTES_PER_PIXEL = 3; HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) : _encoded(in.readAligned(bytes)) { QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888); if (color) { _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); memcpy(_contents.data(), image.constBits(), _contents.size()); } else { _contents.resize(image.width() * image.height()); char* dest = _contents.data(); for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; src != end; src += BYTES_PER_PIXEL) { *dest++ = *src; } } } void HeightfieldData::write(Bitstream& out, bool color) { QMutexLocker locker(&_encodedMutex); if (_encoded.isEmpty()) { QImage image; if (color) { int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); } else { int size = glm::sqrt((float)_contents.size()); image = QImage(size, size, QImage::Format_RGB888); uchar* dest = image.bits(); for (const char* src = _contents.constData(), *end = src + _contents.size(); src != end; src++) { *dest++ = *src; *dest++ = *src; *dest++ = *src; } } QBuffer buffer(&_encoded); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "JPG"); } out << _encoded.size(); out.writeAligned(_encoded); } HeightfieldAttribute::HeightfieldAttribute(const QString& name) : InlineAttribute(name) { } void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { if (isLeaf) { int size; in >> size; if (size == 0) { *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); } else { *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); } } } void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const { if (isLeaf) { HeightfieldDataPointer data = decodeInline(value); if (data) { data->write(out, false); } else { out << 0; } } } bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) const { int maxSize = 0; for (int i = 0; i < MERGE_COUNT; i++) { HeightfieldDataPointer pointer = decodeInline(children[i]); if (pointer) { maxSize = qMax(maxSize, pointer->getContents().size()); } } if (maxSize == 0) { *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); return true; } int size = glm::sqrt((float)maxSize); QByteArray contents(size * size, 0); int halfSize = size / 2; for (int i = 0; i < MERGE_COUNT; i++) { HeightfieldDataPointer child = decodeInline(children[i]); if (!child) { continue; } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt((float)childContents.size()); if (childSize != size) { continue; // TODO: handle differently-sized children } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; int yIndex = (i >> Y_SHIFT) & INDEX_MASK; if (yIndex == 0 && decodeInline(children[i | (1 << Y_SHIFT)])) { continue; // bottom is overriden by top } const int HALF_RANGE = 128; int yOffset = yIndex * HALF_RANGE; int Z_SHIFT = 2; int zIndex = (i >> Z_SHIFT) & INDEX_MASK; char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize); uchar* src = (uchar*)childContents.data(); int childSizePlusOne = childSize + 1; for (int z = 0; z < halfSize; z++) { for (char* end = dest + halfSize; dest != end; src += 2) { *dest++ = yOffset + (qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])) >> 1); } dest += halfSize; src += childSize; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); return false; } HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : InlineAttribute(name) { } void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { if (isLeaf) { int size; in >> size; if (size == 0) { *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); } else { *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); } } } void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const { if (isLeaf) { HeightfieldDataPointer data = decodeInline(value); if (data) { data->write(out, true); } else { out << 0; } } } bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool postRead) const { int maxSize = 0; for (int i = 0; i < MERGE_COUNT; i++) { HeightfieldDataPointer pointer = decodeInline(children[i]); if (pointer) { maxSize = qMax(maxSize, pointer->getContents().size()); } } if (maxSize == 0) { *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); return true; } int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL); QByteArray contents(size * size * BYTES_PER_PIXEL, 0); int halfSize = size / 2; for (int i = 0; i < MERGE_COUNT; i++) { HeightfieldDataPointer child = decodeInline(children[i]); if (!child) { continue; } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); if (childSize != size) { continue; // TODO: handle differently-sized children } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; int yIndex = (i >> Y_SHIFT) & INDEX_MASK; if (yIndex == 0 && decodeInline(children[i | (1 << Y_SHIFT)])) { continue; // bottom is overriden by top } int Z_SHIFT = 2; int zIndex = (i >> Z_SHIFT) & INDEX_MASK; char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; uchar* src = (uchar*)childContents.data(); int childStride = childSize * BYTES_PER_PIXEL; int halfStride = halfSize * BYTES_PER_PIXEL; int childStep = 2 * BYTES_PER_PIXEL; int redOffset3 = childStride + BYTES_PER_PIXEL; int greenOffset1 = BYTES_PER_PIXEL + 1; int greenOffset2 = childStride + 1; int greenOffset3 = childStride + BYTES_PER_PIXEL + 1; int blueOffset1 = BYTES_PER_PIXEL + 2; int blueOffset2 = childStride + 2; int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; for (int z = 0; z < halfSize; z++) { for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; } dest += halfStride; src += childStride; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); return false; } SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject, const SharedObjectPointer& defaultValue) : InlineAttribute(name, defaultValue), _metaObject(metaObject) { } void SharedObjectAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { if (isLeaf) { in >> *((SharedObjectPointer*)&value); } } void SharedObjectAttribute::write(Bitstream& out, void* value, bool isLeaf) const { if (isLeaf) { out << decodeInline(value); } } bool SharedObjectAttribute::deepEqual(void* first, void* second) const { SharedObjectPointer firstObject = decodeInline(first); SharedObjectPointer secondObject = decodeInline(second); return firstObject ? firstObject->equals(secondObject) : !secondObject; } bool SharedObjectAttribute::merge(void*& parent, void* children[], bool postRead) const { SharedObjectPointer firstChild = decodeInline(children[0]); for (int i = 1; i < MERGE_COUNT; i++) { if (firstChild != decodeInline(children[i])) { *(SharedObjectPointer*)&parent = _defaultValue; return false; } } *(SharedObjectPointer*)&parent = firstChild; return true; } void* SharedObjectAttribute::createFromVariant(const QVariant& value) const { return create(encodeInline(value.value())); } QWidget* SharedObjectAttribute::createEditor(QWidget* parent) const { SharedObjectEditor* editor = new SharedObjectEditor(_metaObject, parent); editor->setObject(_defaultValue); return editor; } SharedObjectSetAttribute::SharedObjectSetAttribute(const QString& name, const QMetaObject* metaObject) : InlineAttribute(name), _metaObject(metaObject) { } void SharedObjectSetAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { in >> *((SharedObjectSet*)&value); } void SharedObjectSetAttribute::write(Bitstream& out, void* value, bool isLeaf) const { out << decodeInline(value); } MetavoxelNode* SharedObjectSetAttribute::createMetavoxelNode( const AttributeValue& value, const MetavoxelNode* original) const { return new MetavoxelNode(value, original); } static bool setsEqual(const SharedObjectSet& firstSet, const SharedObjectSet& secondSet) { if (firstSet.size() != secondSet.size()) { return false; } // some hackiness here: we assume that the local ids of the first set correspond to the remote ids of the second, // so that this will work with the tests foreach (const SharedObjectPointer& firstObject, firstSet) { int id = firstObject->getID(); bool found = false; foreach (const SharedObjectPointer& secondObject, secondSet) { if (secondObject->getRemoteID() == id) { if (!firstObject->equals(secondObject)) { return false; } found = true; break; } } if (!found) { return false; } } return true; } bool SharedObjectSetAttribute::deepEqual(void* first, void* second) const { return setsEqual(decodeInline(first), decodeInline(second)); } bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const { for (int i = 0; i < MERGE_COUNT; i++) { if (!decodeInline(children[i]).isEmpty()) { return false; } } return true; } AttributeValue SharedObjectSetAttribute::inherit(const AttributeValue& parentValue) const { return AttributeValue(parentValue.getAttribute()); } QWidget* SharedObjectSetAttribute::createEditor(QWidget* parent) const { return new SharedObjectEditor(_metaObject, parent); } SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject* metaObject) : SharedObjectSetAttribute(name, metaObject) { } void SpannerSetAttribute::readMetavoxelRoot(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.base.stream >> object; if (!object) { break; } data.insert(state.base.attribute, object); } // even if the root is empty, it should still exist if (!data.getRoot(state.base.attribute)) { data.createRoot(state.base.attribute); } } void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, MetavoxelStreamState& state) { state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpanners(state); state.base.stream << SharedObjectPointer(); } void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.base.stream >> object; if (!object) { break; } data.toggle(state.base.attribute, object); } // even if the root is empty, it should still exist if (!data.getRoot(state.base.attribute)) { data.createRoot(state.base.attribute); } } void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpannerDelta(reference, state); state.base.stream << SharedObjectPointer(); } void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { forever { SharedObjectPointer object; state.base.stream >> object; if (!object) { break; } data.insert(state.base.attribute, object); } } void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { state.base.visit = Spanner::getAndIncrementNextVisit(); root.writeSpannerSubdivision(state); state.base.stream << SharedObjectPointer(); } bool SpannerSetAttribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, const glm::vec3& minimum, float size, const MetavoxelLOD& lod) { SharedObjectSet firstSet; firstRoot.getSpanners(this, minimum, size, lod, firstSet); SharedObjectSet secondSet; secondRoot.getSpanners(this, minimum, size, lod, secondSet); return setsEqual(firstSet, secondSet); }