summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/data
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization/data')
-rw-r--r--src/datavisualization/data/abstractrenderitem_p.h6
-rw-r--r--src/datavisualization/data/customrenderitem.cpp68
-rw-r--r--src/datavisualization/data/customrenderitem_p.h109
-rw-r--r--src/datavisualization/data/data.pri9
-rw-r--r--src/datavisualization/data/labelitem.cpp6
-rw-r--r--src/datavisualization/data/qabstract3dseries.cpp3
-rw-r--r--src/datavisualization/data/qabstract3dseries.h1
-rw-r--r--src/datavisualization/data/qbar3dseries.cpp21
-rw-r--r--src/datavisualization/data/qcustom3ditem.cpp101
-rw-r--r--src/datavisualization/data/qcustom3ditem.h5
-rw-r--r--src/datavisualization/data/qcustom3ditem_p.h5
-rw-r--r--src/datavisualization/data/qcustom3dlabel.cpp1
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp1278
-rw-r--r--src/datavisualization/data/qcustom3dvolume.h147
-rw-r--r--src/datavisualization/data/qcustom3dvolume_p.h108
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy.cpp16
-rw-r--r--src/datavisualization/data/qsurface3dseries.cpp66
-rw-r--r--src/datavisualization/data/qsurface3dseries.h9
-rw-r--r--src/datavisualization/data/qsurface3dseries_p.h3
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.cpp4
20 files changed, 1922 insertions, 44 deletions
diff --git a/src/datavisualization/data/abstractrenderitem_p.h b/src/datavisualization/data/abstractrenderitem_p.h
index 57977a3c..ccee2b00 100644
--- a/src/datavisualization/data/abstractrenderitem_p.h
+++ b/src/datavisualization/data/abstractrenderitem_p.h
@@ -48,10 +48,12 @@ public:
inline void setTranslation(const QVector3D &translation) { m_translation = translation; }
inline const QVector3D &translation() const {return m_translation; }
- inline QQuaternion rotation() const { return m_rotation; }
+ inline const QQuaternion &rotation() const { return m_rotation; }
inline void setRotation(const QQuaternion &rotation)
{
- if (m_rotation != rotation)
+ if (rotation.isNull())
+ m_rotation = identityQuaternion;
+ else
m_rotation = rotation;
}
diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp
index a1c70057..f56ca86e 100644
--- a/src/datavisualization/data/customrenderitem.cpp
+++ b/src/datavisualization/data/customrenderitem.cpp
@@ -23,9 +23,32 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
CustomRenderItem::CustomRenderItem()
: AbstractRenderItem(),
m_texture(0),
+ m_positionAbsolute(false),
+ m_scalingAbsolute(true),
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_labelItem(false),
+ m_textureWidth(0),
+ m_textureHeight(0),
+ m_textureDepth(0),
+ m_isVolume(false),
+ m_textureFormat(QImage::Format_ARGB32),
+ m_sliceIndexX(-1),
+ m_sliceIndexY(-1),
+ m_sliceIndexZ(-1),
+ m_alphaMultiplier(1.0f),
+ m_preserveOpacity(true),
+ m_useHighDefShader(true),
+ m_drawSlices(false),
+ m_drawSliceFrames(false)
+
{
}
@@ -39,4 +62,47 @@ void CustomRenderItem::setMesh(const QString &meshFile)
ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFile);
}
+void CustomRenderItem::setColorTable(const QVector<QRgb> &colors)
+{
+ m_colorTable.resize(256);
+ for (int i = 0; i < 256; i++) {
+ if (i < colors.size()) {
+ 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);
+ } else {
+ m_colorTable[i] = QVector4D(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+}
+
+void CustomRenderItem::setMinBounds(const QVector3D &bounds)
+{
+ m_minBounds = bounds;
+ m_minBoundsNormal = m_minBounds;
+ m_minBoundsNormal.setY(-m_minBoundsNormal.y());
+ m_minBoundsNormal.setZ(-m_minBoundsNormal.z());
+ m_minBoundsNormal = 0.5f * (m_minBoundsNormal + oneVector);
+}
+
+void CustomRenderItem::setMaxBounds(const QVector3D &bounds)
+{
+ m_maxBounds = bounds;
+ m_maxBoundsNormal = m_maxBounds;
+ m_maxBoundsNormal.setY(-m_maxBoundsNormal.y());
+ m_maxBoundsNormal.setZ(-m_maxBoundsNormal.z());
+ m_maxBoundsNormal = 0.5f * (m_maxBoundsNormal + oneVector);
+}
+
+void CustomRenderItem::setSliceFrameColor(const QColor &color)
+{
+ const QRgb &rgb = color.rgba();
+ m_sliceFrameColor = QVector4D(float(qRed(rgb)) / 255.0f,
+ float(qGreen(rgb)) / 255.0f,
+ float(qBlue(rgb)) / 255.0f,
+ float(1.0f)); // Alpha not supported for frames
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h
index 4fb94276..ad868fac 100644
--- a/src/datavisualization/data/customrenderitem_p.h
+++ b/src/datavisualization/data/customrenderitem_p.h
@@ -31,6 +31,9 @@
#include "abstractrenderitem_p.h"
#include "objecthelper_p.h"
+#include <QtGui/QRgb>
+#include <QtGui/QImage>
+#include <QtGui/QColor>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -48,11 +51,17 @@ public:
void setMesh(const QString &meshFile);
inline ObjectHelper *mesh() const { return m_object; }
inline void setScaling(const QVector3D &scaling) { m_scaling = scaling; }
- inline QVector3D scaling() const { return m_scaling; }
+ inline const QVector3D &scaling() const { return m_scaling; }
+ inline void setOrigScaling(const QVector3D &scaling) { m_origScaling = scaling; }
+ inline const QVector3D &origScaling() const { return m_origScaling; }
inline void setPosition(const QVector3D &position) { m_position = position; }
- inline QVector3D position() const { return m_position; }
- inline void setPositionAbsolute(bool absolute) { m_absolute = absolute; }
- inline bool isPositionAbsolute() const { return m_absolute; }
+ inline const QVector3D &position() const { return m_position; }
+ inline void setOrigPosition(const QVector3D &position) { m_origPosition = position; }
+ inline const QVector3D &origPosition() const { return m_origPosition; }
+ inline void setPositionAbsolute(bool absolute) { m_positionAbsolute = absolute; }
+ inline bool isPositionAbsolute() const { return m_positionAbsolute; }
+ inline void setScalingAbsolute(bool absolute) { m_scalingAbsolute = absolute; }
+ inline bool isScalingAbsolute() const { return m_scalingAbsolute; }
inline void setBlendNeeded(bool blend) { m_needBlend = blend; }
inline bool isBlendNeeded() const { return m_needBlend; }
inline void setVisible(bool visible) { m_visible = visible; }
@@ -68,14 +77,78 @@ public:
inline void setFacingCamera(bool facing) { m_isFacingCamera = facing; }
inline bool isFacingCamera() const { return m_isFacingCamera; }
inline void setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; }
+ inline void setLabelItem(bool isLabel) { m_labelItem = isLabel; }
+ inline bool isLabel() const { return m_labelItem; }
+
+ // Volume specific
+ inline void setTextureWidth(int width) { m_textureWidth = width; setSliceIndexX(m_sliceIndexX); }
+ inline int textureWidth() const { return m_textureWidth; }
+ inline void setTextureHeight(int height) { m_textureHeight = height; setSliceIndexY(m_sliceIndexY); }
+ inline int textureHeight() const { return m_textureHeight; }
+ inline void setTextureDepth(int depth) { m_textureDepth = depth; setSliceIndexZ(m_sliceIndexZ); }
+ 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;
+ m_sliceFractions.setX((float(index) + 0.5f) / float(m_textureWidth) * 2.0 - 1.0);
+ }
+ inline void setSliceIndexY(int index)
+ {
+ m_sliceIndexY = index;
+ m_sliceFractions.setY((float(index) + 0.5f) / float(m_textureHeight) * 2.0 - 1.0);
+ }
+ inline void setSliceIndexZ(int index)
+ {
+ m_sliceIndexZ = index;
+ m_sliceFractions.setZ((float(index) + 0.5f) / float(m_textureDepth) * 2.0 - 1.0);
+ }
+ inline const QVector3D &sliceFractions() const { return m_sliceFractions; }
+ 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; }
+ inline void setUseHighDefShader(bool enable) { m_useHighDefShader = enable; }
+ inline bool useHighDefShader() const {return m_useHighDefShader; }
+ void setMinBounds(const QVector3D &bounds);
+ inline const QVector3D &minBounds() const { return m_minBounds; }
+ void setMaxBounds(const QVector3D &bounds);
+ inline const QVector3D &maxBounds() const { return m_maxBounds; }
+ inline const QVector3D &minBoundsNormal() const { return m_minBoundsNormal; }
+ inline const QVector3D &maxBoundsNormal() const { return m_maxBoundsNormal; }
+ inline void setDrawSlices(bool enable) { m_drawSlices = enable; }
+ inline bool drawSlices() const {return m_drawSlices; }
+ inline void setDrawSliceFrames(bool enable) { m_drawSliceFrames = enable; }
+ inline bool drawSliceFrames() const {return m_drawSliceFrames; }
+ void setSliceFrameColor(const QColor &color);
+ inline const QVector4D &sliceFrameColor() const { return m_sliceFrameColor; }
+ inline void setSliceFrameWidths(const QVector3D &widths) { m_sliceFrameWidths = widths * 2.0f; }
+ inline const QVector3D &sliceFrameWidths() const { return m_sliceFrameWidths; }
+ inline void setSliceFrameGaps(const QVector3D &gaps) { m_sliceFrameGaps = gaps * 2.0f; }
+ inline const QVector3D &sliceFrameGaps() const { return m_sliceFrameGaps; }
+ inline void setSliceFrameThicknesses(const QVector3D &thicknesses) { m_sliceFrameThicknesses = thicknesses; }
+ inline const QVector3D &sliceFrameThicknesses() const { return m_sliceFrameThicknesses; }
private:
Q_DISABLE_COPY(CustomRenderItem)
GLuint m_texture;
QVector3D m_scaling;
+ QVector3D m_origScaling;
QVector3D m_position;
- bool m_absolute;
+ QVector3D m_origPosition;
+ bool m_positionAbsolute;
+ bool m_scalingAbsolute;
ObjectHelper *m_object; // shared reference
bool m_needBlend;
bool m_visible;
@@ -85,6 +158,32 @@ private:
bool m_isFacingCamera;
QCustom3DItem *m_item;
Abstract3DRenderer *m_renderer;
+ bool m_labelItem;
+
+ // 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;
+ QVector3D m_sliceFractions;
+ float m_alphaMultiplier;
+ bool m_preserveOpacity;
+ bool m_useHighDefShader;
+ QVector3D m_minBounds;
+ QVector3D m_maxBounds;
+ QVector3D m_minBoundsNormal;
+ QVector3D m_maxBoundsNormal;
+ bool m_drawSlices;
+ bool m_drawSliceFrames;
+ QVector4D m_sliceFrameColor;
+ QVector3D m_sliceFrameWidths;
+ QVector3D m_sliceFrameGaps;
+ QVector3D m_sliceFrameThicknesses;
};
typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray;
diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri
index 73f398bf..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,4 +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/labelitem.cpp b/src/datavisualization/data/labelitem.cpp
index 859b0550..ec8ba3fd 100644
--- a/src/datavisualization/data/labelitem.cpp
+++ b/src/datavisualization/data/labelitem.cpp
@@ -28,7 +28,7 @@ LabelItem::LabelItem()
LabelItem::~LabelItem()
{
- glDeleteTextures(1, &m_textureId);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_textureId);
}
void LabelItem::setSize(const QSize &size)
@@ -43,7 +43,7 @@ QSize LabelItem::size() const
void LabelItem::setTextureId(GLuint textureId)
{
- glDeleteTextures(1, &m_textureId);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_textureId);
m_textureId = textureId;
}
@@ -55,7 +55,7 @@ GLuint LabelItem::textureId() const
void LabelItem::clear()
{
if (m_textureId) {
- glDeleteTextures(1, &m_textureId);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_textureId);
m_textureId = 0;
}
m_size = QSize(0, 0);
diff --git a/src/datavisualization/data/qabstract3dseries.cpp b/src/datavisualization/data/qabstract3dseries.cpp
index f8fe6b4f..caa95062 100644
--- a/src/datavisualization/data/qabstract3dseries.cpp
+++ b/src/datavisualization/data/qabstract3dseries.cpp
@@ -657,6 +657,9 @@ QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q,
m_mesh(QAbstract3DSeries::MeshCube),
m_meshSmooth(false),
m_colorStyle(Q3DTheme::ColorStyleUniform),
+ m_baseColor(Qt::black),
+ m_singleHighlightColor(Qt::black),
+ m_multiHighlightColor(Qt::black),
m_itemLabelDirty(true),
m_itemLabelVisible(true)
{
diff --git a/src/datavisualization/data/qabstract3dseries.h b/src/datavisualization/data/qabstract3dseries.h
index 87c4f3c1..c26c40d1 100644
--- a/src/datavisualization/data/qabstract3dseries.h
+++ b/src/datavisualization/data/qabstract3dseries.h
@@ -153,6 +153,7 @@ private:
friend class Bars3DController;
friend class Surface3DController;
friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
friend class Scatter3DController;
friend class QBar3DSeries;
friend class SeriesRenderCache;
diff --git a/src/datavisualization/data/qbar3dseries.cpp b/src/datavisualization/data/qbar3dseries.cpp
index 19c3bf79..0aa60b66 100644
--- a/src/datavisualization/data/qbar3dseries.cpp
+++ b/src/datavisualization/data/qbar3dseries.cpp
@@ -43,26 +43,27 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \row
* \li @valueTitle \li Title from value axis
* \row
- * \li @rowIdx \li Visible row index
+ * \li @rowIdx \li Visible row index. Localized using graph locale.
* \row
- * \li @colIdx \li Visible Column index
+ * \li @colIdx \li Visible Column index. Localized using graph locale.
* \row
* \li @rowLabel \li Label from row axis
* \row
* \li @colLabel \li Label from column axis
* \row
- * \li @valueLabel \li Item value formatted using the same format the value axis attached to the graph uses,
- * see \l{QValue3DAxis::setLabelFormat()} for more information.
+ * \li @valueLabel \li Item value formatted using the same format the value axis attached to
+ * the graph uses. See \l{QValue3DAxis::labelFormat} for more information.
* \row
* \li @seriesName \li Name of the series
* \row
- * \li %<format spec> \li Item value in specified format.
+ * \li %<format spec> \li Item value in specified format. Formatted using the same rules as
+ * \l{QValue3DAxis::labelFormat}.
* \endtable
*
* For example:
* \snippet doc_src_qtdatavisualization.cpp 1
*
- * \sa {Qt Data Visualization Data Handling}
+ * \sa {Qt Data Visualization Data Handling}, QAbstract3DGraph::locale
*/
/*!
@@ -334,6 +335,10 @@ void QBar3DSeriesPrivate::createItemLabel()
return;
}
+ QLocale locale(QLocale::c());
+ if (m_controller)
+ locale = m_controller->locale();
+
QCategory3DAxis *categoryAxisZ = static_cast<QCategory3DAxis *>(m_controller->axisZ());
QCategory3DAxis *categoryAxisX = static_cast<QCategory3DAxis *>(m_controller->axisX());
QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(m_controller->axisY());
@@ -344,13 +349,13 @@ void QBar3DSeriesPrivate::createItemLabel()
int selBarPosRow = m_selectedBar.x();
int selBarPosCol = m_selectedBar.y();
- m_itemLabel.replace(rowIndexTag, QString::number(selBarPosRow));
+ m_itemLabel.replace(rowIndexTag, locale.toString(selBarPosRow));
if (categoryAxisZ->labels().size() > selBarPosRow)
m_itemLabel.replace(rowLabelTag, categoryAxisZ->labels().at(selBarPosRow));
else
m_itemLabel.replace(rowLabelTag, QString());
m_itemLabel.replace(rowTitleTag, categoryAxisZ->title());
- m_itemLabel.replace(colIndexTag, QString::number(selBarPosCol));
+ m_itemLabel.replace(colIndexTag, locale.toString(selBarPosCol));
if (categoryAxisX->labels().size() > selBarPosCol)
m_itemLabel.replace(colLabelTag, categoryAxisX->labels().at(selBarPosCol));
else
diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp
index efee3b15..b9825732 100644
--- a/src/datavisualization/data/qcustom3ditem.cpp
+++ b/src/datavisualization/data/qcustom3ditem.cpp
@@ -62,13 +62,15 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* Holds the item \a position as a vector3d. Defaults to \c {vector3d(0.0, 0.0, 0.0)}.
*
- * Item position is either in data coordinates or in absolute coordinates, depending on
+ * Item position is either in data coordinates or in absolute coordinates, depending on the
* positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are
* within axis ranges.
*
- * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}.
+ * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false},
+ * unless the item is a Custom3DVolume that would be partially visible and scalingAbsolute is also
+ * \c{false}. In that case, the visible portion of the volume will be rendered.
*
- * \sa positionAbsolute
+ * \sa positionAbsolute, scalingAbsolute
*/
/*! \qmlproperty bool Custom3DItem::positionAbsolute
@@ -83,8 +85,33 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*! \qmlproperty vector3d Custom3DItem::scaling
*
* Holds the item \a scaling as a vector3d. Defaults to \c {vector3d(0.1, 0.1, 0.1)}.
- * The default value sets the item to 10% of the height of the graph, provided the item size is
- * normalized.
+ *
+ * Item scaling is either in data values or in absolute values, depending on the
+ * scalingAbsolute property. The default vector interpreted as absolute values sets the item to
+ * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios
+ * haven't been changed from the defaults.
+ *
+ * \sa scalingAbsolute
+ */
+
+/*! \qmlproperty bool Custom3DItem::scalingAbsolute
+ * \since QtDataVisualization 1.2
+ *
+ * This property dictates if item scaling is to be handled in data values or in absolute
+ * values. Defaults to \c{true}. Items with absolute scaling will be rendered at the same
+ * size, regardless of axis ranges. Items with data scaling will change their apparent size
+ * according to the axis ranges. If positionAbsolute value is \c{true}, this property is ignored
+ * and scaling is interpreted as an absolute value. If the item has rotation, the data scaling
+ * is calculated on the unrotated item. Similarly, for Custom3DVolume items, the range clipping
+ * is calculated on the unrotated item.
+ *
+ * \note: Only absolute scaling is supported for Custom3DLabel items or for custom items used in
+ * \l{AbstractGraph3D::polar}{polar} graphs.
+ *
+ * \note: The custom item's mesh must be normalized to range \c{[-1 ,1]}, or the data
+ * scaling will not be accurate.
+ *
+ * \sa scaling, positionAbsolute
*/
/*! \qmlproperty quaternion Custom3DItem::rotation
@@ -180,7 +207,9 @@ QString QCustom3DItem::meshFile() const
* positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are
* within axis ranges.
*
- * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}.
+ * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false},
+ * unless the item is a QCustom3DVolume that would be partially visible and scalingAbsolute is also
+ * \c{false}. In that case, the visible portion of the volume will be rendered.
*
* \sa positionAbsolute
*/
@@ -211,7 +240,7 @@ void QCustom3DItem::setPositionAbsolute(bool positionAbsolute)
{
if (d_ptr->m_positionAbsolute != positionAbsolute) {
d_ptr->m_positionAbsolute = positionAbsolute;
- d_ptr->m_dirtyBits.positionAbsoluteDirty = true;
+ d_ptr->m_dirtyBits.positionDirty = true;
emit positionAbsoluteChanged(positionAbsolute);
emit d_ptr->needUpdate();
}
@@ -225,8 +254,13 @@ bool QCustom3DItem::isPositionAbsolute() const
/*! \property QCustom3DItem::scaling
*
* Holds the item \a scaling as a QVector3D. Defaults to \c {QVector3D(0.1, 0.1, 0.1)}.
- * The default value sets the item to 10% of the height of the graph, provided the item size is
- * normalized.
+ *
+ * Item scaling is either in data values or in absolute values, depending on the
+ * scalingAbsolute property. The default vector interpreted as absolute values sets the item to
+ * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios
+ * haven't been changed from the defaults.
+ *
+ * \sa scalingAbsolute
*/
void QCustom3DItem::setScaling(const QVector3D &scaling)
{
@@ -243,6 +277,42 @@ QVector3D QCustom3DItem::scaling() const
return d_ptr->m_scaling;
}
+/*! \property QCustom3DItem::scalingAbsolute
+ * \since QtDataVisualization 1.2
+ *
+ * This property dictates if item scaling is to be handled in data values or in absolute
+ * values. Defaults to \c{true}. Items with absolute scaling will be rendered at the same
+ * size, regardless of axis ranges. Items with data scaling will change their apparent size
+ * according to the axis ranges. If positionAbsolute value is \c{true}, this property is ignored
+ * and scaling is interpreted as an absolute value. If the item has rotation, the data scaling
+ * is calculated on the unrotated item. Similarly, for QCustom3DVolume items, the range clipping
+ * is calculated on the unrotated item.
+ *
+ * \note: Only absolute scaling is supported for QCustom3DLabel items or for custom items used in
+ * \l{QAbstract3DGraph::polar}{polar} graphs.
+ *
+ * \note: The custom item's mesh must be normalized to range \c{[-1 ,1]}, or the data
+ * scaling will not be accurate.
+ *
+ * \sa scaling, positionAbsolute
+ */
+void QCustom3DItem::setScalingAbsolute(bool scalingAbsolute)
+{
+ if (d_ptr->m_isLabelItem && !scalingAbsolute) {
+ qWarning() << __FUNCTION__ << "Data bounds are not supported for label items.";
+ } else if (d_ptr->m_scalingAbsolute != scalingAbsolute) {
+ d_ptr->m_scalingAbsolute = scalingAbsolute;
+ d_ptr->m_dirtyBits.scalingDirty = true;
+ emit scalingAbsoluteChanged(scalingAbsolute);
+ emit d_ptr->needUpdate();
+ }
+}
+
+bool QCustom3DItem::isScalingAbsolute() const
+{
+ return d_ptr->m_scalingAbsolute;
+}
+
/*! \property QCustom3DItem::rotation
*
* Holds the item \a rotation as a QQuaternion. Defaults to \c {QQuaternion(0.0, 0.0, 0.0, 0.0)}.
@@ -367,13 +437,16 @@ QString QCustom3DItem::textureFile() const
QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) :
q_ptr(q),
+ m_textureImage(QImage(1, 1, QImage::Format_ARGB32)),
m_position(QVector3D(0.0f, 0.0f, 0.0f)),
m_positionAbsolute(false),
m_scaling(QVector3D(0.1f, 0.1f, 0.1f)),
- m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)),
+ m_scalingAbsolute(true),
+ m_rotation(identityQuaternion),
m_visible(true),
m_shadowCasting(true),
- m_isLabelItem(false)
+ m_isLabelItem(false),
+ m_isVolumeItem(false)
{
}
@@ -381,14 +454,17 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &mesh
const QVector3D &position, const QVector3D &scaling,
const QQuaternion &rotation) :
q_ptr(q),
+ m_textureImage(QImage(1, 1, QImage::Format_ARGB32)),
m_meshFile(meshFile),
m_position(position),
m_positionAbsolute(false),
m_scaling(scaling),
+ m_scalingAbsolute(true),
m_rotation(rotation),
m_visible(true),
m_shadowCasting(true),
- m_isLabelItem(false)
+ m_isLabelItem(false),
+ m_isVolumeItem(false)
{
}
@@ -412,7 +488,6 @@ void QCustom3DItemPrivate::resetDirtyBits()
m_dirtyBits.textureDirty = false;
m_dirtyBits.meshDirty = false;
m_dirtyBits.positionDirty = false;
- m_dirtyBits.positionAbsoluteDirty = false;
m_dirtyBits.scalingDirty = false;
m_dirtyBits.rotationDirty = false;
m_dirtyBits.visibleDirty = false;
diff --git a/src/datavisualization/data/qcustom3ditem.h b/src/datavisualization/data/qcustom3ditem.h
index 2f7f37cf..5c880213 100644
--- a/src/datavisualization/data/qcustom3ditem.h
+++ b/src/datavisualization/data/qcustom3ditem.h
@@ -39,6 +39,7 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DItem : public QObject
Q_PROPERTY(QQuaternion rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(bool shadowCasting READ isShadowCasting WRITE setShadowCasting NOTIFY shadowCastingChanged)
+ Q_PROPERTY(bool scalingAbsolute READ isScalingAbsolute WRITE setScalingAbsolute NOTIFY scalingAbsoluteChanged REVISION 1)
public:
explicit QCustom3DItem(QObject *parent = 0);
@@ -62,6 +63,9 @@ public:
void setScaling(const QVector3D &scaling);
QVector3D scaling() const;
+ void setScalingAbsolute(bool scalingAbsolute);
+ bool isScalingAbsolute() const;
+
void setRotation(const QQuaternion &rotation);
QQuaternion rotation();
@@ -84,6 +88,7 @@ signals:
void rotationChanged(const QQuaternion &rotation);
void visibleChanged(bool visible);
void shadowCastingChanged(bool shadowCasting);
+ Q_REVISION(1) void scalingAbsoluteChanged(bool scalingAbsolute);
protected:
QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent = 0);
diff --git a/src/datavisualization/data/qcustom3ditem_p.h b/src/datavisualization/data/qcustom3ditem_p.h
index c1ce5996..627bf53f 100644
--- a/src/datavisualization/data/qcustom3ditem_p.h
+++ b/src/datavisualization/data/qcustom3ditem_p.h
@@ -29,6 +29,7 @@
#ifndef QCUSTOM3DITEM_P_H
#define QCUSTOM3DITEM_P_H
+#include "datavisualizationglobal_p.h"
#include "qcustom3ditem.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -37,7 +38,6 @@ struct QCustomItemDirtyBitField {
bool textureDirty : 1;
bool meshDirty : 1;
bool positionDirty : 1;
- bool positionAbsoluteDirty : 1;
bool scalingDirty : 1;
bool rotationDirty : 1;
bool visibleDirty : 1;
@@ -47,7 +47,6 @@ struct QCustomItemDirtyBitField {
: textureDirty(false),
meshDirty(false),
positionDirty(false),
- positionAbsoluteDirty(false),
scalingDirty(false),
rotationDirty(false),
visibleDirty(false),
@@ -77,11 +76,13 @@ public:
QVector3D m_position;
bool m_positionAbsolute;
QVector3D m_scaling;
+ bool m_scalingAbsolute;
QQuaternion m_rotation;
bool m_visible;
bool m_shadowCasting;
bool m_isLabelItem;
+ bool m_isVolumeItem;
QCustomItemDirtyBitField m_dirtyBits;
diff --git a/src/datavisualization/data/qcustom3dlabel.cpp b/src/datavisualization/data/qcustom3dlabel.cpp
index 85a37e2d..bb5d71d0 100644
--- a/src/datavisualization/data/qcustom3dlabel.cpp
+++ b/src/datavisualization/data/qcustom3dlabel.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \since QtDataVisualization 1.1
* \ingroup datavisualization_qml
* \instantiates QCustom3DLabel
+ * \inherits Custom3DItem
* \brief The Custom3DLabel type is for creating custom labels to be added to a graph.
*
* This type is for creating custom labels to be added to a graph. You can set text, font,
diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp
new file mode 100644
index 00000000..f8287a81
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume.cpp
@@ -0,0 +1,1278 @@
+/****************************************************************************
+**
+** 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.
+ *
+ * Rendering volume objects is very performance intensive, especially when the volume is largely
+ * transparent, as the contents of the volume are ray-traced. The performance scales nearly linearly
+ * with the amount of pixels that the volume occupies on the screen, so showing the volume in a
+ * smaller view or limiting the zoom level of the graph are easy ways to improve performance.
+ * Similarly, the volume texture dimensions have a large impact on performance.
+ * If the frame rate is more important than pixel-perfect rendering of the volume contents, consider
+ * turning the high definition shader off by setting useHighDefShader property to \c{false}.
+ *
+ * \note Volumetric objects are only supported with orthographic projection.
+ *
+ * \note Volumetric objects utilize 3D textures, which are not supported in OpenGL ES2 environments.
+ *
+ * \sa QAbstract3DGraph::addCustomItem(), QAbstract3DGraph::orthoProjection, useHighDefShader
+ */
+
+/*!
+ * \qmltype Custom3DVolume
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.2
+ * \ingroup datavisualization_qml
+ * \instantiates QCustom3DVolume
+ * \inherits Custom3DItem
+ * \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.
+ *
+ * Rendering volume objects is very performance intensive, especially when the volume is largely
+ * transparent, as the contents of the volume are ray-traced. The performance scales nearly linearly
+ * with the amount of pixels that the volume occupies on the screen, so showing the volume in a
+ * smaller view or limiting the zoom level of the graph are easy ways to improve performance.
+ * Similarly, the volume texture dimensions have a large impact on performance.
+ * If the frame rate is more important than pixel-perfect rendering of the volume contents, consider
+ * turning the high definition shader off by setting useHighDefShader property to \c{false}.
+ *
+ * \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 a QML UI.
+ *
+ * \note Volumetric objects are only supported with orthographic projection.
+ *
+ * \note Volumetric objects utilize 3D textures, which are not supported in OpenGL ES2 environments.
+ *
+ * \sa AbstractGraph3D::orthoProjection, useHighDefShader
+ */
+
+/*! \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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData, drawSlices, drawSliceFrames
+ */
+
+/*! \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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData, drawSlices, drawSliceFrames
+ */
+
+/*! \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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa QCustom3DVolume::textureData, drawSlices, drawSliceFrames
+ */
+
+/*!
+ * \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
+ */
+
+/*!
+ * \qmlproperty bool Custom3DVolume::useHighDefShader
+ *
+ * If this property value is \c{true}, a high definition shader is used to render the volume.
+ * If it is \c{false}, a low definition shader is used.
+ *
+ * The high definition shader guarantees that every visible texel of the volume texture is sampled
+ * when the volume is rendered.
+ * The low definition shader renders only a rough approximation of the volume contents,
+ * but at much higher frame rate. The low definition shader doesn't guarantee every texel of the
+ * volume texture is sampled, so there may be flickering if the volume contains distinct thin
+ * features.
+ *
+ * \note This value doesn't affect the level of detail when rendering the slices of the volume.
+ *
+ * Defaults to \c{true}.
+ */
+
+/*!
+ * \qmlproperty bool Custom3DVolume::drawSlices
+ *
+ * If this property value is \c{true}, the slices indicated by slice index properties
+ * will be drawn instead of the full volume.
+ * If it is \c{false}, the full volume will always be drawn.
+ * Defaults to \c{false}.
+ *
+ * \note The slices are always drawn along the item axes, so if the item is rotated, the slices are
+ * rotated as well.
+ *
+ * \sa sliceIndexX, sliceIndexY, sliceIndexZ
+ */
+
+/*!
+ * \qmlproperty bool Custom3DVolume::drawSliceFrames
+ *
+ * If this property value is \c{true}, the frames of slices indicated by slice index properties
+ * will be drawn around the volume.
+ * If it is \c{false}, no slice frames will be drawn.
+ * Drawing slice frames is independent of drawing slices, so you can show the full volume and
+ * still draw the slice frames around it.
+ * Defaults to \c{false}.
+ *
+ * \sa sliceIndexX, sliceIndexY, sliceIndexZ, drawSlices
+ */
+
+/*!
+ * \qmlproperty color Custom3DVolume::sliceFrameColor
+ *
+ * Indicates the color of the slice frame. Transparent slice frame color is not supported.
+ *
+ * Defaults to black.
+ *
+ * \sa drawSliceFrames
+ */
+
+/*!
+ * \qmlproperty vector3d Custom3DVolume::sliceFrameWidths
+ *
+ * Indicates the widths of the slice frame. The width can be different on different dimensions,
+ * so you can for example omit drawing the frames on certain sides of the volume by setting the
+ * value for that dimension to zero. The values are fractions of the volume thickness in the same
+ * dimension. The values cannot be negative.
+ *
+ * Defaults to \c{vector3d(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+
+/*!
+ * \qmlproperty vector3d Custom3DVolume::sliceFrameGaps
+ *
+ * Indicates the amount of air gap left between the volume itself and the frame in each dimension.
+ * The gap can be different on different dimensions. The values are fractions of the volume
+ * thickness in the same dimension. The values cannot be negative.
+ *
+ * Defaults to \c{vector3d(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+
+/*!
+ * \qmlproperty vector3d Custom3DVolume::sliceFrameThicknesses
+ *
+ * Indicates the thickness of the slice frames for each dimension. The values are fractions of
+ * the volume thickness in the same dimension. The values cannot be negative.
+ *
+ * Defaults to \c{vector3d(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+
+/*!
+ * 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, setTextureFormat(), 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, setTextureFormat(), 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, setTextureFormat()
+ */
+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, setTextureFormat()
+ */
+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);
+ setTextureHeight(height);
+ setTextureDepth(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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData, drawSlices, drawSliceFrames
+ */
+void QCustom3DVolume::setSliceIndexX(int value)
+{
+ if (dptr()->m_sliceIndexX != value) {
+ dptr()->m_sliceIndexX = value;
+ dptr()->m_dirtyBitsVolume.slicesDirty = 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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData, drawSlices, drawSliceFrames
+ */
+void QCustom3DVolume::setSliceIndexY(int value)
+{
+ if (dptr()->m_sliceIndexY != value) {
+ dptr()->m_sliceIndexY = value;
+ dptr()->m_dirtyBitsVolume.slicesDirty = 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 or slice frame for that dimension is drawn.
+ * If all dimensions are negative, no slices or slice frames are drawn and the volume is drawn
+ * normally.
+ * Defaults to \c{-1}.
+ *
+ * \sa textureData, drawSlices, drawSliceFrames
+ */
+void QCustom3DVolume::setSliceIndexZ(int value)
+{
+ if (dptr()->m_sliceIndexZ != value) {
+ dptr()->m_sliceIndexZ = value;
+ dptr()->m_dirtyBitsVolume.slicesDirty = 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, setTextureFormat(), 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. The padding bytes should indicate an fully transparent color
+ * to avoid rendering artifacts.
+ *
+ * Defaults to \c{0}.
+ *
+ * \sa colorTable, setTextureFormat(), 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, setTextureFormat()
+ */
+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 along the specified
+ * \a axis of the volume.
+ * The \a index parameter specifies the subtexture to set.
+ * The texture \a data must be in the format specified by textureFormat property and have size of
+ * the cross-section of the volume texture along the specified axis multiplied by
+ * the texture format color depth in bytes.
+ * The \a data is expected to be ordered similarly to the data in images produced by renderSlice()
+ * method along the same axis.
+ *
+ * \note Each X-line of the data needs to be 32bit aligned when targeting Y-axis or Z-axis.
+ * 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 in cases it is not already
+ * properly aligned. The padding bytes should indicate an fully transparent color to avoid
+ * rendering artifacts.
+ *
+ * \sa textureData, renderSlice()
+ */
+void QCustom3DVolume::setSubTextureData(Qt::Axis axis, int index, const uchar *data)
+{
+ if (data) {
+ int lineSize = textureDataWidth();
+ int frameSize = lineSize * dptr()->m_textureHeight;
+ int dataSize = dptr()->m_textureData->size();
+ int pixelWidth = (dptr()->m_textureFormat == QImage::Format_Indexed8) ? 1 : 4;
+ int targetIndex;
+ uchar *dataPtr = dptr()->m_textureData->data();
+ bool invalid = (index < 0);
+ if (axis == Qt::XAxis) {
+ targetIndex = index * pixelWidth;
+ if (index >= dptr()->m_textureWidth
+ || (frameSize * (dptr()->m_textureDepth - 1) + targetIndex) > dataSize) {
+ invalid = true;
+ }
+ } else if (axis == Qt::YAxis) {
+ targetIndex = (index * lineSize) + (frameSize * (dptr()->m_textureDepth - 1));
+ if (index >= dptr()->m_textureHeight || (targetIndex + lineSize > dataSize))
+ invalid = true;
+ } else {
+ targetIndex = index * frameSize;
+ if (index >= dptr()->m_textureDepth || ((targetIndex + frameSize) > dataSize))
+ invalid = true;
+ }
+
+ if (invalid) {
+ qWarning() << __FUNCTION__ << "Attempted to set invalid subtexture.";
+ } else {
+ const uchar *sourcePtr = data;
+ uchar *targetPtr = dataPtr + targetIndex;
+ if (axis == Qt::XAxis) {
+ int targetWidth = dptr()->m_textureDepth;
+ int targetHeight = dptr()->m_textureHeight;
+ for (int i = 0; i < targetHeight; i++) {
+ targetPtr = dataPtr + targetIndex + (lineSize * i);
+ for (int j = 0; j < targetWidth; j++) {
+ for (int k = 0; k < pixelWidth; k++)
+ *targetPtr++ = *sourcePtr++;
+ targetPtr += (frameSize - pixelWidth);
+ }
+ }
+ } else if (axis == Qt::YAxis) {
+ int targetHeight = dptr()->m_textureDepth;
+ for (int i = 0; i < targetHeight; i++){
+ for (int j = 0; j < lineSize; j++)
+ *targetPtr++ = *sourcePtr++;
+ targetPtr -= (frameSize + lineSize);
+ }
+ } else {
+ void *subTexPtr = dataPtr + targetIndex;
+ 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 along the specified
+ * \a axis of the volume.
+ * The \a index parameter specifies the subtexture to set.
+ * The source \a 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 the cross-section of the volume texture along
+ * the specified axis. The orientation of the image should correspond to the orientation of
+ * the slice image produced by renderSlice() method along the same axis.
+ *
+ * \note Each X-line of the data needs to be 32bit aligned when targeting Y-axis or Z-axis.
+ * 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 image in cases it is not already
+ * properly aligned. The padding bytes should indicate an fully transparent color to avoid
+ * rendering artifacts. It is not guaranteed QImage will do this automatically.
+ *
+ * \sa textureData, renderSlice()
+ */
+void QCustom3DVolume::setSubTextureData(Qt::Axis axis, int index, const QImage &image)
+{
+ int sourceWidth = image.width();
+ int sourceHeight = image.height();
+ int targetWidth;
+ int targetHeight;
+ if (axis == Qt::XAxis) {
+ targetWidth = dptr()->m_textureDepth;
+ targetHeight = dptr()->m_textureHeight;
+ } else if (axis == Qt::YAxis) {
+ targetWidth = dptr()->m_textureWidth;
+ targetHeight = dptr()->m_textureDepth;
+ } else {
+ targetWidth = dptr()->m_textureWidth;
+ targetHeight = dptr()->m_textureHeight;
+ }
+
+ if (sourceWidth == targetWidth
+ && sourceHeight == targetHeight
+ && (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(axis, index, convertedImage.bits());
+ } else {
+ qWarning() << __FUNCTION__ << "Invalid image size or format.";
+ }
+}
+
+// Note: textureFormat is not a Q_PROPERTY to work around an issue in meta object system that
+// doesn't allow QImage::format to be a property type. Qt 5.2.1 at least has this problem.
+
+/*!
+ * Sets the format of the textureData to \a format. 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.";
+ }
+}
+
+/*!
+ * \return the format of the textureData.
+ *
+ * \sa setTextureFormat()
+ */
+QImage::Format QCustom3DVolume::textureFormat() const
+{
+ return dptrc()->m_textureFormat;
+}
+
+/*!
+ * \fn void QCustom3DVolume::textureFormatChanged(QImage::Format format)
+ *
+ * This signal is emitted when the textureData \a format changes.
+ *
+ * \sa setTextureFormat()
+ */
+
+/*!
+ * \property QCustom3DVolume::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.0f}.
+ *
+ * \sa preserveOpacity, textureData
+ */
+void QCustom3DVolume::setAlphaMultiplier(float mult)
+{
+ 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 {
+ qWarning() << __FUNCTION__ << "Attempted to set negative multiplier.";
+ }
+}
+
+float QCustom3DVolume::alphaMultiplier() const
+{
+ return dptrc()->m_alphaMultiplier;
+}
+
+/*!
+ * \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();
+ }
+}
+
+bool QCustom3DVolume::preserveOpacity() const
+{
+ return dptrc()->m_preserveOpacity;
+}
+
+/*!
+ * \property QCustom3DVolume::useHighDefShader
+ *
+ * If this property value is \c{true}, a high definition shader is used to render the volume.
+ * If it is \c{false}, a low definition shader is used.
+ *
+ * The high definition shader guarantees that every visible texel of the volume texture is sampled
+ * when the volume is rendered.
+ * The low definition shader renders only a rough approximation of the volume contents,
+ * but at much higher frame rate. The low definition shader doesn't guarantee every texel of the
+ * volume texture is sampled, so there may be flickering if the volume contains distinct thin
+ * features.
+ *
+ * \note This value doesn't affect the level of detail when rendering the slices of the volume.
+ *
+ * Defaults to \c{true}.
+ *
+ * \sa renderSlice()
+ */
+void QCustom3DVolume::setUseHighDefShader(bool enable)
+{
+ if (dptr()->m_useHighDefShader != enable) {
+ dptr()->m_useHighDefShader = enable;
+ dptr()->m_dirtyBitsVolume.shaderDirty = true;
+ emit useHighDefShaderChanged(enable);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DVolume::useHighDefShader() const
+{
+ return dptrc()->m_useHighDefShader;
+}
+
+/*!
+ * \property QCustom3DVolume::drawSlices
+ *
+ * If this property value is \c{true}, the slices indicated by slice index properties
+ * will be drawn instead of the full volume.
+ * If it is \c{false}, the full volume will always be drawn.
+ * Defaults to \c{false}.
+ *
+ * \note The slices are always drawn along the item axes, so if the item is rotated, the slices are
+ * rotated as well.
+ *
+ * \sa sliceIndexX, sliceIndexY, sliceIndexZ
+ */
+void QCustom3DVolume::setDrawSlices(bool enable)
+{
+ if (dptr()->m_drawSlices != enable) {
+ dptr()->m_drawSlices = enable;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit drawSlicesChanged(enable);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DVolume::drawSlices() const
+{
+ return dptrc()->m_drawSlices;
+}
+
+/*!
+ * \property QCustom3DVolume::drawSliceFrames
+ *
+ * If this property value is \c{true}, the frames of slices indicated by slice index properties
+ * will be drawn around the volume.
+ * If it is \c{false}, no slice frames will be drawn.
+ * Drawing slice frames is independent of drawing slices, so you can show the full volume and
+ * still draw the slice frames around it. This is useful when using renderSlice() to display the
+ * slices outside the graph itself.
+ * Defaults to \c{false}.
+ *
+ * \sa sliceIndexX, sliceIndexY, sliceIndexZ, drawSlices, renderSlice()
+ */
+void QCustom3DVolume::setDrawSliceFrames(bool enable)
+{
+ if (dptr()->m_drawSliceFrames != enable) {
+ dptr()->m_drawSliceFrames = enable;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit drawSliceFramesChanged(enable);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DVolume::drawSliceFrames() const
+{
+ return dptrc()->m_drawSliceFrames;
+}
+
+/*!
+ * \property QCustom3DVolume::sliceFrameColor
+ *
+ * Indicates the color of the slice frame. Transparent slice frame color is not supported.
+ *
+ * Defaults to black.
+ *
+ * \sa drawSliceFrames
+ */
+void QCustom3DVolume::setSliceFrameColor(const QColor &color)
+{
+ if (dptr()->m_sliceFrameColor != color) {
+ dptr()->m_sliceFrameColor = color;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit sliceFrameColorChanged(color);
+ emit dptr()->needUpdate();
+ }
+}
+
+QColor QCustom3DVolume::sliceFrameColor() const
+{
+ return dptrc()->m_sliceFrameColor;
+}
+
+/*!
+ * \property QCustom3DVolume::sliceFrameWidths
+ *
+ * Indicates the widths of the slice frame. The width can be different on different dimensions,
+ * so you can for example omit drawing the frames on certain sides of the volume by setting the
+ * value for that dimension to zero. The values are fractions of the volume thickness in the same
+ * dimension. The values cannot be negative.
+ *
+ * Defaults to \c{QVector3D(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+void QCustom3DVolume::setSliceFrameWidths(const QVector3D &values)
+{
+ if (values.x() < 0.0f || values.y() < 0.0f || values.z() < 0.0f) {
+ qWarning() << __FUNCTION__ << "Attempted to set negative values.";
+ } else if (dptr()->m_sliceFrameWidths != values) {
+ dptr()->m_sliceFrameWidths = values;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit sliceFrameWidthsChanged(values);
+ emit dptr()->needUpdate();
+ }
+}
+
+QVector3D QCustom3DVolume::sliceFrameWidths() const
+{
+ return dptrc()->m_sliceFrameWidths;
+}
+
+/*!
+ * \property QCustom3DVolume::sliceFrameGaps
+ *
+ * Indicates the amount of air gap left between the volume itself and the frame in each dimension.
+ * The gap can be different on different dimensions. The values are fractions of the volume
+ * thickness in the same dimension. The values cannot be negative.
+ *
+ * Defaults to \c{QVector3D(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+void QCustom3DVolume::setSliceFrameGaps(const QVector3D &values)
+{
+ if (values.x() < 0.0f || values.y() < 0.0f || values.z() < 0.0f) {
+ qWarning() << __FUNCTION__ << "Attempted to set negative values.";
+ } else if (dptr()->m_sliceFrameGaps != values) {
+ dptr()->m_sliceFrameGaps = values;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit sliceFrameGapsChanged(values);
+ emit dptr()->needUpdate();
+ }
+}
+
+QVector3D QCustom3DVolume::sliceFrameGaps() const
+{
+ return dptrc()->m_sliceFrameGaps;
+}
+
+/*!
+ * \property QCustom3DVolume::sliceFrameThicknesses
+ *
+ * Indicates the thickness of the slice frames for each dimension. The values are fractions of
+ * the volume thickness in the same dimension. The values cannot be negative.
+ *
+ * Defaults to \c{QVector3D(0.01, 0.01, 0.01)}.
+ *
+ * \sa drawSliceFrames
+ */
+void QCustom3DVolume::setSliceFrameThicknesses(const QVector3D &values)
+{
+ if (values.x() < 0.0f || values.y() < 0.0f || values.z() < 0.0f) {
+ qWarning() << __FUNCTION__ << "Attempted to set negative values.";
+ } else if (dptr()->m_sliceFrameThicknesses != values) {
+ dptr()->m_sliceFrameThicknesses = values;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
+ emit sliceFrameThicknessesChanged(values);
+ emit dptr()->needUpdate();
+ }
+}
+
+QVector3D QCustom3DVolume::sliceFrameThicknesses() const
+{
+ return dptrc()->m_sliceFrameThicknesses;
+}
+
+/*!
+ * 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 setTextureFormat()
+ */
+QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index)
+{
+ return dptr()->renderSlice(axis, index);
+}
+
+/*!
+ * \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_textureWidth(0),
+ m_textureHeight(0),
+ m_textureDepth(0),
+ m_sliceIndexX(-1),
+ m_sliceIndexY(-1),
+ m_sliceIndexZ(-1),
+ m_textureFormat(QImage::Format_ARGB32),
+ m_textureData(0),
+ m_alphaMultiplier(1.0f),
+ m_preserveOpacity(true),
+ m_useHighDefShader(true),
+ m_drawSlices(false),
+ m_drawSliceFrames(false),
+ m_sliceFrameColor(Qt::black),
+ m_sliceFrameWidths(QVector3D(0.01f, 0.01f, 0.01f)),
+ m_sliceFrameGaps(QVector3D(0.01f, 0.01f, 0.01f)),
+ m_sliceFrameThicknesses(QVector3D(0.01f, 0.01f, 0.01f))
+{
+ 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_textureWidth(textureWidth),
+ m_textureHeight(textureHeight),
+ m_textureDepth(textureDepth),
+ m_sliceIndexX(-1),
+ m_sliceIndexY(-1),
+ m_sliceIndexZ(-1),
+ m_textureFormat(textureFormat),
+ m_colorTable(colorTable),
+ m_textureData(textureData),
+ m_alphaMultiplier(1.0f),
+ m_preserveOpacity(true),
+ m_useHighDefShader(true),
+ m_drawSlices(false),
+ m_drawSliceFrames(false),
+ m_sliceFrameColor(Qt::black),
+ m_sliceFrameWidths(QVector3D(0.01f, 0.01f, 0.01f)),
+ m_sliceFrameGaps(QVector3D(0.01f, 0.01f, 0.01f)),
+ m_sliceFrameThicknesses(QVector3D(0.01f, 0.01f, 0.01f))
+{
+ 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_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.slicesDirty = false;
+ m_dirtyBitsVolume.colorTableDirty = false;
+ m_dirtyBitsVolume.textureDataDirty = false;
+ m_dirtyBitsVolume.textureFormatDirty = false;
+ m_dirtyBitsVolume.alphaDirty = false;
+ m_dirtyBitsVolume.shaderDirty = 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 = y - 1; i >= 0; 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);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h
new file mode 100644
index 00000000..a9dfda86
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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(float alphaMultiplier READ alphaMultiplier WRITE setAlphaMultiplier NOTIFY alphaMultiplierChanged)
+ Q_PROPERTY(bool preserveOpacity READ preserveOpacity WRITE setPreserveOpacity NOTIFY preserveOpacityChanged)
+ Q_PROPERTY(bool useHighDefShader READ useHighDefShader WRITE setUseHighDefShader NOTIFY useHighDefShaderChanged)
+ Q_PROPERTY(bool drawSlices READ drawSlices WRITE setDrawSlices NOTIFY drawSlicesChanged)
+ Q_PROPERTY(bool drawSliceFrames READ drawSliceFrames WRITE setDrawSliceFrames NOTIFY drawSliceFramesChanged)
+ Q_PROPERTY(QColor sliceFrameColor READ sliceFrameColor WRITE setSliceFrameColor NOTIFY sliceFrameColorChanged)
+ Q_PROPERTY(QVector3D sliceFrameWidths READ sliceFrameWidths WRITE setSliceFrameWidths NOTIFY sliceFrameWidthsChanged)
+ Q_PROPERTY(QVector3D sliceFrameGaps READ sliceFrameGaps WRITE setSliceFrameGaps NOTIFY sliceFrameGapsChanged)
+ Q_PROPERTY(QVector3D sliceFrameThicknesses READ sliceFrameThicknesses WRITE setSliceFrameThicknesses NOTIFY sliceFrameThicknessesChanged)
+
+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(Qt::Axis axis, int index, const uchar *data);
+ void setSubTextureData(Qt::Axis axis, int index, const QImage &image);
+
+ void setTextureFormat(QImage::Format format);
+ QImage::Format textureFormat() const;
+
+ void setAlphaMultiplier(float mult);
+ float alphaMultiplier() const;
+ void setPreserveOpacity(bool enable);
+ bool preserveOpacity() const;
+
+ void setUseHighDefShader(bool enable);
+ bool useHighDefShader() const;
+
+ void setDrawSlices(bool enable);
+ bool drawSlices() const;
+ void setDrawSliceFrames(bool enable);
+ bool drawSliceFrames() const;
+
+ void setSliceFrameColor(const QColor &color);
+ QColor sliceFrameColor() const;
+ void setSliceFrameWidths(const QVector3D &values);
+ QVector3D sliceFrameWidths() const;
+ void setSliceFrameGaps(const QVector3D &values);
+ QVector3D sliceFrameGaps() const;
+ void setSliceFrameThicknesses(const QVector3D &values);
+ QVector3D sliceFrameThicknesses() const;
+
+ QImage renderSlice(Qt::Axis axis, int index);
+
+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);
+ void alphaMultiplierChanged(float mult);
+ void preserveOpacityChanged(bool enabled);
+ void useHighDefShaderChanged(bool enabled);
+ void drawSlicesChanged(bool enabled);
+ void drawSliceFramesChanged(bool enabled);
+ void sliceFrameColorChanged(const QColor &color);
+ void sliceFrameWidthsChanged(const QVector3D &values);
+ void sliceFrameGapsChanged(const QVector3D &values);
+ void sliceFrameThicknessesChanged(const QVector3D &values);
+
+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..642d2af5
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dvolume_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 slicesDirty : 1;
+ bool colorTableDirty : 1;
+ bool textureDataDirty : 1;
+ bool textureFormatDirty : 1;
+ bool alphaDirty : 1;
+ bool shaderDirty : 1;
+
+ QCustomVolumeDirtyBitField()
+ : textureDimensionsDirty(false),
+ slicesDirty(false),
+ colorTableDirty(false),
+ textureDataDirty(false),
+ textureFormatDirty(false),
+ alphaDirty(false),
+ shaderDirty(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();
+ QImage renderSlice(Qt::Axis axis, int index);
+
+ 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;
+
+ float m_alphaMultiplier;
+ bool m_preserveOpacity;
+ bool m_useHighDefShader;
+
+ bool m_drawSlices;
+ bool m_drawSliceFrames;
+ QColor m_sliceFrameColor;
+ QVector3D m_sliceFrameWidths;
+ QVector3D m_sliceFrameGaps;
+ QVector3D m_sliceFrameThicknesses;
+
+ QCustomVolumeDirtyBitField m_dirtyBitsVolume;
+
+private:
+ int multipliedAlphaValue(int alpha);
+
+ friend class QCustom3DVolume;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
index d64046be..85aed432 100644
--- a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
@@ -84,7 +84,7 @@ const float defaultMaxValue = 10.0f;
/*!
* \qmlproperty real HeightMapSurfaceDataProxy::minXValue
*
- * The minimum X value for the generated surface points.
+ * The minimum X value for the generated surface points. Defaults to \c{0.0}.
* When setting this property the corresponding maximum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -92,7 +92,7 @@ const float defaultMaxValue = 10.0f;
/*!
* \qmlproperty real HeightMapSurfaceDataProxy::maxXValue
*
- * The maximum X value for the generated surface points.
+ * The maximum X value for the generated surface points. Defaults to \c{10.0}.
* When setting this property the corresponding minimum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -100,7 +100,7 @@ const float defaultMaxValue = 10.0f;
/*!
* \qmlproperty real HeightMapSurfaceDataProxy::minZValue
*
- * The minimum Z value for the generated surface points.
+ * The minimum Z value for the generated surface points. Defaults to \c{0.0}.
* When setting this property the corresponding maximum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -108,7 +108,7 @@ const float defaultMaxValue = 10.0f;
/*!
* \qmlproperty real HeightMapSurfaceDataProxy::maxZValue
*
- * The maximum Z value for the generated surface points.
+ * The maximum Z value for the generated surface points. Defaults to \c{10.0}.
* When setting this property the corresponding minimum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -228,7 +228,7 @@ void QHeightMapSurfaceDataProxy::setValueRanges(float minX, float maxX, float mi
/*!
* \property QHeightMapSurfaceDataProxy::minXValue
*
- * The minimum X value for the generated surface points.
+ * The minimum X value for the generated surface points. Defaults to \c{0.0}.
* When setting this property the corresponding maximum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -245,7 +245,7 @@ float QHeightMapSurfaceDataProxy::minXValue() const
/*!
* \property QHeightMapSurfaceDataProxy::maxXValue
*
- * The maximum X value for the generated surface points.
+ * The maximum X value for the generated surface points. Defaults to \c{10.0}.
* When setting this property the corresponding minimum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -262,7 +262,7 @@ float QHeightMapSurfaceDataProxy::maxXValue() const
/*!
* \property QHeightMapSurfaceDataProxy::minZValue
*
- * The minimum Z value for the generated surface points.
+ * The minimum Z value for the generated surface points. Defaults to \c{0.0}.
* When setting this property the corresponding maximum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
@@ -279,7 +279,7 @@ float QHeightMapSurfaceDataProxy::minZValue() const
/*!
* \property QHeightMapSurfaceDataProxy::maxZValue
*
- * The maximum Z value for the generated surface points.
+ * The maximum Z value for the generated surface points. Defaults to \c{10.0}.
* When setting this property the corresponding minimum value is adjusted if necessary,
* to ensure that the range remains valid.
*/
diff --git a/src/datavisualization/data/qsurface3dseries.cpp b/src/datavisualization/data/qsurface3dseries.cpp
index 1107d721..7d4dacfe 100644
--- a/src/datavisualization/data/qsurface3dseries.cpp
+++ b/src/datavisualization/data/qsurface3dseries.cpp
@@ -141,6 +141,14 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \qmlproperty string Surface3DSeries::textureFile
+ *
+ * Holds the texture file name for the surface texture. To clear the texture, set empty
+ * file name.
+ */
+
+
+/*!
* \enum QSurface3DSeries::DrawFlag
*
* Drawing mode of the surface. Values of this enumeration can be combined with OR operator.
@@ -300,6 +308,57 @@ QSurface3DSeries::DrawFlags QSurface3DSeries::drawMode() const
}
/*!
+ * \property QSurface3DSeries::texture
+ *
+ * Set the \a texture as a QImage for the surface. To clear the texture, set empty
+ * QImage as texture.
+ */
+void QSurface3DSeries::setTexture(const QImage &texture)
+{
+ if (dptr()->m_texture != texture) {
+ dptr()->setTexture(texture);
+
+ emit textureChanged(texture);
+ dptr()->m_textureFile.clear();
+ }
+}
+
+QImage QSurface3DSeries::texture() const
+{
+ return dptrc()->m_texture;
+}
+
+/*!
+ * \property QSurface3DSeries::textureFile
+ *
+ * Holds the texture file name for the surface texture. To clear the texture, set empty
+ * file name.
+ */
+void QSurface3DSeries::setTextureFile(const QString &filename)
+{
+ if (dptr()->m_textureFile != filename) {
+ if (filename.isEmpty()) {
+ setTexture(QImage());
+ } else {
+ QImage image(filename);
+ if (image.isNull()) {
+ qWarning() << "Warning: Tried to set invalid image file as surface texture.";
+ return;
+ }
+ setTexture(image);
+ }
+
+ dptr()->m_textureFile = filename;
+ emit textureFileChanged(filename);
+ }
+}
+
+QString QSurface3DSeries::textureFile() const
+{
+ return dptrc()->m_textureFile;
+}
+
+/*!
* \internal
*/
QSurface3DSeriesPrivate *QSurface3DSeries::dptr()
@@ -445,4 +504,11 @@ void QSurface3DSeriesPrivate::setDrawMode(QSurface3DSeries::DrawFlags mode)
}
}
+void QSurface3DSeriesPrivate::setTexture(const QImage &texture)
+{
+ m_texture = texture;
+ if (static_cast<Surface3DController *>(m_controller))
+ static_cast<Surface3DController *>(m_controller)->updateSurfaceTexture(qptr());
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qsurface3dseries.h b/src/datavisualization/data/qsurface3dseries.h
index 64df7202..7051e583 100644
--- a/src/datavisualization/data/qsurface3dseries.h
+++ b/src/datavisualization/data/qsurface3dseries.h
@@ -35,6 +35,8 @@ class QT_DATAVISUALIZATION_EXPORT QSurface3DSeries : public QAbstract3DSeries
Q_PROPERTY(bool flatShadingEnabled READ isFlatShadingEnabled WRITE setFlatShadingEnabled NOTIFY flatShadingEnabledChanged)
Q_PROPERTY(bool flatShadingSupported READ isFlatShadingSupported NOTIFY flatShadingSupportedChanged)
Q_PROPERTY(DrawFlags drawMode READ drawMode WRITE setDrawMode NOTIFY drawModeChanged)
+ Q_PROPERTY(QImage texture READ texture WRITE setTexture NOTIFY textureChanged)
+ Q_PROPERTY(QString textureFile READ textureFile WRITE setTextureFile NOTIFY textureFileChanged)
public:
enum DrawFlag {
@@ -63,12 +65,19 @@ public:
bool isFlatShadingSupported() const;
+ void setTexture(const QImage &texture);
+ QImage texture() const;
+ void setTextureFile(const QString &filename);
+ QString textureFile() const;
+
signals:
void dataProxyChanged(QSurfaceDataProxy *proxy);
void selectedPointChanged(const QPoint &position);
void flatShadingEnabledChanged(bool enable);
void flatShadingSupportedChanged(bool enable);
void drawModeChanged(QSurface3DSeries::DrawFlags mode);
+ void textureChanged(const QImage &image);
+ void textureFileChanged(const QString &filename);
protected:
explicit QSurface3DSeries(QSurface3DSeriesPrivate *d, QObject *parent = 0);
diff --git a/src/datavisualization/data/qsurface3dseries_p.h b/src/datavisualization/data/qsurface3dseries_p.h
index d4cc2820..270a3ad1 100644
--- a/src/datavisualization/data/qsurface3dseries_p.h
+++ b/src/datavisualization/data/qsurface3dseries_p.h
@@ -48,6 +48,7 @@ public:
void setSelectedPoint(const QPoint &position);
void setFlatShadingEnabled(bool enabled);
void setDrawMode(QSurface3DSeries::DrawFlags mode);
+ void setTexture(const QImage &texture);
private:
QSurface3DSeries *qptr();
@@ -55,6 +56,8 @@ private:
QPoint m_selectedPoint;
bool m_flatShadingEnabled;
QSurface3DSeries::DrawFlags m_drawMode;
+ QImage m_texture;
+ QString m_textureFile;
private:
friend class QSurface3DSeries;
diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp
index dbe7cc49..12b24465 100644
--- a/src/datavisualization/data/qsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qsurfacedataproxy.cpp
@@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \note Surfaces with less than two rows or columns are not considered valid surfaces and will
* not be rendered.
*
+ * \note On some environments, surfaces with a lot of visible vertices may not render, because
+ * they exceed the per-draw vertex count supported by the graphics driver.
+ * This is mostly an issue on 32bit and/or OpenGL ES2 platforms.
+ *
* \sa {Qt Data Visualization Data Handling}
*/