diff options
Diffstat (limited to 'src/datavisualization/engine/scatter3drenderer.cpp')
-rw-r--r-- | src/datavisualization/engine/scatter3drenderer.cpp | 1924 |
1 files changed, 1159 insertions, 765 deletions
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index de1a769a..21d86d03 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -17,25 +17,16 @@ ****************************************************************************/ #include "scatter3drenderer_p.h" -#include "scatter3dcontroller_p.h" -#include "q3dcamera.h" #include "q3dcamera_p.h" #include "shaderhelper_p.h" -#include "objecthelper_p.h" #include "texturehelper_p.h" #include "utils_p.h" -#include "q3dlight.h" -#include "qscatter3dseries_p.h" +#include "scatterseriesrendercache_p.h" +#include "scatterobjectbufferhelper_p.h" +#include "scatterpointbufferhelper_p.h" -#include <QtGui/QMatrix4x4> -#include <QtGui/QMouseEvent> -#include <QtCore/QThread> #include <QtCore/qmath.h> -// Commenting this draws the shadow map with perspective projection. Otherwise it's drawn in -// orthographic projection. -//#define USE_WIDER_SHADOWS - // You can verify that depth buffer drawing works correctly by uncommenting this. // You should see the scene from where the light is //#define SHOW_DEPTH_TEXTURE_SCENE @@ -44,20 +35,14 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION //#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values -const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd. -const GLfloat labelMargin = 0.05f; const GLfloat defaultMinSize = 0.01f; const GLfloat defaultMaxSize = 0.1f; -const GLfloat defaultMargin = 1.0f + defaultMaxSize; // Default margin for background const GLfloat itemScaler = 3.0f; const GLfloat gridLineWidth = 0.005f; Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) : Abstract3DRenderer(controller), m_selectedItem(0), - m_xFlipped(false), - m_zFlipped(false), - m_yFlipped(false), m_updateLabels(false), m_dotShader(0), m_dotGradientShader(0), @@ -68,9 +53,6 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_selectionShader(0), m_backgroundShader(0), m_labelShader(0), - m_backgroundObj(0), - m_gridLineObj(0), - m_labelObj(0), m_bgrTexture(0), m_depthTexture(0), m_selectionTexture(0), @@ -82,16 +64,22 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_heightNormalizer(1.0f), m_scaleFactor(0), m_selectedItemIndex(Scatter3DController::invalidSelectionIndex()), - m_selectedItemTotalIndex(Scatter3DController::invalidSelectionIndex()), - m_selectedItemSeriesIndex(Scatter3DController::invalidSelectionIndex()), - m_selectedSeries(0), + m_selectedSeriesCache(0), + m_oldSelectedSeriesCache(0), m_areaSize(QSizeF(0.0, 0.0)), m_dotSizeScale(1.0f), m_hasHeightAdjustmentChanged(true), - m_backgroundMargin(defaultMargin), + m_backgroundMargin(defaultMaxSize), m_maxItemSize(0.0f), - m_clickedIndex(Scatter3DController::invalidSelectionIndex()) + m_clickedIndex(Scatter3DController::invalidSelectionIndex()), + m_havePointSeries(false), + m_haveMeshSeries(false), + m_haveUniformColorMeshSeries(false), + m_haveGradientMeshSeries(false) { + m_axisCacheY.setScale(2.0f); + m_axisCacheY.setTranslate(-1.0f); + initializeOpenGLFunctions(); initializeOpenGL(); } @@ -111,9 +99,6 @@ Scatter3DRenderer::~Scatter3DRenderer() delete m_selectionShader; delete m_backgroundShader; delete m_labelShader; - delete m_backgroundObj; - delete m_gridLineObj; - delete m_labelObj; } void Scatter3DRenderer::initializeOpenGL() @@ -135,8 +120,10 @@ void Scatter3DRenderer::initializeOpenGL() // Init selection shader initSelectionShader(); +#if !defined(QT_OPENGL_ES_2) // Load grid line mesh loadGridLineMesh(); +#endif // Load label mesh loadLabelMesh(); @@ -151,78 +138,153 @@ void Scatter3DRenderer::initializeOpenGL() loadBackgroundMesh(); } -void Scatter3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList, - bool updateVisibility) +void Scatter3DRenderer::updateData() { - Abstract3DRenderer::updateSeries(seriesList, updateVisibility); + calculateSceneScalingFactors(); + int totalDataSize = 0; - int seriesCount = m_visibleSeriesList.size(); + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + ScatterSeriesRenderCache *cache = static_cast<ScatterSeriesRenderCache *>(baseCache); + if (cache->isVisible() && cache->dataDirty()) { + const QScatter3DSeries *currentSeries = cache->series(); + ScatterRenderItemArray &renderArray = cache->renderArray(); + QScatterDataProxy *dataProxy = currentSeries->dataProxy(); + const QScatterDataArray &dataArray = *dataProxy->array(); + int dataSize = dataArray.size(); + totalDataSize += dataSize; + if (dataSize != renderArray.size()) + renderArray.resize(dataSize); + + for (int i = 0; i < dataSize; i++) + updateRenderItem(dataArray.at(i), renderArray[i]); + cache->setDataDirty(false); + } + } + + if (totalDataSize) { + m_dotSizeScale = GLfloat(qBound(defaultMinSize, 2.0f / float(qSqrt(qreal(totalDataSize))), + defaultMaxSize)); + } + + if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic)) { + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + ScatterSeriesRenderCache *cache = static_cast<ScatterSeriesRenderCache *>(baseCache); + if (cache->isVisible()) { + ScatterRenderItemArray &renderArray = cache->renderArray(); + const int renderArraySize = renderArray.size(); + + if (cache->mesh() == QAbstract3DSeries::MeshPoint) { + ScatterPointBufferHelper *points = cache->bufferPoints(); + if (!points) { + points = new ScatterPointBufferHelper(); + cache->setBufferPoints(points); + } + points->load(cache); + } else { + ScatterObjectBufferHelper *object = cache->bufferObject(); + if (!object) { + object = new ScatterObjectBufferHelper(); + cache->setBufferObject(object); + } + if (renderArraySize != cache->oldArraySize() + || cache->object()->objectFile() != cache->oldMeshFileName()) { + object->fullLoad(cache, m_dotSizeScale); + cache->setOldArraySize(renderArraySize); + cache->setOldMeshFileName(cache->object()->objectFile()); + } else { + object->update(cache, m_dotSizeScale); + } + } + } + } + } + + updateSelectedItem(m_selectedItemIndex, + m_selectedSeriesCache ? m_selectedSeriesCache->series() : 0); +} + +void Scatter3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList) +{ + Abstract3DRenderer::updateSeries(seriesList); + + int seriesCount = seriesList.size(); float maxItemSize = 0.0f; float itemSize = 0.0f; + bool noSelection = true; - if (m_cachedItemSize.size() != seriesCount) - m_cachedItemSize.resize(seriesCount); + m_havePointSeries = false; + m_haveMeshSeries = false; + m_haveUniformColorMeshSeries = false; + m_haveGradientMeshSeries = false; - for (int series = 0; series < seriesCount; series++) { - itemSize = static_cast<QScatter3DSeries *>(m_visibleSeriesList.at(series).series())->itemSize(); - if (maxItemSize < itemSize) - maxItemSize = itemSize; - if (m_cachedItemSize.at(series) != itemSize) - m_cachedItemSize[series] = itemSize; + for (int i = 0; i < seriesCount; i++) { + QScatter3DSeries *scatterSeries = static_cast<QScatter3DSeries *>(seriesList[i]); + if (scatterSeries->isVisible()) { + ScatterSeriesRenderCache *cache = + static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(scatterSeries)); + itemSize = scatterSeries->itemSize(); + if (maxItemSize < itemSize) + maxItemSize = itemSize; + if (cache->itemSize() != itemSize) + cache->setItemSize(itemSize); + if (noSelection + && scatterSeries->selectedItem() != QScatter3DSeries::invalidSelectionIndex()) { + if (m_selectionLabel != cache->itemLabel()) + m_selectionLabelDirty = true; + noSelection = false; + } + + if (cache->mesh() == QAbstract3DSeries::MeshPoint) { + m_havePointSeries = true; + } else { + m_haveMeshSeries = true; + if (cache->colorStyle() == Q3DTheme::ColorStyleUniform) + m_haveUniformColorMeshSeries = true; + else + m_haveGradientMeshSeries = true; + } + } } - m_backgroundMargin = defaultMargin; m_maxItemSize = maxItemSize; if (maxItemSize > defaultMaxSize) - m_backgroundMargin += maxItemSize / itemScaler; + m_backgroundMargin = maxItemSize / itemScaler; + else + m_backgroundMargin = defaultMaxSize; + + if (noSelection) { + if (!selectionLabel().isEmpty()) + m_selectionLabelDirty = true; + m_selectedSeriesCache = 0; + } } -void Scatter3DRenderer::updateData() +SeriesRenderCache *Scatter3DRenderer::createNewCache(QAbstract3DSeries *series) { - int seriesCount = m_visibleSeriesList.size(); - calculateSceneScalingFactors(); - float minX = float(m_axisCacheX.min()); - float maxX = float(m_axisCacheX.max()); - float minY = float(m_axisCacheY.min()); - float maxY = float(m_axisCacheY.max()); - float minZ = float(m_axisCacheZ.min()); - float maxZ = float(m_axisCacheZ.max()); - int totalDataSize = 0; + return new ScatterSeriesRenderCache(series, this); +} - if (m_renderingArrays.size() != seriesCount) - m_renderingArrays.resize(seriesCount); - - for (int series = 0; series < seriesCount; series++) { - QScatterDataProxy *dataProxy = - static_cast<QScatter3DSeries *>(m_visibleSeriesList.at(series).series())->dataProxy(); - const QScatterDataArray &dataArray = *dataProxy->array(); - int dataSize = dataArray.size(); - totalDataSize += dataSize; - - if (dataSize != m_renderingArrays.at(series).size()) - m_renderingArrays[series].resize(dataSize); - - for (int i = 0; i < dataSize; i++) { - QVector3D dotPos = dataArray.at(i).position(); - ScatterRenderItem &renderItem = m_renderingArrays[series][i]; - if ((dotPos.x() >= minX && dotPos.x() <= maxX ) - && (dotPos.y() >= minY && dotPos.y() <= maxY) - && (dotPos.z() >= minZ && dotPos.z() <= maxZ)) { - renderItem.setPosition(dotPos); - renderItem.setVisible(true); - if (!dataArray.at(i).rotation().isIdentity()) - renderItem.setRotation(dataArray.at(i).rotation().normalized()); - else - renderItem.setRotation(identityQuaternion); - calculateTranslation(renderItem); - } else { - renderItem.setVisible(false); - } +void Scatter3DRenderer::updateItems(const QVector<Scatter3DController::ChangeItem> &items) +{ + ScatterSeriesRenderCache *cache = 0; + const QScatter3DSeries *prevSeries = 0; + const QScatterDataArray *dataArray = 0; + + foreach (Scatter3DController::ChangeItem item, items) { + QScatter3DSeries *currentSeries = item.series; + if (currentSeries != prevSeries) { + cache = static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(currentSeries)); + prevSeries = currentSeries; + dataArray = item.series->dataProxy()->array(); + // Invisible series render caches are not updated, but instead just marked dirty, so that + // they can be completely recalculated when they are turned visible. + if (!cache->isVisible() && !cache->dataDirty()) + cache->setDataDirty(true); + } + if (cache->isVisible()) { + const int index = item.index; + updateRenderItem(dataArray->at(index), cache->renderArray()[index]); } } - m_dotSizeScale = GLfloat(qBound(defaultMinSize, 2.0f / float(qSqrt(qreal(totalDataSize))), - defaultMaxSize)); - - updateSelectedItem(m_selectedItemIndex, m_selectedSeries); } void Scatter3DRenderer::updateScene(Q3DScene *scene) @@ -231,7 +293,8 @@ void Scatter3DRenderer::updateScene(Q3DScene *scene) if (m_hasHeightAdjustmentChanged) { // Set initial camera position. Also update if height adjustment has changed. - scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector, upVector); + scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector, + upVector); m_hasHeightAdjustmentChanged = false; } @@ -249,6 +312,13 @@ void Scatter3DRenderer::render(GLuint defaultFboHandle) // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); + if (m_axisCacheX.positionsDirty()) + m_axisCacheX.updateAllPositions(); + if (m_axisCacheY.positionsDirty()) + m_axisCacheY.updateAllPositions(); + if (m_axisCacheZ.positionsDirty()) + m_axisCacheZ.updateAllPositions(); + // Draw dots scene drawScene(defaultFboHandle); } @@ -258,9 +328,13 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) GLfloat backgroundRotation = 0; GLfloat selectedItemSize = 0.0f; + // Get the optimization flag + const bool optimizationDefault = + !m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic); + const Q3DCamera *activeCamera = m_cachedScene->activeCamera(); - QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor()); + QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor()); // Specify viewport glViewport(m_primarySubViewport.x(), @@ -272,14 +346,19 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) QMatrix4x4 projectionMatrix; GLfloat viewPortRatio = (GLfloat)m_primarySubViewport.width() / (GLfloat)m_primarySubViewport.height(); - projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f); + if (m_useOrthoProjection) { + GLfloat orthoRatio = 2.0f; + projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio, + -orthoRatio, orthoRatio, + 0.0f, 100.0f); + } else { + projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f); + } // Calculate view matrix QMatrix4x4 viewMatrix = activeCamera->d_ptr->viewMatrix(); QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix; - int seriesCount = m_visibleSeriesList.size(); - // Calculate label flipping if (viewMatrix.row(0).x() > 0) m_zFlipped = false; @@ -314,25 +393,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) QMatrix4x4 depthProjectionMatrix; QMatrix4x4 depthProjectionViewMatrix; - // Check if we have any series with points - bool havePointSeries = false; - bool haveMeshSeries = false; - bool haveUniformColorMeshSeries = false; - bool haveGradientMeshSeries = false; - for (int i = 0; i < seriesCount; i++) { - if (m_visibleSeriesList.at(i).mesh() == QAbstract3DSeries::MeshPoint) { - havePointSeries = true; - } else { - haveMeshSeries = true; - if (m_visibleSeriesList.at(i).colorStyle() == Q3DTheme::ColorStyleUniform) - haveUniformColorMeshSeries = true; - else - haveGradientMeshSeries = true; - } - } - #if !defined(QT_OPENGL_ES_2) - if (havePointSeries) { + if (m_havePointSeries) { glEnable(GL_POINT_SMOOTH); glEnable(GL_PROGRAM_POINT_SIZE); } @@ -360,77 +422,107 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) zeroVector, 0.0f, 2.5f / m_autoScaleAdjustment); depthViewMatrix.lookAt(depthLightPos, zeroVector, upVector); // Set the depth projection matrix -#ifndef USE_WIDER_SHADOWS - // Use this for perspective shadows depthProjectionMatrix.perspective(15.0f, viewPortRatio, 3.0f, 100.0f); -#else - // Use these for orthographic shadows - GLfloat testAspectRatio = viewPortRatio; - depthProjectionMatrix.ortho(-testAspectRatio * 2.0f, testAspectRatio * 2.0f, - -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f, - 0.0f, 100.0f); -#endif depthProjectionViewMatrix = depthProjectionMatrix * depthViewMatrix; // Draw dots to depth buffer - for (int series = 0; series < seriesCount; series++) { - ObjectHelper *dotObj = m_visibleSeriesList.at(series).object(); - QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation(); - bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint); - - float itemSize = m_cachedItemSize.at(series) / itemScaler; - if (itemSize == 0.0f) - itemSize = m_dotSizeScale; - if (drawingPoints) { - // Scale points based on shadow quality for shadows, not by zoom level - glPointSize(itemSize * 100.0f * m_shadowQualityMultiplier); - } - QVector3D modelScaler(itemSize, itemSize, itemSize); - - for (int dot = 0; dot < m_renderingArrays.at(series).size(); dot++) { - const ScatterRenderItem &item = m_renderingArrays.at(series).at(dot); - if (!item.isVisible()) - continue; - - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - - modelMatrix.translate(item.translation()); - if (!drawingPoints) { - if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) - modelMatrix.rotate(seriesRotation * item.rotation()); - modelMatrix.scale(modelScaler); - } - - MVPMatrix = depthProjectionViewMatrix * modelMatrix; - - m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); - + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + if (baseCache->isVisible()) { + ScatterSeriesRenderCache *cache = + static_cast<ScatterSeriesRenderCache *>(baseCache); + ObjectHelper *dotObj = cache->object(); + QQuaternion seriesRotation(cache->meshRotation()); + const ScatterRenderItemArray &renderArray = cache->renderArray(); + const int renderArraySize = renderArray.size(); + bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint); + float itemSize = cache->itemSize() / itemScaler; + if (itemSize == 0.0f) + itemSize = m_dotSizeScale; if (drawingPoints) { - m_drawer->drawPoint(m_depthShader); - } else { - // 1st attribute buffer : vertices - glEnableVertexAttribArray(m_depthShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf()); - glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, - (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT, - (void *)0); - - // Free buffers - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(m_depthShader->posAtt()); + // Scale points based on shadow quality for shadows, not by zoom level + glPointSize(itemSize * 100.0f * m_shadowQualityMultiplier); + } + QVector3D modelScaler(itemSize, itemSize, itemSize); + + int loopCount = 1; + if (optimizationDefault) + loopCount = renderArraySize; + for (int dot = 0; dot < loopCount; dot++) { + const ScatterRenderItem &item = renderArray.at(dot); + if (!item.isVisible() && optimizationDefault) + continue; + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + if (optimizationDefault) { + modelMatrix.translate(item.translation()); + if (!drawingPoints) { + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); + modelMatrix.scale(modelScaler); + } + } + + MVPMatrix = depthProjectionViewMatrix * modelMatrix; + + m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); + + if (drawingPoints) { + if (optimizationDefault) + m_drawer->drawPoint(m_depthShader); + else + m_drawer->drawPoints(m_depthShader, cache->bufferPoints()); + } else { + if (optimizationDefault) { + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_depthShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf()); + glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, + (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT, + (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_depthShader->posAtt()); + } else { + ScatterObjectBufferHelper *object = cache->bufferObject(); + // 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); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_depthShader->posAtt()); + } + } } } } + Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix, + projectionViewMatrix, depthProjectionViewMatrix, + m_depthTexture, m_shadowQualityToShader); + // Disable drawing to framebuffer (= enable drawing to screen) glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); @@ -446,14 +538,14 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) ShaderHelper *pointSelectionShader = m_selectionShader; #else - Q_UNUSED(havePointSeries); ShaderHelper *pointSelectionShader = m_pointShader; #endif ShaderHelper *selectionShader = m_selectionShader; // Skip selection mode drawing if we have no selection mode if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone - && SelectOnScene == m_selectionState && seriesCount > 0) { + && SelectOnScene == m_selectionState + && (m_visibleSeriesCount > 0 || !m_customRenderCache.isEmpty())) { // Draw dots to selection buffer glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); glViewport(0, 0, @@ -465,94 +557,80 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled - int arraySize = 0; - int totalArraySize = 0; - int dotNo = 0; - - // Init previous to opposite of first to ensure we change binding for first series - bool previousDrawingPoints = (m_visibleSeriesList.at(0).mesh() != QAbstract3DSeries::MeshPoint); - for (int series = 0; series < seriesCount; series++) { - ObjectHelper *dotObj = m_visibleSeriesList.at(series).object(); - QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation(); - bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint); - - float itemSize = m_cachedItemSize.at(series) / itemScaler; - if (itemSize == 0.0f) - itemSize = m_dotSizeScale; + bool previousDrawingPoints = false; + int totalIndex = 0; + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + if (baseCache->isVisible()) { + ScatterSeriesRenderCache *cache = + static_cast<ScatterSeriesRenderCache *>(baseCache); + ObjectHelper *dotObj = cache->object(); + QQuaternion seriesRotation(cache->meshRotation()); + const ScatterRenderItemArray &renderArray = cache->renderArray(); + const int renderArraySize = renderArray.size(); + bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint); + float itemSize = cache->itemSize() / itemScaler; + if (itemSize == 0.0f) + itemSize = m_dotSizeScale; #if !defined(QT_OPENGL_ES_2) - if (drawingPoints) - glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom -#endif - QVector3D modelScaler(itemSize, itemSize, itemSize); - - // Rebind selection shader if it has changed - if (drawingPoints != previousDrawingPoints) { - previousDrawingPoints = drawingPoints; if (drawingPoints) - selectionShader = pointSelectionShader; - else - selectionShader = m_selectionShader; - - selectionShader->bind(); - } - arraySize = m_renderingArrays.at(series).size(); - totalArraySize += arraySize; - - if (totalArraySize > 0xfffffe) // Max possible different selection colors, 0xffffff being skipColor - qFatal("Too many objects"); - - for (int dot = 0; dot < arraySize; dot++) { - const ScatterRenderItem &item = m_renderingArrays.at(series).at(dot); - if (!item.isVisible()) - continue; + glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom +#endif + QVector3D modelScaler(itemSize, itemSize, itemSize); - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; + // Rebind selection shader if it has changed + if (!totalIndex || drawingPoints != previousDrawingPoints) { + previousDrawingPoints = drawingPoints; + if (drawingPoints) + selectionShader = pointSelectionShader; + else + selectionShader = m_selectionShader; - modelMatrix.translate(item.translation()); - if (!drawingPoints) { - if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) - modelMatrix.rotate(seriesRotation * item.rotation()); - modelMatrix.scale(modelScaler); + selectionShader->bind(); } - - MVPMatrix = projectionViewMatrix * modelMatrix; - - QVector3D dotColor = indexToSelectionColor(dotNo); - dotColor /= 255.0f; - - selectionShader->setUniformValue(selectionShader->MVP(), MVPMatrix); - selectionShader->setUniformValue(selectionShader->color(), dotColor); - - if (drawingPoints) { - m_drawer->drawPoint(selectionShader); - } else { - // 1st attribute buffer : vertices - glEnableVertexAttribArray(selectionShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf()); - glVertexAttribPointer(selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, - (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT, - (void *)0); - - // Free buffers - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(selectionShader->posAtt()); + cache->setSelectionIndexOffset(totalIndex); + for (int dot = 0; dot < renderArraySize; dot++) { + const ScatterRenderItem &item = renderArray.at(dot); + if (!item.isVisible()) { + totalIndex++; + continue; + } + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + modelMatrix.translate(item.translation()); + if (!drawingPoints) { + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); + modelMatrix.scale(modelScaler); + } + + MVPMatrix = projectionViewMatrix * modelMatrix; + + QVector4D dotColor = indexToSelectionColor(totalIndex++); + dotColor /= 255.0f; + + selectionShader->setUniformValue(selectionShader->MVP(), MVPMatrix); + selectionShader->setUniformValue(selectionShader->color(), dotColor); + + if (drawingPoints) + m_drawer->drawPoint(selectionShader); + else + m_drawer->drawSelectionObject(selectionShader, dotObj); } - dotNo++; } } + + Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, viewMatrix, + projectionViewMatrix, depthProjectionViewMatrix, + m_depthTexture, m_shadowQualityToShader); + + drawLabels(true, activeCamera, viewMatrix, projectionMatrix); + glEnable(GL_DITHER); // Read color under cursor - QVector3D clickedColor = Utils::getSelection(m_inputPosition, + QVector4D clickedColor = Utils::getSelection(m_inputPosition, m_viewport.height()); selectionColorToSeriesAndIndex(clickedColor, m_clickedIndex, m_clickedSeries); @@ -571,15 +649,14 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) GLuint gradientTexture = 0; bool dotSelectionFound = false; ScatterRenderItem *selectedItem(0); - int dotNo = 0; - QVector3D baseColor; - QVector3D dotColor; + QVector4D baseColor; + QVector4D dotColor; bool previousDrawingPoints = false; Q3DTheme::ColorStyle previousMeshColorStyle = Q3DTheme::ColorStyleUniform; - if (haveMeshSeries) { + if (m_haveMeshSeries) { // Set unchanging shader bindings - if (haveGradientMeshSeries) { + if (m_haveGradientMeshSeries) { m_dotGradientShader->bind(); m_dotGradientShader->setUniformValue(m_dotGradientShader->lightP(), lightPos); m_dotGradientShader->setUniformValue(m_dotGradientShader->view(), viewMatrix); @@ -587,7 +664,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) m_cachedTheme->ambientLightStrength()); m_dotGradientShader->setUniformValue(m_dotGradientShader->lightColor(), lightColor); } - if (haveUniformColorMeshSeries) { + if (m_haveUniformColorMeshSeries) { m_dotShader->bind(); m_dotShader->setUniformValue(m_dotShader->lightP(), lightPos); m_dotShader->setUniformValue(m_dotShader->view(), viewMatrix); @@ -607,152 +684,281 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) dotShader->bind(); } - for (int series = 0; series < seriesCount; series++) { - const SeriesRenderCache ¤tSeries = m_visibleSeriesList.at(series); - QQuaternion seriesRotation = currentSeries.meshRotation(); - ObjectHelper *dotObj = currentSeries.object(); - bool drawingPoints = (currentSeries.mesh() == QAbstract3DSeries::MeshPoint); - Q3DTheme::ColorStyle colorStyle = currentSeries.colorStyle(); - bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform); - bool useColor = colorStyleIsUniform || drawingPoints; - - float itemSize = m_cachedItemSize.at(series) / itemScaler; - if (itemSize == 0.0f) - itemSize = m_dotSizeScale; + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + if (baseCache->isVisible()) { + ScatterSeriesRenderCache *cache = + static_cast<ScatterSeriesRenderCache *>(baseCache); + ObjectHelper *dotObj = cache->object(); + QQuaternion seriesRotation(cache->meshRotation()); + ScatterRenderItemArray &renderArray = cache->renderArray(); + const int renderArraySize = renderArray.size(); + bool selectedSeries = m_cachedSelectionMode > QAbstract3DGraph::SelectionNone + && (m_selectedSeriesCache == cache); + bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint); + Q3DTheme::ColorStyle colorStyle = cache->colorStyle(); + bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform); + bool useColor = colorStyleIsUniform || drawingPoints; + bool rangeGradientPoints = drawingPoints + && (colorStyle == Q3DTheme::ColorStyleRangeGradient); + float itemSize = cache->itemSize() / itemScaler; + if (itemSize == 0.0f) + itemSize = m_dotSizeScale; #if !defined(QT_OPENGL_ES_2) - if (drawingPoints) - glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom + if (drawingPoints) + glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom #endif - QVector3D modelScaler(itemSize, itemSize, itemSize); - - // Rebind shader if it has changed - if (drawingPoints != previousDrawingPoints - || (!drawingPoints && - (colorStyleIsUniform != (previousMeshColorStyle == Q3DTheme::ColorStyleUniform)))) { - previousDrawingPoints = drawingPoints; - if (drawingPoints) { - dotShader = pointSelectionShader; - } else { - if (colorStyleIsUniform) - dotShader = m_dotShader; - else - dotShader = m_dotGradientShader; + QVector3D modelScaler(itemSize, itemSize, itemSize); + + // Rebind shader if it has changed + if (drawingPoints != previousDrawingPoints + || (!drawingPoints && + (colorStyleIsUniform != (previousMeshColorStyle + == Q3DTheme::ColorStyleUniform)))) { + previousDrawingPoints = drawingPoints; + if (drawingPoints) { + dotShader = pointSelectionShader; + } else { + if (colorStyleIsUniform) + dotShader = m_dotShader; + else + dotShader = m_dotGradientShader; + } + dotShader->bind(); } - dotShader->bind(); - } - if (!drawingPoints && !colorStyleIsUniform && previousMeshColorStyle != colorStyle) { - if (colorStyle == Q3DTheme::ColorStyleObjectGradient) { - m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientMin(), 0.0f); - m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), 0.5f); - } else { - // Each ball is of uniform color according to its Y-coordinate - m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), 0.0f); + if (!drawingPoints && !colorStyleIsUniform && previousMeshColorStyle != colorStyle) { + if (colorStyle == Q3DTheme::ColorStyleObjectGradient) { + m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientMin(), 0.0f); + m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), + 0.5f); + } else { + // Each dot is of uniform color according to its Y-coordinate + m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), + 0.0f); + } } - } - if (!drawingPoints) - previousMeshColorStyle = colorStyle; + if (!drawingPoints) + previousMeshColorStyle = colorStyle; - if (useColor) { - baseColor = currentSeries.baseColor(); - dotColor = baseColor; - } + if (useColor) { + baseColor = cache->baseColor(); + dotColor = baseColor; + } + int loopCount = 1; + if (optimizationDefault) + loopCount = renderArraySize; + for (int i = 0; i < loopCount; i++) { + ScatterRenderItem &item = renderArray[i]; + if (!item.isVisible() && optimizationDefault) + continue; - int seriesSize = m_renderingArrays.at(series).size(); - for (int dot = 0; dot < seriesSize; dot++) { - ScatterRenderItem &item = m_renderingArrays[series][dot]; - if (!item.isVisible()) - continue; - - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(item.translation()); - if (!drawingPoints) { - if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) { - QQuaternion totalRotation = seriesRotation * item.rotation(); - modelMatrix.rotate(totalRotation); - itModelMatrix.rotate(totalRotation); + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + if (optimizationDefault) { + modelMatrix.translate(item.translation()); + if (!drawingPoints) { + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) { + QQuaternion totalRotation = seriesRotation * item.rotation(); + modelMatrix.rotate(totalRotation); + itModelMatrix.rotate(totalRotation); + } + modelMatrix.scale(modelScaler); + itModelMatrix.scale(modelScaler); + } } - modelMatrix.scale(modelScaler); - itModelMatrix.scale(modelScaler); - } #ifdef SHOW_DEPTH_TEXTURE_SCENE - MVPMatrix = depthProjectionViewMatrix * modelMatrix; + MVPMatrix = depthProjectionViewMatrix * modelMatrix; #else - MVPMatrix = projectionViewMatrix * modelMatrix; + MVPMatrix = projectionViewMatrix * modelMatrix; #endif - if (useColor) - dotColor = baseColor; - else - gradientTexture = currentSeries.baseGradientTexture(); + if (useColor) { + if (rangeGradientPoints) { + // Drawing points with range gradient + // Get color from gradient based on items y position converted to percent + int position = int(item.translation().y() * 50.0f) + 50; + dotColor = Utils::vectorFromColor( + cache->gradientImage().pixel(0, position)); + } else { + dotColor = baseColor; + } + } else { + gradientTexture = cache->baseGradientTexture(); + } + + GLfloat lightStrength = m_cachedTheme->lightStrength(); + if (optimizationDefault && selectedSeries && (m_selectedItemIndex == i)) { + if (useColor) + dotColor = cache->singleHighlightColor(); + else + gradientTexture = cache->singleHighlightGradientTexture(); + lightStrength = m_cachedTheme->highlightLightStrength(); + // Insert data to ScatterRenderItem + // We don't have ownership, so don't delete the previous one + selectedItem = &item; + dotSelectionFound = true; + // Save selected item size (adjusted with font size) for selection label + // positioning + selectedItemSize = itemSize + (m_cachedTheme->font().pointSizeF() / 500.0f); + } + + if (!drawingPoints) { + // Set shader bindings + dotShader->setUniformValue(dotShader->model(), modelMatrix); + dotShader->setUniformValue(dotShader->nModel(), + itModelMatrix.inverted().transposed()); + } + + dotShader->setUniformValue(dotShader->MVP(), MVPMatrix); + if (useColor) { + dotShader->setUniformValue(dotShader->color(), dotColor); + } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) { + dotShader->setUniformValue(dotShader->gradientMin(), + (item.translation().y() + 1.0f) / 2.0f); + } +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + if (!drawingPoints) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + dotShader->setUniformValue(dotShader->shadowQ(), m_shadowQualityToShader); + dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix); + dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f); + + // Draw the object + if (optimizationDefault) { + m_drawer->drawObject(dotShader, dotObj, gradientTexture, + m_depthTexture); + } else { + m_drawer->drawObject(dotShader, cache->bufferObject(), gradientTexture, + m_depthTexture); + } + } else { + // Draw the object + if (optimizationDefault) + m_drawer->drawPoint(dotShader); + else + m_drawer->drawPoints(dotShader, cache->bufferPoints()); + } + } else +#endif + { + if (!drawingPoints) { + // Set shadowless shader bindings + dotShader->setUniformValue(dotShader->lightS(), lightStrength); + // Draw the object + if (optimizationDefault) + m_drawer->drawObject(dotShader, dotObj, gradientTexture); + else + m_drawer->drawObject(dotShader, cache->bufferObject(), gradientTexture); + } else { + // Draw the object + if (optimizationDefault) + m_drawer->drawPoint(dotShader); + else + m_drawer->drawPoints(dotShader, cache->bufferPoints()); + } + } + } + + // Draw the selected item on static optimization + if (!optimizationDefault && selectedSeries + && m_selectedItemIndex != Scatter3DController::invalidSelectionIndex()) { + ScatterRenderItem &item = renderArray[m_selectedItemIndex]; + ObjectHelper *dotObj = cache->object(); + + QMatrix4x4 modelMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(item.translation()); + if (!drawingPoints) { + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) { + QQuaternion totalRotation = seriesRotation * item.rotation(); + modelMatrix.rotate(totalRotation); + itModelMatrix.rotate(totalRotation); + } + modelMatrix.scale(modelScaler); + itModelMatrix.scale(modelScaler); + } + + QMatrix4x4 MVPMatrix; +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionViewMatrix * modelMatrix; +#else + MVPMatrix = projectionViewMatrix * modelMatrix; +#endif - GLfloat lightStrength = m_cachedTheme->lightStrength(); - if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone - && (m_selectedItemTotalIndex == dotNo)) { if (useColor) - dotColor = currentSeries.singleHighlightColor(); + dotColor = cache->singleHighlightColor(); else - gradientTexture = currentSeries.singleHighlightGradientTexture(); - lightStrength = m_cachedTheme->highlightLightStrength(); - // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one + gradientTexture = cache->singleHighlightGradientTexture(); + GLfloat lightStrength = m_cachedTheme->highlightLightStrength(); + // Save the reference to the item to be used on label drawing selectedItem = &item; dotSelectionFound = true; - // Save selected item size (adjusted with font size) for selection label positioning + // Save selected item size (adjusted with font size) for selection label + // positioning selectedItemSize = itemSize + (m_cachedTheme->font().pointSizeF() / 500.0f); - } - if (!drawingPoints) { - // Set shader bindings - dotShader->setUniformValue(dotShader->model(), modelMatrix); - dotShader->setUniformValue(dotShader->nModel(), - itModelMatrix.inverted().transposed()); - } - - dotShader->setUniformValue(dotShader->MVP(), MVPMatrix); - if (useColor) { - dotShader->setUniformValue(dotShader->color(), dotColor); - } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) { - dotShader->setUniformValue(dotShader->gradientMin(), - (item.translation().y() + 1.0f) / 2.0f); - } -#if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { if (!drawingPoints) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - dotShader->setUniformValue(dotShader->shadowQ(), m_shadowQualityToShader); - dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix); - dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f); + // Set shader bindings + dotShader->setUniformValue(dotShader->model(), modelMatrix); + dotShader->setUniformValue(dotShader->nModel(), + itModelMatrix.inverted().transposed()); + } - // Draw the object - m_drawer->drawObject(dotShader, dotObj, gradientTexture, m_depthTexture); - } else { - // Draw the object - m_drawer->drawPoint(dotShader); + dotShader->setUniformValue(dotShader->MVP(), MVPMatrix); + if (useColor) { + dotShader->setUniformValue(dotShader->color(), dotColor); + } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) { + dotShader->setUniformValue(dotShader->gradientMin(), + (item.translation().y() + 1.0f) / 2.0f); } - } else -#endif - { + if (!drawingPoints) { - // Set shadowless shader bindings - dotShader->setUniformValue(dotShader->lightS(), lightStrength); - // Draw the object - m_drawer->drawObject(dotShader, dotObj, gradientTexture); - } else { - // Draw the object - m_drawer->drawPoint(dotShader); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-0.5f, 1.0f); + } + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + if (!drawingPoints) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix); + dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(dotShader, dotObj, gradientTexture, m_depthTexture); + } else { + // Draw the object + m_drawer->drawPoint(dotShader); + } + } else +#endif + { + if (!drawingPoints) { + // Set shadowless shader bindings + dotShader->setUniformValue(dotShader->lightS(), lightStrength); + // Draw the object + m_drawer->drawObject(dotShader, dotObj, gradientTexture); + } else { + // Draw the object + m_drawer->drawPoint(dotShader); + } } + + if (!drawingPoints) + glDisable(GL_POLYGON_OFFSET_FILL); } - dotNo++; } } #if !defined(QT_OPENGL_ES_2) - if (havePointSeries) { + if (m_havePointSeries) { glDisable(GL_POINT_SMOOTH); glDisable(GL_PROGRAM_POINT_SIZE); } @@ -770,17 +976,19 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) QMatrix4x4 itModelMatrix; #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor; + GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor + + m_backgroundMargin; + GLfloat zScale = (m_graphAspectRatio * m_areaSize.height()) / m_scaleFactor + + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; if (m_maxItemSize > zScale) zScale = m_maxItemSize; - QVector3D bgScale(xScale, m_backgroundMargin, zScale); + QVector3D bgScale(xScale, 1.0f + m_backgroundMargin, zScale); #else // ..and this if we want uniform scaling based on largest dimension - QVector3D bgScale((aspectRatio * m_backgroundMargin), - m_backgroundMargin, - (aspectRatio * m_backgroundMargin)); + QVector3D bgScale((m_graphAspectRatio + m_backgroundMargin), + 1.0f + m_backgroundMargin, + (m_graphAspectRatio + m_backgroundMargin)); #endif modelMatrix.scale(bgScale); // If we're viewing from below, background object must be flipped @@ -797,7 +1005,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else MVPMatrix = projectionViewMatrix * modelMatrix; #endif - QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor()); + QVector4D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor()); // Set shader bindings m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos); @@ -839,22 +1047,18 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) glDisable(GL_TEXTURE_2D); // Draw grid lines -#ifdef USE_UNIFORM_SCALING - AxisRenderCache *axisCacheMax; - if (m_axisCacheZ.max() > m_axisCacheX.max()) - axisCacheMax = &m_axisCacheZ; - else - axisCacheMax = &m_axisCacheX; -#endif - - if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { + if (m_cachedTheme->isGridEnabled()) { +#if !(defined QT_OPENGL_ES_2) ShaderHelper *lineShader = m_backgroundShader; +#else + ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES +#endif // Bind line shader lineShader->bind(); // Set unchanging shader bindings - QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor()); + QVector4D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor()); lineShader->setUniformValue(lineShader->lightP(), lightPos); lineShader->setUniformValue(lineShader->view(), viewMatrix); lineShader->setUniformValue(lineShader->color(), lineColor); @@ -887,39 +1091,33 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) else lineXRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f); - GLfloat yFloorLinePosition = -m_backgroundMargin + gridLineOffset; + GLfloat yFloorLinePosition = -1.0f - m_backgroundMargin + gridLineOffset; if (m_yFlipped) yFloorLinePosition = -yFloorLinePosition; // Rows (= Z) if (m_axisCacheZ.segmentCount() > 0) { // Floor lines -#ifndef USE_UNIFORM_SCALING - GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep(); - GLfloat linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line - int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); -#else - GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); - GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line - int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); -#endif + int gridLineCount = m_axisCacheZ.gridLineCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; + GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor + + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth); #else // ..and this if we want uniform scaling based on largest dimension - QVector3D gridLineScaler((aspectRatio * m_backgroundMargin), + QVector3D gridLineScaler((m_graphAspectRatio + m_backgroundMargin), gridLineWidth, gridLineWidth); #endif - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, yFloorLinePosition, linePos / m_scaleFactor); + modelMatrix.translate(0.0f, yFloorLinePosition, + m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -942,42 +1140,45 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos -= lineStep; +#else + m_drawer->drawLine(lineShader); +#endif } // Side wall lines - gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth); + gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth); #ifndef USE_UNIFORM_SCALING - GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor - gridLineOffset; + GLfloat lineXTrans = (m_graphAspectRatio * m_areaSize.width()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineXTrans) lineXTrans = m_maxItemSize - gridLineOffset; - linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line #else - GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - linePos = -aspectRatio * m_scaleFactor; // Start line + GLfloat lineXTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset; #endif if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, 0.0f, linePos / m_scaleFactor); + modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); +#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; @@ -994,41 +1195,42 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos -= lineStep; +#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 // Floor lines + int gridLineCount = m_axisCacheX.gridLineCount(); + #ifndef USE_UNIFORM_SCALING - GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep(); - GLfloat linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); - int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor; + GLfloat zScale = (m_graphAspectRatio * m_areaSize.height()) / m_scaleFactor + + m_backgroundMargin; if (m_maxItemSize > zScale) zScale = m_maxItemSize; QVector3D gridLineScaler(gridLineWidth, gridLineWidth, zScale); #else - GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); - GLfloat linePos = -aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); QVector3D gridLineScaler(gridLineWidth, gridLineWidth, - aspectRatio * m_backgroundMargin); + m_graphAspectRatio + m_backgroundMargin); #endif - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos / m_scaleFactor, yFloorLinePosition, 0.0f); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition, + 0.0f); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1051,45 +1253,48 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos += lineStep; +#else + m_drawer->drawLine(lineShader); +#endif } // Back wall lines #ifndef USE_UNIFORM_SCALING - GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor - gridLineOffset; + GLfloat lineZTrans = (m_graphAspectRatio * m_areaSize.height()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineZTrans) lineZTrans = m_maxItemSize - gridLineOffset; - linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); #else - GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - linePos = -aspectRatio * m_scaleFactor; + GLfloat lineZTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset; #endif if (!m_zFlipped) lineZTrans = -lineZTrans; - gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth); + gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos / m_scaleFactor, 0.0f, lineZTrans); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); +#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 MVPMatrix = projectionViewMatrix * modelMatrix; @@ -1106,46 +1311,45 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos += lineStep; +#else + m_drawer->drawLine(lineShader); +#endif } } // Horizontal wall lines if (m_axisCacheY.segmentCount() > 0) { // Back wall - GLfloat lineStep = m_axisCacheY.subSegmentStep(); - GLfloat linePos = m_axisCacheY.min() - m_translationOffset.y(); - int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + int gridLineCount = m_axisCacheY.gridLineCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor - gridLineOffset; + GLfloat lineZTrans = (m_graphAspectRatio * m_areaSize.height()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineZTrans) lineZTrans = m_maxItemSize - gridLineOffset; - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; + GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor + + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth); #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - QVector3D gridLineScaler((aspectRatio * m_backgroundMargin), + GLfloat lineZTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset; + QVector3D gridLineScaler((m_graphAspectRatio + m_backgroundMargin), gridLineWidth, gridLineWidth); #endif if (!m_zFlipped) lineZTrans = -lineZTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, linePos / m_heightNormalizer, lineZTrans); + modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), lineZTrans); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1170,42 +1374,40 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos += lineStep; +#else + m_drawer->drawLine(lineShader); +#endif } // Side wall - linePos = m_axisCacheY.min() - m_translationOffset.y(); - lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor - gridLineOffset; + GLfloat lineXTrans = (m_graphAspectRatio * m_areaSize.width()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineXTrans) lineXTrans = m_maxItemSize - gridLineOffset; - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat zScale = (m_graphAspectRatio * m_areaSize.height()) + / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > zScale) zScale = m_maxItemSize; gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, zScale); #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset; + GLfloat lineXTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset; gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, - aspectRatio * m_backgroundMargin); + m_graphAspectRatio + m_backgroundMargin); #endif if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, linePos / m_heightNormalizer, 0.0f); + modelMatrix.translate(lineXTrans, m_axisCacheY.gridLinePosition(line), 0.0f); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1228,328 +1430,478 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); - } else -#endif - { + } else { // Draw the object m_drawer->drawObject(lineShader, m_gridLineObj); } - linePos += lineStep; +#else + m_drawer->drawLine(lineShader); +#endif + } + } + } + + Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix, + projectionViewMatrix, depthProjectionViewMatrix, + m_depthTexture, m_shadowQualityToShader); + + drawLabels(false, activeCamera, viewMatrix, projectionMatrix); + + // Handle selection clearing and selection label drawing + if (!dotSelectionFound) { + // We have no ownership, don't delete. Just NULL the pointer. + m_selectedItem = NULL; + } else { + glDisable(GL_DEPTH_TEST); + // Draw the selection label + LabelItem &labelItem = selectionLabelItem(); + if (m_selectedItem != selectedItem || m_updateLabels + || !labelItem.textureId() || m_selectionLabelDirty) { + QString labelText = selectionLabel(); + if (labelText.isNull() || m_selectionLabelDirty) { + labelText = m_selectedSeriesCache->itemLabel(); + setSelectionLabel(labelText); + m_selectionLabelDirty = false; } + m_drawer->generateLabelItem(labelItem, labelText); + m_selectedItem = selectedItem; } + + m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix, + zeroVector, identityQuaternion, selectedItemSize, m_cachedSelectionMode, + m_labelShader, m_labelObj, activeCamera, true, false, + Drawer::LabelOver); + + // Reset label update flag; they should have been updated when we get here + m_updateLabels = false; + glEnable(GL_DEPTH_TEST); } - // Draw axis labels - // Bind label shader - m_labelShader->bind(); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // Release shader + glUseProgram(0); + + m_selectionDirty = false; +} + +void Scatter3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCamera, + const QMatrix4x4 &viewMatrix, + const QMatrix4x4 &projectionMatrix) { + ShaderHelper *shader = 0; + GLfloat alphaForValueSelection = labelValueAlpha / 255.0f; + GLfloat alphaForRowSelection = labelRowAlpha / 255.0f; + GLfloat alphaForColumnSelection = labelColumnAlpha / 255.0f; + if (drawSelection) { + shader = m_selectionShader; + // m_selectionShader is already bound + } else { + shader = m_labelShader; + shader->bind(); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_POLYGON_OFFSET_FILL); + float labelAutoAngle = m_axisCacheZ.labelAutoRotation(); + float labelAngleFraction = labelAutoAngle / 90.0f; + float fractionCamY = activeCamera->yRotation() * labelAngleFraction; + float fractionCamX = activeCamera->xRotation() * labelAngleFraction; + float labelsMaxWidth = 0.0f; + + int startIndex; + int endIndex; + int indexStep; + // Z Labels if (m_axisCacheZ.segmentCount() > 0) { + int labelCount = m_axisCacheZ.labelCount(); #ifndef USE_UNIFORM_SCALING - GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep(); - GLfloat labelPos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); - int lastSegment = m_axisCacheZ.segmentCount(); - GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor + labelMargin; + GLfloat labelXTrans = (m_graphAspectRatio * m_areaSize.width()) + / m_scaleFactor + labelMargin + m_backgroundMargin; if (m_maxItemSize > labelXTrans) labelXTrans = m_maxItemSize + labelMargin; #else - GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); - GLfloat labelPos = aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->segmentCount(); - GLfloat labelXTrans = aspectRatio * m_backgroundMargin + labelMargin; + GLfloat labelXTrans = m_graphAspectRatio + m_backgroundMargin + labelMargin; #endif - int labelNbr = 0; - GLfloat labelYTrans = -m_backgroundMargin; - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 0.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignRight; - if (m_zFlipped) - rotLabelY = 180.0f; - if (m_xFlipped) { + GLfloat labelYTrans = -1.0f - m_backgroundMargin; + Qt::AlignmentFlag alignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; + QVector3D labelRotation; + if (m_xFlipped) labelXTrans = -labelXTrans; - alignment = Qt::AlignLeft; - } - if (m_yFlipped) { - rotLabelZ += 180.0f; - rotLabelY += 180.0f; + if (m_yFlipped) labelYTrans = -labelYTrans; + if (labelAutoAngle == 0.0f) { + labelRotation.setX(-90.0f); + if (m_zFlipped) + labelRotation.setY(180.0f); + if (m_yFlipped) { + if (m_zFlipped) + labelRotation.setY(0.0f); + else + labelRotation.setY(180.0f); + labelRotation.setZ(180.0f); + } + } else { + if (m_zFlipped) + labelRotation.setY(180.0f); + if (m_yFlipped) { + if (m_zFlipped) { + if (m_xFlipped) { + labelRotation.setX(90.0f - (labelAutoAngle - fractionCamX) + * (-labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle + fractionCamY); + } else { + labelRotation.setX(90.0f + (labelAutoAngle + fractionCamX) + * (labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle - fractionCamY); + } + } else { + if (m_xFlipped) { + labelRotation.setX(90.0f + (labelAutoAngle - fractionCamX) + * -(labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle - fractionCamY); + } else { + labelRotation.setX(90.0f - (labelAutoAngle + fractionCamX) + * (labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle + fractionCamY); + } + } + } else { + if (m_zFlipped) { + if (m_xFlipped) { + labelRotation.setX(-90.0f + (labelAutoAngle - fractionCamX) + * (-labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle + fractionCamY); + } else { + labelRotation.setX(-90.0f - (labelAutoAngle + fractionCamX) + * (labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle - fractionCamY); + } + } else { + if (m_xFlipped) { + labelRotation.setX(-90.0f - (labelAutoAngle - fractionCamX) + * (-labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle - fractionCamY); + } else { + labelRotation.setX(-90.0f + (labelAutoAngle + fractionCamX) + * (labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle + fractionCamY); + } + } + } } - QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ); + QQuaternion totalRotation = Utils::calculateRotation(labelRotation); QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, 0.0f); - for (int segment = 0; segment <= lastSegment; segment++) { -#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - if (m_axisCacheZ.labelItems().size() > labelNbr) { -#else // ..and this if we want uniform scaling based on largest dimension - if (axisCacheMax->labelItems().size() > labelNbr) { -#endif - labelTrans.setZ(labelPos / m_scaleFactor); + if (m_zFlipped) { + startIndex = 0; + endIndex = labelCount; + indexStep = 1; + } else { + startIndex = labelCount - 1; + endIndex = -1; + indexStep = -1; + } + for (int label = startIndex; label != endIndex; label = label + indexStep) { + labelTrans.setZ(m_axisCacheZ.labelPosition(label)); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); - // Draw the label here - m_dummyRenderItem.setTranslation(labelTrans); -#ifndef USE_UNIFORM_SCALING - const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); -#else - const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); -#endif + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(label); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - zeroVector, labelRotateVector, 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, activeCamera, true, true, - Drawer::LabelMid, alignment); + if (drawSelection) { + QVector4D labelColor = QVector4D(label / 255.0f, 0.0f, 0.0f, + alphaForRowSelection); + shader->setUniformValue(shader->color(), labelColor); } - labelNbr++; - labelPos -= posStep; + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + zeroVector, totalRotation, 0, m_cachedSelectionMode, + shader, m_labelObj, activeCamera, true, true, + Drawer::LabelMid, alignment, false, drawSelection); + labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width())); + } + if (!drawSelection && m_axisCacheZ.isTitleVisible()) { + labelTrans.setZ(0.0f); + drawAxisTitleZ(labelRotation, labelTrans, totalRotation, m_dummyRenderItem, + activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader); } } + // X Labels if (m_axisCacheX.segmentCount() > 0) { + labelsMaxWidth = 0.0f; + labelAutoAngle = m_axisCacheX.labelAutoRotation(); + labelAngleFraction = labelAutoAngle / 90.0f; + fractionCamY = activeCamera->yRotation() * labelAngleFraction; + fractionCamX = activeCamera->xRotation() * labelAngleFraction; + int labelCount = m_axisCacheX.labelCount(); #ifndef USE_UNIFORM_SCALING - GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep(); - GLfloat labelPos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); - int lastSegment = m_axisCacheX.segmentCount(); - GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor + labelMargin; + GLfloat labelZTrans = (m_graphAspectRatio * m_areaSize.height()) + / m_scaleFactor + labelMargin + m_backgroundMargin; if (m_maxItemSize > labelZTrans) labelZTrans = m_maxItemSize + labelMargin; #else - GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); - GLfloat labelPos = -aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->segmentCount(); - GLfloat labelZTrans = aspectRatio * m_backgroundMargin + labelMargin; + GLfloat labelZTrans = m_graphAspectRatio + m_backgroundMargin + labelMargin; #endif - int labelNbr = 0; - GLfloat labelYTrans = -m_backgroundMargin; - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 90.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignLeft; - if (m_xFlipped) - rotLabelY = -90.0f; - if (m_zFlipped) { + GLfloat labelYTrans = -1.0f - m_backgroundMargin; + Qt::AlignmentFlag alignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; + QVector3D labelRotation; + if (m_zFlipped) labelZTrans = -labelZTrans; - alignment = Qt::AlignRight; - } - if (m_yFlipped) { - rotLabelZ += 180.0f; - rotLabelY += 180.0f; + if (m_yFlipped) labelYTrans = -labelYTrans; + if (labelAutoAngle == 0.0f) { + labelRotation = QVector3D(-90.0f, 90.0f, 0.0f); + if (m_xFlipped) + labelRotation.setY(-90.0f); + if (m_yFlipped) { + if (m_xFlipped) + labelRotation.setY(90.0f); + else + labelRotation.setY(-90.0f); + labelRotation.setZ(180.0f); + } + } else { + if (m_xFlipped) + labelRotation.setY(-90.0f); + else + labelRotation.setY(90.0f); + if (m_yFlipped) { + if (m_zFlipped) { + if (m_xFlipped) { + labelRotation.setX(90.0f - (2.0f * labelAutoAngle - fractionCamX) + * (labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle - fractionCamY); + } else { + labelRotation.setX(90.0f - (2.0f * labelAutoAngle + fractionCamX) + * (labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle + fractionCamY); + } + } else { + if (m_xFlipped) { + labelRotation.setX(90.0f + fractionCamX + * -(labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle + fractionCamY); + } else { + labelRotation.setX(90.0f - fractionCamX + * (-labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle - fractionCamY); + } + } + } else { + if (m_zFlipped) { + if (m_xFlipped) { + labelRotation.setX(-90.0f + (2.0f * labelAutoAngle - fractionCamX) + * (labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle - fractionCamY); + } else { + labelRotation.setX(-90.0f + (2.0f * labelAutoAngle + fractionCamX) + * (labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle + fractionCamY); + } + } else { + if (m_xFlipped) { + labelRotation.setX(-90.0f - fractionCamX + * (-labelAutoAngle + fractionCamY) / labelAutoAngle); + labelRotation.setZ(-labelAutoAngle + fractionCamY); + } else { + labelRotation.setX(-90.0f + fractionCamX + * -(labelAutoAngle - fractionCamY) / labelAutoAngle); + labelRotation.setZ(labelAutoAngle - fractionCamY); + } + } + } } - QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ); + + QQuaternion totalRotation = Utils::calculateRotation(labelRotation); QVector3D labelTrans = QVector3D(0.0f, labelYTrans, labelZTrans); - for (int segment = 0; segment <= lastSegment; segment++) { -#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - if (m_axisCacheX.labelItems().size() > labelNbr) { -#else // ..and this if we want uniform scaling based on largest dimension - if (axisCacheMax->labelItems().size() > labelNbr) { -#endif - labelTrans.setX(labelPos / m_scaleFactor); + if (m_xFlipped) { + startIndex = labelCount - 1; + endIndex = -1; + indexStep = -1; + } else { + startIndex = 0; + endIndex = labelCount; + indexStep = 1; + } + for (int label = startIndex; label != endIndex; label = label + indexStep) { + labelTrans.setX(m_axisCacheX.labelPosition(label)); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); - // Draw the label here - m_dummyRenderItem.setTranslation(labelTrans); -#ifndef USE_UNIFORM_SCALING - const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); -#else - const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); -#endif + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(label); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - zeroVector, labelRotateVector, 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, activeCamera, true, true, - Drawer::LabelMid, alignment); + if (drawSelection) { + QVector4D labelColor = QVector4D(0.0f, label / 255.0f, 0.0f, + alphaForColumnSelection); + shader->setUniformValue(shader->color(), labelColor); } - labelNbr++; - labelPos += posStep; + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + zeroVector, totalRotation, 0, m_cachedSelectionMode, + shader, m_labelObj, activeCamera, true, true, + Drawer::LabelMid, alignment, false, drawSelection); + labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width())); + } + if (!drawSelection && m_axisCacheX.isTitleVisible()) { + labelTrans.setX(0.0f); + drawAxisTitleX(labelRotation, labelTrans, totalRotation, m_dummyRenderItem, + activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader); } } + // Y Labels if (m_axisCacheY.segmentCount() > 0) { - GLfloat posStep = m_axisCacheY.segmentStep(); - GLfloat labelPos = m_axisCacheY.min() - m_translationOffset.y(); - int labelNbr = 0; + labelsMaxWidth = 0.0f; + labelAutoAngle = m_axisCacheY.labelAutoRotation(); + labelAngleFraction = labelAutoAngle / 90.0f; + fractionCamY = activeCamera->yRotation() * labelAngleFraction; + fractionCamX = activeCamera->xRotation() * labelAngleFraction; + int labelCount = m_axisCacheY.labelCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor; - GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat labelXTrans = (m_graphAspectRatio* m_areaSize.width()) + / m_scaleFactor + m_backgroundMargin; + GLfloat labelZTrans = (m_graphAspectRatio * m_areaSize.height()) + / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > labelXTrans) labelXTrans = m_maxItemSize; if (m_maxItemSize > labelZTrans) labelZTrans = m_maxItemSize; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat labelXTrans = aspectRatio * m_backgroundMargin; + GLfloat labelXTrans = m_graphAspectRatio + m_backgroundMargin; GLfloat labelZTrans = labelXTrans; #endif - // Back wall init + // Back & side wall GLfloat labelMarginXTrans = labelMargin; GLfloat labelMarginZTrans = labelMargin; - GLfloat rotLabelX = 0.0f; - GLfloat rotLabelY = -90.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignmentBack = Qt::AlignLeft; + QVector3D backLabelRotation(0.0f, -90.0f, 0.0f); + QVector3D sideLabelRotation(0.0f, 0.0f, 0.0f); + Qt::AlignmentFlag backAlignment = + (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; + Qt::AlignmentFlag sideAlignment = + (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight; if (!m_xFlipped) { labelXTrans = -labelXTrans; labelMarginXTrans = -labelMargin; - rotLabelY = 90.0f; } if (m_zFlipped) { labelZTrans = -labelZTrans; labelMarginZTrans = -labelMargin; - alignmentBack = Qt::AlignRight; } - QVector3D labelRotateVectorBack(rotLabelX, rotLabelY, rotLabelZ); - QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans); + if (labelAutoAngle == 0.0f) { + if (!m_xFlipped) + backLabelRotation.setY(90.0f); + if (m_zFlipped) + sideLabelRotation.setY(180.f); + } else { + // Orient side labels somewhat towards the camera + if (m_xFlipped) { + if (m_zFlipped) + sideLabelRotation.setY(180.0f + (2.0f * labelAutoAngle) - fractionCamX); + else + sideLabelRotation.setY(-fractionCamX); + backLabelRotation.setY(-90.0f + labelAutoAngle - fractionCamX); + } else { + if (m_zFlipped) + sideLabelRotation.setY(180.0f - (2.0f * labelAutoAngle) - fractionCamX); + else + sideLabelRotation.setY(-fractionCamX); + backLabelRotation.setY(90.0f - labelAutoAngle - fractionCamX); + } + } + sideLabelRotation.setX(-fractionCamY); + backLabelRotation.setX(-fractionCamY); - // Side wall init - Qt::AlignmentFlag alignmentSide = Qt::AlignLeft; - if (m_xFlipped) - alignmentSide = Qt::AlignLeft; - else - alignmentSide = Qt::AlignRight; - if (m_zFlipped) - rotLabelY = 180.0f; - else - rotLabelY = 0.0f; + QQuaternion totalSideRotation = Utils::calculateRotation(sideLabelRotation); + QQuaternion totalBackRotation = Utils::calculateRotation(backLabelRotation); - QVector3D labelRotateVectorSide(rotLabelX, rotLabelY, rotLabelZ); + QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans); QVector3D labelTransSide(-labelXTrans - labelMarginXTrans, 0.0f, -labelZTrans); - for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { - if (m_axisCacheY.labelItems().size() > labelNbr) { - const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); - const GLfloat labelYTrans = labelPos / m_heightNormalizer; - - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); - - // Back wall - labelTransBack.setY(labelYTrans); - m_dummyRenderItem.setTranslation(labelTransBack); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - zeroVector, labelRotateVectorBack, 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, activeCamera, true, true, - Drawer::LabelMid, alignmentBack); - - // Side wall - labelTransSide.setY(labelYTrans); - m_dummyRenderItem.setTranslation(labelTransSide); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - zeroVector, labelRotateVectorSide, 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, activeCamera, true, true, - Drawer::LabelMid, alignmentSide); - } - labelNbr++; - labelPos += posStep; + if (m_yFlipped) { + startIndex = labelCount - 1; + endIndex = -1; + indexStep = -1; + } else { + startIndex = 0; + endIndex = labelCount; + indexStep = 1; } - } - glDisable(GL_POLYGON_OFFSET_FILL); + for (int label = startIndex; label != endIndex; label = label + indexStep) { + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(label); + const GLfloat labelYTrans = m_axisCacheY.labelPosition(label); - // Handle selection clearing and selection label drawing - if (!dotSelectionFound) { - // We have no ownership, don't delete. Just NULL the pointer. - m_selectedItem = NULL; - } else { - glDisable(GL_DEPTH_TEST); - // Draw the selection label - LabelItem &labelItem = selectionLabelItem(); - if (m_selectedItem != selectedItem || m_updateLabels - || !labelItem.textureId() || m_selectionLabelDirty) { - QString labelText = selectionLabel(); - if (labelText.isNull() || m_selectionLabelDirty) { - static const QString xTitleTag(QStringLiteral("@xTitle")); - static const QString yTitleTag(QStringLiteral("@yTitle")); - static const QString zTitleTag(QStringLiteral("@zTitle")); - static const QString xLabelTag(QStringLiteral("@xLabel")); - static const QString yLabelTag(QStringLiteral("@yLabel")); - static const QString zLabelTag(QStringLiteral("@zLabel")); - static const QString seriesNameTag(QStringLiteral("@seriesName")); - - labelText = m_visibleSeriesList[m_selectedItemSeriesIndex].itemLabelFormat(); - - labelText.replace(xTitleTag, m_axisCacheX.title()); - labelText.replace(yTitleTag, m_axisCacheY.title()); - labelText.replace(zTitleTag, m_axisCacheZ.title()); - - if (labelText.contains(xLabelTag)) { - QString labelFormat = m_axisCacheX.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().x()); - labelText.replace(xLabelTag, valueLabelText); - } - if (labelText.contains(yLabelTag)) { - QString labelFormat = m_axisCacheY.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().y()); - labelText.replace(yLabelTag, valueLabelText); - } - if (labelText.contains(zLabelTag)) { - QString labelFormat = m_axisCacheZ.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().z()); - labelText.replace(zLabelTag, valueLabelText); - } - labelText.replace(seriesNameTag, m_visibleSeriesList[m_selectedItemSeriesIndex].name()); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); - setSelectionLabel(labelText); - m_selectionLabelDirty = false; + if (drawSelection) { + QVector4D labelColor = QVector4D(0.0f, 0.0f, label / 255.0f, + alphaForValueSelection); + shader->setUniformValue(shader->color(), labelColor); } - m_drawer->generateLabelItem(labelItem, labelText); - m_selectedItem = selectedItem; - } - m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix, - zeroVector, zeroVector, selectedItemSize, m_cachedSelectionMode, - m_labelShader, m_labelObj, activeCamera, true, false, - Drawer::LabelOver); + // Back wall + labelTransBack.setY(labelYTrans); + m_dummyRenderItem.setTranslation(labelTransBack); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + zeroVector, totalBackRotation, 0, m_cachedSelectionMode, + shader, m_labelObj, activeCamera, true, true, + Drawer::LabelMid, backAlignment, false, drawSelection); - // Reset label update flag; they should have been updated when we get here - m_updateLabels = false; - glEnable(GL_DEPTH_TEST); + // Side wall + labelTransSide.setY(labelYTrans); + m_dummyRenderItem.setTranslation(labelTransSide); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + zeroVector, totalSideRotation, 0, m_cachedSelectionMode, + shader, m_labelObj, activeCamera, true, true, + Drawer::LabelMid, sideAlignment, false, drawSelection); + labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width())); + } + if (!drawSelection && m_axisCacheY.isTitleVisible()) { + labelTransSide.setY(0.0f); + labelTransBack.setY(0.0f); + drawAxisTitleY(sideLabelRotation, backLabelRotation, labelTransSide, labelTransBack, + totalSideRotation, totalBackRotation, m_dummyRenderItem, activeCamera, + labelsMaxWidth, viewMatrix, projectionMatrix, + shader); + } } - - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - // Release shader - glUseProgram(0); - - m_selectionDirty = false; + glDisable(GL_POLYGON_OFFSET_FILL); } -void Scatter3DRenderer::updateSelectedItem(int index, const QScatter3DSeries *series) +void Scatter3DRenderer::updateSelectedItem(int index, QScatter3DSeries *series) { m_selectionDirty = true; m_selectionLabelDirty = true; - m_selectedSeries = series; + m_selectedSeriesCache = + static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(series, 0)); m_selectedItemIndex = Scatter3DController::invalidSelectionIndex(); - m_selectedItemTotalIndex = Scatter3DController::invalidSelectionIndex(); - m_selectedItemSeriesIndex = Scatter3DController::invalidSelectionIndex(); - if (!m_renderingArrays.isEmpty() && index != Scatter3DController::invalidSelectionIndex()) { - int totalIndex = 0; - for (int i = 0; i < m_visibleSeriesList.size(); i++) { - if (m_visibleSeriesList.at(i).series() == series) { - m_selectedItemSeriesIndex = i; - m_selectedItemIndex = index; - m_selectedItemTotalIndex = index + totalIndex; - break; + if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic) + && m_oldSelectedSeriesCache + && m_oldSelectedSeriesCache->mesh() == QAbstract3DSeries::MeshPoint) { + m_oldSelectedSeriesCache->bufferPoints()->popPoint(); + m_oldSelectedSeriesCache = 0; + } + + if (m_selectedSeriesCache) { + const ScatterRenderItemArray &renderArray = m_selectedSeriesCache->renderArray(); + if (index < renderArray.size() && index >= 0) { + m_selectedItemIndex = index; + + if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic) + && m_selectedSeriesCache->mesh() == QAbstract3DSeries::MeshPoint) { + m_selectedSeriesCache->bufferPoints()->pushPoint(m_selectedItemIndex); + m_oldSelectedSeriesCache = m_selectedSeriesCache; } - totalIndex += m_renderingArrays.at(i).size(); } } } @@ -1598,26 +1950,8 @@ void Scatter3DRenderer::updateShadowQuality(QAbstract3DGraph::ShadowQuality qual void Scatter3DRenderer::loadBackgroundMesh() { - if (m_backgroundObj) - delete m_backgroundObj; - m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); - m_backgroundObj->load(); -} - -void Scatter3DRenderer::loadGridLineMesh() -{ - if (m_gridLineObj) - delete m_gridLineObj; - m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane")); - m_gridLineObj->load(); -} - -void Scatter3DRenderer::loadLabelMesh() -{ - if (m_labelObj) - delete m_labelObj; - m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane")); - m_labelObj->load(); + ObjectHelper::resetObjectHelper(this, m_backgroundObj, + QStringLiteral(":/defaultMeshes/background")); } void Scatter3DRenderer::updateTextures() @@ -1640,11 +1974,10 @@ void Scatter3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Me void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item) { // We need to normalize translations - GLfloat xTrans = (aspectRatio * (item.position().x() - m_translationOffset.x())) - / m_scaleFactor; - GLfloat zTrans = -(aspectRatio * (item.position().z() - m_translationOffset.z())) - / m_scaleFactor; - GLfloat yTrans = (item.position().y() - m_translationOffset.y()) / m_heightNormalizer; + const QVector3D &pos = item.position(); + float xTrans = m_axisCacheX.positionAt(pos.x()); + float yTrans = m_axisCacheY.positionAt(pos.y()); + float zTrans = m_axisCacheZ.positionAt(pos.z()); item.setTranslation(QVector3D(xTrans, yTrans, zTrans)); } @@ -1655,10 +1988,16 @@ void Scatter3DRenderer::calculateSceneScalingFactors() m_areaSize.setWidth((m_axisCacheX.max() - m_axisCacheX.min()) / 2.0f); m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); - // Calculate translation offsets - m_translationOffset = QVector3D((m_axisCacheX.max() + m_axisCacheX.min()) / 2.0f, - (m_axisCacheY.max() + m_axisCacheY.min()) / 2.0f, - (m_axisCacheZ.max() + m_axisCacheZ.min()) / 2.0f); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + float factorScaler = 2.0f * m_graphAspectRatio / m_scaleFactor; + m_axisCacheX.setScale(factorScaler * m_areaSize.width()); + m_axisCacheZ.setScale(-factorScaler * m_areaSize.height()); +#else // ..and this if we want uniform scaling based on largest dimension + m_axisCacheX.setScale(2.0f * m_graphAspectRatio); + m_axisCacheZ.setScale(-m_axisCacheX.scale()); +#endif + m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f); + m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f); } void Scatter3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader) @@ -1689,10 +2028,7 @@ void Scatter3DRenderer::initSelectionShader() void Scatter3DRenderer::initSelectionBuffer() { - if (m_selectionTexture) { - m_textureHelper->deleteTexture(&m_selectionTexture); - m_selectionTexture = 0; - } + m_textureHelper->deleteTexture(&m_selectionTexture); if (m_primarySubViewport.size().isEmpty()) return; @@ -1714,10 +2050,7 @@ void Scatter3DRenderer::initDepthShader() void Scatter3DRenderer::updateDepthBuffer() { - if (m_depthTexture) { - m_textureHelper->deleteTexture(&m_depthTexture); - m_depthTexture = 0; - } + m_textureHelper->deleteTexture(&m_depthTexture); if (m_primarySubViewport.size().isEmpty()) return; @@ -1758,30 +2091,54 @@ void Scatter3DRenderer::initLabelShaders(const QString &vertexShader, const QStr m_labelShader->initialize(); } -QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index) -{ - GLubyte dotIdxRed = index & 0xff; - GLubyte dotIdxGreen = (index & 0xff00) >> 8; - GLubyte dotIdxBlue = (index & 0xff0000) >> 16; - - return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue); -} - -void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector3D &color, +void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector4D &color, int &index, QAbstract3DSeries *&series) { + m_clickedType = QAbstract3DGraph::ElementNone; + m_selectedLabelIndex = -1; + m_selectedCustomItemIndex = -1; if (color != selectionSkipColor) { - index = int(color.x()) - + (int(color.y()) << 8) - + (int(color.z()) << 16); - // Find the series and adjust the index accordingly - for (int i = 0; i < m_renderingArrays.size(); i++) { - if (index < m_renderingArrays.at(i).size()) { - series = m_visibleSeriesList.at(i).series(); - return; // Valid found and already set to return parameters, so we can return - } else { - index -= m_renderingArrays.at(i).size(); + if (color.w() == labelRowAlpha) { + // Row selection + index = Scatter3DController::invalidSelectionIndex(); + m_selectedLabelIndex = color.x(); + m_clickedType = QAbstract3DGraph::ElementAxisZLabel; + } else if (color.w() == labelColumnAlpha) { + // Column selection + index = Scatter3DController::invalidSelectionIndex(); + m_selectedLabelIndex = color.y(); + m_clickedType = QAbstract3DGraph::ElementAxisXLabel; + } else if (color.w() == labelValueAlpha) { + // Value selection + index = Scatter3DController::invalidSelectionIndex(); + m_selectedLabelIndex = color.z(); + m_clickedType = QAbstract3DGraph::ElementAxisYLabel; + } else if (color.w() == customItemAlpha) { + // Custom item selection + index = Scatter3DController::invalidSelectionIndex(); + m_selectedCustomItemIndex = int(color.x()) + + (int(color.y()) << 8) + + (int(color.z()) << 16); + m_clickedType = QAbstract3DGraph::ElementCustomItem; + } else { + int totalIndex = int(color.x()) + + (int(color.y()) << 8) + + (int(color.z()) << 16); + // Find the series and adjust the index accordingly + foreach (SeriesRenderCache *baseCache, m_renderCacheList) { + if (baseCache->isVisible()) { + ScatterSeriesRenderCache *cache = + static_cast<ScatterSeriesRenderCache *>(baseCache); + int offset = cache->selectionIndexOffset(); + if (totalIndex >= offset + && totalIndex < (offset + cache->renderArray().size())) { + index = totalIndex - offset; + series = cache->series(); + m_clickedType = QAbstract3DGraph::ElementSeries; + return; + } + } } } } @@ -1791,4 +2148,41 @@ void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector3D &color, series = 0; } +void Scatter3DRenderer::updateRenderItem(const QScatterDataItem &dataItem, + ScatterRenderItem &renderItem) +{ + QVector3D dotPos = dataItem.position(); + if ((dotPos.x() >= m_axisCacheX.min() && dotPos.x() <= m_axisCacheX.max() ) + && (dotPos.y() >= m_axisCacheY.min() && dotPos.y() <= m_axisCacheY.max()) + && (dotPos.z() >= m_axisCacheZ.min() && dotPos.z() <= m_axisCacheZ.max())) { + renderItem.setPosition(dotPos); + renderItem.setVisible(true); + if (!dataItem.rotation().isIdentity()) + renderItem.setRotation(dataItem.rotation().normalized()); + else + renderItem.setRotation(identityQuaternion); + calculateTranslation(renderItem); + } else { + renderItem.setVisible(false); + } +} + +QVector3D Scatter3DRenderer::convertPositionToTranslation(const QVector3D &position, + bool isAbsolute) +{ + float xTrans = 0.0f; + float yTrans = 0.0f; + float zTrans = 0.0f; + if (!isAbsolute) { + xTrans = m_axisCacheX.positionAt(position.x()); + yTrans = m_axisCacheY.positionAt(position.y()); + zTrans = m_axisCacheZ.positionAt(position.z()); + } else { + xTrans = position.x() * m_axisCacheX.scale() / 2.0f; + yTrans = position.y(); + zTrans = position.z() * m_axisCacheZ.scale() / 2.0f; + } + return QVector3D(xTrans, yTrans, zTrans); +} + QT_END_NAMESPACE_DATAVISUALIZATION |