summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/data/qcustom3dvolume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization/data/qcustom3dvolume.cpp')
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp251
1 files changed, 182 insertions, 69 deletions
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);