From e26bc838a8b2a5c6ce5013992a81c4b9ad040514 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 22 Aug 2013 13:02:38 +0300 Subject: Add selection signaling for scatter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Fix crashes associated with selection + Optimized selection color handling Task-number: QTRD-2132 Task-number: QTRD-2208 Change-Id: Ie38c6779591fb0467cffb052edf7609f6677278a Reviewed-by: Tomi Korpipää --- src/datavis3d/data/abstractrenderitem.cpp | 7 ++ src/datavis3d/data/abstractrenderitem_p.h | 1 + src/datavis3d/data/barrenderitem.cpp | 11 ++ src/datavis3d/data/barrenderitem_p.h | 1 + src/datavis3d/data/maprenderitem.cpp | 8 ++ src/datavis3d/data/maprenderitem_p.h | 1 + src/datavis3d/data/scatterrenderitem.cpp | 10 +- src/datavis3d/data/scatterrenderitem_p.h | 17 ++- src/datavis3d/engine/bars3drenderer.cpp | 38 +++---- src/datavis3d/engine/bars3drenderer_p.h | 3 +- src/datavis3d/engine/q3dscatter.cpp | 18 ++++ src/datavis3d/engine/q3dscatter.h | 5 + src/datavis3d/engine/scatter3dcontroller.cpp | 42 +++++++- src/datavis3d/engine/scatter3dcontroller_p.h | 11 +- src/datavis3d/engine/scatter3drenderer.cpp | 155 +++++++++++---------------- src/datavis3d/engine/scatter3drenderer_p.h | 13 ++- 16 files changed, 216 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/src/datavis3d/data/abstractrenderitem.cpp b/src/datavis3d/data/abstractrenderitem.cpp index b97ea79e..296cebb4 100644 --- a/src/datavis3d/data/abstractrenderitem.cpp +++ b/src/datavis3d/data/abstractrenderitem.cpp @@ -25,6 +25,13 @@ AbstractRenderItem::AbstractRenderItem() { } +AbstractRenderItem::AbstractRenderItem(const AbstractRenderItem &other) +{ + m_selectionLabel = other.m_selectionLabel; + m_translation = other.m_translation; + m_selectionLabelItem = 0; +} + AbstractRenderItem::~AbstractRenderItem() { delete m_selectionLabelItem; diff --git a/src/datavis3d/data/abstractrenderitem_p.h b/src/datavis3d/data/abstractrenderitem_p.h index 669ba200..becacbe5 100644 --- a/src/datavis3d/data/abstractrenderitem_p.h +++ b/src/datavis3d/data/abstractrenderitem_p.h @@ -42,6 +42,7 @@ class AbstractRenderItem { public: AbstractRenderItem(); + AbstractRenderItem(const AbstractRenderItem &other); virtual ~AbstractRenderItem(); // Position in 3D scene diff --git a/src/datavis3d/data/barrenderitem.cpp b/src/datavis3d/data/barrenderitem.cpp index 8cfb97d2..3530704b 100644 --- a/src/datavis3d/data/barrenderitem.cpp +++ b/src/datavis3d/data/barrenderitem.cpp @@ -29,6 +29,17 @@ BarRenderItem::BarRenderItem() { } +BarRenderItem::BarRenderItem(const BarRenderItem &other) + : AbstractRenderItem(other) +{ + m_renderer = other.m_renderer; + m_value = other.m_value; + m_position = other.m_position; + m_height = other.m_height; + m_sliceLabel = other.m_sliceLabel; + m_sliceLabelItem = 0; +} + BarRenderItem::~BarRenderItem() { delete m_sliceLabelItem; diff --git a/src/datavis3d/data/barrenderitem_p.h b/src/datavis3d/data/barrenderitem_p.h index d90c7e04..0b7dc639 100644 --- a/src/datavis3d/data/barrenderitem_p.h +++ b/src/datavis3d/data/barrenderitem_p.h @@ -39,6 +39,7 @@ class BarRenderItem : public AbstractRenderItem { public: BarRenderItem(); + BarRenderItem(const BarRenderItem &other); virtual ~BarRenderItem(); // Position relative to data window (for bar label generation) diff --git a/src/datavis3d/data/maprenderitem.cpp b/src/datavis3d/data/maprenderitem.cpp index 062898aa..d737e6f6 100644 --- a/src/datavis3d/data/maprenderitem.cpp +++ b/src/datavis3d/data/maprenderitem.cpp @@ -28,6 +28,14 @@ MapRenderItem::MapRenderItem() { } +MapRenderItem::MapRenderItem(const MapRenderItem &other) + : BarRenderItem(other) +{ + m_renderer = other.m_renderer; + m_mapPosition = other.m_mapPosition; + m_itemLabel = other.m_itemLabel; +} + MapRenderItem::~MapRenderItem() { } diff --git a/src/datavis3d/data/maprenderitem_p.h b/src/datavis3d/data/maprenderitem_p.h index f3674ec5..f8f877af 100644 --- a/src/datavis3d/data/maprenderitem_p.h +++ b/src/datavis3d/data/maprenderitem_p.h @@ -40,6 +40,7 @@ class MapRenderItem : public BarRenderItem { public: MapRenderItem(); + MapRenderItem(const MapRenderItem &other); virtual ~MapRenderItem(); inline const QPointF &mapPosition() const { return m_mapPosition; } diff --git a/src/datavis3d/data/scatterrenderitem.cpp b/src/datavis3d/data/scatterrenderitem.cpp index a7238310..4e6fbe9b 100644 --- a/src/datavis3d/data/scatterrenderitem.cpp +++ b/src/datavis3d/data/scatterrenderitem.cpp @@ -23,10 +23,18 @@ QT_DATAVIS3D_BEGIN_NAMESPACE ScatterRenderItem::ScatterRenderItem() - : BarRenderItem() + : AbstractRenderItem(), + m_renderer(0) { } +ScatterRenderItem::ScatterRenderItem(const ScatterRenderItem &other) + : AbstractRenderItem(other) +{ + m_renderer = other.m_renderer; + m_position = other.m_position; +} + ScatterRenderItem::~ScatterRenderItem() { } diff --git a/src/datavis3d/data/scatterrenderitem_p.h b/src/datavis3d/data/scatterrenderitem_p.h index 4c9de38c..6fade03e 100644 --- a/src/datavis3d/data/scatterrenderitem_p.h +++ b/src/datavis3d/data/scatterrenderitem_p.h @@ -29,20 +29,21 @@ #ifndef SCATTERRENDERITEM_P_H #define SCATTERRENDERITEM_P_H -#include "barrenderitem_p.h" +#include "abstractrenderitem_p.h" QT_DATAVIS3D_BEGIN_NAMESPACE class Scatter3DRenderer; -class ScatterRenderItem : public BarRenderItem +class ScatterRenderItem : public AbstractRenderItem { public: ScatterRenderItem(); + ScatterRenderItem(const ScatterRenderItem &other); virtual ~ScatterRenderItem(); inline const QVector3D &position() const { return m_position; } - inline void setPosition(const QVector3D &pos) { m_position = pos; } + inline void setPosition(const QVector3D &pos); //inline void setSize(qreal size); //inline qreal size() const { return m_size; } @@ -59,6 +60,16 @@ protected: friend class QScatterDataItem; }; +void ScatterRenderItem::setPosition(const QVector3D &pos) +{ + if (m_position != pos) { + m_position = pos; + // Force reformatting on next access by setting label string to null string + if (!m_selectionLabel.isNull()) + setSelectionLabel(QString()); + } +} + typedef QVector ScatterRenderItemArray; QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/bars3drenderer.cpp b/src/datavis3d/engine/bars3drenderer.cpp index 17e1d098..049d9003 100644 --- a/src/datavis3d/engine/bars3drenderer.cpp +++ b/src/datavis3d/engine/bars3drenderer.cpp @@ -50,7 +50,6 @@ Bars3dRenderer::Bars3dRenderer(Bars3dController *controller) : Abstract3DRenderer(controller), m_controller(controller), m_selectedBar(0), - m_previouslySelectedBar(0), m_sliceSelection(0), m_sliceCache(0), m_sliceTitleItem(0), @@ -709,6 +708,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, // Draw bars bool barSelectionFound = false; + BarRenderItem *selectedBar(0); for (int row = startRow; row != stopRow; row += stepRow) { for (int bar = startBar; bar != stopBar; bar += stepBar) { BarRenderItem &item = m_renderItemArray[row][bar]; @@ -756,8 +756,8 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, lightStrength = m_cachedTheme.m_highlightLightStrength; // Insert position data into render item. We have no ownership, don't delete the previous one if (!m_cachedIsSlicingActivated) { - m_selectedBar = &item; - m_selectedBar->setPosition(QPoint(row, bar)); + selectedBar = &item; + selectedBar->setPosition(QPoint(row, bar)); item.setTranslation(modelMatrix.column(3).toVector3D()); barSelectionFound = true; } @@ -1335,9 +1335,9 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, // Print value of selected bar glDisable(GL_DEPTH_TEST); // Draw the selection label - LabelItem &labelItem = m_selectedBar->selectionLabelItem(); - if (m_previouslySelectedBar != m_selectedBar || m_updateLabels || !labelItem.textureId()) { - QString labelText = m_selectedBar->selectionLabel(); + LabelItem &labelItem = selectedBar->selectionLabelItem(); + if (m_selectedBar != selectedBar || m_updateLabels || !labelItem.textureId()) { + QString labelText = selectedBar->selectionLabel(); if (labelText.isNull()) { static const QString rowIndexTag(QStringLiteral("@rowIdx")); static const QString rowLabelTag(QStringLiteral("@rowLabel")); @@ -1349,30 +1349,30 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, static const QString valueLabelTag(QStringLiteral("@valueLabel")); // Custom format expects printf format specifier. There is no tag for it. - labelText = generateValueLabel(itemLabelFormat(), m_selectedBar->value()); + labelText = generateValueLabel(itemLabelFormat(), selectedBar->value()); - labelText.replace(rowIndexTag, QString::number(m_selectedBar->position().x())); - labelText.replace(rowLabelTag, m_axisCacheX.labels().at(m_selectedBar->position().x())); + labelText.replace(rowIndexTag, QString::number(selectedBar->position().x())); + labelText.replace(rowLabelTag, m_axisCacheX.labels().at(selectedBar->position().x())); labelText.replace(rowTitleTag, m_axisCacheX.title()); - labelText.replace(colIndexTag, QString::number(m_selectedBar->position().y())); - labelText.replace(colLabelTag, m_axisCacheZ.labels().at(m_selectedBar->position().y())); + labelText.replace(colIndexTag, QString::number(selectedBar->position().y())); + labelText.replace(colLabelTag, m_axisCacheZ.labels().at(selectedBar->position().y())); labelText.replace(colTitleTag, m_axisCacheZ.title()); labelText.replace(valueTitleTag, m_axisCacheY.title()); if (labelText.contains(valueLabelTag)) { - QString valueLabelText = generateValueLabel(m_axisCacheY.labelFormat(), m_selectedBar->value()); + QString valueLabelText = generateValueLabel(m_axisCacheY.labelFormat(), selectedBar->value()); labelText.replace(valueLabelTag, valueLabelText); } - m_selectedBar->setSelectionLabel(labelText); + selectedBar->setSelectionLabel(labelText); } m_drawer->generateLabelItem(labelItem, labelText); - m_previouslySelectedBar = m_selectedBar; + m_selectedBar = selectedBar; } - m_drawer->drawLabel(*m_selectedBar, labelItem, viewMatrix, projectionMatrix, + m_drawer->drawLabel(*selectedBar, labelItem, viewMatrix, projectionMatrix, QVector3D(0.0f, m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), m_selectedBar->height(), + QVector3D(0.0f, 0.0f, 0.0f), selectedBar->height(), m_cachedSelectionMode, m_labelShader, m_labelObj, camera, true, false); @@ -1497,12 +1497,12 @@ void Bars3dRenderer::updateBackgroundEnabled(bool enable) } } -void Bars3dRenderer::updateSelectedBarPos(QPoint selectedBarPos) +void Bars3dRenderer::updateSelectedBarPos(QPoint position) { - if (selectedBarPos == Bars3dController::noSelectionPoint()) + if (position == Bars3dController::noSelectionPoint()) m_selection = selectionSkipColor; else - m_selection = QVector3D(selectedBarPos.x(), selectedBarPos.y(), 0); + m_selection = QVector3D(position.x(), position.y(), 0); } void Bars3dRenderer::updateShadowQuality(QDataVis::ShadowQuality quality) diff --git a/src/datavis3d/engine/bars3drenderer_p.h b/src/datavis3d/engine/bars3drenderer_p.h index 5426a5ae..5cd33809 100644 --- a/src/datavis3d/engine/bars3drenderer_p.h +++ b/src/datavis3d/engine/bars3drenderer_p.h @@ -63,7 +63,6 @@ private: // Internal state BarRenderItem *m_selectedBar; // points to renderitem array - BarRenderItem *m_previouslySelectedBar; // points to renderitem array QList *m_sliceSelection; AxisRenderCache *m_sliceCache; // not owned const LabelItem *m_sliceTitleItem; // not owned @@ -127,7 +126,7 @@ public slots: void updateSlicingActive(bool isSlicing); void updateSampleSpace(int rowCount, int columnCount); void updateBackgroundEnabled(bool enable); - void updateSelectedBarPos(QPoint selectedBarPos); + void updateSelectedBarPos(QPoint position); // Overloaded from abstract renderer virtual void updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max); diff --git a/src/datavis3d/engine/q3dscatter.cpp b/src/datavis3d/engine/q3dscatter.cpp index 30a5eb81..7fc6f628 100644 --- a/src/datavis3d/engine/q3dscatter.cpp +++ b/src/datavis3d/engine/q3dscatter.cpp @@ -78,6 +78,8 @@ Q3DScatter::Q3DScatter() : d_ptr(new Q3DScatterPrivate(this, geometry())) { d_ptr->m_shared->initializeOpenGL(); + QObject::connect(d_ptr->m_shared, &Scatter3DController::selectedItemIndexChanged, this, + &Q3DScatter::selectedItemIndexChanged); } /*! @@ -326,6 +328,22 @@ bool Q3DScatter::isBackgroundVisible() const return d_ptr->m_shared->backgroundEnabled(); } +/*! + * \property Q3DScatter::selectedItemIndex + * + * Selects an item in the \a index. Only one item can be selected at a time. + * To clear selection, specify an illegal \a index, e.g. -1. + */ +void Q3DScatter::setSelectedItemIndex(int index) +{ + d_ptr->m_shared->setSelectedItemIndex(index); +} + +int Q3DScatter::selectedItemIndex() const +{ + return d_ptr->m_shared->selectedItemIndex(); +} + /*! * \property Q3DScatter::shadowQuality * diff --git a/src/datavis3d/engine/q3dscatter.h b/src/datavis3d/engine/q3dscatter.h index 2094bb5d..26e3da08 100644 --- a/src/datavis3d/engine/q3dscatter.h +++ b/src/datavis3d/engine/q3dscatter.h @@ -40,6 +40,7 @@ class QT_DATAVIS3D_EXPORT Q3DScatter : public Q3DWindow Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) + Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged) Q_ENUMS(QtDataVis3D::QDataVis::SelectionMode) Q_ENUMS(QtDataVis3D::QDataVis::ShadowQuality) Q_ENUMS(QtDataVis3D::QDataVis::LabelTransparency) @@ -79,6 +80,9 @@ public: void setBackgroundVisible(bool visible); bool isBackgroundVisible() const; + void setSelectedItemIndex(int index); + int selectedItemIndex() const; + void setShadowQuality(QDataVis::ShadowQuality quality); QDataVis::ShadowQuality shadowQuality() const; @@ -96,6 +100,7 @@ public: signals: void shadowQualityChanged(QDataVis::ShadowQuality quality); + void selectedItemIndexChanged(int index); protected: void render(); diff --git a/src/datavis3d/engine/scatter3dcontroller.cpp b/src/datavis3d/engine/scatter3dcontroller.cpp index ef56fc23..3b0a2c1f 100644 --- a/src/datavis3d/engine/scatter3dcontroller.cpp +++ b/src/datavis3d/engine/scatter3dcontroller.cpp @@ -35,7 +35,8 @@ Scatter3DController::Scatter3DController(QRect boundRect) m_mousePos(QPoint(0, 0)), m_isSlicingActivated(false), m_renderer(0), - m_data(0) + m_data(0), + m_selectedItemIndex(noSelectionIndex()) { // Default axes setAxisX(new QValueAxis()); @@ -62,6 +63,9 @@ void Scatter3DController::initializeOpenGL() m_renderer = new Scatter3DRenderer(this); setRenderer(m_renderer); synchDataToRenderer(); + + QObject::connect(m_renderer, &Scatter3DRenderer::selectedItemIndexChanged, this, + &Scatter3DController::handleSelectedItemIndexChanged, Qt::QueuedConnection); } void Scatter3DController::synchDataToRenderer() @@ -77,6 +81,11 @@ void Scatter3DController::synchDataToRenderer() m_changeTracker.slicingActiveChanged = false; } + if (m_changeTracker.selectedItemIndexChanged) { + m_renderer->updateSelectedItemIndex(m_selectedItemIndex); + m_changeTracker.selectedItemIndexChanged = false; + } + if (m_isDataDirty) { m_renderer->updateDataModel(m_data); m_isDataDirty = false; @@ -243,6 +252,7 @@ void Scatter3DController::setDataProxy(QScatterDataProxy *proxy) adjustValueAxisRange(); m_isDataDirty = true; + setSelectedItemIndex(noSelectionIndex()); } QScatterDataProxy *Scatter3DController::dataProxy() @@ -255,6 +265,7 @@ void Scatter3DController::handleArrayReset() setSlicingActive(false); adjustValueAxisRange(); m_isDataDirty = true; + setSelectedItemIndex(noSelectionIndex()); } void Scatter3DController::handleItemsAdded(int startIndex, int count) @@ -282,6 +293,8 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count) // TODO should dirty only affected values? adjustValueAxisRange(); m_isDataDirty = true; + if (startIndex >= m_data->itemCount()) + setSelectedItemIndex(noSelectionIndex()); } void Scatter3DController::handleItemsInserted(int startIndex, int count) @@ -293,6 +306,14 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) m_isDataDirty = true; } +void Scatter3DController::handleSelectedItemIndexChanged(int index) +{ + if (index != m_selectedItemIndex) { + m_selectedItemIndex = index; + emit selectedItemIndexChanged(index); + } +} + void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation( QAbstractAxis::AxisOrientation orientation, bool autoAdjust) { @@ -329,6 +350,25 @@ void Scatter3DController::setSelectionMode(QDataVis::SelectionMode mode) Abstract3DController::setSelectionMode(mode); } +void Scatter3DController::setSelectedItemIndex(int index) +{ + // TODO If items not within axis ranges are culled from drawing, should they be + // TODO unselectable as well? + if (index < 0 || index >= m_data->itemCount()) + index = noSelectionIndex(); + + if (index != m_selectedItemIndex) { + m_selectedItemIndex = index; + m_changeTracker.selectedItemIndexChanged = true; + emit selectedItemIndexChanged(index); + } +} + +int Scatter3DController::selectedItemIndex() const +{ + return m_selectedItemIndex; +} + QPoint Scatter3DController::mousePosition() { return m_mousePos; diff --git a/src/datavis3d/engine/scatter3dcontroller_p.h b/src/datavis3d/engine/scatter3dcontroller_p.h index 437664b7..9d847852 100644 --- a/src/datavis3d/engine/scatter3dcontroller_p.h +++ b/src/datavis3d/engine/scatter3dcontroller_p.h @@ -41,9 +41,11 @@ class QScatterDataProxy; struct Scatter3DChangeBitField { bool slicingActiveChanged : 1; + bool selectedItemIndexChanged : 1; Scatter3DChangeBitField() : - slicingActiveChanged(true) + slicingActiveChanged(true), + selectedItemIndexChanged(true) { } }; @@ -63,6 +65,7 @@ private: // Rendering Scatter3DRenderer *m_renderer; QScatterDataProxy *m_data; + int m_selectedItemIndex; public: explicit Scatter3DController(QRect rect); @@ -85,6 +88,10 @@ public: // Change selection mode void setSelectionMode(QDataVis::SelectionMode mode); + void setSelectedItemIndex(int index); + int selectedItemIndex() const; + static inline int noSelectionIndex() { return -1; } + #if defined(Q_OS_ANDROID) void mouseDoubleClickEvent(QMouseEvent *event); void touchEvent(QTouchEvent *event); @@ -108,9 +115,11 @@ public slots: void handleItemsChanged(int startIndex, int count); void handleItemsRemoved(int startIndex, int count); void handleItemsInserted(int startIndex, int count); + void handleSelectedItemIndexChanged(int index); signals: void slicingActiveChanged(bool isSlicing); + void selectedItemIndexChanged(int index); private: void adjustValueAxisRange(); diff --git a/src/datavis3d/engine/scatter3drenderer.cpp b/src/datavis3d/engine/scatter3drenderer.cpp index 93e7cca1..096de7ed 100644 --- a/src/datavis3d/engine/scatter3drenderer.cpp +++ b/src/datavis3d/engine/scatter3drenderer.cpp @@ -52,7 +52,6 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) : Abstract3DRenderer(controller), m_controller(controller), m_selectedItem(0), - m_previouslySelectedItem(0), m_xFlipped(false), m_zFlipped(false), m_yFlipped(false), @@ -76,6 +75,7 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_heightNormalizer(1.0f), m_scaleFactor(0), m_selection(selectionSkipColor), + m_previousSelection(selectionSkipColor), m_areaSize(QSizeF(0.0, 0.0)), m_dotSizeScale(1.0f), m_hasHeightAdjustmentChanged(true) @@ -143,15 +143,12 @@ void Scatter3DRenderer::updateDataModel(QScatterDataProxy *dataProxy) int dataSize = dataArray.size(); m_renderItemArray.resize(dataSize); for (int i = 0; i < dataSize ; i++) { - qreal value = dataArray.at(i).position().y(); - m_renderItemArray[i].setValue(value); m_renderItemArray[i].setPosition(dataArray.at(i).position()); - //m_renderItemArray[i].setHeight(value / m_heightNormalizer); - //m_renderItemArray[i].setItemLabel(dataArray.at(i).label()); calculateTranslation(m_renderItemArray[i]); m_renderItemArray[i].setRenderer(this); } m_dotSizeScale = (GLfloat)qBound(0.01, (2.0 / qSqrt((qreal)dataSize)), 0.1); + m_selectedItem = 0; Abstract3DRenderer::updateDataModel(dataProxy); } @@ -402,14 +399,15 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, // Draw dots to selection buffer glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used - glClearColor(selectionSkipColor.x() / 255, selectionSkipColor.y() / 255, - selectionSkipColor.z() / 255, 1.0f); // Set clear color to white (= skipColor) + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (= skipColor) 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 - GLint dotIdxRed = 0; - GLint dotIdxGreen = 0; - GLint dotIdxBlue = 0; - for (int dot = 0; dot < m_renderItemArray.size(); dot++, dotIdxRed++) { + + int arraySize = m_renderItemArray.size(); + if (arraySize > 0xfffffe) // Max possible different selection colors, 0xffffff being skipColor + qFatal("Too many objects"); + + for (int dot = 0; dot < arraySize; dot++) { const ScatterRenderItem &item = m_renderItemArray.at(dot); QMatrix4x4 modelMatrix; @@ -427,20 +425,8 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - if (dotIdxRed > 0 && dotIdxRed % 256 == 0) { - dotIdxRed = 0; - dotIdxGreen++; - } - if (dotIdxGreen > 0 && dotIdxGreen % 256 == 0) { - dotIdxGreen = 0; - dotIdxBlue++; - } - if (dotIdxBlue > 255) - qFatal("Too many objects"); - - QVector3D dotColor = QVector3D((GLfloat)dotIdxRed / 255.0f, - (GLfloat)dotIdxGreen / 255.0f, - (GLfloat)dotIdxBlue / 255.0f); + QVector3D dotColor = indexToSelectionColor(dot); + dotColor /= 255.0f; m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); m_selectionShader->setUniformValue(m_selectionShader->color(), dotColor); @@ -501,6 +487,22 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, // Draw dots bool dotSelectionFound = false; + int selectedIndex; + if (m_selection == selectionSkipColor) { + selectedIndex = Scatter3DController::noSelectionIndex(); + } else { + selectedIndex = int(m_selection.x()) + + (int(m_selection.y()) << 8) + + (int(m_selection.z()) << 16); + } + + if (m_selection != m_previousSelection) { + emit selectedItemIndexChanged(selectedIndex); + m_previousSelection = m_selection; + } + + ScatterRenderItem *selectedItem(0); + for (int dot = 0; dot < m_renderItemArray.size(); dot++) { ScatterRenderItem &item = m_renderItemArray[dot]; @@ -539,28 +541,12 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, QVector3D dotColor = baseColor + heightColor; GLfloat lightStrength = m_cachedTheme.m_lightStrength; - if (m_cachedSelectionMode > QDataVis::ModeNone) { - Scatter3DController::SelectionType selectionType = isSelected(dot, m_selection); - switch (selectionType) { - case Scatter3DController::SelectionItem: { - dotColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); - lightStrength = m_cachedTheme.m_highlightLightStrength; - // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one - m_selectedItem = &item; - dotSelectionFound = true; - break; - } - case Scatter3DController::SelectionNone: { - // Current dot is not selected, nor on a row or column - // do nothing - break; - } - default: { - // Unsupported selection mode - // do nothing - break; - } - } + if (m_cachedSelectionMode > QDataVis::ModeNone && (selectedIndex == dot)) { + dotColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); + lightStrength = m_cachedTheme.m_highlightLightStrength; + // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one + selectedItem = &item; + dotSelectionFound = true; } // Set shader bindings @@ -1214,10 +1200,10 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, } else { glDisable(GL_DEPTH_TEST); // Draw the selection label - LabelItem &labelItem = m_selectedItem->selectionLabelItem(); - if (m_previouslySelectedItem != m_selectedItem || m_updateLabels + LabelItem &labelItem = selectedItem->selectionLabelItem(); + if (m_selectedItem != selectedItem || m_updateLabels || !labelItem.textureId()) { - QString labelText = m_selectedItem->selectionLabel(); + QString labelText = selectedItem->selectionLabel(); if (labelText.isNull()) { static const QString xTitleTag(QStringLiteral("@xTitle")); static const QString yTitleTag(QStringLiteral("@yTitle")); @@ -1234,29 +1220,29 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, if (labelText.contains(xLabelTag)) { QString valueLabelText = generateValueLabel(m_axisCacheX.labelFormat(), - m_selectedItem->position().x()); + selectedItem->position().x()); labelText.replace(xLabelTag, valueLabelText); } if (labelText.contains(yLabelTag)) { QString valueLabelText = generateValueLabel(m_axisCacheY.labelFormat(), - m_selectedItem->position().y()); + selectedItem->position().y()); labelText.replace(yLabelTag, valueLabelText); } if (labelText.contains(zLabelTag)) { QString valueLabelText = generateValueLabel(m_axisCacheZ.labelFormat(), - m_selectedItem->position().z()); + selectedItem->position().z()); labelText.replace(zLabelTag, valueLabelText); } - m_selectedItem->setSelectionLabel(labelText); + selectedItem->setSelectionLabel(labelText); } m_drawer->generateLabelItem(labelItem, labelText); - m_previouslySelectedItem = m_selectedItem; + m_selectedItem = selectedItem; } - m_drawer->drawLabel(*m_selectedItem, labelItem, viewMatrix, projectionMatrix, + m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix, QVector3D(0.0f, 0.0f, zComp), - QVector3D(0.0f, 0.0f, 0.0f), m_selectedItem->height(), + QVector3D(0.0f, 0.0f, 0.0f), 0, m_cachedSelectionMode, m_labelShader, m_labelObj, camera, true, false, Drawer::LabelMid); @@ -1273,6 +1259,14 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, m_labelShader->release(); } +void Scatter3DRenderer::updateSelectedItemIndex(int index) +{ + if (index == Scatter3DController::noSelectionIndex()) + m_selection = selectionSkipColor; + else + m_selection = indexToSelectionColor(index); +} + void Scatter3DRenderer::handleResize() { //qDebug() << __FUNCTION__; @@ -1395,44 +1389,6 @@ void Scatter3DRenderer::calculateSceneScalingFactors() //qDebug() << m_heightNormalizer << m_areaSize << m_scaleFactor << m_axisCacheY.max() << m_axisCacheX.max() << m_axisCacheZ.max(); } -Scatter3DController::SelectionType Scatter3DRenderer::isSelected(GLint dot, - const QVector3D &selection) -{ - //qDebug() << __FUNCTION__; - GLubyte dotIdxRed = 0; - GLubyte dotIdxGreen = 0; - GLubyte dotIdxBlue = 0; - //static QVector3D prevSel = selection; // TODO: For debugging - Scatter3DController::SelectionType isSelectedType = Scatter3DController::SelectionNone; - - if (selection == selectionSkipColor) - return isSelectedType; // skip window - - if (dot <= 255) { - dotIdxRed = dot; - } else if (dot <= 65535) { - dotIdxGreen = dot / 256; - dotIdxRed = dot % 256; - } else { - dotIdxBlue = dot / 65535; - dotIdxGreen = dot % 65535; - dotIdxRed = dot % 256; - } - - QVector3D current = QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue); - - // TODO: For debugging - //if (selection != prevSel) { - // qDebug() << selection.x() << selection .y() << selection.z(); - // prevSel = selection; - //} - - if (current == selection) - isSelectedType = Scatter3DController::SelectionItem; - - return isSelectedType; -} - QRect Scatter3DRenderer::mainViewPort() { //qDebug() << __FUNCTION__; @@ -1534,4 +1490,13 @@ 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); +} + QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/scatter3drenderer_p.h b/src/datavis3d/engine/scatter3drenderer_p.h index 2fb81855..12fa7a04 100644 --- a/src/datavis3d/engine/scatter3drenderer_p.h +++ b/src/datavis3d/engine/scatter3drenderer_p.h @@ -60,7 +60,6 @@ private: // Internal state ScatterRenderItem *m_selectedItem; // points to renderitem array - ScatterRenderItem *m_previouslySelectedItem; // points to renderitem array bool m_xFlipped; bool m_zFlipped; bool m_yFlipped; @@ -85,6 +84,7 @@ private: GLfloat m_heightNormalizer; GLfloat m_scaleFactor; QVector3D m_selection; + QVector3D m_previousSelection; QSizeF m_areaSize; GLfloat m_dotSizeScale; @@ -127,7 +127,6 @@ private: #endif void calculateTranslation(ScatterRenderItem &item); void calculateSceneScalingFactors(); - Scatter3DController::SelectionType isSelected(GLint dot, const QVector3D &selection); Q_DISABLE_COPY(Scatter3DRenderer) @@ -138,8 +137,16 @@ public slots: // Overloaded from abstract renderer virtual void updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max); -}; + void updateSelectedItemIndex(int index); + +signals: + void selectionUpdated(QVector3D selection); + void selectedItemIndexChanged(int index); + +private: + QVector3D indexToSelectionColor(GLint index); +}; QT_DATAVIS3D_END_NAMESPACE -- cgit v1.2.3