From 8fb766a5d07b6e172c691641893b8c6ac315b201 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 3 Dec 2014 16:44:13 -0800 Subject: [PATCH] Only recreate the renderers for nodes that have changed. --- interface/src/MetavoxelSystem.cpp | 116 ++++++++++++--------------- interface/src/MetavoxelSystem.h | 36 +++------ libraries/metavoxels/src/Spanner.cpp | 21 ++++- libraries/metavoxels/src/Spanner.h | 18 +++++ 4 files changed, 97 insertions(+), 94 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 6a227614cb..fff91d9052 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -578,6 +578,12 @@ void MetavoxelSystem::setVoxelMaterial(const SharedObjectPointer& spanner, const applyMaterialEdit(edit, true); } +void MetavoxelSystem::deleteTextures(int heightTextureID, int colorTextureID, int materialTextureID) const { + glDeleteTextures(1, (const GLuint*)&heightTextureID); + glDeleteTextures(1, (const GLuint*)&colorTextureID); + glDeleteTextures(1, (const GLuint*)&materialTextureID); +} + class SpannerRenderVisitor : public SpannerVisitor { public: @@ -2090,48 +2096,10 @@ void StaticModelRenderer::applyURL(const QUrl& url) { HeightfieldRenderer::HeightfieldRenderer() { } -void HeightfieldRenderer::init(Spanner* spanner) { - SpannerRenderer::init(spanner); - - Heightfield* heightfield = static_cast(spanner); - connect(heightfield, &Heightfield::rootChanged, this, &HeightfieldRenderer::updateRoot); - updateRoot(); -} - -void HeightfieldRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { - Heightfield* heightfield = static_cast(_spanner); - _root->render(heightfield, heightfield->transformLOD(lod), glm::vec2(), 1.0f, contained, cursor); -} - -void HeightfieldRenderer::updateRoot() { - Heightfield* heightfield = static_cast(_spanner); - _root = new HeightfieldRendererNode(heightfield->getRoot()); -} - -HeightfieldRendererNode::HeightfieldRendererNode(const HeightfieldNodePointer& heightfieldNode) : - _heightfieldNode(heightfieldNode), - _heightTextureID(0), - _colorTextureID(0), - _materialTextureID(0) { - - for (int i = 0; i < CHILD_COUNT; i++) { - HeightfieldNodePointer child = heightfieldNode->getChild(i); - if (child) { - _children[i] = new HeightfieldRendererNode(child); - } - } -} - -HeightfieldRendererNode::~HeightfieldRendererNode() { - glDeleteTextures(1, &_heightTextureID); - glDeleteTextures(1, &_colorTextureID); - glDeleteTextures(1, &_materialTextureID); -} - const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; -void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLOD& lod, +static void renderNode(const HeightfieldNodePointer& node, Heightfield* heightfield, const MetavoxelLOD& lod, const glm::vec2& minimum, float size, bool contained, bool cursor) { const glm::quat& rotation = heightfield->getRotation(); glm::vec3 scale(heightfield->getScale() * size, heightfield->getScale() * heightfield->getAspectY(), @@ -2148,19 +2116,44 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO contained = true; } } - if (!isLeaf() && lod.shouldSubdivide(minimum, size)) { + if (!node->isLeaf() && lod.shouldSubdivide(minimum, size)) { float nextSize = size * 0.5f; - for (int i = 0; i < CHILD_COUNT; i++) { - _children[i]->render(heightfield, lod, minimum + glm::vec2(i & X_MAXIMUM_FLAG ? nextSize : 0.0f, + for (int i = 0; i < HeightfieldNode::CHILD_COUNT; i++) { + renderNode(node->getChild(i), heightfield, lod, minimum + glm::vec2(i & X_MAXIMUM_FLAG ? nextSize : 0.0f, i & Y_MAXIMUM_FLAG ? nextSize : 0.0f), nextSize, contained, cursor); } return; } - if (!_heightfieldNode->getHeight()) { + HeightfieldNodeRenderer* renderer = static_cast(node->getRenderer()); + if (!renderer) { + node->setRenderer(renderer = new HeightfieldNodeRenderer()); + } + renderer->render(node, translation, rotation, scale, cursor); +} + +void HeightfieldRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { + Heightfield* heightfield = static_cast(_spanner); + renderNode(heightfield->getRoot(), heightfield, heightfield->transformLOD(lod), glm::vec2(), 1.0f, contained, cursor); +} + +HeightfieldNodeRenderer::HeightfieldNodeRenderer() : + _heightTextureID(0), + _colorTextureID(0), + _materialTextureID(0) { +} + +HeightfieldNodeRenderer::~HeightfieldNodeRenderer() { + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", Q_ARG(int, _heightTextureID), + Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID)); +} + +void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, + const glm::quat& rotation, const glm::vec3& scale, bool cursor) { + if (!node->getHeight()) { return; } - int width = _heightfieldNode->getHeight()->getWidth(); - int height = _heightfieldNode->getHeight()->getContents().size() / width; + int width = node->getHeight()->getWidth(); + int height = node->getHeight()->getContents().size() / width; int innerWidth = width - 2 * HeightfieldHeight::HEIGHT_BORDER; int innerHeight = height - 2 * HeightfieldHeight::HEIGHT_BORDER; int vertexCount = width * height; @@ -2225,7 +2218,7 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - const QVector& heightContents = _heightfieldNode->getHeight()->getContents(); + const QVector& heightContents = node->getHeight()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, heightContents.constData()); @@ -2234,10 +2227,10 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (_heightfieldNode->getColor()) { - const QByteArray& contents = _heightfieldNode->getColor()->getContents(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _heightfieldNode->getColor()->getWidth(), - contents.size() / (_heightfieldNode->getColor()->getWidth() * DataBlock::COLOR_BYTES), + if (node->getColor()) { + const QByteArray& contents = node->getColor()->getContents(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, node->getColor()->getWidth(), + contents.size() / (node->getColor()->getWidth() * DataBlock::COLOR_BYTES), 0, GL_RGB, GL_UNSIGNED_BYTE, contents.constData()); } else { @@ -2251,13 +2244,13 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (_heightfieldNode->getMaterial()) { - const QByteArray& contents = _heightfieldNode->getMaterial()->getContents(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, _heightfieldNode->getMaterial()->getWidth(), - contents.size() / _heightfieldNode->getMaterial()->getWidth(), + if (node->getMaterial()) { + const QByteArray& contents = node->getMaterial()->getContents(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, node->getMaterial()->getWidth(), + contents.size() / node->getMaterial()->getWidth(), 0, GL_RED, GL_UNSIGNED_BYTE, contents.constData()); - const QVector& materials = _heightfieldNode->getMaterial()->getMaterials(); + const QVector& materials = node->getMaterial()->getMaterials(); _networkTextures.resize(materials.size()); for (int i = 0; i < materials.size(); i++) { const SharedObjectPointer& material = materials.at(i); @@ -2330,7 +2323,7 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO glm::dot(translation, rotation * glm::vec3(1.0f, 0.0f, 0.0f)) / scale.x, glm::dot(translation, rotation * glm::vec3(0.0f, 0.0f, 1.0f)) / scale.z); - const QVector& materials = _heightfieldNode->getMaterial()->getMaterials(); + const QVector& materials = node->getMaterial()->getMaterials(); for (int i = 0; i < materials.size(); i += SPLAT_COUNT) { for (int j = 0; j < SPLAT_COUNT; j++) { int index = i + j; @@ -2355,14 +2348,5 @@ void HeightfieldRendererNode::render(Heightfield* heightfield, const MetavoxelLO } } -bool HeightfieldRendererNode::isLeaf() const { - for (int i = 0; i < CHILD_COUNT; i++) { - if (_children[i]) { - return false; - } - } - return true; -} - -QHash HeightfieldRendererNode::_bufferPairs; +QHash HeightfieldNodeRenderer::_bufferPairs; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 99c55549c7..26f3bd68a3 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -24,7 +24,6 @@ #include "renderer/ProgramObject.h" class HeightfieldBaseLayerBatch; -class HeightfieldRendererNode; class HeightfieldSplatBatch; class HermiteBatch; class Model; @@ -91,7 +90,9 @@ public: void addVoxelSplatBatch(const VoxelSplatBatch& batch) { _voxelSplatBatches.append(batch); } void addHermiteBatch(const HermiteBatch& batch) { _hermiteBatches.append(batch); } - + + Q_INVOKABLE void deleteTextures(int heightTextureID, int colorTextureID, int materialTextureID) const; + signals: void rendering(); @@ -431,8 +432,6 @@ private: Model* _model; }; -typedef QExplicitlySharedDataPointer HeightfieldRendererNodePointer; - /// Renders heightfields. class HeightfieldRenderer : public SpannerRenderer { Q_OBJECT @@ -441,38 +440,21 @@ public: Q_INVOKABLE HeightfieldRenderer(); - virtual void init(Spanner* spanner); virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false); - -private slots: - - void updateRoot(); - -private: - - HeightfieldRendererNodePointer _root; }; -/// A node in the heightfield renderer quadtree. -class HeightfieldRendererNode : public QSharedData { +/// Renders a single quadtree node. +class HeightfieldNodeRenderer : public AbstractHeightfieldNodeRenderer { public: - static const int CHILD_COUNT = 4; + HeightfieldNodeRenderer(); + virtual ~HeightfieldNodeRenderer(); - HeightfieldRendererNode(const HeightfieldNodePointer& heightfieldNode); - virtual ~HeightfieldRendererNode(); - - void render(Heightfield* heightfield, const MetavoxelLOD& lod, const glm::vec2& minimum, float size, - bool contained, bool cursor = false); + void render(const HeightfieldNodePointer& node, const glm::vec3& translation, + const glm::quat& rotation, const glm::vec3& scale, bool cursor); private: - bool isLeaf() const; - - HeightfieldNodePointer _heightfieldNode; - - HeightfieldRendererNodePointer _children[CHILD_COUNT]; - GLuint _heightTextureID; GLuint _colorTextureID; GLuint _materialTextureID; diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index f249ae2912..f2a1ebb27f 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -1143,7 +1143,23 @@ HeightfieldNode::HeightfieldNode(const HeightfieldHeightPointer& height, const H const HeightfieldMaterialPointer& material) : _height(height), _color(color), - _material(material) { + _material(material), + _renderer(NULL) { +} + +HeightfieldNode::HeightfieldNode(const HeightfieldNode& other) : + _height(other.getHeight()), + _color(other.getColor()), + _material(other.getMaterial()), + _renderer(NULL) { + + for (int i = 0; i < CHILD_COUNT; i++) { + _children[i] = other.getChild(i); + } +} + +HeightfieldNode::~HeightfieldNode() { + delete _renderer; } const int HEIGHT_LEAF_SIZE = 256 + HeightfieldHeight::HEIGHT_EXTENSION; @@ -2479,6 +2495,9 @@ int HeightfieldNode::getMaterialAt(const glm::vec3& location) const { return src[(int)glm::round(relative.z) * width + (int)glm::round(relative.x)]; } +AbstractHeightfieldNodeRenderer::~AbstractHeightfieldNodeRenderer() { +} + Heightfield::Heightfield() : _aspectY(1.0f), _aspectZ(1.0f) { diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index c4fe185a58..bbfcbff1ff 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -17,6 +17,8 @@ #include "AttributeRegistry.h" #include "MetavoxelUtil.h" +class AbstractHeightfieldNodeRenderer; +class Heightfield; class HeightfieldColor; class HeightfieldHeight; class HeightfieldMaterial; @@ -499,6 +501,10 @@ public: const HeightfieldColorPointer& color = HeightfieldColorPointer(), const HeightfieldMaterialPointer& material = HeightfieldMaterialPointer()); + HeightfieldNode(const HeightfieldNode& other); + + ~HeightfieldNode(); + void setContents(const HeightfieldHeightPointer& height, const HeightfieldColorPointer& color, const HeightfieldMaterialPointer& material); @@ -511,6 +517,9 @@ public: void setMaterial(const HeightfieldMaterialPointer& material) { _material = material; } const HeightfieldMaterialPointer& getMaterial() const { return _material; } + void setRenderer(AbstractHeightfieldNodeRenderer* renderer) { _renderer = renderer; } + AbstractHeightfieldNodeRenderer* getRenderer() const { return _renderer; } + bool isLeaf() const; void setChild(int index, const HeightfieldNodePointer& child) { _children[index] = child; } @@ -559,6 +568,15 @@ private: HeightfieldMaterialPointer _material; HeightfieldNodePointer _children[CHILD_COUNT]; + + AbstractHeightfieldNodeRenderer* _renderer; +}; + +/// Base class for heightfield node rendering. +class AbstractHeightfieldNodeRenderer { +public: + + virtual ~AbstractHeightfieldNodeRenderer(); }; /// A heightfield represented as a spanner.