diff options
Diffstat (limited to 'src/datavisualization/engine/surface3drenderer.cpp')
-rw-r--r-- | src/datavisualization/engine/surface3drenderer.cpp | 1326 |
1 files changed, 813 insertions, 513 deletions
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 38c8d8fe..37d6b463 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -30,10 +30,6 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION //#define SHOW_DEPTH_TEXTURE_SCENE -// Margin for background (1.10 make it 10% larger to avoid -// selection ball being drawn inside background) -const GLfloat backgroundMargin = 1.1f; -const GLfloat gridLineWidth = 0.005f; const GLfloat sliceZScale = 0.1f; const GLfloat sliceUnits = 2.5f; const uint greenMultiplier = 256; @@ -47,19 +43,16 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_backgroundShader(0), m_surfaceFlatShader(0), m_surfaceSmoothShader(0), + m_surfaceTexturedSmoothShader(0), + m_surfaceTexturedFlatShader(0), m_surfaceGridShader(0), m_surfaceSliceFlatShader(0), m_surfaceSliceSmoothShader(0), m_selectionShader(0), - m_labelShader(0), m_heightNormalizer(0.0f), - m_scaleFactor(0.0f), m_scaleX(0.0f), + m_scaleY(0.0f), m_scaleZ(0.0f), - m_scaleXWithBackground(0.0f), - m_scaleZWithBackground(0.0f), - m_depthTexture(0), - m_depthModelTexture(0), m_depthFrameBuffer(0), m_selectionFrameBuffer(0), m_selectionDepthBuffer(0), @@ -68,16 +61,12 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_flatSupported(true), m_selectionActive(false), m_shadowQualityMultiplier(3), - m_hasHeightAdjustmentChanged(true), m_selectedPoint(Surface3DController::invalidSelectionPosition()), m_selectedSeries(0), m_clickedPosition(Surface3DController::invalidSelectionPosition()), m_selectionTexturesDirty(false), m_noShadowTexture(0) { - m_axisCacheY.setScale(2.0f); - m_axisCacheY.setTranslate(-1.0f); - // Check if flat feature is supported ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), QStringLiteral(":/shaders/fragmentSurfaceFlat")); @@ -90,12 +79,13 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) " Requires at least GLSL version 1.2 with GL_EXT_gpu_shader4 extension."; } - initializeOpenGLFunctions(); initializeOpenGL(); } Surface3DRenderer::~Surface3DRenderer() { + fixContextBeforeDelete(); + if (QOpenGLContext::currentContext()) { m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); @@ -103,7 +93,6 @@ Surface3DRenderer::~Surface3DRenderer() m_textureHelper->deleteTexture(&m_noShadowTexture); m_textureHelper->deleteTexture(&m_depthTexture); - m_textureHelper->deleteTexture(&m_depthModelTexture); m_textureHelper->deleteTexture(&m_selectionResultTexture); } delete m_depthShader; @@ -111,10 +100,11 @@ Surface3DRenderer::~Surface3DRenderer() delete m_selectionShader; delete m_surfaceFlatShader; delete m_surfaceSmoothShader; + delete m_surfaceTexturedSmoothShader; + delete m_surfaceTexturedFlatShader; delete m_surfaceGridShader; delete m_surfaceSliceFlatShader; delete m_surfaceSliceSmoothShader; - delete m_labelShader; } void Surface3DRenderer::initializeOpenGL() @@ -123,25 +113,15 @@ void Surface3DRenderer::initializeOpenGL() // Initialize shaders initSurfaceShaders(); - initLabelShaders(QStringLiteral(":/shaders/vertexLabel"), - QStringLiteral(":/shaders/fragmentLabel")); -#if !defined(QT_OPENGL_ES_2) - // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api. - initDepthShader(); -#endif + if (!m_isOpenGLES) { + initDepthShader(); // For shadows + loadGridLineMesh(); + } // Init selection shader initSelectionShaders(); -#if !(defined QT_OPENGL_ES_2) - // Load grid line mesh - loadGridLineMesh(); -#endif - - // Load label mesh - loadLabelMesh(); - // Resize in case we've missed resize events // Resize calls initSelectionBuffer and initDepthBuffer, so they don't need to be called here handleResize(); @@ -155,6 +135,53 @@ void Surface3DRenderer::initializeOpenGL() m_noShadowTexture = m_textureHelper->create2DTexture(image, false, true, false, true); } +void Surface3DRenderer::fixCameraTarget(QVector3D &target) +{ + target.setX(target.x() * m_scaleX); + target.setY(target.y() * m_scaleY); + target.setZ(target.z() * -m_scaleZ); +} + +void Surface3DRenderer::getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds) +{ + // The inputs are the item bounds in OpenGL coordinates. + // The outputs limit these bounds to visible ranges, normalized to range [-1, 1] + // Volume shader flips the Y and Z axes, so we need to set negatives of actual values to those + float itemRangeX = (maxBounds.x() - minBounds.x()); + float itemRangeY = (maxBounds.y() - minBounds.y()); + float itemRangeZ = (maxBounds.z() - minBounds.z()); + + if (minBounds.x() < -m_scaleX) + minBounds.setX(-1.0f + (2.0f * qAbs(minBounds.x() + m_scaleX) / itemRangeX)); + else + minBounds.setX(-1.0f); + + if (minBounds.y() < -m_scaleY) + minBounds.setY(-(-1.0f + (2.0f * qAbs(minBounds.y() + m_scaleY) / itemRangeY))); + else + minBounds.setY(1.0f); + + if (minBounds.z() < -m_scaleZ) + minBounds.setZ(-(-1.0f + (2.0f * qAbs(minBounds.z() + m_scaleZ) / itemRangeZ))); + else + minBounds.setZ(1.0f); + + if (maxBounds.x() > m_scaleX) + maxBounds.setX(1.0f - (2.0f * qAbs(maxBounds.x() - m_scaleX) / itemRangeX)); + else + maxBounds.setX(1.0f); + + if (maxBounds.y() > m_scaleY) + maxBounds.setY(-(1.0f - (2.0f * qAbs(maxBounds.y() - m_scaleY) / itemRangeY))); + else + maxBounds.setY(-1.0f); + + if (maxBounds.z() > m_scaleZ) + maxBounds.setZ(-(1.0f - (2.0f * qAbs(maxBounds.z() - m_scaleZ) / itemRangeZ))); + else + maxBounds.setZ(-1.0f); +} + void Surface3DRenderer::updateData() { calculateSceneScalingFactors(); @@ -264,6 +291,33 @@ void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesLis } } +void Surface3DRenderer::updateSurfaceTextures(QVector<QSurface3DSeries *> seriesList) +{ + foreach (QSurface3DSeries *series, seriesList) { + SurfaceSeriesRenderCache *cache = + static_cast<SurfaceSeriesRenderCache *>(m_renderCacheList.value(series)); + if (cache) { + GLuint oldTexture = cache->surfaceTexture(); + m_textureHelper->deleteTexture(&oldTexture); + cache->setSurfaceTexture(0); + + const QSurface3DSeries *currentSeries = cache->series(); + QSurfaceDataProxy *dataProxy = currentSeries->dataProxy(); + const QSurfaceDataArray &array = *dataProxy->array(); + + if (!series->texture().isNull()) { + cache->setSurfaceTexture(m_textureHelper->create2DTexture( + series->texture(), true, true, true)); + + if (cache->isFlatShadingEnabled()) + cache->surfaceObject()->coarseUVs(array, cache->dataArray()); + else + cache->surfaceObject()->smoothUVs(array, cache->dataArray()); + } + } + } +} + SeriesRenderCache *Surface3DRenderer::createNewCache(QAbstract3DSeries *series) { m_selectionTexturesDirty = true; @@ -301,10 +355,13 @@ void Surface3DRenderer::updateRows(const QVector<Surface3DController::ChangeRow> srcArray->at(row)->at(j + sampleSpace.x()); } - if (cache->isFlatShadingEnabled()) - cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y()); - else - cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y()); + if (cache->isFlatShadingEnabled()) { + cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y(), + m_polarGraph); + } else { + cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y(), + m_polarGraph); + } } if (updateBuffers) cache->surfaceObject()->uploadBuffers(); @@ -343,9 +400,9 @@ void Surface3DRenderer::updateItems(const QVector<Surface3DController::ChangeIte (*(dstArray.at(y)))[x] = srcArray->at(point.x())->at(point.y()); if (cache->isFlatShadingEnabled()) - cache->surfaceObject()->updateCoarseItem(dstArray, y, x); + cache->surfaceObject()->updateCoarseItem(dstArray, y, x, m_polarGraph); else - cache->surfaceObject()->updateSmoothItem(dstArray, y, x); + cache->surfaceObject()->updateSmoothItem(dstArray, y, x, m_polarGraph); } if (updateBuffers) cache->surfaceObject()->uploadBuffers(); @@ -538,10 +595,12 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const QRect sliceRect(0, 0, sliceRow->size(), 2); if (sliceRow->size() > 0) { - if (cache->isFlatShadingEnabled()) - cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect, true, flipZX); - else - cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect, true, flipZX); + if (cache->isFlatShadingEnabled()) { + cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect, true, false, flipZX); + } else { + cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect, true, false, + flipZX); + } } } @@ -664,15 +723,6 @@ QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array) void Surface3DRenderer::updateScene(Q3DScene *scene) { - // Set initial camera position - // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later - if (m_hasHeightAdjustmentChanged) { - scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector, - upVector); - // For now this is used just to make things once. Proper use will come - m_hasHeightAdjustmentChanged = false; - } - Abstract3DRenderer::updateScene(scene); if (m_selectionActive @@ -716,6 +766,14 @@ void Surface3DRenderer::render(GLuint defaultFboHandle) void Surface3DRenderer::drawSlicedScene() { + if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow) + == m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn)) { + qWarning("Invalid selection mode. Either QAbstract3DGraph::SelectionRow or" + " QAbstract3DGraph::SelectionColumn must be set before calling" + " setSlicingActive(true)."); + return; + } + QVector3D lightPos; QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor()); @@ -751,6 +809,19 @@ void Surface3DRenderer::drawSlicedScene() AxisRenderCache &sliceCache = rowMode ? m_axisCacheX : m_axisCacheZ; GLfloat scaleXBackground = 0.0f; + if (rowMode) { + // Don't use the regular margin for polar, as the graph is not going to be to scale anyway, + // and polar graphs often have quite a bit of margin, resulting in ugly slices. + if (m_polarGraph) + scaleXBackground = m_scaleX + 0.1f; + else + scaleXBackground = m_scaleXWithBackground; + } else { + if (m_polarGraph) + scaleXBackground = m_scaleZ + 0.1f; + else + scaleXBackground = m_scaleZWithBackground; + } // Disable culling to avoid ugly conditionals with reversed axes and data glDisable(GL_CULL_FACE); @@ -767,11 +838,6 @@ void Surface3DRenderer::drawSlicedScene() drawGrid = true; } - if (rowMode) - scaleXBackground = m_scaleXWithBackground; - else - scaleXBackground = m_scaleZWithBackground; - QMatrix4x4 MVPMatrix; QMatrix4x4 modelMatrix; QMatrix4x4 itModelMatrix; @@ -790,9 +856,27 @@ void Surface3DRenderer::drawSlicedScene() surfaceShader->bind(); - GLuint colorTexture = cache->baseUniformTexture();; - if (cache->colorStyle() != Q3DTheme::ColorStyleUniform) + GLuint colorTexture = cache->baseUniformTexture(); + if (cache->colorStyle() == Q3DTheme::ColorStyleUniform) { + colorTexture = cache->baseUniformTexture(); + surfaceShader->setUniformValue(surfaceShader->gradientMin(), 0.0f); + surfaceShader->setUniformValue(surfaceShader->gradientHeight(), 0.0f); + } else { colorTexture = cache->baseGradientTexture(); + if (cache->colorStyle() == Q3DTheme::ColorStyleObjectGradient) { + float objMin = cache->surfaceObject()->minYValue(); + float objMax = cache->surfaceObject()->maxYValue(); + float objRange = objMax - objMin; + surfaceShader->setUniformValue(surfaceShader->gradientMin(), + -(objMin / objRange)); + surfaceShader->setUniformValue(surfaceShader->gradientHeight(), + 1.0f / objRange); + } else { + surfaceShader->setUniformValue(surfaceShader->gradientMin(), 0.5f); + surfaceShader->setUniformValue(surfaceShader->gradientHeight(), + 1.0f / (m_scaleY * 2.0f)); + } + } // Set shader bindings surfaceShader->setUniformValue(surfaceShader->lightP(), lightPos); @@ -801,9 +885,10 @@ void Surface3DRenderer::drawSlicedScene() surfaceShader->setUniformValue(surfaceShader->nModel(), itModelMatrix.inverted().transposed()); surfaceShader->setUniformValue(surfaceShader->MVP(), MVPMatrix); - surfaceShader->setUniformValue(surfaceShader->lightS(), 0.15f); + surfaceShader->setUniformValue(surfaceShader->lightS(), 0.0f); surfaceShader->setUniformValue(surfaceShader->ambientS(), - m_cachedTheme->ambientLightStrength() * 2.3f); + m_cachedTheme->ambientLightStrength() + + m_cachedTheme->lightStrength() / 10.0f); surfaceShader->setUniformValue(surfaceShader->lightColor(), lightColor); m_drawer->drawObject(surfaceShader, cache->sliceSurfaceObject(), colorTexture); @@ -830,19 +915,16 @@ void Surface3DRenderer::drawSlicedScene() } } - // Disable textures - glDisable(GL_TEXTURE_2D); - glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Grid lines - if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { -#if !(defined QT_OPENGL_ES_2) - ShaderHelper *lineShader = m_backgroundShader; -#else - ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES -#endif + if (m_cachedTheme->isGridEnabled()) { + ShaderHelper *lineShader; + if (m_isOpenGLES) + lineShader = m_selectionShader; // Plain color shader for GL_LINES + else + lineShader = m_backgroundShader; // Bind line shader lineShader->bind(); @@ -853,7 +935,8 @@ void Surface3DRenderer::drawSlicedScene() lineShader->setUniformValue(lineShader->view(), viewMatrix); lineShader->setUniformValue(lineShader->color(), lineColor); lineShader->setUniformValue(lineShader->ambientS(), - m_cachedTheme->ambientLightStrength() * 2.3f); + m_cachedTheme->ambientLightStrength() + + m_cachedTheme->lightStrength() / 10.0f); lineShader->setUniformValue(lineShader->lightS(), 0.0f); lineShader->setUniformValue(lineShader->lightColor(), lightColor); @@ -881,16 +964,15 @@ void Surface3DRenderer::drawSlicedScene() lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); // Draw the object -#if !(defined QT_OPENGL_ES_2) - m_drawer->drawObject(lineShader, m_gridLineObj); -#else - m_drawer->drawLine(lineShader); -#endif + if (m_isOpenGLES) + m_drawer->drawLine(lineShader); + else + m_drawer->drawObject(lineShader, m_gridLineObj); } } // Vertical lines - QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth); + QVector3D gridLineScaleY(gridLineWidth, m_scaleYWithBackground, gridLineWidth); gridLineCount = sliceCache.gridLineCount(); for (int line = 0; line < gridLineCount; line++) { @@ -901,10 +983,11 @@ void Surface3DRenderer::drawSlicedScene() modelMatrix.translate(sliceCache.gridLinePosition(line), 0.0f, -1.0f); modelMatrix.scale(gridLineScaleY); itModelMatrix.scale(gridLineScaleY); -#if (defined QT_OPENGL_ES_2) - modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); - itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); -#endif + + if (m_isOpenGLES) { + modelMatrix.rotate(m_zRightAngleRotation); + itModelMatrix.rotate(m_zRightAngleRotation); + } MVPMatrix = projectionViewMatrix * modelMatrix; @@ -915,17 +998,15 @@ void Surface3DRenderer::drawSlicedScene() lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); // Draw the object -#if !(defined QT_OPENGL_ES_2) - m_drawer->drawObject(lineShader, m_gridLineObj); -#else - m_drawer->drawLine(lineShader); -#endif + if (m_isOpenGLES) + m_drawer->drawLine(lineShader); + else + m_drawer->drawObject(lineShader, m_gridLineObj); } } // Draw labels m_labelShader->bind(); - glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -959,12 +1040,15 @@ void Surface3DRenderer::drawSlicedScene() labelNbr = 0; positionComp.setY(-0.1f); - labelTrans.setY(-backgroundMargin); + labelTrans.setY(-m_scaleYWithBackground); labelCount = sliceCache.labelCount(); for (int label = 0; label < labelCount; label++) { if (countLabelItems > labelNbr) { // Draw the label here - labelTrans.setX(sliceCache.labelPosition(label)); + if (rowMode) + labelTrans.setX(sliceCache.labelPosition(label)); + else + labelTrans.setX(-sliceCache.labelPosition(label)); m_dummyRenderItem.setTranslation(labelTrans); @@ -998,7 +1082,6 @@ void Surface3DRenderer::drawSlicedScene() m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera, false, false, Drawer::LabelMid, Qt::AlignBottom); - glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); @@ -1048,6 +1131,21 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) else m_xFlipped = true; + m_yFlippedForGrid = m_yFlipped; + if (m_flipHorizontalGrid) { + if (!m_useOrthoProjection) { + // Need to determine if camera is below graph top + float distanceToCenter = activeCamera->position().length() + / activeCamera->zoomLevel() / m_autoScaleAdjustment * 100.0f; + qreal cameraAngle = qreal(activeCamera->yRotation()) / 180.0 * M_PI; + float cameraYPos = float(qSin(cameraAngle)) * distanceToCenter; + m_yFlippedForGrid = cameraYPos < (m_scaleYWithBackground - m_oldCameraTarget.y()); + } else if (m_useOrthoProjection && activeCamera->yRotation() == 0.0f) { + // With ortho we only need to flip at angle zero, to fix label autorotation angles + m_yFlippedForGrid = !m_yFlipped; + } + } + // calculate background rotation based on view matrix rotation if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() <= 0) backgroundRotation = 270.0f; @@ -1065,9 +1163,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 depthProjectionViewMatrix; // Draw depth buffer -#if !defined(QT_OPENGL_ES_2) GLfloat adjustedLightStrength = m_cachedTheme->lightStrength() / 10.0f; - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && + if (!m_isOpenGLES && m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && (!m_renderCacheList.isEmpty() || !m_customRenderCache.isEmpty())) { // Render scene into a depth texture for using with shadow mapping // Enable drawing to depth framebuffer @@ -1097,6 +1194,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) / (GLfloat)m_primarySubViewport.height(), 3.0f, 100.0f); depthProjectionViewMatrix = depthProjectionMatrix * depthViewMatrix; + // Surface is not closed, so don't cull anything glDisable(GL_CULL_FACE); foreach (SeriesRenderCache *baseCache, m_renderCacheList) { @@ -1104,45 +1202,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) SurfaceObject *object = cache->surfaceObject(); if (object->indexCount() && cache->surfaceVisible() && cache->isVisible() && cache->sampleSpace().width() >= 2 && cache->sampleSpace().height() >= 2) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - - MVPMatrix = depthProjectionViewMatrix * modelMatrix; - cache->setMVPMatrix(MVPMatrix); - m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); - - // 1st attribute buffer : vertices - glEnableVertexAttribArray(m_depthShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf()); - glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, - (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, object->indexCount(), - object->indicesType(), (void *)0); - } - } - - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - - Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, - projectionViewMatrix, depthProjectionViewMatrix, - m_depthTexture, m_shadowQualityToShader); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - m_depthModelTexture, 0); - glClear(GL_DEPTH_BUFFER_BIT); - - foreach (SeriesRenderCache *baseCache, m_renderCacheList) { - SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache); - SurfaceObject *object = cache->surfaceObject(); - if (object->indexCount() && cache->surfaceVisible() && cache->isVisible() - && cache->sampleSpace().width() >= 2 && cache->sampleSpace().height() >= 2) { - m_depthShader->setUniformValue(m_depthShader->MVP(), cache->MVPMatrix()); + // No translation nor scaling for surfaces, therefore no modelMatrix + // Use directly projectionViewMatrix + m_depthShader->setUniformValue(m_depthShader->MVP(), depthProjectionViewMatrix); // 1st attribute buffer : vertices glEnableVertexAttribArray(m_depthShader->posAtt()); @@ -1165,9 +1227,13 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) glDisableVertexAttribArray(m_depthShader->posAtt()); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, - projectionViewMatrix, depthProjectionViewMatrix, - m_depthTexture, m_shadowQualityToShader); + projectionViewMatrix, + depthProjectionViewMatrix, m_depthTexture, + m_shadowQualityToShader); // Disable drawing to depth framebuffer (= enable drawing to screen) glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); @@ -1182,15 +1248,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } -#endif - // Enable texturing - glEnable(GL_TEXTURE_2D); + + // Do position mapping when necessary + if (m_graphPositionQueryPending) { + QVector3D graphDimensions(m_scaleX, m_scaleY, m_scaleZ); + queriedGraphPosition(projectionViewMatrix, graphDimensions, defaultFboHandle); + emit needRender(); + } // Draw selection buffer if (!m_cachedIsSlicingActivated && (!m_renderCacheList.isEmpty() || !m_customRenderCache.isEmpty()) && m_selectionState == SelectOnScene - && m_cachedSelectionMode > QAbstract3DGraph::SelectionNone) { + && m_cachedSelectionMode > QAbstract3DGraph::SelectionNone + && m_selectionResultTexture) { m_selectionShader->bind(); glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); glViewport(0, @@ -1208,18 +1279,17 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) foreach (SeriesRenderCache *baseCache, m_renderCacheList) { SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache); if (cache->surfaceObject()->indexCount() && cache->renderable()) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; + m_selectionShader->setUniformValue(m_selectionShader->MVP(), projectionViewMatrix); - MVPMatrix = projectionViewMatrix * modelMatrix; - m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); + cache->surfaceObject()->activateSurfaceTexture(false); m_drawer->drawObject(m_selectionShader, cache->surfaceObject(), cache->selectionTexture()); } } m_surfaceGridShader->bind(); - Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader, viewMatrix, + Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader, + viewMatrix, projectionViewMatrix, depthProjectionViewMatrix, m_depthTexture, m_shadowQualityToShader); drawLabels(true, activeCamera, viewMatrix, projectionMatrix); @@ -1237,6 +1307,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) + uint(clickedColor.w()) * alphaMultiplier; m_clickedPosition = selectionIdToSurfacePoint(selectionId); + m_clickResolved = true; emit needRender(); @@ -1249,7 +1320,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) // Draw the surface if (!m_renderCacheList.isEmpty()) { - // For surface we can see climpses from underneath + // For surface we can see glimpses from underneath glDisable(GL_CULL_FACE); bool drawGrid = false; @@ -1261,9 +1332,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 itModelMatrix; #ifdef SHOW_DEPTH_TEXTURE_SCENE - MVPMatrix = depthProjectionViewMatrix * modelMatrix; + MVPMatrix = depthProjectionViewMatrix; #else - MVPMatrix = projectionViewMatrix * modelMatrix; + MVPMatrix = projectionViewMatrix; #endif cache->setMVPMatrix(MVPMatrix); @@ -1279,8 +1350,13 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) if (cache->surfaceVisible()) { ShaderHelper *shader = m_surfaceFlatShader; - if (!cache->isFlatShadingEnabled()) + if (cache->surfaceTexture()) + shader = m_surfaceTexturedFlatShader; + if (!cache->isFlatShadingEnabled()) { shader = m_surfaceSmoothShader; + if (cache->surfaceTexture()) + shader = m_surfaceTexturedSmoothShader; + } shader->bind(); // Set shader bindings @@ -1294,14 +1370,35 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) m_cachedTheme->ambientLightStrength()); shader->setUniformValue(shader->lightColor(), lightColor); - GLuint gradientTexture; - if (cache->colorStyle() == Q3DTheme::ColorStyleUniform) - gradientTexture = cache->baseUniformTexture(); - else - gradientTexture = cache->baseGradientTexture(); + // Set the surface texturing + cache->surfaceObject()->activateSurfaceTexture(false); + GLuint texture; + if (cache->surfaceTexture()) { + texture = cache->surfaceTexture(); + cache->surfaceObject()->activateSurfaceTexture(true); + } else { + if (cache->colorStyle() == Q3DTheme::ColorStyleUniform) { + texture = cache->baseUniformTexture(); + shader->setUniformValue(shader->gradientMin(), 0.0f); + shader->setUniformValue(shader->gradientHeight(), 0.0f); + } else { + texture = cache->baseGradientTexture(); + if (cache->colorStyle() == Q3DTheme::ColorStyleObjectGradient) { + float objMin = cache->surfaceObject()->minYValue(); + float objMax = cache->surfaceObject()->maxYValue(); + float objRange = objMax - objMin; + shader->setUniformValue(shader->gradientMin(), -(objMin / objRange)); + shader->setUniformValue(shader->gradientHeight(), 1.0f / objRange); + } else { + shader->setUniformValue(shader->gradientMin(), 0.5f); + shader->setUniformValue(shader->gradientHeight(), + 1.0f / (m_scaleY * 2.0f)); + } + } + } -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + if (!m_isOpenGLES && + m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { // Set shadow shader bindings QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; shader->setUniformValue(shader->shadowQ(), m_shadowQualityToShader); @@ -1309,17 +1406,13 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) shader->setUniformValue(shader->lightS(), adjustedLightStrength); // Draw the objects - m_drawer->drawObject(shader, cache->surfaceObject(), gradientTexture, - m_depthModelTexture); - } else -#endif - { + m_drawer->drawObject(shader, cache->surfaceObject(), texture, + m_depthTexture); + } else { // Set shadowless shader bindings - shader->setUniformValue(shader->lightS(), - m_cachedTheme->lightStrength()); - + shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength()); // Draw the objects - m_drawer->drawObject(shader, cache->surfaceObject(), gradientTexture); + m_drawer->drawObject(shader, cache->surfaceObject(), texture); } } } @@ -1359,12 +1452,12 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - QVector3D bgScale(m_scaleXWithBackground, backgroundMargin, m_scaleZWithBackground); + QVector3D bgScale(m_scaleXWithBackground, m_scaleYWithBackground, m_scaleZWithBackground); modelMatrix.scale(bgScale); // If we're viewing from below, background object must be flipped if (m_yFlipped) { - modelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f); + modelMatrix.rotate(m_xFlipRotation); modelMatrix.rotate(270.0f - backgroundRotation, 0.0f, 1.0f, 0.0f); } else { modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); @@ -1392,8 +1485,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) m_cachedTheme->ambientLightStrength() * 2.0f); m_backgroundShader->setUniformValue(m_backgroundShader->lightColor(), lightColor); -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && !m_isOpenGLES) { // Set shadow shader bindings QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(), @@ -1406,11 +1498,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_noShadowTexture); else m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture); - } else -#else - Q_UNUSED(noShadows); -#endif - { + } else { // Set shadowless shader bindings m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), m_cachedTheme->lightStrength()); @@ -1423,14 +1511,14 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) // Draw grid lines QVector3D gridLineScaleX(m_scaleXWithBackground, gridLineWidth, gridLineWidth); QVector3D gridLineScaleZ(gridLineWidth, gridLineWidth, m_scaleZWithBackground); - QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth); + QVector3D gridLineScaleY(gridLineWidth, m_scaleYWithBackground, gridLineWidth); - if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { -#if !(defined QT_OPENGL_ES_2) - ShaderHelper *lineShader = m_backgroundShader; -#else - ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES -#endif + if (m_cachedTheme->isGridEnabled()) { + ShaderHelper *lineShader; + if (m_isOpenGLES) + lineShader = m_surfaceGridShader; // Plain color shader for GL_LINES + else + lineShader = m_backgroundShader; // Bind line shader lineShader->bind(); @@ -1442,15 +1530,12 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->color(), lineColor); lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme->ambientLightStrength()); lineShader->setUniformValue(lineShader->lightColor(), lightColor); -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && !m_isOpenGLES) { // Set shadowed shader bindings lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme->lightStrength() / 20.0f); - } else -#endif - { + } else { // Set shadowless shader bindings lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme->lightStrength() / 2.5f); @@ -1460,205 +1545,211 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QQuaternion lineXRotation; if (m_xFlipped) - lineYRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, -90.0f); + lineYRotation = m_yRightAngleRotationNeg; else - lineYRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f); + lineYRotation = m_yRightAngleRotation; - if (m_yFlipped) - lineXRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 90.0f); + if (m_yFlippedForGrid) + lineXRotation = m_xRightAngleRotation; else - lineXRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f); + lineXRotation = m_xRightAngleRotationNeg; - GLfloat yFloorLinePosition = -backgroundMargin + gridLineOffset; - if (m_yFlipped) + float yFloorLinePosition = -m_scaleYWithBackground + gridLineOffset; + if (m_yFlipped != m_flipHorizontalGrid) yFloorLinePosition = -yFloorLinePosition; // Rows (= Z) if (m_axisCacheZ.segmentCount() > 0) { - // Floor lines int gridLineCount = m_axisCacheZ.gridLineCount(); - - for (int line = 0; line < gridLineCount; line++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(0.0f, yFloorLinePosition, - m_axisCacheZ.gridLinePosition(line)); - - modelMatrix.scale(gridLineScaleX); - itModelMatrix.scale(gridLineScaleX); - - modelMatrix.rotate(lineXRotation); - itModelMatrix.rotate(lineXRotation); - - MVPMatrix = projectionViewMatrix * modelMatrix; - - // Set the rest of the shader bindings - lineShader->setUniformValue(lineShader->model(), modelMatrix); - lineShader->setUniformValue(lineShader->nModel(), - itModelMatrix.inverted().transposed()); - lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + // Floor lines + if (m_polarGraph) { + drawRadialGrid(lineShader, yFloorLinePosition, projectionViewMatrix, + depthProjectionViewMatrix); + } else { + for (int line = 0; line < gridLineCount; line++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, yFloorLinePosition, + m_axisCacheZ.gridLinePosition(line)); + + modelMatrix.scale(gridLineScaleX); + itModelMatrix.scale(gridLineScaleX); + + modelMatrix.rotate(lineXRotation); + itModelMatrix.rotate(lineXRotation); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } else { + m_drawer->drawLine(lineShader); + } } -#else - m_drawer->drawLine(lineShader); -#endif - } + // Side wall lines + GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset; - // Side wall lines - GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset; + if (!m_xFlipped) + lineXTrans = -lineXTrans; - if (!m_xFlipped) - lineXTrans = -lineXTrans; + for (int line = 0; line < gridLineCount; line++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; - for (int line = 0; line < gridLineCount; line++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line)); + modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line)); - modelMatrix.scale(gridLineScaleY); - itModelMatrix.scale(gridLineScaleY); + modelMatrix.scale(gridLineScaleY); + itModelMatrix.scale(gridLineScaleY); -#if !defined(QT_OPENGL_ES_2) - modelMatrix.rotate(lineYRotation); - itModelMatrix.rotate(lineYRotation); -#else - modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); - itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); -#endif - - MVPMatrix = projectionViewMatrix * modelMatrix; - - // Set the rest of the shader bindings - lineShader->setUniformValue(lineShader->model(), modelMatrix); - lineShader->setUniformValue(lineShader->nModel(), - itModelMatrix.inverted().transposed()); - lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + if (m_isOpenGLES) { + modelMatrix.rotate(m_zRightAngleRotation); + itModelMatrix.rotate(m_zRightAngleRotation); + } else { + modelMatrix.rotate(lineYRotation); + itModelMatrix.rotate(lineYRotation); + } -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } else { + m_drawer->drawLine(lineShader); + } } -#else - m_drawer->drawLine(lineShader); -#endif } } // Columns (= X) if (m_axisCacheX.segmentCount() > 0) { -#if defined(QT_OPENGL_ES_2) - lineXRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f); -#endif + if (m_isOpenGLES) + lineXRotation = m_yRightAngleRotation; + // Floor lines int gridLineCount = m_axisCacheX.gridLineCount(); - for (int line = 0; line < gridLineCount; line++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition, - 0.0f); - - modelMatrix.scale(gridLineScaleZ); - itModelMatrix.scale(gridLineScaleZ); - - modelMatrix.rotate(lineXRotation); - itModelMatrix.rotate(lineXRotation); - - MVPMatrix = projectionViewMatrix * modelMatrix; - - // Set the rest of the shader bindings - lineShader->setUniformValue(lineShader->model(), modelMatrix); - lineShader->setUniformValue(lineShader->nModel(), - itModelMatrix.inverted().transposed()); - lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + if (m_polarGraph) { + drawAngularGrid(lineShader, yFloorLinePosition, projectionViewMatrix, + depthProjectionViewMatrix); + } else { + for (int line = 0; line < gridLineCount; line++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition, + 0.0f); + + modelMatrix.scale(gridLineScaleZ); + itModelMatrix.scale(gridLineScaleZ); + + modelMatrix.rotate(lineXRotation); + itModelMatrix.rotate(lineXRotation); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } else { + m_drawer->drawLine(lineShader); + } } -#else - m_drawer->drawLine(lineShader); -#endif - } - // Back wall lines - GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset; + // Back wall lines + GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset; - if (!m_zFlipped) - lineZTrans = -lineZTrans; - - for (int line = 0; line < gridLineCount; line++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans); + if (!m_zFlipped) + lineZTrans = -lineZTrans; - modelMatrix.scale(gridLineScaleY); - itModelMatrix.scale(gridLineScaleY); + for (int line = 0; line < gridLineCount; line++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; -#if !defined(QT_OPENGL_ES_2) - if (m_zFlipped) { - modelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f); - itModelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f); - } -#else - modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); - itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f); -#endif + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans); - MVPMatrix = projectionViewMatrix * modelMatrix; + modelMatrix.scale(gridLineScaleY); + itModelMatrix.scale(gridLineScaleY); - // Set the rest of the shader bindings - lineShader->setUniformValue(lineShader->model(), modelMatrix); - lineShader->setUniformValue(lineShader->nModel(), - itModelMatrix.inverted().transposed()); - lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + if (m_isOpenGLES) { + modelMatrix.rotate(m_zRightAngleRotation); + itModelMatrix.rotate(m_zRightAngleRotation); + } else if (m_zFlipped) { + modelMatrix.rotate(m_xFlipRotation); + itModelMatrix.rotate(m_xFlipRotation); + } -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } else { + m_drawer->drawLine(lineShader); + } } -#else - m_drawer->drawLine(lineShader); -#endif } } @@ -1683,8 +1774,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) itModelMatrix.scale(gridLineScaleX); if (m_zFlipped) { - modelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f); - itModelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f); + modelMatrix.rotate(m_xFlipRotation); + itModelMatrix.rotate(m_xFlipRotation); } MVPMatrix = projectionViewMatrix * modelMatrix; @@ -1695,20 +1786,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) itModelMatrix.inverted().transposed()); lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + m_drawer->drawLine(lineShader); } -#else - m_drawer->drawLine(lineShader); -#endif } // Side wall @@ -1738,20 +1829,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) itModelMatrix.inverted().transposed()); lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + if (!m_isOpenGLES) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else { + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } } else { - // Draw the object - m_drawer->drawObject(lineShader, m_gridLineObj); + m_drawer->drawLine(lineShader); } -#else - m_drawer->drawLine(lineShader); -#endif } } } @@ -1811,7 +1902,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa } else { shader = m_labelShader; shader->bind(); - glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } @@ -1832,8 +1923,14 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa QVector3D positionZComp(0.0f, 0.0f, 0.0f); if (m_axisCacheZ.segmentCount() > 0) { int labelCount = m_axisCacheZ.labelCount(); - GLfloat labelXTrans = m_scaleXWithBackground + labelMargin; - GLfloat labelYTrans = -backgroundMargin; + float labelXTrans = m_scaleXWithBackground + labelMargin; + float labelYTrans = m_flipHorizontalGrid ? m_scaleYWithBackground : -m_scaleYWithBackground; + if (m_polarGraph) { + labelXTrans *= m_radialLabelOffset; + // YTrans up only if over background + if (m_radialLabelOffset < 1.0f) + labelYTrans += gridLineOffset + gridLineWidth; + } Qt::AlignmentFlag alignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; QVector3D labelRotation; if (m_xFlipped) @@ -1843,7 +1940,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa if (labelAutoAngle == 0.0f) { if (m_zFlipped) labelRotation.setY(180.0f); - if (m_yFlipped) { + if (m_yFlippedForGrid) { if (m_zFlipped) labelRotation.setY(180.0f); else @@ -1855,7 +1952,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa } else { if (m_zFlipped) labelRotation.setY(180.0f); - if (m_yFlipped) { + if (m_yFlippedForGrid) { if (m_zFlipped) { if (m_xFlipped) { labelRotation.setX(90.0f - (labelAutoAngle - fractionCamX) @@ -1920,10 +2017,34 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa float offsetValue = 0.0f; for (int label = startIndex; label != endIndex; label = label + indexStep) { glPolygonOffset(offsetValue++ / -10.0f, 1.0f); + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(label); // Draw the label here - labelTrans.setZ(m_axisCacheZ.labelPosition(label)); + if (m_polarGraph) { + float direction = m_zFlipped ? -1.0f : 1.0f; + labelTrans.setZ((m_axisCacheZ.formatter()->labelPositions().at(label) + * -m_polarRadius + + m_drawer->scaledFontSize() + gridLineWidth) * direction); + } else { + labelTrans.setZ(m_axisCacheZ.labelPosition(label)); + } + if (label == 0 || label == (labelCount - 1)) { + // If the margin is small, adjust the position of the edge labels to avoid overlapping + // with labels of the other axes. + float scaleFactor = m_drawer->scaledFontSize() / axisLabelItem.size().height(); + float labelOverlap = qAbs(labelTrans.z()) + + (scaleFactor * axisLabelItem.size().height() / 2.0f) + - m_scaleZWithBackground + labelMargin; + // No need to adjust quite as much on the front edges + if (label != startIndex) + labelOverlap /= 2.0f; + if (labelOverlap > 0.0f) { + if (label == 0) + labelTrans.setZ(labelTrans.z() - labelOverlap); + else + labelTrans.setZ(labelTrans.z() + labelOverlap); + } + } m_dummyRenderItem.setTranslation(labelTrans); - const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(label); if (drawSelection) { QVector4D labelColor = QVector4D(label / 255.0f, 0.0f, 0.0f, @@ -1938,7 +2059,14 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width())); } if (!drawSelection && m_axisCacheZ.isTitleVisible()) { - labelTrans.setZ(0.0f); + if (m_polarGraph) { + float titleZ = -m_polarRadius / 2.0f; + if (m_zFlipped) + titleZ = -titleZ; + labelTrans.setZ(titleZ); + } else { + labelTrans.setZ(0.0f); + } drawAxisTitleZ(labelRotation, labelTrans, totalRotation, m_dummyRenderItem, activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader); } @@ -1952,8 +2080,13 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa fractionCamX = activeCamera->xRotation() * labelAngleFraction; int labelCount = m_axisCacheX.labelCount(); - GLfloat labelZTrans = m_scaleZWithBackground + labelMargin; - GLfloat labelYTrans = -backgroundMargin; + float labelZTrans = 0.0f; + float labelYTrans = m_flipHorizontalGrid ? m_scaleYWithBackground : -m_scaleYWithBackground; + if (m_polarGraph) + labelYTrans += gridLineOffset + gridLineWidth; + else + labelZTrans = m_scaleZWithBackground + labelMargin; + Qt::AlignmentFlag alignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; QVector3D labelRotation; if (m_zFlipped) @@ -1964,7 +2097,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa labelRotation = QVector3D(-90.0f, 90.0f, 0.0f); if (m_xFlipped) labelRotation.setY(-90.0f); - if (m_yFlipped) { + if (m_yFlippedForGrid) { if (m_xFlipped) labelRotation.setY(-90.0f); else @@ -1976,7 +2109,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa labelRotation.setY(-90.0f); else labelRotation.setY(90.0f); - if (m_yFlipped) { + if (m_yFlippedForGrid) { if (m_zFlipped) { if (m_xFlipped) { labelRotation.setX(90.0f - (2.0f * labelAutoAngle - fractionCamX) @@ -2022,7 +2155,16 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa } } } + QQuaternion totalRotation = Utils::calculateRotation(labelRotation); + if (m_polarGraph) { + if ((!m_yFlippedForGrid && (m_zFlipped != m_xFlipped)) + || (m_yFlippedForGrid && (m_zFlipped == m_xFlipped))) { + totalRotation *= m_zRightAngleRotation; + } else { + totalRotation *= m_zRightAngleRotationNeg; + } + } QVector3D labelTrans = QVector3D(0.0f, labelYTrans, @@ -2038,12 +2180,64 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa indexStep = 1; } float offsetValue = 0.0f; + bool showLastLabel = false; + QVector<float> &labelPositions = m_axisCacheX.formatter()->labelPositions(); + int lastLabelPosIndex = labelPositions.size() - 1; + if (labelPositions.size() + && (labelPositions.at(lastLabelPosIndex) != 1.0f || labelPositions.at(0) != 0.0f)) { + // Avoid overlapping first and last label if they would get on same position + showLastLabel = true; + } + for (int label = startIndex; label != endIndex; label = label + indexStep) { glPolygonOffset(offsetValue++ / -10.0f, 1.0f); // Draw the label here - labelTrans.setX(m_axisCacheX.labelPosition(label)); - m_dummyRenderItem.setTranslation(labelTrans); + if (m_polarGraph) { + // Calculate angular position + if (label == lastLabelPosIndex && !showLastLabel) + continue; + float labelPosition = labelPositions.at(label); + qreal angle = labelPosition * M_PI * 2.0; + labelTrans.setX((m_polarRadius + labelMargin) * float(qSin(angle))); + labelTrans.setZ(-(m_polarRadius + labelMargin) * float(qCos(angle))); + // Alignment depends on label angular position, as well as flips + Qt::AlignmentFlag vAlignment = Qt::AlignCenter; + Qt::AlignmentFlag hAlignment = Qt::AlignCenter; + const float centerMargin = 0.005f; + if (labelPosition < 0.25f - centerMargin || labelPosition > 0.75f + centerMargin) + vAlignment = m_zFlipped ? Qt::AlignTop : Qt::AlignBottom; + else if (labelPosition > 0.25f + centerMargin && labelPosition < 0.75f - centerMargin) + vAlignment = m_zFlipped ? Qt::AlignBottom : Qt::AlignTop; + + if (labelPosition < 0.50f - centerMargin && labelPosition > centerMargin) + hAlignment = m_zFlipped ? Qt::AlignRight : Qt::AlignLeft; + else if (labelPosition < 1.0f - centerMargin && labelPosition > 0.5f + centerMargin) + hAlignment = m_zFlipped ? Qt::AlignLeft : Qt::AlignRight; + if (m_yFlippedForGrid && vAlignment != Qt::AlignCenter) + vAlignment = (vAlignment == Qt::AlignTop) ? Qt::AlignBottom : Qt::AlignTop; + alignment = Qt::AlignmentFlag(vAlignment | hAlignment); + } else { + labelTrans.setX(m_axisCacheX.labelPosition(label)); + } const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(label); + if (label == 0 || label == (labelCount - 1)) { + // If the margin is small, adjust the position of the edge labels to avoid overlapping + // with labels of the other axes. + float scaleFactor = m_drawer->scaledFontSize() / axisLabelItem.size().height(); + float labelOverlap = qAbs(labelTrans.x()) + + (scaleFactor * axisLabelItem.size().height() / 2.0f) + - m_scaleXWithBackground + labelMargin; + // No need to adjust quite as much on the front edges + if (label != startIndex) + labelOverlap /= 2.0f; + if (labelOverlap > 0.0f) { + if (label == 0) + labelTrans.setX(labelTrans.x() + labelOverlap); + else + labelTrans.setX(labelTrans.x() - labelOverlap); + } + } + m_dummyRenderItem.setTranslation(labelTrans); if (drawSelection) { QVector4D labelColor = QVector4D(0.0f, label / 255.0f, 0.0f, @@ -2059,8 +2253,20 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa } if (!drawSelection && m_axisCacheX.isTitleVisible()) { labelTrans.setX(0.0f); + bool radial = false; + if (m_polarGraph) { + if (m_xFlipped == m_zFlipped) + totalRotation *= m_zRightAngleRotation; + else + totalRotation *= m_zRightAngleRotationNeg; + if (m_yFlippedForGrid) + totalRotation *= QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, -180.0f); + labelTrans.setZ(-m_polarRadius); + radial = true; + } drawAxisTitleX(labelRotation, labelTrans, totalRotation, m_dummyRenderItem, - activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader); + activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader, + radial); } } // Y Labels @@ -2072,12 +2278,12 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa fractionCamX = activeCamera->xRotation() * labelAngleFraction; int labelCount = m_axisCacheY.labelCount(); - GLfloat labelXTrans = m_scaleXWithBackground; - GLfloat labelZTrans = m_scaleZWithBackground; + float labelXTrans = m_scaleXWithBackground; + float labelZTrans = m_scaleZWithBackground; // Back & side wall - GLfloat labelMarginXTrans = labelMargin; - GLfloat labelMarginZTrans = labelMargin; + float labelMarginXTrans = labelMargin; + float labelMarginZTrans = labelMargin; QVector3D backLabelRotation(0.0f, -90.0f, 0.0f); QVector3D sideLabelRotation(0.0f, 0.0f, 0.0f); Qt::AlignmentFlag backAlignment = @@ -2134,7 +2340,7 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa float offsetValue = 0.0f; for (int label = startIndex; label != endIndex; label = label + indexStep) { const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(label); - const GLfloat labelYTrans = m_axisCacheY.labelPosition(label); + float labelYTrans = m_axisCacheY.labelPosition(label); glPolygonOffset(offsetValue++ / -10.0f, 1.0f); @@ -2144,6 +2350,21 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa shader->setUniformValue(shader->color(), labelColor); } + if (label == startIndex) { + // If the margin is small, adjust the position of the edge label to avoid + // overlapping with labels of the other axes. + float scaleFactor = m_drawer->scaledFontSize() / axisLabelItem.size().height(); + float labelOverlap = qAbs(labelYTrans) + + (scaleFactor * axisLabelItem.size().height() / 2.0f) + - m_scaleYWithBackground + labelMargin; + if (labelOverlap > 0.0f) { + if (label == 0) + labelYTrans += labelOverlap; + else + labelYTrans -= labelOverlap; + } + } + // Back wall labelTransBack.setY(labelYTrans); m_dummyRenderItem.setTranslation(labelTransBack); @@ -2174,10 +2395,8 @@ void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCa } glDisable(GL_POLYGON_OFFSET_FILL); - if (!drawSelection) { - glDisable(GL_TEXTURE_2D); + if (!drawSelection) glDisable(GL_BLEND); - } } void Surface3DRenderer::updateSelectionMode(QAbstract3DGraph::SelectionFlags mode) @@ -2205,11 +2424,12 @@ void Surface3DRenderer::updateSelectionTextures() void Surface3DRenderer::createSelectionTexture(SurfaceSeriesRenderCache *cache, uint &lastSelectionId) { - // Create the selection ID image. Each grid corner gets 2x2 pixel area of - // ID color so that each vertex (data point) has 4x4 pixel area of ID color + // Create the selection ID image. Each grid corner gets 1 pixel area of + // ID color so that each vertex (data point) has 2x2 pixel area of ID color, + // except the vertices on the edges. const QRect &sampleSpace = cache->sampleSpace(); - int idImageWidth = (sampleSpace.width() - 1) * 4; - int idImageHeight = (sampleSpace.height() - 1) * 4; + int idImageWidth = (sampleSpace.width() - 1) * 2; + int idImageHeight = (sampleSpace.height() - 1) * 2; if (idImageHeight <= 0 || idImageWidth <= 0) { cache->setSelectionIdRange(-1, -1); @@ -2221,21 +2441,21 @@ void Surface3DRenderer::createSelectionTexture(SurfaceSeriesRenderCache *cache, uint idStart = lastSelectionId; uchar *bits = new uchar[idImageWidth * idImageHeight * 4 * sizeof(uchar)]; - for (int i = 0; i < idImageHeight; i += 4) { - for (int j = 0; j < idImageWidth; j += 4) { + for (int i = 0; i < idImageHeight; i += 2) { + for (int j = 0; j < idImageWidth; j += 2) { int p = (i * idImageWidth + j) * 4; uchar r, g, b, a; idToRGBA(lastSelectionId, &r, &g, &b, &a); - fillIdCorner(&bits[p], r, g, b, a, stride); + fillIdCorner(&bits[p], r, g, b, a); idToRGBA(lastSelectionId + 1, &r, &g, &b, &a); - fillIdCorner(&bits[p + 8], r, g, b, a, stride); + fillIdCorner(&bits[p + 4], r, g, b, a); idToRGBA(lastSelectionId + sampleSpace.width(), &r, &g, &b, &a); - fillIdCorner(&bits[p + 2 * stride], r, g, b, a, stride); + fillIdCorner(&bits[p + stride], r, g, b, a); idToRGBA(lastSelectionId + sampleSpace.width() + 1, &r, &g, &b, &a); - fillIdCorner(&bits[p + 2 * stride + 8], r, g, b, a, stride); + fillIdCorner(&bits[p + stride + 4], r, g, b, a); lastSelectionId++; } @@ -2263,24 +2483,12 @@ void Surface3DRenderer::initSelectionBuffer() m_selectionDepthBuffer); } -void Surface3DRenderer::fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride) +void Surface3DRenderer::fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a) { p[0] = r; p[1] = g; p[2] = b; p[3] = a; - p[4] = r; - p[5] = g; - p[6] = b; - p[7] = a; - p[stride + 0] = r; - p[stride + 1] = g; - p[stride + 2] = b; - p[stride + 3] = a; - p[stride + 4] = r; - p[stride + 5] = g; - p[stride + 6] = b; - p[stride + 7] = a; } void Surface3DRenderer::idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a) @@ -2293,21 +2501,66 @@ void Surface3DRenderer::idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a void Surface3DRenderer::calculateSceneScalingFactors() { + // Margin for background (the default 0.10 makes it 10% larger to avoid + // selection ball being drawn inside background) + if (m_requestedMargin < 0.0f) { + m_hBackgroundMargin = 0.1f; + m_vBackgroundMargin = 0.1f; + } else { + m_hBackgroundMargin = m_requestedMargin; + m_vBackgroundMargin = m_requestedMargin; + } + if (m_polarGraph) { + float polarMargin = calculatePolarBackgroundMargin(); + m_hBackgroundMargin = qMax(m_hBackgroundMargin, polarMargin); + } + // Calculate scene scaling and translation factors m_heightNormalizer = GLfloat(m_axisCacheY.max() - m_axisCacheY.min()); - m_areaSize.setHeight(m_axisCacheZ.max() - m_axisCacheZ.min()); - m_areaSize.setWidth(m_axisCacheX.max() - m_axisCacheX.min()); - m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); - m_scaleX = m_graphAspectRatio * m_areaSize.width() / m_scaleFactor; - m_scaleZ = m_graphAspectRatio * m_areaSize.height() / m_scaleFactor; - m_scaleXWithBackground = m_scaleX + backgroundMargin - 1.0f; - m_scaleZWithBackground = m_scaleZ + backgroundMargin - 1.0f; - - float factorScaler = 2.0f * m_graphAspectRatio / m_scaleFactor; - m_axisCacheX.setScale(factorScaler * m_areaSize.width()); - m_axisCacheZ.setScale(-factorScaler * m_areaSize.height()); - m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f); - m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f); + + float horizontalAspectRatio; + if (m_polarGraph) + horizontalAspectRatio = 1.0f; + else + horizontalAspectRatio = m_graphHorizontalAspectRatio; + + QSizeF areaSize; + if (horizontalAspectRatio == 0.0f) { + areaSize.setHeight(m_axisCacheZ.max() - m_axisCacheZ.min()); + areaSize.setWidth(m_axisCacheX.max() - m_axisCacheX.min()); + } else { + areaSize.setHeight(1.0f); + areaSize.setWidth(horizontalAspectRatio); + } + + float horizontalMaxDimension; + if (m_graphAspectRatio > 2.0f) { + horizontalMaxDimension = 2.0f; + m_scaleY = 2.0f / m_graphAspectRatio; + } else { + horizontalMaxDimension = m_graphAspectRatio; + m_scaleY = 1.0f; + } + if (m_polarGraph) + m_polarRadius = horizontalMaxDimension; + + float scaleFactor = qMax(areaSize.width(), areaSize.height()); + m_scaleX = horizontalMaxDimension * areaSize.width() / scaleFactor; + m_scaleZ = horizontalMaxDimension * areaSize.height() / scaleFactor; + + m_scaleXWithBackground = m_scaleX + m_hBackgroundMargin; + m_scaleYWithBackground = m_scaleY + m_vBackgroundMargin; + m_scaleZWithBackground = m_scaleZ + m_hBackgroundMargin; + + m_axisCacheX.setScale(m_scaleX * 2.0f); + m_axisCacheY.setScale(m_scaleY * 2.0f); + m_axisCacheZ.setScale(-m_scaleZ * 2.0f); + m_axisCacheX.setTranslate(-m_scaleX); + m_axisCacheY.setTranslate(-m_scaleY); + m_axisCacheZ.setTranslate(m_scaleZ); + + updateCameraViewport(); + updateCustomItemPositions(); } void Surface3DRenderer::checkFlatSupport(SurfaceSeriesRenderCache *cache) @@ -2326,10 +2579,20 @@ void Surface3DRenderer::updateObjects(SurfaceSeriesRenderCache *cache, bool dime QSurfaceDataArray &dataArray = cache->dataArray(); const QRect &sampleSpace = cache->sampleSpace(); - if (cache->isFlatShadingEnabled()) - cache->surfaceObject()->setUpData(dataArray, sampleSpace, dimensionChanged); - else - cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, dimensionChanged); + const QSurface3DSeries *currentSeries = cache->series(); + QSurfaceDataProxy *dataProxy = currentSeries->dataProxy(); + const QSurfaceDataArray &array = *dataProxy->array(); + + if (cache->isFlatShadingEnabled()) { + cache->surfaceObject()->setUpData(dataArray, sampleSpace, dimensionChanged, m_polarGraph); + if (cache->surfaceTexture()) + cache->surfaceObject()->coarseUVs(array, dataArray); + } else { + cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, dimensionChanged, + m_polarGraph); + if (cache->surfaceTexture()) + cache->surfaceObject()->smoothUVs(array, dataArray); + } } void Surface3DRenderer::updateSelectedPoint(const QPoint &position, QSurface3DSeries *series) @@ -2339,6 +2602,11 @@ void Surface3DRenderer::updateSelectedPoint(const QPoint &position, QSurface3DSe m_selectionDirty = true; } +void Surface3DRenderer::updateFlipHorizontalGrid(bool flip) +{ + m_flipHorizontalGrid = flip; +} + void Surface3DRenderer::resetClickedStatus() { m_clickedPosition = Surface3DController::invalidSelectionPosition(); @@ -2539,14 +2807,15 @@ void Surface3DRenderer::updateShadowQuality(QAbstract3DGraph::ShadowQuality qual handleShadowQualityChange(); -#if !defined(QT_OPENGL_ES_2) updateDepthBuffer(); -#endif } void Surface3DRenderer::updateTextures() { - // Do nothing, but required as it is pure virtual on parent + Abstract3DRenderer::updateTextures(); + + if (m_polarGraph) + calculateSceneScalingFactors(); } void Surface3DRenderer::updateSlicingActive(bool isSlicing) @@ -2556,12 +2825,13 @@ void Surface3DRenderer::updateSlicingActive(bool isSlicing) m_cachedIsSlicingActivated = isSlicing; - if (!m_cachedIsSlicingActivated) - initSelectionBuffer(); // We need to re-init selection buffer in case there has been a resize + if (!m_cachedIsSlicingActivated) { + // We need to re-init selection buffer in case there has been a resize + initSelectionBuffer(); + initCursorPositionBuffer(); + } -#if !defined(QT_OPENGL_ES_2) updateDepthBuffer(); // Re-init depth buffer as well -#endif m_selectionDirty = true; @@ -2577,55 +2847,68 @@ void Surface3DRenderer::initShaders(const QString &vertexShader, const QString & Q_UNUSED(vertexShader); Q_UNUSED(fragmentShader); - // draw the shader for the surface according to smooth status, shadow and uniform color - if (m_surfaceFlatShader) - delete m_surfaceFlatShader; - if (m_surfaceSmoothShader) - delete m_surfaceSmoothShader; - if (m_surfaceSliceFlatShader) - delete m_surfaceSliceFlatShader; - if (m_surfaceSliceSmoothShader) - delete m_surfaceSliceSmoothShader; - -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentSurfaceShadowNoTex")); - } else { - m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurface")); - } - m_surfaceSliceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurface")); - if (m_flatSupported) { + delete m_surfaceFlatShader; + delete m_surfaceSmoothShader; + delete m_surfaceTexturedSmoothShader; + delete m_surfaceTexturedFlatShader; + delete m_surfaceSliceFlatShader; + delete m_surfaceSliceSmoothShader; + + if (!m_isOpenGLES) { if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceShadowFlat"), - QStringLiteral(":/shaders/fragmentSurfaceShadowFlat")); + m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentSurfaceShadowNoTex")); + m_surfaceTexturedSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentTexturedSurfaceShadow")); + } else { + m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurface")); + m_surfaceTexturedSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexTexture"), + QStringLiteral(":/shaders/fragmentTexture")); + } + m_surfaceSliceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurface")); + if (m_flatSupported) { + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceShadowFlat"), + QStringLiteral(":/shaders/fragmentSurfaceShadowFlat")); + m_surfaceTexturedFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceShadowFlat"), + QStringLiteral(":/shaders/fragmentTexturedSurfaceShadowFlat")); + } else { + m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), + QStringLiteral(":/shaders/fragmentSurfaceFlat")); + m_surfaceTexturedFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), + QStringLiteral(":/shaders/fragmentSurfaceTexturedFlat")); + } + m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), + QStringLiteral(":/shaders/fragmentSurfaceFlat")); } else { - m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), - QStringLiteral(":/shaders/fragmentSurfaceFlat")); + m_surfaceFlatShader = 0; + m_surfaceSliceFlatShader = 0; + m_surfaceTexturedFlatShader = 0; } - m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), - QStringLiteral(":/shaders/fragmentSurfaceFlat")); } else { - m_surfaceFlatShader = 0; - m_surfaceSliceFlatShader = 0; + m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurfaceES2")); + m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurfaceES2")); + m_surfaceTexturedSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexTexture"), + QStringLiteral(":/shaders/fragmentTextureES2")); + m_surfaceTexturedFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexTexture"), + QStringLiteral(":/shaders/fragmentTextureES2")); + m_surfaceSliceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurfaceES2")); + m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentSurfaceES2")); } -#else - m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurfaceES2")); - m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurfaceES2")); - m_surfaceSliceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurfaceES2")); - m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentSurfaceES2")); -#endif + m_surfaceSmoothShader->initialize(); m_surfaceSliceSmoothShader->initialize(); + m_surfaceTexturedSmoothShader->initialize(); if (m_flatSupported) { m_surfaceFlatShader->initialize(); m_surfaceSliceFlatShader->initialize(); + m_surfaceTexturedFlatShader->initialize(); } } @@ -2660,45 +2943,33 @@ void Surface3DRenderer::initSurfaceShaders() handleShadowQualityChange(); } -void Surface3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) -{ - if (m_labelShader) - delete m_labelShader; - m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader); - m_labelShader->initialize(); -} - -#if !defined(QT_OPENGL_ES_2) void Surface3DRenderer::initDepthShader() { - if (m_depthShader) + if (!m_isOpenGLES) { delete m_depthShader; - m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), - QStringLiteral(":/shaders/fragmentDepth")); - m_depthShader->initialize(); + m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), + QStringLiteral(":/shaders/fragmentDepth")); + m_depthShader->initialize(); + } } void Surface3DRenderer::updateDepthBuffer() { - m_textureHelper->deleteTexture(&m_depthTexture); - m_textureHelper->deleteTexture(&m_depthModelTexture); + if (!m_isOpenGLES) { + m_textureHelper->deleteTexture(&m_depthTexture); - if (m_primarySubViewport.size().isEmpty()) - return; + if (m_primarySubViewport.size().isEmpty()) + return; - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - m_depthTexture = m_textureHelper->createDepthTextureFrameBuffer(m_primarySubViewport.size(), - m_depthFrameBuffer, - m_shadowQualityMultiplier); - m_textureHelper->fillDepthTexture(m_depthTexture, m_primarySubViewport.size(), - m_shadowQualityMultiplier, 1.0f); - m_depthModelTexture = m_textureHelper->createDepthTexture(m_primarySubViewport.size(), - m_shadowQualityMultiplier); - if (!m_depthTexture || !m_depthModelTexture) - lowerShadowQuality(); + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + m_depthTexture = m_textureHelper->createDepthTextureFrameBuffer(m_primarySubViewport.size(), + m_depthFrameBuffer, + m_shadowQualityMultiplier); + if (!m_depthTexture) + lowerShadowQuality(); + } } } -#endif QVector3D Surface3DRenderer::convertPositionToTranslation(const QVector3D &position, bool isAbsolute) @@ -2707,15 +2978,44 @@ QVector3D Surface3DRenderer::convertPositionToTranslation(const QVector3D &posit float yTrans = 0.0f; float zTrans = 0.0f; if (!isAbsolute) { - xTrans = m_axisCacheX.positionAt(position.x()); + if (m_polarGraph) { + calculatePolarXZ(position, xTrans, zTrans); + } else { + xTrans = m_axisCacheX.positionAt(position.x()); + zTrans = m_axisCacheZ.positionAt(position.z()); + } yTrans = m_axisCacheY.positionAt(position.y()); - zTrans = m_axisCacheZ.positionAt(position.z()); } else { xTrans = position.x() * m_scaleX; - yTrans = position.y(); - zTrans = position.z() * m_scaleZ; + yTrans = position.y() * m_scaleY; + zTrans = position.z() * -m_scaleZ; } return QVector3D(xTrans, yTrans, zTrans); } +void Surface3DRenderer::updateAxisLabels(QAbstract3DAxis::AxisOrientation orientation, + const QStringList &labels) +{ + Abstract3DRenderer::updateAxisLabels(orientation, labels); + + // Angular axis label dimensions affect the chart dimensions + if (m_polarGraph && orientation == QAbstract3DAxis::AxisOrientationX) + calculateSceneScalingFactors(); +} + +void Surface3DRenderer::updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientation orientation, bool visible) +{ + Abstract3DRenderer::updateAxisTitleVisibility(orientation, visible); + + // Angular axis title existence affects the chart dimensions + if (m_polarGraph && orientation == QAbstract3DAxis::AxisOrientationX) + calculateSceneScalingFactors(); +} + +void Surface3DRenderer::updateMargin(float margin) +{ + Abstract3DRenderer::updateMargin(margin); + calculateSceneScalingFactors(); +} + QT_END_NAMESPACE_DATAVISUALIZATION |