diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7faf1a5bf4..cb2673b08d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1564,14 +1564,13 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { VoxelColorDataPointer color = info.inputValues.at(0).getInlineValue(); VoxelMaterialDataPointer material = info.inputValues.at(1).getInlineValue(); VoxelHermiteDataPointer hermite = info.inputValues.at(2).getInlineValue(); - if (color && material && hermite) { + if (color && hermite) { QVector vertices; QVector indices; // see http://www.frankpetterson.com/publications/dualcontour/dualcontour.pdf for a description of the // dual contour algorithm for generating meshes from voxel data using Hermite-tagged edges const QVector& colorContents = color->getContents(); - const QByteArray& materialContents = material->getContents(); const QVector& hermiteContents = hermite->getContents(); int size = color->getSize(); int area = size * size; @@ -1589,7 +1588,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { int hermiteStride = hermite->getSize() * VoxelHermiteData::EDGE_COUNT; int hermiteArea = hermiteStride * hermite->getSize(); - const char* materialData = materialContents.constData(); + const char* materialData = material ? material->getContents().constData() : NULL; // as we scan down the cube generating vertices between grid points, we remember the indices of the last // (element, line, section--x, y, z) so that we can connect generated vertices as quads @@ -1667,7 +1666,8 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { int clampedX = qMax(x - 1, 0), clampedY = qMax(y - 1, 0), clampedZ = qMax(z - 1, 0); const QRgb* hermiteBase = hermiteData + clampedZ * hermiteArea + clampedY * hermiteStride + clampedX * VoxelHermiteData::EDGE_COUNT; - const char* materialBase = materialData + clampedZ * area + clampedY * size + clampedX; + const char* materialBase = materialData ? + (materialData + clampedZ * area + clampedY * size + clampedX) : NULL; int crossingCount = 0; if (middleX) { if (alpha0 != alpha1) { @@ -1676,10 +1676,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha0 == 0) { crossing.color = colorX[1]; - crossing.material = materialBase[1]; + crossing.material = materialBase ? materialBase[1] : 0; } else { crossing.color = colorX[0]; - crossing.material = materialBase[0]; + crossing.material = materialBase ? materialBase[0] : 0; } crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 0.0f); crossing.axis = 0; @@ -1691,10 +1691,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha1 == 0) { crossing.color = colorX[offset3]; - crossing.material = materialBase[offset3]; + crossing.material = materialBase ? materialBase[offset3] : 0; } else { crossing.color = colorX[1]; - crossing.material = materialBase[1]; + crossing.material = materialBase ? materialBase[1] : 0; } crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f); crossing.axis = 1; @@ -1705,10 +1705,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha2 == 0) { crossing.color = colorX[offset3]; - crossing.material = materialBase[offset3]; + crossing.material = materialBase ? materialBase[offset3] : 0; } else { crossing.color = colorX[size]; - crossing.material = materialBase[size]; + crossing.material = materialBase ? materialBase[size] : 0; } crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 0.0f); crossing.axis = 0; @@ -1720,10 +1720,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha3 == 0) { crossing.color = colorX[offset7]; - crossing.material = materialBase[offset7]; + crossing.material = materialBase ? materialBase[offset7] : 0; } else { crossing.color = colorX[offset3]; - crossing.material = materialBase[offset3]; + crossing.material = materialBase ? materialBase[offset3] : 0; } crossing.point = glm::vec3(1.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL); crossing.axis = 2; @@ -1734,10 +1734,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha5 == 0) { crossing.color = colorX[offset7]; - crossing.material = materialBase[offset7]; + crossing.material = materialBase ? materialBase[offset7] : 0; } else { crossing.color = colorX[offset5]; - crossing.material = materialBase[offset5]; + crossing.material = materialBase ? materialBase[offset5] : 0; } crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f); crossing.axis = 1; @@ -1748,10 +1748,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha6 == 0) { crossing.color = colorX[offset7]; - crossing.material = materialBase[offset7]; + crossing.material = materialBase ? materialBase[offset7] : 0; } else { crossing.color = colorX[offset6]; - crossing.material = materialBase[offset6]; + crossing.material = materialBase ? materialBase[offset6] : 0; } crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 1.0f); crossing.axis = 0; @@ -1765,10 +1765,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha1 == 0) { crossing.color = colorX[offset5]; - crossing.material = materialBase[offset5]; + crossing.material = materialBase ? materialBase[offset5] : 0; } else { crossing.color = colorX[1]; - crossing.material = materialBase[1]; + crossing.material = materialBase ? materialBase[1] : 0; } crossing.point = glm::vec3(1.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL); crossing.axis = 2; @@ -1779,10 +1779,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha4 == 0) { crossing.color = colorX[offset5]; - crossing.material = materialBase[offset5]; + crossing.material = materialBase ? materialBase[offset5] : 0; } else { crossing.color = colorX[area]; - crossing.material = materialBase[area]; + crossing.material = materialBase ? materialBase[area] : 0; } crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 1.0f); crossing.axis = 0; @@ -1796,10 +1796,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha0 == 0) { crossing.color = colorX[size]; - crossing.material = materialBase[size]; + crossing.material = materialBase ? materialBase[size] : 0; } else { crossing.color = colorX[0]; - crossing.material = materialBase[0]; + crossing.material = materialBase ? materialBase[0] : 0; } crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f); crossing.axis = 1; @@ -1811,10 +1811,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha2 == 0) { crossing.color = colorX[offset6]; - crossing.material = materialBase[offset6]; + crossing.material = materialBase ? materialBase[offset6] : 0; } else { crossing.color = colorX[size]; - crossing.material = materialBase[size]; + crossing.material = materialBase ? materialBase[size] : 0; } crossing.point = glm::vec3(0.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL); crossing.axis = 2; @@ -1825,10 +1825,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha4 == 0) { crossing.color = colorX[offset6]; - crossing.material = materialBase[offset6]; + crossing.material = materialBase ? materialBase[offset6] : 0; } else { crossing.color = colorX[area]; - crossing.material = materialBase[area]; + crossing.material = materialBase ? materialBase[area] : 0; } crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f); crossing.axis = 1; @@ -1841,10 +1841,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { crossing.normal = unpackNormal(hermite); if (alpha0 == 0) { crossing.color = colorX[area]; - crossing.material = materialBase[area]; + crossing.material = materialBase ? materialBase[area] : 0; } else { crossing.color = colorX[0]; - crossing.material = materialBase[0]; + crossing.material = materialBase ? materialBase[0] : 0; } crossing.point = glm::vec3(0.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL); crossing.axis = 2; @@ -2091,7 +2091,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { } } - buffer = new VoxelBuffer(vertices, indices, material->getMaterials()); + buffer = new VoxelBuffer(vertices, indices, material ? material->getMaterials() : QVector()); } BufferDataPointer pointer(buffer); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index dffc02ee07..45911d9626 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -48,7 +48,7 @@ enum GridPlane { const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX); MetavoxelEditor::MetavoxelEditor() : - QWidget(Application::getInstance()->getGLWidget(), Qt::Tool | Qt::WindowStaysOnTopHint) { + QWidget(Application::getInstance()->getGLWidget(), Qt::Tool) { setWindowTitle("Metavoxel Editor"); setAttribute(Qt::WA_DeleteOnClose); diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index aec9a069be..3ea011c265 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -1616,8 +1616,74 @@ bool VoxelColorAttribute::merge(void*& parent, void* children[], bool postRead) maxSize = qMax(maxSize, pointer->getSize()); } } - *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer(); - return maxSize == 0; + if (maxSize == 0) { + *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer(); + return true; + } + int size = maxSize; + int area = size * size; + QVector contents(area * size); + int halfSize = size / 2; + int halfSizeComplement = size - halfSize; + for (int i = 0; i < MERGE_COUNT; i++) { + VoxelColorDataPointer child = decodeInline(children[i]); + if (!child) { + continue; + } + const QVector& childContents = child->getContents(); + int childSize = child->getSize(); + int childArea = childSize * childSize; + const int INDEX_MASK = 1; + int xIndex = i & INDEX_MASK; + const int Y_SHIFT = 1; + int yIndex = (i >> Y_SHIFT) & INDEX_MASK; + int Z_SHIFT = 2; + int zIndex = (i >> Z_SHIFT) & INDEX_MASK; + QRgb* dest = contents.data() + (zIndex * halfSize * area) + (yIndex * halfSize * size) + (xIndex * halfSize); + const QRgb* src = childContents.data(); + + const int MAX_ALPHA = 255; + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSizeComplement; z++) { + int offset4 = (z == halfSize) ? 0 : childArea; + for (int y = 0; y < halfSizeComplement; y++) { + int offset2 = (y == halfSize) ? 0 : childSize; + int offset6 = offset4 + offset2; + for (QRgb* end = dest + halfSizeComplement; dest != end; ) { + int offset1 = (dest == end - 1) ? 0 : 1; + QRgb v0 = src[0], v1 = src[offset1], v2 = src[offset2], v3 = src[offset2 + offset1], v4 = src[offset4], + v5 = src[offset4 + offset1], v6 = src[offset6], v7 = src[offset6 + offset1]; + src += (1 + offset1); + int a0 = qAlpha(v0), a1 = qAlpha(v1), a2 = qAlpha(v2), a3 = qAlpha(v3), + a4 = qAlpha(v4), a5 = qAlpha(v5), a6 = qAlpha(v6), a7 = qAlpha(v7); + int alphaTotal = a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7; + if (alphaTotal == 0) { + *dest++ = qRgba(0, 0, 0, 0); + continue; + } + *dest++ = qRgba( + (qRed(v0) * a0 + qRed(v1) * a1 + qRed(v2) * a2 + qRed(v3) * a3 + + qRed(v4) * a4 + qRed(v5) * a5 + qRed(v6) * a6 + qRed(v7) * a7) / alphaTotal, + (qGreen(v0) * a0 + qGreen(v1) * a1 + qGreen(v2) * a2 + qGreen(v3) * a3 + + qGreen(v4) * a4 + qGreen(v5) * a5 + qGreen(v6) * a6 + qGreen(v7) * a7) / alphaTotal, + (qBlue(v0) * a0 + qBlue(v1) * a1 + qBlue(v2) * a2 + qBlue(v3) * a3 + + qBlue(v4) * a4 + qBlue(v5) * a5 + qBlue(v6) * a6 + qBlue(v7) * a7) / alphaTotal, + MAX_ALPHA); + } + dest += halfSize; + src += offset2; + } + dest += halfSize * size; + src += offset4; + } + } else { + // more complex: N destination values for four child values + // ... + } + } + *(VoxelColorDataPointer*)&parent = VoxelColorDataPointer(new VoxelColorData(contents, size)); + return false; } const int VOXEL_MATERIAL_HEADER_SIZE = sizeof(qint32) * 6; @@ -2020,8 +2086,87 @@ bool VoxelHermiteAttribute::merge(void*& parent, void* children[], bool postRead maxSize = qMax(maxSize, pointer->getSize()); } } - *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer(); - return maxSize == 0; + if (maxSize == 0) { + *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer(); + return true; + } + int size = maxSize; + int area = size * size; + QVector contents(area * size * VoxelHermiteData::EDGE_COUNT); + int halfSize = size / 2; + int halfSizeComplement = size - halfSize; + for (int i = 0; i < MERGE_COUNT; i++) { + VoxelHermiteDataPointer child = decodeInline(children[i]); + if (!child) { + continue; + } + const QVector& childContents = child->getContents(); + int childSize = child->getSize(); + int childArea = childSize * childSize; + const int INDEX_MASK = 1; + int xIndex = i & INDEX_MASK; + const int Y_SHIFT = 1; + int yIndex = (i >> Y_SHIFT) & INDEX_MASK; + int Z_SHIFT = 2; + int zIndex = (i >> Z_SHIFT) & INDEX_MASK; + QRgb* dest = contents.data() + ((zIndex * halfSize * area) + (yIndex * halfSize * size) + (xIndex * halfSize)) * + VoxelHermiteData::EDGE_COUNT; + const QRgb* src = childContents.data(); + + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSizeComplement; z++) { + int offset4 = (z == halfSize) ? 0 : (childArea * VoxelHermiteData::EDGE_COUNT); + for (int y = 0; y < halfSizeComplement; y++) { + int offset2 = (y == halfSize) ? 0 : (childSize * VoxelHermiteData::EDGE_COUNT); + int offset6 = offset4 + offset2; + for (QRgb* end = dest + halfSizeComplement * VoxelHermiteData::EDGE_COUNT; dest != end; + dest += VoxelHermiteData::EDGE_COUNT) { + int offset1 = (dest == end - VoxelHermiteData::EDGE_COUNT) ? 0 : VoxelHermiteData::EDGE_COUNT; + for (int i = 0; i < VoxelHermiteData::EDGE_COUNT; i++) { + QRgb v[] = { src[i], src[offset1 + i], src[offset2 + i], src[offset2 + offset1 + i], + src[offset4 + i], src[offset4 + offset1 + i], src[offset6 + i], src[offset6 + offset1 + i] }; + glm::vec3 n[] = { unpackNormal(v[0]), unpackNormal(v[1]), unpackNormal(v[2]), unpackNormal(v[3]), + unpackNormal(v[4]), unpackNormal(v[5]), unpackNormal(v[6]), unpackNormal(v[7]) }; + float l[] = { glm::length(n[0]), glm::length(n[1]), glm::length(n[2]), glm::length(n[3]), + glm::length(n[4]), glm::length(n[5]), glm::length(n[6]), glm::length(n[7]) }; + float lengthTotal = l[0] + l[1] + l[2] + l[3] + l[4] + l[5] + l[6] + l[7]; + if (lengthTotal == 0.0f) { + dest[i] = qRgba(0, 0, 0, 0); + continue; + } + glm::vec3 combinedNormal = n[0] * l[0] + n[1] * l[1] + n[2] * l[2] + n[3] * l[3] + n[4] * l[4] + + n[5] * l[5] + n[6] * l[6] + n[7] * l[7]; + float combinedLength = glm::length(combinedNormal); + if (combinedLength > 0.0f) { + combinedNormal /= combinedLength; + } + float combinedOffset = 0.0f; + int mask = 1 << i; + for (int j = 0; j < MERGE_COUNT; j++) { + float offset = qAlpha(v[j]) * (0.5f / EIGHT_BIT_MAXIMUM); + if (j & mask) { + offset += 0.5f; + } + combinedOffset += offset * l[j]; + } + dest[i] = packNormal(combinedNormal, EIGHT_BIT_MAXIMUM * combinedOffset / lengthTotal); + } + src += (VoxelHermiteData::EDGE_COUNT + offset1); + } + dest += (halfSize * VoxelHermiteData::EDGE_COUNT); + src += offset2; + } + dest += (halfSize * size * VoxelHermiteData::EDGE_COUNT); + src += offset4; + } + } else { + // more complex: N destination values for four child values + // ... + } + } + *(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer(new VoxelHermiteData(contents, size)); + return false; } SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,