summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/datavisualization/data/customrenderitem.cpp25
-rw-r--r--src/datavisualization/data/customrenderitem_p.h35
-rw-r--r--src/datavisualization/data/data.pri7
-rw-r--r--src/datavisualization/data/qcustom3ditem.cpp6
-rw-r--r--src/datavisualization/data/qcustom3ditem_p.h1
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp669
-rw-r--r--src/datavisualization/data/qcustom3dvolume.h106
-rw-r--r--src/datavisualization/data/qcustom3dvolume_p.h90
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp176
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h11
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp15
-rw-r--r--src/datavisualization/engine/drawer.cpp19
-rw-r--r--src/datavisualization/engine/drawer_p.h2
-rw-r--r--src/datavisualization/engine/engine.qrc3
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp19
-rw-r--r--src/datavisualization/engine/shaders/default.frag1
-rw-r--r--src/datavisualization/engine/shaders/texture3d.frag70
-rw-r--r--src/datavisualization/engine/shaders/texture3d.vert12
-rw-r--r--src/datavisualization/engine/shaders/texture3dslice.frag119
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp23
-rw-r--r--src/datavisualization/utils/shaderhelper.cpp37
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h9
-rw-r--r--src/datavisualization/utils/texturehelper.cpp60
-rw-r--r--src/datavisualization/utils/texturehelper_p.h11
24 files changed, 1483 insertions, 43 deletions
diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp
index a1c70057..b96a4957 100644
--- a/src/datavisualization/data/customrenderitem.cpp
+++ b/src/datavisualization/data/customrenderitem.cpp
@@ -23,9 +23,20 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
CustomRenderItem::CustomRenderItem()
: AbstractRenderItem(),
m_texture(0),
+ m_absolute(false),
m_object(0),
+ m_needBlend(true),
m_visible(true),
- m_renderer(0)
+ m_valid(true),
+ m_index(0),
+ m_shadowCasting(false),
+ m_isFacingCamera(false),
+ m_item(0),
+ m_renderer(0),
+ m_textureWidth(0),
+ m_textureHeight(0),
+ m_textureDepth(0),
+ m_isVolume(false)
{
}
@@ -39,4 +50,16 @@ void CustomRenderItem::setMesh(const QString &meshFile)
ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFile);
}
+void CustomRenderItem::setColorTable(const QVector<QRgb> &colors)
+{
+ m_colorTable.resize(colors.size());
+ for (int i = 0; i < m_colorTable.size(); i++) {
+ const QRgb &rgb = colors.at(i);
+ m_colorTable[i] = QVector4D(float(qRed(rgb)) / 255.0f,
+ float(qGreen(rgb)) / 255.0f,
+ float(qBlue(rgb)) / 255.0f,
+ float(qAlpha(rgb)) / 255.0f);
+ }
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h
index 4fb94276..e21b6f39 100644
--- a/src/datavisualization/data/customrenderitem_p.h
+++ b/src/datavisualization/data/customrenderitem_p.h
@@ -31,6 +31,8 @@
#include "abstractrenderitem_p.h"
#include "objecthelper_p.h"
+#include <QtGui/QRgb>
+#include <QtGui/QImage>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -69,6 +71,28 @@ public:
inline bool isFacingCamera() const { return m_isFacingCamera; }
inline void setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; }
+ // Volume specific
+ inline void setTextureWidth(int width) { m_textureWidth = width; }
+ inline int textureWidth() const { return m_textureWidth; }
+ inline void setTextureHeight(int height) { m_textureHeight = height; }
+ inline int textureHeight() const { return m_textureHeight; }
+ inline void setTextureDepth(int depth) { m_textureDepth = depth; }
+ inline int textureDepth() const { return m_textureDepth; }
+ inline int textureSize() const { return m_textureWidth * m_textureHeight * m_textureDepth; }
+ inline void setColorTable(const QVector<QVector4D> &colors) { m_colorTable = colors; }
+ void setColorTable(const QVector<QRgb> &colors);
+ inline const QVector<QVector4D> &colorTable() const { return m_colorTable; }
+ inline void setVolume(bool volume) { m_isVolume = volume; }
+ inline bool isVolume() const { return m_isVolume; }
+ inline void setTextureFormat(QImage::Format format) { m_textureFormat = format; }
+ inline QImage::Format textureFormat() const { return m_textureFormat; }
+ 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; }
+
private:
Q_DISABLE_COPY(CustomRenderItem)
@@ -85,6 +109,17 @@ private:
bool m_isFacingCamera;
QCustom3DItem *m_item;
Abstract3DRenderer *m_renderer;
+
+ // Volume specific
+ int m_textureWidth;
+ int m_textureHeight;
+ int m_textureDepth;
+ QVector<QVector4D> m_colorTable;
+ bool m_isVolume;
+ QImage::Format m_textureFormat;
+ int m_sliceIndexX;
+ int m_sliceIndexY;
+ int m_sliceIndexZ;
};
typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray;
diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri
index 37a8d084..e2bbd6eb 100644
--- a/src/datavisualization/data/data.pri
+++ b/src/datavisualization/data/data.pri
@@ -41,7 +41,9 @@ HEADERS += \
$$PWD/qcustom3ditem.h \
$$PWD/qcustom3ditem_p.h \
$$PWD/qcustom3dlabel.h \
- $$PWD/qcustom3dlabel_p.h
+ $$PWD/qcustom3dlabel_p.h \
+ $$PWD/qcustom3dvolume.h \
+ $$PWD/qcustom3dvolume_p.h
SOURCES += \
$$PWD/labelitem.cpp \
@@ -69,6 +71,7 @@ SOURCES += \
$$PWD/qsurface3dseries.cpp \
$$PWD/customrenderitem.cpp \
$$PWD/qcustom3ditem.cpp \
- $$PWD/qcustom3dlabel.cpp
+ $$PWD/qcustom3dlabel.cpp \
+ $$PWD/qcustom3dvolume.cpp
INCLUDEPATH += $$PWD
diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp
index efee3b15..1d419cee 100644
--- a/src/datavisualization/data/qcustom3ditem.cpp
+++ b/src/datavisualization/data/qcustom3ditem.cpp
@@ -373,7 +373,8 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) :
m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)),
m_visible(true),
m_shadowCasting(true),
- m_isLabelItem(false)
+ m_isLabelItem(false),
+ m_isVolumeItem(false)
{
}
@@ -388,7 +389,8 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &mesh
m_rotation(rotation),
m_visible(true),
m_shadowCasting(true),
- m_isLabelItem(false)
+ m_isLabelItem(false),
+ m_isVolumeItem(false)
{
}
diff --git a/src/datavisualization/data/qcustom3ditem_p.h b/src/datavisualization/data/qcustom3ditem_p.h
index c1ce5996..d766bcf3 100644
--- a/src/datavisualization/data/qcustom3ditem_p.h
+++ b/src/datavisualization/data/qcustom3ditem_p.h
@@ -82,6 +82,7 @@ public:
bool m_shadowCasting;
bool m_isLabelItem;
+ bool m_isVolumeItem;
QCustomItemDirtyBitField m_dirtyBits;
diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp
new file mode 100644
index 00000000..766f1589
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume.cpp
@@ -0,0 +1,669 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qcustom3dvolume_p.h"
+#include "utils_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QCustom3DVolume
+ * \inmodule QtDataVisualization
+ * \brief The QCustom3DVolume class is for creating volume rendered objects to be added to a graph.
+ * \since QtDataVisualization 1.2
+ *
+ * This class is for creating volume rendered objects to be added to a graph. A volume rendered
+ * object is a box with a 3D texture. Three slice planes are supported for the volume, one along
+ * each main axis of the volume.
+ *
+ * \note Volumetric objects are only supported with orthographic projection.
+ *
+ * \sa QAbstract3DGraph::addCustomItem(), QAbstract3DGraph::orthoProjection
+ */
+
+/*!
+ * \qmltype Custom3DVolume
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.2
+ * \ingroup datavisualization_qml
+ * \instantiates QCustom3DVolume
+ * \brief The Custom3DVolume type is for creating volume rendered objects to be added to a graph.
+ *
+ * This class is for creating volume rendered objects to be added to a graph. A volume rendered
+ * object is a box with a 3D texture. Three slice planes are supported for the volume, one along
+ * each main axis of the volume.
+ *
+ * \note: Filling in the volume data would not typically be efficient or practical from pure QML,
+ * so properties directly related to that are not fully supported from QML.
+ * Make a hybrid QML/C++ application if you want to use volume objects with QML ui.
+ *
+ * \note Volumetric objects are only supported with orthographic projection.
+ *
+ * \sa AbstractGraph3D::orthoProjection
+ */
+
+/*! \qmlproperty int Custom3DVolume::textureWidth
+ *
+ * The width of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note: Changing this property from QML is not supported, as the texture data cannot be resized
+ * to match.
+ */
+
+/*! \qmlproperty int Custom3DVolume::textureHeight
+ *
+ * The height of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note: Changing this property from QML is not supported, as the texture data cannot be resized
+ * to match.
+ */
+
+/*! \qmlproperty int Custom3DVolume::textureDepth
+ *
+ * The depth of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note: Changing this property from QML is not supported, as the texture data cannot be resized
+ * to match.
+ */
+
+/*! \qmlproperty int Custom3DVolume::sliceIndexX
+ *
+ * The X dimension index into the texture data indicating which vertical slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData
+ */
+
+/*! \qmlproperty int Custom3DVolume::sliceIndexY
+ *
+ * The Y dimension index into the texture data indicating which horizontal slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData
+ */
+
+/*! \qmlproperty int Custom3DVolume::sliceIndexZ
+ *
+ * The Z dimension index into the texture data indicating which vertical slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData
+ */
+
+/*!
+ * Constructs QCustom3DVolume with given \a parent.
+ */
+QCustom3DVolume::QCustom3DVolume(QObject *parent) :
+ QCustom3DItem(new QCustom3DVolumePrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QCustom3DVolume with given \a position, \a scaling, \a rotation,
+ * \a textureWidth, \a textureHeight, \a textureDepth, \a textureData, \a textureFormat,
+ * \a colorTable, and optional \a parent.
+ *
+ * \sa textureData, textureFormat, colorTable
+ */
+QCustom3DVolume::QCustom3DVolume(const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation, int textureWidth,
+ int textureHeight, int textureDepth,
+ QVector<uchar> *textureData, QImage::Format textureFormat,
+ const QVector<QRgb> &colorTable, QObject *parent) :
+ QCustom3DItem(new QCustom3DVolumePrivate(this, position, scaling, rotation, textureWidth,
+ textureHeight, textureDepth,
+ textureData, textureFormat, colorTable), parent)
+{
+}
+
+
+/*!
+ * Destroys QCustom3DVolume.
+ */
+QCustom3DVolume::~QCustom3DVolume()
+{
+}
+
+/*! \property QCustom3DVolume::textureWidth
+ *
+ * The width of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note The textureData may need to be resized or recreated if this value is changed.
+ * Defaults to \c{0}.
+ *
+ * \sa textureData, textureHeight, textureDepth, textureFormat, textureDataWidth()
+ */
+void QCustom3DVolume::setTextureWidth(int value)
+{
+ if (value >= 0) {
+ if (dptr()->m_textureWidth != value) {
+ dptr()->m_textureWidth = value;
+ dptr()->m_dirtyBitsVolume.textureDimensionsDirty = true;
+ emit textureWidthChanged(value);
+ emit dptr()->needUpdate();
+ }
+ } else {
+ qWarning() << __FUNCTION__ << "Cannot set negative value.";
+ }
+}
+
+int QCustom3DVolume::textureWidth() const
+{
+ return dptrc()->m_textureWidth;
+}
+
+/*! \property QCustom3DVolume::textureHeight
+ *
+ * The height of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note The textureData may need to be resized or recreated if this value is changed.
+ * Defaults to \c{0}.
+ *
+ * \sa textureData, textureWidth, textureDepth, textureFormat
+ */
+void QCustom3DVolume::setTextureHeight(int value)
+{
+ if (value >= 0) {
+ if (dptr()->m_textureHeight != value) {
+ dptr()->m_textureHeight = value;
+ dptr()->m_dirtyBitsVolume.textureDimensionsDirty = true;
+ emit textureHeightChanged(value);
+ emit dptr()->needUpdate();
+ }
+ } else {
+ qWarning() << __FUNCTION__ << "Cannot set negative value.";
+ }
+
+}
+
+int QCustom3DVolume::textureHeight() const
+{
+ return dptrc()->m_textureHeight;
+}
+
+/*! \property QCustom3DVolume::textureDepth
+ *
+ * The depth of the 3D texture defining the volume content in pixels. Defaults to \c{0}.
+ *
+ * \note The textureData may need to be resized or recreated if this value is changed.
+ * Defaults to \c{0}.
+ *
+ * \sa textureData, textureWidth, textureHeight, textureFormat
+ */
+void QCustom3DVolume::setTextureDepth(int value)
+{
+ if (value >= 0) {
+ if (dptr()->m_textureDepth != value) {
+ dptr()->m_textureDepth = value;
+ dptr()->m_dirtyBitsVolume.textureDimensionsDirty = true;
+ emit textureDepthChanged(value);
+ emit dptr()->needUpdate();
+ }
+ } else {
+ qWarning() << __FUNCTION__ << "Cannot set negative value.";
+ }
+}
+
+int QCustom3DVolume::textureDepth() const
+{
+ return dptrc()->m_textureDepth;
+}
+
+/*!
+ * A convenience function for setting all three texture dimensions
+ * (\a width, \a height, and \a depth) at once.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setTextureDimensions(int width, int height, int depth)
+{
+ setTextureWidth(width);
+ setTextureWidth(height);
+ setTextureWidth(depth);
+}
+
+/*!
+ * \return the actual texture data width. When the texture format is QImage::Format_Indexed8,
+ * this is textureWidth aligned to 32bit boundary. Otherwise this is four times textureWidth.
+ */
+int QCustom3DVolume::textureDataWidth() const
+{
+ int dataWidth = dptrc()->m_textureWidth;
+
+ if (dptrc()->m_textureFormat == QImage::Format_Indexed8)
+ dataWidth += dataWidth % 4;
+ else
+ dataWidth *= 4;
+
+ return dataWidth;
+}
+
+/*! \property QCustom3DVolume::sliceIndexX
+ *
+ * The X dimension index into the texture data indicating which vertical slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSliceIndexX(int value)
+{
+ if (dptr()->m_sliceIndexX != value) {
+ dptr()->m_sliceIndexX = value;
+ dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ emit sliceIndexXChanged(value);
+ emit dptr()->needUpdate();
+ }
+}
+
+int QCustom3DVolume::sliceIndexX() const
+{
+ return dptrc()->m_sliceIndexX;
+}
+
+/*! \property QCustom3DVolume::sliceIndexY
+ *
+ * The Y dimension index into the texture data indicating which horizontal slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSliceIndexY(int value)
+{
+ if (dptr()->m_sliceIndexY != value) {
+ dptr()->m_sliceIndexY = value;
+ dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ emit sliceIndexYChanged(value);
+ emit dptr()->needUpdate();
+ }
+}
+
+int QCustom3DVolume::sliceIndexY() const
+{
+ return dptrc()->m_sliceIndexY;
+}
+
+/*! \property QCustom3DVolume::sliceIndexZ
+ *
+ * The Z dimension index into the texture data indicating which vertical slice to show.
+ * Setting any dimension to negative indicates no slice for that dimension is drawn.
+ * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSliceIndexZ(int value)
+{
+ if (dptr()->m_sliceIndexZ != value) {
+ dptr()->m_sliceIndexZ = value;
+ dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ emit sliceIndexZChanged(value);
+ emit dptr()->needUpdate();
+ }
+}
+
+int QCustom3DVolume::sliceIndexZ() const
+{
+ return dptrc()->m_sliceIndexZ;
+}
+
+/*!
+ * A convenience function for setting all three slice indices (\a x, \a y, and \a z) at once.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSliceIndices(int x, int y, int z)
+{
+ setSliceIndexX(x);
+ setSliceIndexY(y);
+ setSliceIndexZ(z);
+}
+
+/*! \property QCustom3DVolume::colorTable
+ *
+ * The array containing the colors for indexed texture formats. If the texture format is not
+ * indexed, this array is not used and can be empty.
+ *
+ * Defaults to \c{0}.
+ *
+ * \sa textureData, textureFormat, QImage::colorTable()
+ */
+void QCustom3DVolume::setColorTable(const QVector<QRgb> &colors)
+{
+ if (dptr()->m_colorTable != colors) {
+ dptr()->m_colorTable = colors;
+ dptr()->m_dirtyBitsVolume.colorTableDirty = true;
+ emit colorTableChanged();
+ emit dptr()->needUpdate();
+ }
+}
+
+QVector<QRgb> QCustom3DVolume::colorTable() const
+{
+ return dptrc()->m_colorTable;
+}
+
+/*! \property QCustom3DVolume::textureData
+ *
+ * The array containing the texture data in the format specified by textureFormat.
+ * The size of this array must be at least
+ * (\c{textureDataWidth * textureHeight * textureDepth * texture format color depth in bytes}).
+ *
+ * A 3D texture is defined by a stack of 2D subtextures. Each subtexture must be of identical size
+ * (\c{textureDataWidth * textureHeight}), and the depth of the stack is defined by textureDepth
+ * property. Each 2D texture data is identical to a QImage data with the same format, so
+ * QImage::bits() can be used to supply the data for each subtexture.
+ *
+ * Ownership of the new array transfers to QCustom3DVolume instance.
+ * If another array is set, the previous array is deleted.
+ * If the same array is set again, it is assumed that the array contents have been changed and the
+ * graph rendering is triggered.
+ *
+ * \note Each X-line of the data needs to be 32bit aligned. If the textureFormat is
+ * QImage::Format_Indexed8 and textureWidth is not divisible by four, padding bytes need
+ * to be added to each X-line of the \a data. You can get the padded byte count with
+ * textureDataWidth() function.
+ *
+ * Defaults to \c{0}.
+ *
+ * \sa colorTable, textureFormat, setSubTextureData(), textureDataWidth()
+ */
+void QCustom3DVolume::setTextureData(QVector<uchar> *data)
+{
+ if (dptr()->m_textureData != data)
+ delete dptr()->m_textureData;
+
+ // Even if the pointer is same as previously, consider this property changed, as the values
+ // can be changed unbeknownst to us via the array pointer.
+ dptr()->m_textureData = data;
+ dptr()->m_dirtyBitsVolume.textureDataDirty = true;
+ emit textureDataChanged(data);
+ emit dptr()->needUpdate();
+}
+
+/*!
+ * This function creates a new texture data array from an array of \a images and sets it as
+ * textureData for this volume object. The texture dimensions are also set according to image
+ * and array dimensions. All of the images in the array must be the same size. If the images are not
+ * all in QImage::Format_Indexed8 format, all texture data will be converted into
+ * QImage::Format_ARGB32 format. If the images are in QImage::Format_Indexed8 format, the colorTable
+ * for the entire volume will be taken from the first image.
+ *
+ * \return pointer to the newly created array.
+ *
+ * \sa textureData, textureWidth, textureHeight, textureDepth, textureFormat
+ */
+QVector<uchar> *QCustom3DVolume::createTextureData(const QVector<QImage *> &images)
+{
+ int imageCount = images.size();
+ if (imageCount) {
+ QImage *currentImage = images.at(0);
+ int imageWidth = currentImage->width();
+ int imageHeight = currentImage->height();
+ QImage::Format imageFormat = currentImage->format();
+ bool convert = false;
+ if (imageFormat != QImage::Format_Indexed8 && imageFormat != QImage::Format_ARGB32) {
+ convert = true;
+ imageFormat = QImage::Format_ARGB32;
+ } else {
+ for (int i = 0; i < imageCount; i++) {
+ currentImage = images.at(i);
+ if (imageWidth != currentImage->width() || imageHeight != currentImage->height()) {
+ qWarning() << __FUNCTION__ << "Not all images were of the same size.";
+ setTextureData(0);
+ setTextureWidth(0);
+ setTextureHeight(0);
+ setTextureDepth(0);
+ return 0;
+
+ }
+ if (currentImage->format() != imageFormat) {
+ convert = true;
+ imageFormat = QImage::Format_ARGB32;
+ break;
+ }
+ }
+ }
+ int colorBytes = (imageFormat == QImage::Format_Indexed8) ? 1 : 4;
+ int imageByteWidth = (imageFormat == QImage::Format_Indexed8)
+ ? currentImage->bytesPerLine() : imageWidth;
+ int frameSize = imageByteWidth * imageHeight * colorBytes;
+ QVector<uchar> *newTextureData = new QVector<uchar>;
+ newTextureData->resize(frameSize * imageCount);
+ uchar *texturePtr = newTextureData->data();
+ QImage convertedImage;
+
+ for (int i = 0; i < imageCount; i++) {
+ currentImage = images.at(i);
+ if (convert) {
+ convertedImage = currentImage->convertToFormat(imageFormat);
+ currentImage = &convertedImage;
+ }
+ memcpy(texturePtr, static_cast<void *>(currentImage->bits()), frameSize);
+ texturePtr += frameSize;
+ }
+
+ if (imageFormat == QImage::Format_Indexed8)
+ setColorTable(images.at(0)->colorTable());
+ setTextureData(newTextureData);
+ setTextureFormat(imageFormat);
+ setTextureWidth(imageWidth);
+ setTextureHeight(imageHeight);
+ setTextureDepth(imageCount);
+ } else {
+ setTextureData(0);
+ setTextureWidth(0);
+ setTextureHeight(0);
+ setTextureDepth(0);
+ }
+ return dptr()->m_textureData;
+}
+
+QVector<uchar> *QCustom3DVolume::textureData() const
+{
+ return dptrc()->m_textureData;
+}
+
+/*!
+ * This function allows setting a single 2D subtexture of the 3D texture.
+ * The \a depthIndex parameter specifies the subtexture to set.
+ * The texture\a data must be in the format specified by textureFormat property and have size of
+ * (\c{textureDataWidth * textureHeight * texture format color depth in bytes}).
+ *
+ * \note Each X-line of the data needs to be 32bit aligned. If the textureFormat is
+ * QImage::Format_Indexed8 and textureWidth is not divisible by four, padding bytes need
+ * to be added to each X-line of the \a data.
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSubTextureData(int depthIndex, const uchar *data)
+{
+ if (data) {
+ int frameSize = textureDataWidth() * dptr()->m_textureHeight;
+ int startIndex = depthIndex * frameSize;
+
+ if (depthIndex >= dptr()->m_textureDepth
+ || (startIndex + frameSize) > dptr()->m_textureData->size()) {
+ qWarning() << __FUNCTION__ << "Attempted to set invalid subtexture.";
+ } else {
+ void *subTexPtr = dptr()->m_textureData->data() + startIndex;
+ memcpy(subTexPtr, static_cast<const void *>(data), frameSize);
+ dptr()->m_dirtyBitsVolume.textureDataDirty = true;
+ emit textureDataChanged(dptr()->m_textureData);
+ emit dptr()->needUpdate();
+ }
+ } else {
+ qWarning() << __FUNCTION__ << "Tried to set null data.";
+ }
+}
+
+/*!
+ * This function allows setting a single 2D subtexture of the 3D texture to a source \a image;
+ * The \a depthIndex parameter specifies the subtexture to set.
+ * The image must be in the format specified by the textureFormat property if the textureFormat
+ * is indexed. If the textureFormat is QImage::Format_ARGB32, the image is converted to that format.
+ * The image must have the size of (\c{textureWidth * textureHeight}).
+ *
+ * \sa textureData
+ */
+void QCustom3DVolume::setSubTextureData(int depthIndex, const QImage &image)
+{
+ if (image.width() == dptr()->m_textureWidth
+ && image.height() == dptr()->m_textureHeight
+ && (image.format() == dptr()->m_textureFormat
+ || dptr()->m_textureFormat == QImage::Format_ARGB32)) {
+ QImage convertedImage;
+ if (dptr()->m_textureFormat == QImage::Format_ARGB32
+ && image.format() != QImage::Format_ARGB32) {
+ convertedImage = image.convertToFormat(QImage::Format_ARGB32);
+ } else {
+ convertedImage = image;
+ }
+ setSubTextureData(depthIndex, convertedImage.bits());
+ } else {
+ qWarning() << __FUNCTION__ << "Invalid image size or format.";
+ }
+}
+
+/*! \property QCustom3DVolume::textureFormat
+ *
+ * The format of the textureData. Only two formats are supported currently:
+ * QImage::Format_Indexed8 and QImage::Format_ARGB32. If an indexed format is specified, colorTable
+ * must also be set.
+ * Defaults to QImage::Format_ARGB32.
+ *
+ * \sa colorTable, textureData
+ */
+void QCustom3DVolume::setTextureFormat(QImage::Format format)
+{
+ if (format == QImage::Format_ARGB32 || format == QImage::Format_Indexed8) {
+ if (dptr()->m_textureFormat != format) {
+ dptr()->m_textureFormat = format;
+ dptr()->m_dirtyBitsVolume.textureFormatDirty = true;
+ emit textureFormatChanged(format);
+ emit dptr()->needUpdate();
+ }
+ } else {
+ qWarning() << __FUNCTION__ << "Attempted to set invalid texture format.";
+ }
+}
+
+QImage::Format QCustom3DVolume::textureFormat() const
+{
+ return dptrc()->m_textureFormat;
+}
+
+
+/*!
+ * \internal
+ */
+QCustom3DVolumePrivate *QCustom3DVolume::dptr()
+{
+ return static_cast<QCustom3DVolumePrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QCustom3DVolumePrivate *QCustom3DVolume::dptrc() const
+{
+ return static_cast<const QCustom3DVolumePrivate *>(d_ptr.data());
+}
+
+QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q) :
+ QCustom3DItemPrivate(q),
+ m_sliceIndexX(-1),
+ m_sliceIndexY(-1),
+ m_sliceIndexZ(-1),
+ m_textureWidth(0),
+ m_textureHeight(0),
+ m_textureDepth(0),
+ m_textureFormat(QImage::Format_ARGB32),
+ m_textureData(0)
+{
+ m_isVolumeItem = true;
+ m_meshFile = QStringLiteral(":/defaultMeshes/barFull");
+}
+
+QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector3D &position,
+ const QVector3D &scaling,
+ const QQuaternion &rotation,
+ int textureWidth, int textureHeight,
+ int textureDepth, QVector<uchar> *textureData,
+ QImage::Format textureFormat,
+ const QVector<QRgb> &colorTable) :
+ QCustom3DItemPrivate(q, QStringLiteral(":/defaultMeshes/barFull"), position, scaling, rotation),
+ m_sliceIndexX(-1),
+ m_sliceIndexY(-1),
+ m_sliceIndexZ(-1),
+ m_textureWidth(textureWidth),
+ m_textureHeight(textureHeight),
+ m_textureDepth(textureDepth),
+ m_textureFormat(textureFormat),
+ m_colorTable(colorTable),
+ m_textureData(textureData)
+{
+ m_isVolumeItem = true;
+ m_shadowCasting = false;
+
+ if (m_textureWidth < 0)
+ m_textureWidth = 0;
+ if (m_textureHeight < 0)
+ m_textureHeight = 0;
+ if (m_textureDepth < 0)
+ m_textureDepth = 0;
+
+ if (m_colorTable.size() != 256)
+ m_colorTable.clear();
+
+ if (m_textureFormat != QImage::Format_Indexed8)
+ m_textureFormat = QImage::Format_ARGB32;
+
+}
+
+QCustom3DVolumePrivate::~QCustom3DVolumePrivate()
+{
+ delete m_textureData;
+}
+
+void QCustom3DVolumePrivate::resetDirtyBits()
+{
+ QCustom3DItemPrivate::resetDirtyBits();
+
+ m_dirtyBitsVolume.textureDimensionsDirty = false;
+ m_dirtyBitsVolume.sliceIndicesDirty = false;
+ m_dirtyBitsVolume.colorTableDirty = false;
+ m_dirtyBitsVolume.textureDataDirty = false;
+ m_dirtyBitsVolume.textureFormatDirty = false;
+}
+
+QCustom3DVolume *QCustom3DVolumePrivate::qptr()
+{
+ return static_cast<QCustom3DVolume *>(q_ptr);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h
new file mode 100644
index 00000000..498922e8
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QCUSTOM3DVOLUME_H
+#define QCUSTOM3DVOLUME_H
+
+#include <QtDataVisualization/qdatavisualizationglobal.h>
+#include <QtDataVisualization/QCustom3DItem>
+#include <QtGui/QColor>
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QCustom3DVolumePrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QCustom3DVolume : public QCustom3DItem
+{
+ Q_OBJECT
+ Q_PROPERTY(int textureWidth READ textureWidth WRITE setTextureWidth NOTIFY textureWidthChanged)
+ Q_PROPERTY(int textureHeight READ textureHeight WRITE setTextureHeight NOTIFY textureHeightChanged)
+ Q_PROPERTY(int textureDepth READ textureDepth WRITE setTextureDepth NOTIFY textureDepthChanged)
+ Q_PROPERTY(int sliceIndexX READ sliceIndexX WRITE setSliceIndexX NOTIFY sliceIndexXChanged)
+ Q_PROPERTY(int sliceIndexY READ sliceIndexY WRITE setSliceIndexY NOTIFY sliceIndexYChanged)
+ Q_PROPERTY(int sliceIndexZ READ sliceIndexZ WRITE setSliceIndexZ NOTIFY sliceIndexZChanged)
+ 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)
+
+public:
+
+ explicit QCustom3DVolume(QObject *parent = 0);
+ explicit QCustom3DVolume(const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation, int textureWidth,
+ int textureHeight, int textureDepth,
+ QVector<uchar> *textureData, QImage::Format textureFormat,
+ const QVector<QRgb> &colorTable, QObject *parent = 0);
+ virtual ~QCustom3DVolume();
+
+ void setTextureWidth(int value);
+ int textureWidth() const;
+ void setTextureHeight(int value);
+ int textureHeight() const;
+ void setTextureDepth(int value);
+ int textureDepth() const;
+ void setTextureDimensions(int width, int height, int depth);
+ int textureDataWidth() const;
+
+ void setSliceIndexX(int value);
+ int sliceIndexX() const;
+ void setSliceIndexY(int value);
+ int sliceIndexY() const;
+ void setSliceIndexZ(int value);
+ int sliceIndexZ() const;
+ void setSliceIndices(int x, int y, int z);
+
+ void setColorTable(const QVector<QRgb> &colors);
+ QVector<QRgb> colorTable() const;
+
+ void setTextureData(QVector<uchar> *data);
+ QVector<uchar> *createTextureData(const QVector<QImage *> &images);
+ QVector<uchar> *textureData() const;
+ void setSubTextureData(int depthIndex, const uchar *data);
+ void setSubTextureData(int depthIndex, const QImage &image);
+
+ void setTextureFormat(QImage::Format format);
+ QImage::Format textureFormat() const;
+
+signals:
+ void textureWidthChanged(int value);
+ void textureHeightChanged(int value);
+ void textureDepthChanged(int value);
+ void sliceIndexXChanged(int value);
+ void sliceIndexYChanged(int value);
+ void sliceIndexZChanged(int value);
+ void colorTableChanged();
+ void textureDataChanged(QVector<uchar> *data);
+ void textureFormatChanged(QImage::Format format);
+
+protected:
+ QCustom3DVolumePrivate *dptr();
+ const QCustom3DVolumePrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QCustom3DVolume)
+
+ friend class Abstract3DRenderer;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qcustom3dvolume_p.h b/src/datavisualization/data/qcustom3dvolume_p.h
new file mode 100644
index 00000000..69dd1eb2
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QCUSTOM3DVOLUME_P_H
+#define QCUSTOM3DVOLUME_P_H
+
+#include "qcustom3dvolume.h"
+#include "qcustom3ditem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+struct QCustomVolumeDirtyBitField {
+ bool textureDimensionsDirty : 1;
+ bool sliceIndicesDirty : 1;
+ bool colorTableDirty : 1;
+ bool textureDataDirty : 1;
+ bool textureFormatDirty : 1;
+
+ QCustomVolumeDirtyBitField()
+ : textureDimensionsDirty(false),
+ sliceIndicesDirty(false),
+ colorTableDirty(false),
+ textureDataDirty(false),
+ textureFormatDirty(false)
+ {
+ }
+};
+
+class QCustom3DVolumePrivate : public QCustom3DItemPrivate
+{
+ Q_OBJECT
+
+public:
+ QCustom3DVolumePrivate(QCustom3DVolume *q);
+ QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation, int textureWidth,
+ int textureHeight, int textureDepth, QVector<uchar> *textureData,
+ QImage::Format textureFormat, const QVector<QRgb> &colorTable);
+ virtual ~QCustom3DVolumePrivate();
+
+ void resetDirtyBits();
+
+ QCustom3DVolume *qptr();
+
+public:
+ int m_textureWidth;
+ int m_textureHeight;
+ int m_textureDepth;
+ int m_sliceIndexX;
+ int m_sliceIndexY;
+ int m_sliceIndexZ;
+
+ QImage::Format m_textureFormat;
+ QVector<QRgb> m_colorTable;
+ QVector<uchar> *m_textureData;
+
+ QCustomVolumeDirtyBitField m_dirtyBitsVolume;
+
+private:
+ friend class QCustom3DVolume;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index 14cf7109..cbb90af0 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -24,6 +24,7 @@
#include "shaderhelper_p.h"
#include "qcustom3ditem_p.h"
#include "qcustom3dlabel_p.h"
+#include "qcustom3dvolume_p.h"
#include <QtCore/qmath.h>
@@ -57,6 +58,8 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
m_selectionLabelItem(0),
m_visibleSeriesCount(0),
m_customItemShader(0),
+ m_volumeTextureShader(0),
+ m_volumeTextureSliceShader(0),
m_useOrthoProjection(false),
m_xFlipped(false),
m_yFlipped(false),
@@ -96,6 +99,8 @@ Abstract3DRenderer::~Abstract3DRenderer()
delete m_cachedTheme;
delete m_selectionLabelItem;
delete m_customItemShader;
+ delete m_volumeTextureShader;
+ delete m_volumeTextureSliceShader;
foreach (SeriesRenderCache *cache, m_renderCacheList) {
cache->cleanup(m_textureHelper);
@@ -196,6 +201,20 @@ void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader,
m_customItemShader->initialize();
}
+void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader,
+ const QString &fragmentShader,
+ const QString &sliceShader)
+{
+ if (m_volumeTextureShader)
+ delete m_volumeTextureShader;
+ m_volumeTextureShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_volumeTextureShader->initialize();
+ if (m_volumeTextureSliceShader)
+ delete m_volumeTextureSliceShader;
+ m_volumeTextureSliceShader = new ShaderHelper(this, vertexShader, sliceShader);
+ m_volumeTextureSliceShader->initialize();
+}
+
void Abstract3DRenderer::updateTheme(Q3DTheme *theme)
{
// Synchronize the controller theme with renderer
@@ -279,6 +298,9 @@ void Abstract3DRenderer::reInitShaders()
initCustomItemShaders(QStringLiteral(":/shaders/vertexTexture"),
QStringLiteral(":/shaders/fragmentTexture"));
}
+ initVolumeTextureShaders(QStringLiteral(":/shaders/vertexTexture3D"),
+ QStringLiteral(":/shaders/fragmentTexture3D"),
+ QStringLiteral(":/shaders/fragmentTexture3DSlice"));
#else
initGradientShaders(QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentColorOnYES2"));
@@ -906,6 +928,7 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
QVector3D scaling = item->scaling();
QImage textureImage = item->d_ptr->textureImage();
bool facingCamera = false;
+ GLuint texture;
if (item->d_ptr->m_isLabelItem) {
QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item);
float pointSize = labelItem->font().pointSizeF();
@@ -925,13 +948,39 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
scaling.setY(scaling.y() * textureImage.height() * scaledFontSize);
// Check if facing camera
facingCamera = labelItem->isFacingCamera();
+#if !defined(QT_OPENGL_ES_2)
+ } else if (item->d_ptr->m_isVolumeItem) {
+ QCustom3DVolume *volumeItem = static_cast<QCustom3DVolume *>(item);
+ newItem->setTextureWidth(volumeItem->textureWidth());
+ newItem->setTextureHeight(volumeItem->textureHeight());
+ newItem->setTextureDepth(volumeItem->textureDepth());
+ if (volumeItem->textureFormat() == QImage::Format_Indexed8)
+ newItem->setColorTable(volumeItem->colorTable());
+ newItem->setTextureFormat(volumeItem->textureFormat());
+ newItem->setVolume(true);
+ newItem->setBlendNeeded(true);
+ texture = m_textureHelper->create3DTexture(volumeItem->textureData(),
+ volumeItem->textureWidth(),
+ volumeItem->textureHeight(),
+ volumeItem->textureDepth(),
+ volumeItem->textureFormat());
+ newItem->setSliceIndexX(volumeItem->sliceIndexX());
+ newItem->setSliceIndexY(volumeItem->sliceIndexY());
+ newItem->setSliceIndexZ(volumeItem->sliceIndexZ());
+#endif
}
newItem->setScaling(scaling);
newItem->setRotation(item->rotation());
newItem->setPosition(item->position());
newItem->setPositionAbsolute(item->isPositionAbsolute());
- newItem->setBlendNeeded(textureImage.hasAlphaChannel());
- GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
+#if !defined(QT_OPENGL_ES_2)
+ // In OpenGL ES we simply draw volumes as regular custom item placeholders.
+ if (!item->d_ptr->m_isVolumeItem)
+#endif
+ {
+ newItem->setBlendNeeded(textureImage.hasAlphaChannel());
+ texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
+ }
newItem->setTexture(texture);
item->d_ptr->clearTextureImage();
QVector3D translation = convertPositionToTranslation(item->position(),
@@ -996,12 +1045,17 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
m_cachedTheme->isLabelBorderEnabled());
textureImage = item->d_ptr->textureImage();
}
+ } else
+#if !defined(QT_OPENGL_ES_2)
+ if (!item->d_ptr->m_isVolumeItem)
+#endif
+ {
+ renderItem->setBlendNeeded(textureImage.hasAlphaChannel());
+ GLuint oldTexture = renderItem->texture();
+ m_textureHelper->deleteTexture(&oldTexture);
+ GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
+ renderItem->setTexture(texture);
}
- renderItem->setBlendNeeded(textureImage.hasAlphaChannel());
- GLuint oldTexture = renderItem->texture();
- m_textureHelper->deleteTexture(&oldTexture);
- GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
- renderItem->setTexture(texture);
item->d_ptr->clearTextureImage();
item->d_ptr->m_dirtyBits.textureDirty = false;
}
@@ -1028,6 +1082,39 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
renderItem->setFacingCamera(labelItem->isFacingCamera());
labelItem->dptr()->m_facingCameraDirty = false;
}
+#if !defined(QT_OPENGL_ES_2)
+ } else if (item->d_ptr->m_isVolumeItem) {
+ QCustom3DVolume *volumeItem = static_cast<QCustom3DVolume *>(item);
+ if (volumeItem->dptr()->m_dirtyBitsVolume.colorTableDirty) {
+ renderItem->setColorTable(volumeItem->colorTable());
+ volumeItem->dptr()->m_dirtyBitsVolume.colorTableDirty = false;
+ }
+ if (volumeItem->dptr()->m_dirtyBitsVolume.textureDimensionsDirty
+ || volumeItem->dptr()->m_dirtyBitsVolume.textureDataDirty
+ || volumeItem->dptr()->m_dirtyBitsVolume.textureFormatDirty) {
+ GLuint oldTexture = renderItem->texture();
+ m_textureHelper->deleteTexture(&oldTexture);
+ GLuint texture = m_textureHelper->create3DTexture(volumeItem->textureData(),
+ volumeItem->textureWidth(),
+ volumeItem->textureHeight(),
+ volumeItem->textureDepth(),
+ volumeItem->textureFormat());
+ renderItem->setTexture(texture);
+ renderItem->setTextureWidth(volumeItem->textureWidth());
+ renderItem->setTextureHeight(volumeItem->textureHeight());
+ renderItem->setTextureDepth(volumeItem->textureDepth());
+ renderItem->setTextureFormat(volumeItem->textureFormat());
+ volumeItem->dptr()->m_dirtyBitsVolume.textureDimensionsDirty = false;
+ volumeItem->dptr()->m_dirtyBitsVolume.textureDataDirty = false;
+ volumeItem->dptr()->m_dirtyBitsVolume.textureFormatDirty = false;
+ }
+ if (volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty) {
+ renderItem->setSliceIndexX(volumeItem->sliceIndexX());
+ renderItem->setSliceIndexY(volumeItem->sliceIndexY());
+ renderItem->setSliceIndexZ(volumeItem->sliceIndexZ());
+ volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty = false;
+ }
+#endif
}
}
@@ -1042,7 +1129,9 @@ void Abstract3DRenderer::updateCustomItemPositions()
#ifdef USE_REFLECTIONS
void Abstract3DRenderer::drawCustomItems(RenderingState state,
- ShaderHelper *shader,
+ ShaderHelper *regularShader,
+ ShaderHelper *volumeShader,
+ ShaderHelper *volumeSliceShader,
const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthProjectionViewMatrix,
@@ -1051,7 +1140,9 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
GLfloat reflection)
#else
void Abstract3DRenderer::drawCustomItems(RenderingState state,
- ShaderHelper *shader,
+ ShaderHelper *regularShader,
+ ShaderHelper *volumeShader,
+ ShaderHelper *volumeSliceShader,
const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthProjectionViewMatrix,
@@ -1059,11 +1150,17 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
GLfloat shadowQuality)
#endif
{
+#if defined(QT_OPENGL_ES_2)
+ Q_UNUSED(volumeShader)
+ Q_UNUSED(volumeSliceShader)
+#endif
if (m_customRenderCache.isEmpty())
return;
+ ShaderHelper *shader = regularShader;
+ shader->bind();
+
if (RenderingNormal == state) {
- shader->bind();
shader->setUniformValue(shader->lightP(), m_cachedScene->activeLight()->position());
shader->setUniformValue(shader->ambientS(), m_cachedTheme->ambientLightStrength());
shader->setUniformValue(shader->lightColor(),
@@ -1137,6 +1234,22 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
if (RenderingNormal == state) {
// Normal render
+#if !defined(QT_OPENGL_ES_2)
+ ShaderHelper *prevShader = shader;
+ if (item->isVolume()) {
+ if (item->sliceIndexX() >= 0
+ || item->sliceIndexY() >= 0
+ || item->sliceIndexZ() >= 0) {
+ shader = volumeSliceShader;
+ } else {
+ shader = volumeShader;
+ }
+ } else {
+ shader = regularShader;
+ }
+ if (shader != prevShader)
+ shader->bind();
+#endif
shader->setUniformValue(shader->model(), modelMatrix);
shader->setUniformValue(shader->MVP(), MVPMatrix);
shader->setUniformValue(shader->nModel(), itModelMatrix.inverted().transposed());
@@ -1144,14 +1257,17 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
if (item->isBlendNeeded()) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_CULL_FACE);
+#if !defined(QT_OPENGL_ES_2)
+ if (!item->isVolume())
+#endif
+ glDisable(GL_CULL_FACE);
} else {
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
}
#if !defined(QT_OPENGL_ES_2)
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && !item->isVolume()) {
// Set shadow shader bindings
shader->setUniformValue(shader->shadowQ(), shadowQuality);
shader->setUniformValue(shader->depth(), depthProjectionViewMatrix * modelMatrix);
@@ -1164,8 +1280,34 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
#endif
{
// Set shadowless shader bindings
- shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength());
- m_drawer->drawObject(shader, item->mesh(), item->texture());
+#if !defined(QT_OPENGL_ES_2)
+ if (item->isVolume()) {
+ // Volume shaders repurpose light position for camera position relative to item
+ QVector3D cameraPos = m_cachedScene->activeCamera()->position();
+ cameraPos = MVPMatrix.inverted().map(cameraPos);
+ shader->setUniformValue(shader->cameraPositionRelativeToModel(), -cameraPos);
+ GLint color8Bit = (item->textureFormat() == QImage::Format_Indexed8) ? 1 : 0;
+ if (color8Bit) {
+ shader->setUniformValueArray(shader->colorIndex(),
+ item->colorTable().constData(), 256);
+ }
+ shader->setUniformValue(shader->color8Bit(), color8Bit);
+ if (shader == volumeSliceShader) {
+ QVector3D slices((float(item->sliceIndexX()) + 0.5f)
+ / float(item->textureWidth()) * 2.0 - 1.0,
+ (float(item->sliceIndexY()) + 0.5f)
+ / float(item->textureHeight()) * 2.0 - 1.0,
+ (float(item->sliceIndexZ()) + 0.5f)
+ / float(item->textureDepth()) * 2.0 - 1.0);
+ shader->setUniformValue(shader->volumeSliceIndices(), slices);
+ }
+ m_drawer->drawObject(shader, item->mesh(), 0, 0, item->texture());
+ } else
+#endif
+ {
+ shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength());
+ m_drawer->drawObject(shader, item->mesh(), item->texture());
+ }
}
} else if (RenderingSelection == state) {
// Selection render
@@ -1203,6 +1345,9 @@ void Abstract3DRenderer::drawRadialGrid(ShaderHelper *shader, float yFloorLinePo
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthMatrix)
{
+#if defined(QT_OPENGL_ES_2)
+ Q_UNUSED(depthMatrix)
+#endif
static QVector<QQuaternion> lineRotations;
if (!lineRotations.size()) {
lineRotations.resize(polarGridRoundness);
@@ -1264,6 +1409,9 @@ void Abstract3DRenderer::drawAngularGrid(ShaderHelper *shader, float yFloorLineP
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthMatrix)
{
+#if defined(QT_OPENGL_ES_2)
+ Q_UNUSED(depthMatrix)
+#endif
float halfRatio((m_polarRadius + (labelMargin / 2.0f)) / 2.0f);
QVector3D gridLineScaler(gridLineWidth, gridLineWidth, halfRatio);
int gridLineCount = m_axisCacheX.gridLineCount();
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
index 50370954..7874a1ad 100644
--- a/src/datavisualization/engine/abstract3drenderer_p.h
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -94,6 +94,9 @@ public:
const QString &fragmentShader) = 0;
virtual void initCustomItemShaders(const QString &vertexShader,
const QString &fragmentShader);
+ virtual void initVolumeTextureShaders(const QString &vertexShader,
+ const QString &fragmentShader,
+ const QString &sliceShader);
virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation,
QAbstract3DAxis::AxisType type);
virtual void updateAxisTitle(QAbstract3DAxis::AxisOrientation orientation,
@@ -145,13 +148,15 @@ public:
QString &selectionLabel();
#ifdef USE_REFLECTIONS
- void drawCustomItems(RenderingState state, ShaderHelper *shader,
+ void drawCustomItems(RenderingState state, ShaderHelper *regularShader,
+ ShaderHelper *volumeShader, ShaderHelper *volumeSliceShader,
const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthProjectionViewMatrix,
GLuint depthTexture, GLfloat shadowQuality, GLfloat reflection = 1.0f);
#else
- void drawCustomItems(RenderingState state, ShaderHelper *shader,
+ void drawCustomItems(RenderingState state, ShaderHelper *regularShader,
+ ShaderHelper *volumeShader, ShaderHelper *volumeSliceShader,
const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionViewMatrix,
const QMatrix4x4 &depthProjectionViewMatrix,
@@ -247,6 +252,8 @@ protected:
int m_visibleSeriesCount;
ShaderHelper *m_customItemShader;
+ ShaderHelper *m_volumeTextureShader;
+ ShaderHelper *m_volumeTextureSliceShader;
bool m_useOrthoProjection;
bool m_xFlipped;
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index 38fa3147..085b881e 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -1093,9 +1093,11 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
}
}
- Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
- projectionViewMatrix, depthProjectionViewMatrix,
- m_depthTexture, m_shadowQualityToShader);
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
+ projectionViewMatrix,
+ depthProjectionViewMatrix, m_depthTexture,
+ m_shadowQualityToShader);
// Disable drawing to depth framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -1179,7 +1181,9 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
}
}
glCullFace(GL_BACK);
- Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, viewMatrix,
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader,
+ m_volumeTextureShader, m_volumeTextureSliceShader,
+ viewMatrix,
projectionViewMatrix, depthProjectionViewMatrix,
m_depthTexture, m_shadowQualityToShader);
drawLabels(true, activeCamera, viewMatrix, projectionMatrix);
@@ -1267,7 +1271,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
drawGridLines(depthProjectionViewMatrix, projectionViewMatrix, viewMatrix);
// Draw custom items
- Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
projectionViewMatrix, depthProjectionViewMatrix,
m_depthTexture, m_shadowQualityToShader);
diff --git a/src/datavisualization/engine/drawer.cpp b/src/datavisualization/engine/drawer.cpp
index b8726840..4191efc4 100644
--- a/src/datavisualization/engine/drawer.cpp
+++ b/src/datavisualization/engine/drawer.cpp
@@ -93,8 +93,11 @@ QFont Drawer::font() const
}
void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId,
- GLuint depthTextureId)
+ GLuint depthTextureId, GLuint textureId3D)
{
+#if defined(QT_OPENGL_ES_2)
+ Q_UNUSED(textureId3D)
+#endif
if (textureId) {
// Activate texture
glActiveTexture(GL_TEXTURE0);
@@ -108,6 +111,14 @@ void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLui
glBindTexture(GL_TEXTURE_2D, depthTextureId);
shader->setUniformValue(shader->shadow(), 1);
}
+#if !defined(QT_OPENGL_ES_2)
+ if (textureId3D) {
+ // Activate texture
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_3D, textureId3D);
+ shader->setUniformValue(shader->texture(), 2);
+ }
+#endif
// 1st attribute buffer : vertices
glEnableVertexAttribArray(shader->posAtt());
@@ -139,6 +150,12 @@ void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLui
glDisableVertexAttribArray(shader->posAtt());
// Release textures
+#if !defined(QT_OPENGL_ES_2)
+ if (textureId3D) {
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_3D, 0);
+ }
+#endif
if (depthTextureId) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
diff --git a/src/datavisualization/engine/drawer_p.h b/src/datavisualization/engine/drawer_p.h
index ffcea315..709503dd 100644
--- a/src/datavisualization/engine/drawer_p.h
+++ b/src/datavisualization/engine/drawer_p.h
@@ -75,7 +75,7 @@ public:
inline GLfloat scaledFontSize() const { return m_scaledFontSize; }
void drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId = 0,
- GLuint depthTextureId = 0);
+ GLuint depthTextureId = 0, GLuint textureId3D = 0);
void drawSelectionObject(ShaderHelper *shader, AbstractObjectHelper *object);
void drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object);
void drawPoint(ShaderHelper *shader);
diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc
index f788b5df..936ed53f 100644
--- a/src/datavisualization/engine/engine.qrc
+++ b/src/datavisualization/engine/engine.qrc
@@ -59,5 +59,8 @@
<file alias="vertexTexture">shaders/texture.vert</file>
<file alias="fragmentTexturedSurfaceShadowFlat">shaders/surfaceTexturedShadowFlat.frag</file>
<file alias="fragmentSurfaceTexturedFlat">shaders/surfaceTexturedFlat.frag</file>
+ <file alias="fragmentTexture3D">shaders/texture3d.frag</file>
+ <file alias="vertexTexture3D">shaders/texture3d.vert</file>
+ <file alias="fragmentTexture3DSlice">shaders/texture3dslice.frag</file>
</qresource>
</RCC>
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
index 09225b99..13f6e02c 100644
--- a/src/datavisualization/engine/scatter3drenderer.cpp
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -538,9 +538,11 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
}
}
- Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
- projectionViewMatrix, depthProjectionViewMatrix,
- m_depthTexture, m_shadowQualityToShader);
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
+ projectionViewMatrix,
+ depthProjectionViewMatrix, m_depthTexture,
+ m_shadowQualityToShader);
// Disable drawing to framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -641,9 +643,11 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
}
}
- Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, viewMatrix,
- projectionViewMatrix, depthProjectionViewMatrix,
- m_depthTexture, m_shadowQualityToShader);
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader,
+ m_volumeTextureShader, m_volumeTextureSliceShader,
+ viewMatrix, projectionViewMatrix,
+ depthProjectionViewMatrix, m_depthTexture,
+ m_shadowQualityToShader);
drawLabels(true, activeCamera, viewMatrix, projectionMatrix);
@@ -1407,7 +1411,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
}
}
- Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
projectionViewMatrix, depthProjectionViewMatrix,
m_depthTexture, m_shadowQualityToShader);
diff --git a/src/datavisualization/engine/shaders/default.frag b/src/datavisualization/engine/shaders/default.frag
index c03b1054..0276ed95 100644
--- a/src/datavisualization/engine/shaders/default.frag
+++ b/src/datavisualization/engine/shaders/default.frag
@@ -33,5 +33,6 @@ void main() {
materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance;
gl_FragColor.a = color_mdl.a;
+ gl_FragColor = clamp(gl_FragColor, 0.0, 1.0);
}
diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag
new file mode 100644
index 00000000..054b59cb
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture3d.frag
@@ -0,0 +1,70 @@
+#version 120
+
+varying highp vec3 pos;
+
+uniform highp sampler3D textureSampler;
+uniform highp vec3 cameraPositionRelativeToModel;
+uniform highp vec4 colorIndex[256];
+uniform highp int color8Bit;
+
+const float maxDist = sqrt(2.0);
+const int sampleCount = 1024;
+const float alphaThreshold = 0.001;
+void main() {
+ // Raytrace into volume, need to sample pixels along the eye ray until we hit opacity 1
+
+ // Find out where ray intersects the object
+ highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 minCorner = vec3(-1.0);
+ highp vec3 maxCorner = vec3(1.0);
+ highp vec3 t1 = invRayDir * (minCorner - pos);
+ highp vec3 t2 = invRayDir * (maxCorner - pos);
+ highp vec3 tmin = min(t1, t2);
+ highp vec3 tmax = max(t1, t2);
+ highp vec2 t = max(tmin.xx, tmin.yz);
+ t = min(tmax.xx, tmax.yz);
+ float tFar = min(t.x, t.y);
+ highp vec3 rayStart = pos;
+ // Flip Y and Z so QImage bits work directly for texture and first image is in the front
+ rayStart.yz = -rayStart.yz;
+ highp vec3 rayStop = pos + rayDir * tFar;
+ rayStop.yz = -rayStop.yz;
+
+ // Convert intersections to texture coords
+ rayStart = 0.5 * (rayStart + 1.0);
+ rayStop = 0.5 * (rayStop + 1.0);
+
+ highp vec3 curPos = rayStart;
+ highp float fullDist = distance(rayStop, rayStart);
+ highp float stepSize = maxDist / float(sampleCount); // TODO: Stepsize needs to be improved
+ highp vec3 step = normalize(rayStop - rayStart) * stepSize;
+ highp float totalDist = 0.0;
+ highp float totalAlpha = 0.0;
+ highp vec4 destColor = vec4(0, 0, 0, 0);
+ highp vec4 curColor = vec4(0, 0, 0, 0);
+ highp vec3 curRgb = vec3(0, 0, 0);
+ highp float curAlpha = 0.0;
+
+ for (int i = 0; i < sampleCount; i++) {
+ curColor = texture3D(textureSampler, curPos);
+ if (color8Bit != 0)
+ curColor = colorIndex[int(curColor.r * 255.0)];
+
+ curAlpha = curColor.a;
+ if (curAlpha > alphaThreshold) {
+ curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha);
+ destColor.rgb += curRgb;
+ totalAlpha += curAlpha;
+ }
+ curPos += step;
+ totalDist += stepSize;
+ if (totalDist > fullDist || totalAlpha >= 1.0) {
+ break;
+ }
+ }
+
+ destColor.a = totalAlpha;
+ gl_FragColor = clamp(destColor, 0.0, 1.0);
+}
+
diff --git a/src/datavisualization/engine/shaders/texture3d.vert b/src/datavisualization/engine/shaders/texture3d.vert
new file mode 100644
index 00000000..cad1ce06
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture3d.vert
@@ -0,0 +1,12 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+varying highp vec3 pos;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ pos = vertexPosition_mdl;
+}
diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag
new file mode 100644
index 00000000..641b32a5
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture3dslice.frag
@@ -0,0 +1,119 @@
+#version 120
+
+varying highp vec3 pos;
+
+uniform highp sampler3D textureSampler;
+uniform highp vec3 cameraPositionRelativeToModel;
+uniform highp vec3 volumeSliceIndices;
+uniform highp vec4 colorIndex[256];
+uniform highp int color8Bit;
+
+const highp vec3 xPlaneNormal = vec3(1.0, 0, 0);
+const highp vec3 yPlaneNormal = vec3(0, 1.0, 0);
+const highp vec3 zPlaneNormal = vec3(0, 0, 1.0);
+
+const float alphaThreshold = 0.001;
+void main() {
+ // Raytrace into volume, need to sample pixels along the eye ray until we hit opacity 1
+
+ // Find out where ray intersects the slice planes
+ highp vec3 rayDir = -(cameraPositionRelativeToModel - pos);
+ highp vec3 rayStart = pos;
+ // Flip Y and Z so QImage bits work directly for texture and first image is in the front
+ rayStart.yz = -rayStart.yz;
+ rayDir.yz = -rayDir.yz;
+ highp vec3 invRayDir = 1.0 / rayDir;
+ highp vec3 minCorner = vec3(-1.0);
+ highp vec3 maxCorner = vec3(1.0);
+ highp vec3 t1 = invRayDir * (minCorner - rayStart);
+ highp vec3 t2 = invRayDir * (maxCorner - rayStart);
+ highp vec3 tmin = min(t1, t2);
+ highp vec3 tmax = max(t1, t2);
+ highp vec2 t = max(tmin.xx, tmin.yz);
+ t = min(tmax.xx, tmax.yz);
+ float tFar = min(t.x, t.y);
+
+ highp vec3 xPoint = vec3(volumeSliceIndices.x, 0, 0);
+ highp vec3 yPoint = vec3(0, volumeSliceIndices.y, 0);
+ highp vec3 zPoint = vec3(0, 0, volumeSliceIndices.z);
+ highp float firstD = tFar + 1.0;
+ highp float secondD = firstD;
+ highp float thirdD = firstD;
+ if (volumeSliceIndices.x >= -1.0) {
+ highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(rayDir, xPlaneNormal);
+ if (dx >= 0.0 && dx <= tFar)
+ firstD = min(dx, firstD);
+ }
+ if (volumeSliceIndices.y >= -1.0) {
+ highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(rayDir, yPlaneNormal);
+ if (dy >= 0.0 && dy <= tFar) {
+ if (dy < firstD) {
+ secondD = firstD;
+ firstD = dy;
+ } else {
+ secondD = dy;
+ }
+ }
+ }
+ if (volumeSliceIndices.z >= -1.0) {
+ highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(rayDir, zPlaneNormal);
+ if (dz >= 0.0) {
+ if (dz < firstD && dz <= tFar) {
+ thirdD = secondD;
+ secondD = firstD;
+ firstD = dz;
+ } else if (dz < secondD){
+ thirdD = secondD;
+ secondD = dz;
+ } else {
+ thirdD = dz;
+ }
+ }
+ }
+
+ highp vec4 destColor = vec4(0.0, 0.0, 0.0, 0.0);
+ highp float totalAlpha = 0.0;
+ highp vec3 curRgb = vec3(0, 0, 0);
+
+ // Convert intersection to texture coords
+
+ if (firstD <= tFar) {
+ highp vec3 firstTex = rayStart + rayDir * firstD;
+ firstTex = 0.5 * (firstTex + 1.0);
+ highp vec4 firstColor = texture3D(textureSampler, firstTex);
+ if (color8Bit != 0)
+ firstColor = colorIndex[int(firstColor.r * 255.0)];
+
+ if (firstColor.a > alphaThreshold) {
+ destColor.rgb = firstColor.rgb * firstColor.a;
+ totalAlpha = firstColor.a;
+ }
+ if (secondD <= tFar && totalAlpha < 1.0) {
+ highp vec3 secondTex = rayStart + rayDir * secondD;
+ secondTex = 0.5 * (secondTex + 1.0);
+ highp vec4 secondColor = texture3D(textureSampler, secondTex);
+ if (color8Bit != 0)
+ secondColor = colorIndex[int(secondColor.r * 255.0)];
+ if (secondColor.a > alphaThreshold) {
+ curRgb = secondColor.rgb * secondColor.a * (1.0 - totalAlpha);
+ destColor.rgb += curRgb;
+ totalAlpha += secondColor.a;
+ }
+ if (thirdD <= tFar && totalAlpha < 1.0) {
+ highp vec3 thirdTex = rayStart + rayDir * thirdD;
+ thirdTex = 0.5 * (thirdTex + 1.0);
+ highp vec4 thirdColor = texture3D(textureSampler, thirdTex);
+ if (color8Bit != 0)
+ thirdColor = colorIndex[int(thirdColor.r * 255.0)];
+ if (thirdColor.a > alphaThreshold) {
+ curRgb = thirdColor.rgb * thirdColor.a * (1.0 - totalAlpha);
+ destColor.rgb += curRgb;
+ totalAlpha += thirdColor.a;
+ }
+ }
+ }
+ }
+ destColor.a = totalAlpha;
+ gl_FragColor = clamp(destColor, 0.0, 1.0);
+}
+
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index 1607f66a..17be3278 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -1196,9 +1196,11 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
- Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
- projectionViewMatrix, depthProjectionViewMatrix,
- m_depthTexture, m_shadowQualityToShader);
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
+ projectionViewMatrix,
+ depthProjectionViewMatrix, m_depthTexture,
+ m_shadowQualityToShader);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
m_depthModelTexture, 0);
@@ -1232,9 +1234,11 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glDisableVertexAttribArray(m_depthShader->posAtt());
- Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
- projectionViewMatrix, depthProjectionViewMatrix,
- m_depthTexture, m_shadowQualityToShader);
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
+ projectionViewMatrix,
+ depthProjectionViewMatrix, m_depthTexture,
+ m_shadowQualityToShader);
// Disable drawing to depth framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -1287,7 +1291,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
}
}
m_surfaceGridShader->bind();
- Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader, viewMatrix,
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader,
+ m_volumeTextureShader, m_volumeTextureSliceShader,
+ viewMatrix,
projectionViewMatrix, depthProjectionViewMatrix,
m_depthTexture, m_shadowQualityToShader);
drawLabels(true, activeCamera, viewMatrix, projectionMatrix);
@@ -1858,7 +1864,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
}
}
- Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, m_volumeTextureShader,
+ m_volumeTextureSliceShader, viewMatrix,
projectionViewMatrix, depthProjectionViewMatrix,
m_depthTexture, m_shadowQualityToShader);
diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp
index 7fb237c6..3c3d93ac 100644
--- a/src/datavisualization/utils/shaderhelper.cpp
+++ b/src/datavisualization/utils/shaderhelper.cpp
@@ -93,6 +93,10 @@ void ShaderHelper::initialize()
m_gradientMinUniform = m_program->uniformLocation("gradMin");
m_gradientHeightUniform = m_program->uniformLocation("gradHeight");
m_lightColorUniform = m_program->uniformLocation("lightColor");
+ m_volumeSliceIndices = m_program->uniformLocation("volumeSliceIndices");
+ m_colorIndex = m_program->uniformLocation("colorIndex");
+ m_cameraPositionRelativeToModel = m_program->uniformLocation("cameraPositionRelativeToModel");
+ m_color8Bit = m_program->uniformLocation("color8Bit");
m_initialized = true;
}
@@ -150,6 +154,11 @@ void ShaderHelper::setUniformValue(GLuint uniform, GLint value)
m_program->setUniformValue(uniform, value);
}
+void ShaderHelper::setUniformValueArray(GLuint uniform, const QVector4D *values, int count)
+{
+ m_program->setUniformValueArray(uniform, values, count);
+}
+
GLuint ShaderHelper::MVP()
{
if (!m_initialized)
@@ -255,6 +264,34 @@ GLuint ShaderHelper::lightColor()
return m_lightColorUniform;
}
+GLuint ShaderHelper::volumeSliceIndices()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_volumeSliceIndices;
+}
+
+GLuint ShaderHelper::colorIndex()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_colorIndex;
+}
+
+GLuint ShaderHelper::cameraPositionRelativeToModel()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_cameraPositionRelativeToModel;
+}
+
+GLuint ShaderHelper::color8Bit()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_color8Bit;
+}
+
GLuint ShaderHelper::posAtt()
{
if (!m_initialized)
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
index fdef0dff..67e8a2f3 100644
--- a/src/datavisualization/utils/shaderhelper_p.h
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -57,6 +57,7 @@ class ShaderHelper
void setUniformValue(GLuint uniform, const QMatrix4x4 &value);
void setUniformValue(GLuint uniform, GLfloat value);
void setUniformValue(GLuint uniform, GLint value);
+ void setUniformValueArray(GLuint uniform, const QVector4D *values, int count);
GLuint MVP();
GLuint view();
@@ -73,6 +74,10 @@ class ShaderHelper
GLuint gradientMin();
GLuint gradientHeight();
GLuint lightColor();
+ GLuint volumeSliceIndices();
+ GLuint colorIndex();
+ GLuint cameraPositionRelativeToModel();
+ GLuint color8Bit();
GLuint posAtt();
GLuint uvAtt();
@@ -107,6 +112,10 @@ class ShaderHelper
GLuint m_gradientMinUniform;
GLuint m_gradientHeightUniform;
GLuint m_lightColorUniform;
+ GLuint m_volumeSliceIndices;
+ GLuint m_colorIndex;
+ GLuint m_cameraPositionRelativeToModel;
+ GLuint m_color8Bit;
GLboolean m_initialized;
};
diff --git a/src/datavisualization/utils/texturehelper.cpp b/src/datavisualization/utils/texturehelper.cpp
index 616c1981..5e21b5cd 100644
--- a/src/datavisualization/utils/texturehelper.cpp
+++ b/src/datavisualization/utils/texturehelper.cpp
@@ -21,11 +21,25 @@
#include <QtGui/QImage>
#include <QtGui/QPainter>
+#include <QtCore/QTime>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+// Defined in shaderhelper.cpp
+extern void discardDebugMsgs(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+
TextureHelper::TextureHelper()
{
+#if !defined(QT_OPENGL_ES_2)
+ // Discard warnings about deprecated functions
+ QtMessageHandler handler = qInstallMessageHandler(discardDebugMsgs);
+
+ m_openGlFunctions_2_1 = new QOpenGLFunctions_2_1;
+ m_openGlFunctions_2_1->initializeOpenGLFunctions();
+
+ // Restore original message handler
+ qInstallMessageHandler(handler);
+#endif
initializeOpenGLFunctions();
}
@@ -73,8 +87,54 @@ GLuint TextureHelper::create2DTexture(const QImage &image, bool useTrilinearFilt
if (clampY)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
+
+ return textureId;
+}
+
+#if !defined(QT_OPENGL_ES_2)
+GLuint TextureHelper::create3DTexture(const QVector<uchar> *data, int width, int height, int depth,
+ QImage::Format dataFormat)
+{
+ if (!width || !height || !depth)
+ return 0;
+
+ glEnable(GL_TEXTURE_3D);
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_3D, textureId);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ GLenum status = glGetError();
+ // glGetError docs advise to call glGetError in loop to clear all error flags
+ while (status)
+ status = glGetError();
+
+ GLint internalFormat = 4;
+ GLint format = GL_BGRA;
+ if (dataFormat == QImage::Format_Indexed8) {
+ internalFormat = 1;
+ format = GL_RED;
+ // Align width to 32bits
+ width = width + width % 4;
+ }
+ m_openGlFunctions_2_1->glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, width, height, depth, 0,
+ format, GL_UNSIGNED_BYTE, data->constData());
+
+ status = glGetError();
+ if (status)
+ qWarning() << __FUNCTION__ << "3D texture creation failed:" << status;
+
+ glBindTexture(GL_TEXTURE_3D, 0);
+ glDisable(GL_TEXTURE_3D);
+
return textureId;
}
+#endif
GLuint TextureHelper::createCubeMapTexture(const QImage &image, bool useTrilinearFiltering)
{
diff --git a/src/datavisualization/utils/texturehelper_p.h b/src/datavisualization/utils/texturehelper_p.h
index c20f293c..c1dfe8c9 100644
--- a/src/datavisualization/utils/texturehelper_p.h
+++ b/src/datavisualization/utils/texturehelper_p.h
@@ -32,6 +32,10 @@
#include "datavisualizationglobal_p.h"
#include <QtGui/QRgb>
#include <QtGui/QLinearGradient>
+#if !defined(QT_OPENGL_ES_2)
+// 3D Textures are not supported by ES set
+# include <QtGui/QOpenGLFunctions_2_1>
+#endif
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -44,6 +48,10 @@ class TextureHelper : protected QOpenGLFunctions
// Ownership of created texture is transferred to caller
GLuint create2DTexture(const QImage &image, bool useTrilinearFiltering = false,
bool convert = true, bool smoothScale = true, bool clampY = false);
+#if !defined(QT_OPENGL_ES_2)
+ GLuint create3DTexture(const QVector<uchar> *data, int width, int height, int depth,
+ QImage::Format dataFormat);
+#endif
GLuint createCubeMapTexture(const QImage &image, bool useTrilinearFiltering = false);
// Returns selection texture and inserts generated framebuffers to framebuffer parameters
GLuint createSelectionTexture(const QSize &size, GLuint &frameBuffer, GLuint &depthBuffer);
@@ -61,6 +69,9 @@ class TextureHelper : protected QOpenGLFunctions
void convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage, GLenum texture_format);
QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format);
+#if !defined(QT_OPENGL_ES_2)
+ QOpenGLFunctions_2_1 *m_openGlFunctions_2_1;
+#endif
friend class Bars3DRenderer;
friend class Surface3DRenderer;
friend class Scatter3DRenderer;