From 02f411bc0e376ecae0195e16888339ececf78bc0 Mon Sep 17 00:00:00 2001 From: Tats Date: Sat, 26 Dec 2015 19:25:16 -0500 Subject: [PATCH] Further improvements on mesh drawing performance: resolution is heightened on mouse release while during edit resolution is kept lower (closes #161). --- MapperGLCanvas.h | 3 ++ ShapeGraphicsItem.cpp | 97 +++++++++++++++++++++++++++++-------------- ShapeGraphicsItem.h | 5 ++- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/MapperGLCanvas.h b/MapperGLCanvas.h index 9829b3b..0124686 100644 --- a/MapperGLCanvas.h +++ b/MapperGLCanvas.h @@ -83,6 +83,9 @@ public: /// Set the currently active vertex void setActiveVertexIndex(int activeVertex) { _activeVertex = activeVertex; } + bool shapeGrabbed() const { return _shapeGrabbed; } + bool vertexGrabbed() const { return _vertexGrabbed; } + qreal getZoomFactor() const { return qBound(qPow(MM::ZOOM_FACTOR, _zoomLevel), MM::ZOOM_MIN, MM::ZOOM_MAX); } /// This function needs to be called after a shape inside the canvas has been changed for appropriate signals to be activated. diff --git a/ShapeGraphicsItem.cpp b/ShapeGraphicsItem.cpp index 44c226d..5c8bc10 100644 --- a/ShapeGraphicsItem.cpp +++ b/ShapeGraphicsItem.cpp @@ -312,9 +312,9 @@ PolygonTextureGraphicsItem::PolygonTextureGraphicsItem(Mapping::ptr mapping, boo MeshTextureGraphicsItem::MeshTextureGraphicsItem(Mapping::ptr mapping, bool output) : PolygonTextureGraphicsItem(mapping, output) { _controlPainter.reset(new MeshControlPainter(this)); _nHorizontalQuads = _nVerticalQuads = -1; + _wasGrabbing = false; } - void MeshTextureGraphicsItem::_doDrawOutput(QPainter* painter) { Q_UNUSED(painter); @@ -326,16 +326,29 @@ void MeshTextureGraphicsItem::_doDrawOutput(QPainter* painter) QVector > inputQuads = inputMesh->getQuads2d(); // Check if we increased or decreased number of columns/rows in mesh. - bool dirty = false; + bool forceRebuild = false; if (_nHorizontalQuads != outputMesh->nHorizontalQuads() || _nVerticalQuads != outputMesh->nVerticalQuads()) { - dirty = true; + forceRebuild = true; _cachedQuadItems.resize(_nHorizontalQuads = outputMesh->nHorizontalQuads()); for (int i=0; i<_nHorizontalQuads; i++) _cachedQuadItems[i].resize(_nVerticalQuads = outputMesh->nVerticalQuads()); } + // Keep track of whether we are currently grabbing the shape or a vertex so as to + // reduce resolution when editing (to prevent lags). + bool grabbing = (getCanvas()->shapeGrabbed() || getCanvas()->vertexGrabbed()); + + // Max depth is adjusted to draw less quads during click & drag. + int maxDepth = (grabbing ? 4 : -1); + + // Force rebuild on shape/vertex release. + if (_wasGrabbing && !grabbing) { + forceRebuild = true; + } + _wasGrabbing = grabbing; + // Go through the mesh quad by quad. for (int x = 0; x < outputMesh->nHorizontalQuads(); x++) { @@ -346,19 +359,22 @@ void MeshTextureGraphicsItem::_doDrawOutput(QPainter* painter) // Verify if item needs recomputing. CacheQuadItem& item = _cachedQuadItems[x][y]; - if (dirty || + if (forceRebuild || item.parent.input.toPolygon() != inputQuad.toPolygon() || item.parent.output.toPolygon() != outputQuad.toPolygon()) { + // Copy input and output quads for verification purposes. item.parent.input = inputQuad; item.parent.output = outputQuad; + + // Recompute sub quads. item.subQuads.clear(); QSizeF size = mapFromScene(outputQuad.toPolygon()).boundingRect().size(); float area = size.width() * size.height(); // Rebuild cache quad item. - _buildCacheQuadItem(item, inputQuad, outputQuad, area); + _buildCacheQuadItem(item, inputQuad, outputQuad, area, 0.0001f, 0.001f, MM::MESH_SUBDIVISION_MIN_AREA, maxDepth); } // Draw all the cached items. @@ -376,38 +392,55 @@ void MeshTextureGraphicsItem::_doDrawOutput(QPainter* painter) } } -void MeshTextureGraphicsItem::_buildCacheQuadItem(CacheQuadItem& item, const Quad& inputQuad, const Quad& outputQuad, float outputArea, float inputThreshod, float outputThreshold) +void MeshTextureGraphicsItem::_buildCacheQuadItem(CacheQuadItem& item, const Quad& inputQuad, const Quad& outputQuad, float outputArea, float inputThreshod, float outputThreshold, int minArea, int maxDepth) { - QPointF oa = mapFromScene(outputQuad.getVertex(0)); - QPointF ob = mapFromScene(outputQuad.getVertex(1)); - QPointF oc = mapFromScene(outputQuad.getVertex(2)); - QPointF od = mapFromScene(outputQuad.getVertex(3)); + bool stop = false; + if (maxDepth == 0 || outputArea < minArea) + stop = true; + else { + QPointF oa = mapFromScene(outputQuad.getVertex(0)); + QPointF ob = mapFromScene(outputQuad.getVertex(1)); + QPointF oc = mapFromScene(outputQuad.getVertex(2)); + QPointF od = mapFromScene(outputQuad.getVertex(3)); - QPointF ia = inputQuad.getVertex(0); - QPointF ib = inputQuad.getVertex(1); - QPointF ic = inputQuad.getVertex(2); - QPointF id = inputQuad.getVertex(3); + QPointF ia = inputQuad.getVertex(0); + QPointF ib = inputQuad.getVertex(1); + QPointF ic = inputQuad.getVertex(2); + QPointF id = inputQuad.getVertex(3); - // compute the dot products for the polygon - float outputV1dotV2 = QPointF::dotProduct(oa-ob, oc-ob); - float outputV3dotV4 = QPointF::dotProduct(oc-od, oa-od); - float outputV1dotV4 = QPointF::dotProduct(oa-ob, oa-od); - float outputV2dotV3 = QPointF::dotProduct(oc-ob, oc-od); + QPointF outputV1 = oa-ob; + QPointF outputV2 = oc-ob; + QPointF outputV3 = oc-od; + QPointF outputV4 = oa-od; - // compute the dot products for the texture - float inputV1dotV2 = QPointF::dotProduct(ia-ib, ic-ib); - float inputV3dotV4 = QPointF::dotProduct(ic-id, ia-id); - float inputV1dotV4 = QPointF::dotProduct(ia-ib, ia-id); - float inputV2dotV3 = QPointF::dotProduct(ic-ib, ic-id); + QPointF inputV1 = ia-ib; + QPointF inputV2 = ic-ib; + QPointF inputV3 = ic-id; + QPointF inputV4 = ia-id; - // Stopping criterion. - if (outputArea < MM::MESH_SUBDIVISION_MIN_AREA || - (fabs(outputV1dotV2 - outputV3dotV4) < outputThreshold && - fabs(outputV1dotV4 - outputV2dotV3) < outputThreshold && - fabs(inputV1dotV2 - inputV3dotV4) < inputThreshod && - fabs(inputV1dotV4 - inputV2dotV3) < inputThreshod)) + // compute the dot products for the polygon + float outputV1dotV2 = QPointF::dotProduct(outputV1, outputV2); + float outputV3dotV4 = QPointF::dotProduct(outputV3, outputV4); + float outputV1dotV4 = QPointF::dotProduct(outputV1, outputV4); + float outputV2dotV3 = QPointF::dotProduct(outputV2, outputV3); + + // compute the dot products for the texture + float inputV1dotV2 = QPointF::dotProduct(inputV1, inputV2); + float inputV3dotV4 = QPointF::dotProduct(inputV3, inputV4); + float inputV1dotV4 = QPointF::dotProduct(inputV1, inputV4); + float inputV2dotV3 = QPointF::dotProduct(inputV2, inputV3); + + // Stopping criterion. + stop = (fabs(outputV1dotV2 - outputV3dotV4) < outputThreshold && + fabs(outputV1dotV4 - outputV2dotV3) < outputThreshold && + fabs(inputV1dotV2 - inputV3dotV4) < inputThreshod && + fabs(inputV1dotV4 - inputV2dotV3) < inputThreshod); + } + + // + if (stop) { - item.subQuads.append( { inputQuad, outputQuad } ); + item.subQuads.append( (CacheQuadMapping){ inputQuad, outputQuad } ); } else // subdivide { @@ -415,7 +448,7 @@ void MeshTextureGraphicsItem::_buildCacheQuadItem(CacheQuadItem& item, const Qua QList outputSubQuads = _split(outputQuad); for (int i = 0; i < inputSubQuads.size(); i++) { - _buildCacheQuadItem(item, inputSubQuads[i], outputSubQuads[i], outputArea*0.25, inputThreshod, outputThreshold); + _buildCacheQuadItem(item, inputSubQuads[i], outputSubQuads[i], outputArea*0.25, inputThreshod, outputThreshold, minArea, (maxDepth == -1 ? -1 : maxDepth - 1)); } } } diff --git a/ShapeGraphicsItem.h b/ShapeGraphicsItem.h index 0b0ca87..fc20b20 100644 --- a/ShapeGraphicsItem.h +++ b/ShapeGraphicsItem.h @@ -225,12 +225,15 @@ public: private: // Draws quad recursively using the technique described in Oliveira, M. "Correcting Texture Mapping Errors Introduced by Graphics Hardware" - void _buildCacheQuadItem(CacheQuadItem& item, const Quad& inputQuad, const Quad& outputQuad, float outputArea, float inputThreshold = 0.0001f, float outputThreshold = 0.001f); + void _buildCacheQuadItem(CacheQuadItem& item, const Quad& inputQuad, const Quad& outputQuad, + float outputArea, float inputThreshold = 0.0001f, float outputThreshold = 0.001f, + int minArea=MM::MESH_SUBDIVISION_MIN_AREA, int maxDepth=-1); QList _split(const Quad& quad); QVector > _cachedQuadItems; int _nHorizontalQuads; int _nVerticalQuads; + bool _wasGrabbing; }; /// Graphics item for textured mesh.