diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-08-25 13:16:04 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-08-25 15:01:10 +0300 |
commit | 5a51d06ec8f0210f51e65abfde9f868ab7bfa8ef (patch) | |
tree | 2319880f2d66e5610d9d1040d886f52cada82ad8 /src/datavisualization/data | |
parent | f9bb71fd11cce59d74e78202a1117c8abb3a2e44 (diff) |
Add alpha multiplier to QCustom3DVolume api
Change-Id: I856c4166513f6d6f7b73fd52bc46d52ab1b8fdff
Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Reviewed-by: Mika Salmela <mika.salmela@digia.com>
Diffstat (limited to 'src/datavisualization/data')
-rw-r--r-- | src/datavisualization/data/customrenderitem.cpp | 8 | ||||
-rw-r--r-- | src/datavisualization/data/customrenderitem_p.h | 12 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume.cpp | 251 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume.h | 10 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume_p.h | 10 |
5 files changed, 216 insertions, 75 deletions
diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp index 3eb68845..c316fd38 100644 --- a/src/datavisualization/data/customrenderitem.cpp +++ b/src/datavisualization/data/customrenderitem.cpp @@ -36,7 +36,13 @@ CustomRenderItem::CustomRenderItem() m_textureWidth(0), m_textureHeight(0), m_textureDepth(0), - m_isVolume(false) + m_isVolume(false), + m_textureFormat(QImage::Format_ARGB32), + m_sliceIndexX(-1), + m_sliceIndexY(-1), + m_sliceIndexZ(-1), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { } diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h index e21b6f39..5428ce43 100644 --- a/src/datavisualization/data/customrenderitem_p.h +++ b/src/datavisualization/data/customrenderitem_p.h @@ -89,9 +89,13 @@ public: inline void setSliceIndexX(int index) { m_sliceIndexX = index; } inline void setSliceIndexY(int index) { m_sliceIndexY = index; } inline void setSliceIndexZ(int index) { m_sliceIndexZ = index; } - int sliceIndexX() const { return m_sliceIndexX; } - int sliceIndexY() const { return m_sliceIndexY; } - int sliceIndexZ() const { return m_sliceIndexZ; } + inline int sliceIndexX() const { return m_sliceIndexX; } + inline int sliceIndexY() const { return m_sliceIndexY; } + inline int sliceIndexZ() const { return m_sliceIndexZ; } + inline void setAlphaMultiplier(float mult) { m_alphaMultiplier = mult; } + inline float alphaMultiplier() const { return m_alphaMultiplier; } + inline void setPreserveOpacity(bool enable) { m_preserveOpacity = enable; } + inline bool preserveOpacity() const { return m_preserveOpacity; } private: Q_DISABLE_COPY(CustomRenderItem) @@ -120,6 +124,8 @@ private: int m_sliceIndexX; int m_sliceIndexY; int m_sliceIndexZ; + float m_alphaMultiplier; + bool m_preserveOpacity; }; typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray; diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp index cab79ac0..c1a77dba 100644 --- a/src/datavisualization/data/qcustom3dvolume.cpp +++ b/src/datavisualization/data/qcustom3dvolume.cpp @@ -112,6 +112,30 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty real Custom3DVolume::alphaMultiplier + * + * The alpha value of every texel of the volume texture is multiplied with this value at + * the render time. This can be used to introduce uniform transparency to the volume. + * If preserveOpacity is \c{true}, only texels with at least some transparency to begin with are + * affected, and fully opaque texels are not affected. + * The value must not be negative. + * Defaults to \c{1.0}. + * + * \sa preserveOpacity + */ + +/*! + * \qmlproperty bool Custom3DVolume::preserveOpacity + * + * If this property value is \c{true}, alphaMultiplier is only applied to texels that already have + * some transparency. If it is \c{false}, the multiplier is applied to the alpha value of all + * texels. + * Defaults to \c{true}. + * + * \sa alphaMultiplier + */ + +/*! * Constructs QCustom3DVolume with given \a parent. */ QCustom3DVolume::QCustom3DVolume(QObject *parent) : @@ -578,84 +602,72 @@ QImage::Format QCustom3DVolume::textureFormat() const } /*! - * Renders the slice specified by \a index along \a axis into an image. - * The texture format of this object is used. + * \property QCustom3DVolume::alphaMultiplier * - * \return the rendered image of the slice, or a null image if invalid index is specified. + * The alpha value of every texel of the volume texture is multiplied with this value at + * the render time. This can be used to introduce uniform transparency to the volume. + * If preserveOpacity is \c{true}, only texels with at least some transparency to begin with are + * affected, and fully opaque texels are not affected. + * The value must not be negative. + * Defaults to \c{1.0f}. * - * \sa textureFormat + * \sa preserveOpacity, textureData */ -QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index) +void QCustom3DVolume::setAlphaMultiplier(float mult) { - if (index < 0) - return QImage(); - - int x; - int y; - if (axis == Qt::XAxis) { - if (index >= textureWidth()) - return QImage(); - x = textureDepth(); - y = textureHeight(); - } else if (axis == Qt::YAxis) { - if (index >= textureHeight()) - return QImage(); - x = textureWidth(); - y = textureDepth(); + if (mult >= 0.0f) { + if (dptr()->m_alphaMultiplier != mult) { + dptr()->m_alphaMultiplier = mult; + dptr()->m_dirtyBitsVolume.alphaDirty = true; + emit alphaMultiplierChanged(mult); + emit dptr()->needUpdate(); + } } else { - if (index >= textureDepth()) - return QImage(); - x = textureWidth(); - y = textureHeight(); + qWarning() << __FUNCTION__ << "Attempted to set negative multiplier."; } +} - int padding = 0; - int pixelWidth = 4; - if (textureFormat() == QImage::Format_Indexed8) { - padding = x % 4; - pixelWidth = 1; - } - QVector<uchar> data((x + padding) * y * pixelWidth); - int frameSize = textureDataWidth() * textureHeight(); +float QCustom3DVolume::alphaMultiplier() const +{ + return dptrc()->m_alphaMultiplier; +} - int dataIndex = 0; - if (axis == Qt::XAxis) { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() - + (index * pixelWidth) + (textureDataWidth() * i); - for (int j = 0; j < x; j++) { - data[dataIndex++] = *p; - for (int k = 1; k < pixelWidth; k++) - data[dataIndex++] = *(p + k); - p += frameSize; - } - } - } else if (axis == Qt::YAxis) { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() + (index * textureDataWidth()) - + (frameSize * i); - for (int j = 0; j < (x * pixelWidth); j++) { - data[dataIndex++] = *p; - p++; - } - } - } else { - for (int i = 0; i < y; i++) { - const uchar *p = textureData()->constData() + (index * frameSize) - + (textureDataWidth() * i); - for (int j = 0; j < (x * pixelWidth); j++) { - data[dataIndex++] = *p; - p++; - } - } +/*! + * \property QCustom3DVolume::preserveOpacity + * + * If this property value is \c{true}, alphaMultiplier is only applied to texels that already have + * some transparency. If it is \c{false}, the multiplier is applied to the alpha value of all + * texels. + * Defaults to \c{true}. + * + * \sa alphaMultiplier + */ +void QCustom3DVolume::setPreserveOpacity(bool enable) +{ + if (dptr()->m_preserveOpacity != enable) { + dptr()->m_preserveOpacity = enable; + dptr()->m_dirtyBitsVolume.alphaDirty = true; + emit preserveOpacityChanged(enable); + emit dptr()->needUpdate(); } +} - QImage image(data.constData(), x, y, x * pixelWidth, textureFormat()); - image.bits(); // Call bits() to detach the new image from local data - if (textureFormat() == QImage::Format_Indexed8) - image.setColorTable(colorTable()); +bool QCustom3DVolume::preserveOpacity() const +{ + return dptrc()->m_preserveOpacity; +} - return image; +/*! + * Renders the slice specified by \a index along \a axis into an image. + * The texture format of this object is used. + * + * \return the rendered image of the slice, or a null image if invalid index is specified. + * + * \sa textureFormat + */ +QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index) +{ + return dptr()->renderSlice(axis, index); } /*! @@ -683,7 +695,9 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q) : m_textureHeight(0), m_textureDepth(0), m_textureFormat(QImage::Format_ARGB32), - m_textureData(0) + m_textureData(0), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { m_isVolumeItem = true; m_meshFile = QStringLiteral(":/defaultMeshes/barFull"); @@ -705,7 +719,9 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector m_textureDepth(textureDepth), m_textureFormat(textureFormat), m_colorTable(colorTable), - m_textureData(textureData) + m_textureData(textureData), + m_alphaMultiplier(1.0f), + m_preserveOpacity(true) { m_isVolumeItem = true; m_shadowCasting = false; @@ -738,6 +754,103 @@ void QCustom3DVolumePrivate::resetDirtyBits() m_dirtyBitsVolume.textureFormatDirty = false; } +QImage QCustom3DVolumePrivate::renderSlice(Qt::Axis axis, int index) +{ + if (index < 0) + return QImage(); + + int x; + int y; + if (axis == Qt::XAxis) { + if (index >= m_textureWidth) + return QImage(); + x = m_textureDepth; + y = m_textureHeight; + } else if (axis == Qt::YAxis) { + if (index >= m_textureHeight) + return QImage(); + x = m_textureWidth; + y = m_textureDepth; + } else { + if (index >= m_textureDepth) + return QImage(); + x = m_textureWidth; + y = m_textureHeight; + } + + int padding = 0; + int pixelWidth = 4; + int dataWidth = qptr()->textureDataWidth(); + if (m_textureFormat == QImage::Format_Indexed8) { + padding = x % 4; + pixelWidth = 1; + } + QVector<uchar> data((x + padding) * y * pixelWidth); + int frameSize = qptr()->textureDataWidth() * m_textureHeight; + + int dataIndex = 0; + if (axis == Qt::XAxis) { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + + (index * pixelWidth) + (dataWidth * i); + for (int j = 0; j < x; j++) { + for (int k = 0; k < pixelWidth; k++) + data[dataIndex++] = *(p + k); + p += frameSize; + } + } + } else if (axis == Qt::YAxis) { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + (index * dataWidth) + + (frameSize * i); + for (int j = 0; j < (x * pixelWidth); j++) { + data[dataIndex++] = *p; + p++; + } + } + } else { + for (int i = 0; i < y; i++) { + const uchar *p = m_textureData->constData() + (index * frameSize) + (dataWidth * i); + for (int j = 0; j < (x * pixelWidth); j++) { + data[dataIndex++] = *p; + p++; + } + } + } + + if (m_textureFormat != QImage::Format_Indexed8 && m_alphaMultiplier != 1.0f) { + for (int i = pixelWidth - 1; i < data.size(); i += pixelWidth) + data[i] = static_cast<uchar>(multipliedAlphaValue(data.at(i))); + } + + QImage image(data.constData(), x, y, x * pixelWidth, m_textureFormat); + image.bits(); // Call bits() to detach the new image from local data + if (m_textureFormat == QImage::Format_Indexed8) { + QVector<QRgb> colorTable = m_colorTable; + if (m_alphaMultiplier != 1.0f) { + for (int i = 0; i < colorTable.size(); i++) { + QRgb curCol = colorTable.at(i); + int alpha = multipliedAlphaValue(qAlpha(curCol)); + if (alpha != qAlpha(curCol)) + colorTable[i] = qRgba(qRed(curCol), qGreen(curCol), qBlue(curCol), alpha); + } + } + image.setColorTable(colorTable); + } + + return image; +} + +int QCustom3DVolumePrivate::multipliedAlphaValue(int alpha) +{ + int modifiedAlpha = alpha; + if (!m_preserveOpacity || alpha != 255) { + modifiedAlpha = int(m_alphaMultiplier * float(alpha)); + modifiedAlpha = qMin(modifiedAlpha, 255); + } + return modifiedAlpha; +} + QCustom3DVolume *QCustom3DVolumePrivate::qptr() { return static_cast<QCustom3DVolume *>(q_ptr); diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h index 00733d17..2f95fa5d 100644 --- a/src/datavisualization/data/qcustom3dvolume.h +++ b/src/datavisualization/data/qcustom3dvolume.h @@ -40,7 +40,8 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DVolume : public QCustom3DItem Q_PROPERTY(QVector<QRgb> colorTable READ colorTable WRITE setColorTable NOTIFY colorTableChanged) Q_PROPERTY(QVector<uchar> *textureData READ textureData WRITE setTextureData NOTIFY textureDataChanged) Q_PROPERTY(QImage::Format textureFormat READ textureFormat WRITE setTextureFormat NOTIFY textureFormatChanged) - + Q_PROPERTY(float alphaMultiplier READ alphaMultiplier WRITE setAlphaMultiplier NOTIFY alphaMultiplierChanged) + Q_PROPERTY(bool preserveOpacity READ preserveOpacity WRITE setPreserveOpacity NOTIFY preserveOpacityChanged) public: explicit QCustom3DVolume(QObject *parent = 0); @@ -80,6 +81,11 @@ public: void setTextureFormat(QImage::Format format); QImage::Format textureFormat() const; + void setAlphaMultiplier(float mult); + float alphaMultiplier() const; + void setPreserveOpacity(bool enable); + bool preserveOpacity() const; + QImage renderSlice(Qt::Axis axis, int index); signals: @@ -92,6 +98,8 @@ signals: void colorTableChanged(); void textureDataChanged(QVector<uchar> *data); void textureFormatChanged(QImage::Format format); + void alphaMultiplierChanged(float mult); + void preserveOpacityChanged(bool enabled); protected: QCustom3DVolumePrivate *dptr(); diff --git a/src/datavisualization/data/qcustom3dvolume_p.h b/src/datavisualization/data/qcustom3dvolume_p.h index 69dd1eb2..b83e27fb 100644 --- a/src/datavisualization/data/qcustom3dvolume_p.h +++ b/src/datavisualization/data/qcustom3dvolume_p.h @@ -40,13 +40,15 @@ struct QCustomVolumeDirtyBitField { bool colorTableDirty : 1; bool textureDataDirty : 1; bool textureFormatDirty : 1; + bool alphaDirty : 1; QCustomVolumeDirtyBitField() : textureDimensionsDirty(false), sliceIndicesDirty(false), colorTableDirty(false), textureDataDirty(false), - textureFormatDirty(false) + textureFormatDirty(false), + alphaDirty(false) { } }; @@ -64,6 +66,7 @@ public: virtual ~QCustom3DVolumePrivate(); void resetDirtyBits(); + QImage renderSlice(Qt::Axis axis, int index); QCustom3DVolume *qptr(); @@ -79,9 +82,14 @@ public: QVector<QRgb> m_colorTable; QVector<uchar> *m_textureData; + float m_alphaMultiplier; + bool m_preserveOpacity; + QCustomVolumeDirtyBitField m_dirtyBitsVolume; private: + int multipliedAlphaValue(int alpha); + friend class QCustom3DVolume; }; |