From bba042e823c8ebc551ee671c51acb7e9dfae22a8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Nov 2014 16:52:29 -0800 Subject: [PATCH] Heightfield material paint bits. --- interface/src/MetavoxelSystem.cpp | 7 +- libraries/metavoxels/src/MetavoxelData.cpp | 39 +++++ libraries/metavoxels/src/MetavoxelData.h | 3 + .../metavoxels/src/MetavoxelMessages.cpp | 137 ++---------------- libraries/metavoxels/src/Spanner.cpp | 110 ++++++++++++++ libraries/metavoxels/src/Spanner.h | 6 + 6 files changed, 172 insertions(+), 130 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 9577a04695..5ff179765e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -2869,8 +2869,7 @@ void HeightfieldRenderer::render(bool cursor) { glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - + Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false); DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().release(); @@ -2946,14 +2945,14 @@ void HeightfieldRenderer::render(bool cursor) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().release(); glDisable(GL_POLYGON_OFFSET_FILL); glDepthMask(true); glDepthFunc(GL_LESS); } + glActiveTexture(GL_TEXTURE0); + glDisable(GL_CULL_FACE); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index cb3c5b94bf..94b3e0be97 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -354,6 +354,45 @@ void MetavoxelData::replace(const AttributePointer& attribute, const Box& bounds guide(visitor); } +class SpannerFetchVisitor : public SpannerVisitor { +public: + + SpannerFetchVisitor(const AttributePointer& attribute, const Box& bounds, QVector& results); + + virtual bool visit(Spanner* spanner); + + virtual int visit(MetavoxelInfo& info); + +private: + + const Box& _bounds; + QVector& _results; +}; + +SpannerFetchVisitor::SpannerFetchVisitor(const AttributePointer& attribute, const Box& bounds, + QVector& results) : + SpannerVisitor(QVector() << attribute), + _bounds(bounds), + _results(results) { +} + +bool SpannerFetchVisitor::visit(Spanner* spanner) { + if (spanner->getBounds().intersects(_bounds)) { + _results.append(spanner); + } + return true; +} + +int SpannerFetchVisitor::visit(MetavoxelInfo& info) { + return info.getBounds().intersects(_bounds) ? SpannerVisitor::visit(info) : STOP_RECURSION; +} + +void MetavoxelData::getIntersecting(const AttributePointer& attribute, const Box& bounds, + QVector& results) { + SpannerFetchVisitor visitor(attribute, bounds, results); + guide(visitor); +} + void MetavoxelData::clear(const AttributePointer& attribute) { MetavoxelNode* node = _roots.take(attribute); if (node) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index b80da9b2a0..7bfd2a7522 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -102,6 +102,9 @@ public: void replace(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject); + /// Retrieves all spanners that intersect the specified bounds. + void getIntersecting(const AttributePointer& attribute, const Box& bounds, QVector& results); + /// Clears all data in the specified attribute layer. void clear(const AttributePointer& attribute); diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d40b49a2e6..c7471e7296 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -242,130 +242,6 @@ MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& av averageColor(averageColor) { } -class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor { -public: - - PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius, - const SharedObjectPointer& material, const QColor& color); - - virtual int visit(MetavoxelInfo& info); - -private: - - glm::vec3 _position; - float _radius; - SharedObjectPointer _material; - QColor _color; - Box _bounds; -}; - -PaintHeightfieldMaterialEditVisitor::PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius, - const SharedObjectPointer& material, const QColor& color) : - MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << - AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector() << - AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << - AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute()), - _position(position), - _radius(radius), - _material(material), - _color(color) { - - const float LARGE_EXTENT = 100000.0f; - glm::vec3 extents(_radius, LARGE_EXTENT, _radius); - _bounds = Box(_position - extents, _position + extents); -} - -int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) { - if (!info.getBounds().intersects(_bounds)) { - return STOP_RECURSION; - } - if (!info.isLeaf) { - return DEFAULT_ORDER; - } - HeightfieldColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue(); - if (colorPointer) { - QByteArray contents(colorPointer->getContents()); - int size = glm::sqrt((float)contents.size() / DataBlock::COLOR_BYTES); - int highest = size - 1; - float heightScale = size / info.size; - - glm::vec3 center = (_position - info.minimum) * heightScale; - float scaledRadius = _radius * heightScale; - glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); - - glm::vec3 start = glm::floor(center - extents); - glm::vec3 end = glm::ceil(center + extents); - - // paint all points within the radius - float z = qMax(start.z, 0.0f); - float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); - int stride = size * DataBlock::COLOR_BYTES; - char* lineDest = contents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES; - float squaredRadius = scaledRadius * scaledRadius; - char red = _color.red(), green = _color.green(), blue = _color.blue(); - bool changed = false; - for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { - char* dest = lineDest; - for (float x = startX; x <= endX; x += 1.0f, dest += DataBlock::COLOR_BYTES) { - float dx = x - center.x, dz = z - center.z; - if (dx * dx + dz * dz <= squaredRadius) { - dest[0] = red; - dest[1] = green; - dest[2] = blue; - changed = true; - } - } - lineDest += stride; - } - if (changed) { - HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents)); - info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(), - encodeInline(newPointer)); - } - } - - HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(1).getInlineValue(); - if (materialPointer) { - QVector materials = materialPointer->getMaterials(); - QByteArray contents(materialPointer->getContents()); - uchar materialIndex = getMaterialIndex(_material, materials, contents); - int size = glm::sqrt((float)contents.size()); - int highest = size - 1; - float heightScale = highest / info.size; - - glm::vec3 center = (_position - info.minimum) * heightScale; - float scaledRadius = _radius * heightScale; - glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); - - glm::vec3 start = glm::floor(center - extents); - glm::vec3 end = glm::ceil(center + extents); - - // paint all points within the radius - float z = qMax(start.z, 0.0f); - float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); - uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX; - float squaredRadius = scaledRadius * scaledRadius; - bool changed = false; - for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { - uchar* dest = lineDest; - for (float x = startX; x <= endX; x += 1.0f, dest++) { - float dx = x - center.x, dz = z - center.z; - if (dx * dx + dz * dz <= squaredRadius) { - *dest = materialIndex; - changed = true; - } - } - lineDest += size; - } - if (changed) { - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newPointer)); - } - } - return STOP_RECURSION; -} - PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& averageColor) : MaterialEdit(material, averageColor), @@ -374,8 +250,17 @@ PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& posi } void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { - PaintHeightfieldMaterialEditVisitor visitor(position, radius, material, averageColor); - data.guide(visitor); + glm::vec3 extents(radius, radius, radius); + QVector results; + data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(), + Box(position - extents, position + extents), results); + + foreach (const SharedObjectPointer& spanner, results) { + Spanner* newSpanner = static_cast(spanner.data())->paint(position, radius, material, averageColor); + if (newSpanner != spanner) { + data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner); + } + } } const int VOXEL_BLOCK_SIZE = 16; diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index 3184795488..0808ae2ed1 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -108,6 +108,10 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire return _bounds.findRayIntersection(origin, direction, distance); } +Spanner* Spanner::paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color) { + return this; +} + bool Spanner::hasOwnColors() const { return false; } @@ -1604,6 +1608,112 @@ bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3& return false; } +Spanner* Heightfield::paint(const glm::vec3& position, float radius, + const SharedObjectPointer& material, const QColor& color) { + if (!_height) { + return this; + } + int heightWidth = _height->getWidth(); + int heightHeight = _height->getContents().size() / heightWidth; + int baseWidth = heightWidth - HeightfieldHeight::HEIGHT_EXTENSION + HeightfieldData::SHARED_EDGE; + int baseHeight = heightHeight - HeightfieldHeight::HEIGHT_EXTENSION + HeightfieldData::SHARED_EDGE; + Heightfield* newHeightfield = static_cast(clone(true)); + + int colorWidth = baseWidth, colorHeight = baseHeight; + QByteArray colorContents; + if (_color) { + colorWidth = _color->getWidth(); + colorHeight = _color->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES); + colorContents = _color->getContents(); + + } else { + colorContents = QByteArray(baseWidth * baseHeight * DataBlock::COLOR_BYTES, 0xFF); + } + + int materialWidth = baseWidth, materialHeight = baseHeight; + QByteArray materialContents; + QVector materials; + if (_material) { + materialWidth = _material->getWidth(); + materialHeight = _material->getContents().size() / materialWidth; + materialContents = _material->getContents(); + materials = _material->getMaterials(); + + } else { + materialContents = QByteArray(baseWidth * baseHeight, 0); + } + + int highestX = colorWidth - 1; + int highestZ = colorHeight - 1; + glm::vec3 inverseScale(highestX / getScale(), 1.0f, highestZ / (getScale() * _aspectZ)); + glm::vec3 center = glm::inverse(getRotation()) * (position - getTranslation()) * inverseScale; + + glm::vec3 extents = glm::vec3(radius, radius, radius) * inverseScale; + glm::vec3 start = glm::floor(center - extents); + glm::vec3 end = glm::ceil(center + extents); + + // paint all points within the radius + float z = qMax(start.z, 0.0f); + float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highestX); + int stride = colorWidth * DataBlock::COLOR_BYTES; + uchar* lineDest = (uchar*)colorContents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES; + float squaredRadius = extents.x * extents.x; + float multiplierZ = inverseScale.x / inverseScale.z; + char red = color.red(), green = color.green(), blue = color.blue(); + bool changed = false; + for (float endZ = qMin(end.z, (float)highestZ); z <= endZ; z += 1.0f) { + uchar* dest = lineDest; + for (float x = startX; x <= endX; x += 1.0f, dest += DataBlock::COLOR_BYTES) { + float dx = x - center.x, dz = (z - center.z) * multiplierZ; + if (dx * dx + dz * dz <= squaredRadius) { + dest[0] = red; + dest[1] = green; + dest[2] = blue; + changed = true; + } + } + lineDest += stride; + } + if (changed) { + newHeightfield->setColor(HeightfieldColorPointer(new HeightfieldColor(colorWidth, colorContents))); + } + + highestX = materialWidth - 1; + highestZ = materialHeight - 1; + inverseScale = glm::vec3(highestX / getScale(), 1.0f, highestZ / (getScale() * _aspectZ)); + center = glm::inverse(getRotation()) * (position - getTranslation()) * inverseScale; + + extents = glm::vec3(radius, radius, radius) * inverseScale; + start = glm::floor(center - extents); + end = glm::ceil(center + extents); + + // paint all points within the radius + z = qMax(start.z, 0.0f); + startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highestX); + lineDest = (uchar*)materialContents.data() + (int)z * materialWidth + (int)startX; + squaredRadius = extents.x * extents.x; + uchar materialIndex = getMaterialIndex(material, materials, materialContents); + changed = false; + for (float endZ = qMin(end.z, (float)highestZ); z <= endZ; z += 1.0f) { + uchar* dest = lineDest; + for (float x = startX; x <= endX; x += 1.0f, dest++) { + float dx = x - center.x, dz = (z - center.z) * multiplierZ; + if (dx * dx + dz * dz <= squaredRadius) { + *dest = materialIndex; + changed = true; + } + } + lineDest += materialWidth; + } + if (changed) { + clearUnusedMaterials(materials, materialContents); + newHeightfield->setMaterial(HeightfieldMaterialPointer(new HeightfieldMaterial(materialWidth, + materialContents, materials))); + } + + return newHeightfield; +} + QByteArray Heightfield::getRendererClassName() const { return "HeightfieldRenderer"; } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 2c8f0d78ca..beaf6c8a7e 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -64,6 +64,10 @@ public: /// Finds the intersection between the described ray and this spanner. virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; + /// Attempts to paint on the spanner. + /// \return the modified spanner, or this if no modification was performed + virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color); + /// Checks whether this spanner has its own colors. virtual bool hasOwnColors() const; @@ -511,6 +515,8 @@ public: virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; + virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color); + signals: void aspectYChanged(float aspectY);