summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-12 11:27:24 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-09-12 12:15:02 +0300
commite5f6ab99b413ad9b8481ad923c5a4a5bc6513ff2 (patch)
tree85fd24fe13281b882e989a5f6826bc3cdad41446 /src
parentddb9be979d93b7e17f1067dc6056de54d9828b29 (diff)
Implement volume slice frames
Change-Id: I409f3c95892b26ca6097dd4509109fc9978b9900 Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/datavisualization/data/abstractrenderitem_p.h6
-rw-r--r--src/datavisualization/data/customrenderitem.cpp32
-rw-r--r--src/datavisualization/data/customrenderitem_p.h78
-rw-r--r--src/datavisualization/data/qcustom3ditem.cpp10
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp303
-rw-r--r--src/datavisualization/data/qcustom3dvolume.h26
-rw-r--r--src/datavisualization/data/qcustom3dvolume_p.h11
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp179
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h7
-rw-r--r--src/datavisualization/engine/engine.qrc2
-rw-r--r--src/datavisualization/engine/shaders/3dsliceframes.frag15
-rw-r--r--src/datavisualization/engine/shaders/colorandposition.vert10
-rw-r--r--src/datavisualization/utils/shaderhelper.cpp14
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h3
14 files changed, 612 insertions, 84 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 64194bac..f56ca86e 100644
--- a/src/datavisualization/data/customrenderitem.cpp
+++ b/src/datavisualization/data/customrenderitem.cpp
@@ -45,7 +45,10 @@ CustomRenderItem::CustomRenderItem()
m_sliceIndexZ(-1),
m_alphaMultiplier(1.0f),
m_preserveOpacity(true),
- m_useHighDefShader(true)
+ m_useHighDefShader(true),
+ m_drawSlices(false),
+ m_drawSliceFrames(false)
+
{
}
@@ -75,4 +78,31 @@ void CustomRenderItem::setColorTable(const QVector<QRgb> &colors)
}
}
+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 84fc898a..ad868fac 100644
--- a/src/datavisualization/data/customrenderitem_p.h
+++ b/src/datavisualization/data/customrenderitem_p.h
@@ -33,6 +33,7 @@
#include "objecthelper_p.h"
#include <QtGui/QRgb>
#include <QtGui/QImage>
+#include <QtGui/QColor>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -50,13 +51,13 @@ 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 QVector3D origScaling() const { return m_origScaling; }
+ 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 const QVector3D &position() const { return m_position; }
inline void setOrigPosition(const QVector3D &position) { m_origPosition = position; }
- inline QVector3D origPosition() const { return m_origPosition; }
+ 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; }
@@ -80,11 +81,11 @@ public:
inline bool isLabel() const { return m_labelItem; }
// Volume specific
- inline void setTextureWidth(int width) { m_textureWidth = width; }
+ 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; }
+ 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; }
+ 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; }
@@ -94,9 +95,22 @@ public:
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; }
+ 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; }
@@ -106,25 +120,24 @@ public:
inline bool preserveOpacity() const { return m_preserveOpacity; }
inline void setUseHighDefShader(bool enable) { m_useHighDefShader = enable; }
inline bool useHighDefShader() const {return m_useHighDefShader; }
- inline void 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);
-
- }
- inline QVector3D minBounds() const { return m_minBounds; }
- inline void 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);
- }
- inline QVector3D maxBounds() const { return m_maxBounds; }
- inline QVector3D minBoundsNormal() const { return m_minBoundsNormal; }
- inline QVector3D maxBoundsNormal() const { return m_maxBoundsNormal; }
+ 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)
@@ -157,6 +170,7 @@ private:
int m_sliceIndexX;
int m_sliceIndexY;
int m_sliceIndexZ;
+ QVector3D m_sliceFractions;
float m_alphaMultiplier;
bool m_preserveOpacity;
bool m_useHighDefShader;
@@ -164,6 +178,12 @@ private:
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/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp
index 4e82d47a..b9825732 100644
--- a/src/datavisualization/data/qcustom3ditem.cpp
+++ b/src/datavisualization/data/qcustom3ditem.cpp
@@ -101,7 +101,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* 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.
+ * 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.
@@ -282,7 +284,9 @@ QVector3D QCustom3DItem::scaling() const
* 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.
+ * 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.
@@ -438,7 +442,7 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) :
m_positionAbsolute(false),
m_scaling(QVector3D(0.1f, 0.1f, 0.1f)),
m_scalingAbsolute(true),
- m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)),
+ m_rotation(identityQuaternion),
m_visible(true),
m_shadowCasting(true),
m_isLabelItem(false),
diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp
index 78c91802..563af31a 100644
--- a/src/datavisualization/data/qcustom3dvolume.cpp
+++ b/src/datavisualization/data/qcustom3dvolume.cpp
@@ -104,31 +104,34 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*! \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.
+ * 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
+ * \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 for that dimension is drawn.
- * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * 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
+ * \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 for that dimension is drawn.
- * If all dimensions are negative, no slices are drawn and the volume is drawn normally.
+ * 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
+ * \sa QCustom3DVolume::textureData, drawSlices, drawSliceFrames
*/
/*!
@@ -174,6 +177,79 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \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) :
@@ -324,17 +400,18 @@ int QCustom3DVolume::textureDataWidth() const
/*! \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.
+ * 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
+ * \sa textureData, drawSlices, drawSliceFrames
*/
void QCustom3DVolume::setSliceIndexX(int value)
{
if (dptr()->m_sliceIndexX != value) {
dptr()->m_sliceIndexX = value;
- dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
emit sliceIndexXChanged(value);
emit dptr()->needUpdate();
}
@@ -348,17 +425,18 @@ int QCustom3DVolume::sliceIndexX() const
/*! \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.
+ * 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
+ * \sa textureData, drawSlices, drawSliceFrames
*/
void QCustom3DVolume::setSliceIndexY(int value)
{
if (dptr()->m_sliceIndexY != value) {
dptr()->m_sliceIndexY = value;
- dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
emit sliceIndexYChanged(value);
emit dptr()->needUpdate();
}
@@ -372,17 +450,18 @@ int QCustom3DVolume::sliceIndexY() const
/*! \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.
+ * 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
+ * \sa textureData, drawSlices, drawSliceFrames
*/
void QCustom3DVolume::setSliceIndexZ(int value)
{
if (dptr()->m_sliceIndexZ != value) {
dptr()->m_sliceIndexZ = value;
- dptr()->m_dirtyBitsVolume.sliceIndicesDirty = true;
+ dptr()->m_dirtyBitsVolume.slicesDirty = true;
emit sliceIndexZChanged(value);
emit dptr()->needUpdate();
}
@@ -817,6 +896,170 @@ bool QCustom3DVolume::useHighDefShader() const
}
/*!
+ * \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.
*
@@ -857,7 +1100,13 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q) :
m_textureData(0),
m_alphaMultiplier(1.0f),
m_preserveOpacity(true),
- m_useHighDefShader(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");
@@ -882,7 +1131,13 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector
m_textureData(textureData),
m_alphaMultiplier(1.0f),
m_preserveOpacity(true),
- m_useHighDefShader(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;
@@ -909,7 +1164,7 @@ void QCustom3DVolumePrivate::resetDirtyBits()
QCustom3DItemPrivate::resetDirtyBits();
m_dirtyBitsVolume.textureDimensionsDirty = false;
- m_dirtyBitsVolume.sliceIndicesDirty = false;
+ m_dirtyBitsVolume.slicesDirty = false;
m_dirtyBitsVolume.colorTableDirty = false;
m_dirtyBitsVolume.textureDataDirty = false;
m_dirtyBitsVolume.textureFormatDirty = false;
diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h
index 04434263..a9dfda86 100644
--- a/src/datavisualization/data/qcustom3dvolume.h
+++ b/src/datavisualization/data/qcustom3dvolume.h
@@ -42,6 +42,12 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DVolume : public QCustom3DItem
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:
@@ -90,6 +96,20 @@ public:
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:
@@ -105,6 +125,12 @@ signals:
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();
diff --git a/src/datavisualization/data/qcustom3dvolume_p.h b/src/datavisualization/data/qcustom3dvolume_p.h
index 8b0b439e..642d2af5 100644
--- a/src/datavisualization/data/qcustom3dvolume_p.h
+++ b/src/datavisualization/data/qcustom3dvolume_p.h
@@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
struct QCustomVolumeDirtyBitField {
bool textureDimensionsDirty : 1;
- bool sliceIndicesDirty : 1;
+ bool slicesDirty : 1;
bool colorTableDirty : 1;
bool textureDataDirty : 1;
bool textureFormatDirty : 1;
@@ -45,7 +45,7 @@ struct QCustomVolumeDirtyBitField {
QCustomVolumeDirtyBitField()
: textureDimensionsDirty(false),
- sliceIndicesDirty(false),
+ slicesDirty(false),
colorTableDirty(false),
textureDataDirty(false),
textureFormatDirty(false),
@@ -88,6 +88,13 @@ public:
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:
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index 305d3df0..4dd58490 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -62,6 +62,7 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
m_volumeTextureShader(0),
m_volumeTextureLowDefShader(0),
m_volumeTextureSliceShader(0),
+ m_volumeSliceFrameShader(0),
m_useOrthoProjection(false),
m_xFlipped(false),
m_yFlipped(false),
@@ -105,6 +106,7 @@ Abstract3DRenderer::~Abstract3DRenderer()
delete m_customItemShader;
delete m_volumeTextureShader;
delete m_volumeTextureLowDefShader;
+ delete m_volumeSliceFrameShader;
delete m_volumeTextureSliceShader;
foreach (SeriesRenderCache *cache, m_renderCacheList) {
@@ -208,7 +210,9 @@ void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader,
void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader,
const QString &fragmentShader,
const QString &fragmentLowDefShader,
- const QString &sliceShader)
+ const QString &sliceShader,
+ const QString &sliceFrameVertexShader,
+ const QString &sliceFrameShader)
{
delete m_volumeTextureShader;
@@ -216,13 +220,16 @@ void Abstract3DRenderer::initVolumeTextureShaders(const QString &vertexShader,
m_volumeTextureShader->initialize();
delete m_volumeTextureLowDefShader;
- m_volumeTextureLowDefShader = new ShaderHelper(this, vertexShader,
- fragmentLowDefShader);
+ m_volumeTextureLowDefShader = new ShaderHelper(this, vertexShader, fragmentLowDefShader);
m_volumeTextureLowDefShader->initialize();
delete m_volumeTextureSliceShader;
m_volumeTextureSliceShader = new ShaderHelper(this, vertexShader, sliceShader);
m_volumeTextureSliceShader->initialize();
+
+ delete m_volumeSliceFrameShader;
+ m_volumeSliceFrameShader = new ShaderHelper(this, sliceFrameVertexShader, sliceFrameShader);
+ m_volumeSliceFrameShader->initialize();
}
void Abstract3DRenderer::updateTheme(Q3DTheme *theme)
@@ -327,7 +334,9 @@ void Abstract3DRenderer::reInitShaders()
initVolumeTextureShaders(QStringLiteral(":/shaders/vertexTexture3D"),
QStringLiteral(":/shaders/fragmentTexture3D"),
QStringLiteral(":/shaders/fragmentTexture3DLowDef"),
- QStringLiteral(":/shaders/fragmentTexture3DSlice"));
+ QStringLiteral(":/shaders/fragmentTexture3DSlice"),
+ QStringLiteral(":/shaders/colorAndPosition"),
+ QStringLiteral(":/shaders/fragment3DSliceFrames"));
#else
if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic)
&& qobject_cast<Scatter3DRenderer *>(this)) {
@@ -1011,6 +1020,13 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
newItem->setAlphaMultiplier(volumeItem->alphaMultiplier());
newItem->setPreserveOpacity(volumeItem->preserveOpacity());
newItem->setUseHighDefShader(volumeItem->useHighDefShader());
+
+ newItem->setDrawSlices(volumeItem->drawSlices());
+ newItem->setDrawSliceFrames(volumeItem->drawSliceFrames());
+ newItem->setSliceFrameColor(volumeItem->sliceFrameColor());
+ newItem->setSliceFrameWidths(volumeItem->sliceFrameWidths());
+ newItem->setSliceFrameGaps(volumeItem->sliceFrameGaps());
+ newItem->setSliceFrameThicknesses(volumeItem->sliceFrameThicknesses());
#endif
}
recalculateCustomItemScalingAndPos(newItem);
@@ -1215,11 +1231,17 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
volumeItem->dptr()->m_dirtyBitsVolume.textureDataDirty = false;
volumeItem->dptr()->m_dirtyBitsVolume.textureFormatDirty = false;
}
- if (volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty) {
+ if (volumeItem->dptr()->m_dirtyBitsVolume.slicesDirty) {
+ renderItem->setDrawSlices(volumeItem->drawSlices());
+ renderItem->setDrawSliceFrames(volumeItem->drawSliceFrames());
+ renderItem->setSliceFrameColor(volumeItem->sliceFrameColor());
+ renderItem->setSliceFrameWidths(volumeItem->sliceFrameWidths());
+ renderItem->setSliceFrameGaps(volumeItem->sliceFrameGaps());
+ renderItem->setSliceFrameThicknesses(volumeItem->sliceFrameThicknesses());
renderItem->setSliceIndexX(volumeItem->sliceIndexX());
renderItem->setSliceIndexY(volumeItem->sliceIndexY());
renderItem->setSliceIndexZ(volumeItem->sliceIndexZ());
- volumeItem->dptr()->m_dirtyBitsVolume.sliceIndicesDirty = false;
+ volumeItem->dptr()->m_dirtyBitsVolume.slicesDirty = false;
}
if (volumeItem->dptr()->m_dirtyBitsVolume.alphaDirty) {
renderItem->setAlphaMultiplier(volumeItem->alphaMultiplier());
@@ -1236,9 +1258,8 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
void Abstract3DRenderer::updateCustomItemPositions()
{
- foreach (CustomRenderItem *renderItem, m_customRenderCache) {
+ foreach (CustomRenderItem *renderItem, m_customRenderCache)
recalculateCustomItemScalingAndPos(renderItem);
- }
}
void Abstract3DRenderer::drawCustomItems(RenderingState state,
@@ -1345,9 +1366,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
#if !defined(QT_OPENGL_ES_2)
ShaderHelper *prevShader = shader;
if (item->isVolume()) {
- if (item->sliceIndexX() >= 0
- || item->sliceIndexY() >= 0
- || item->sliceIndexZ() >= 0) {
+ if (item->drawSlices() &&
+ (item->sliceIndexX() >= 0
+ || item->sliceIndexY() >= 0
+ || item->sliceIndexZ() >= 0)) {
shader = m_volumeTextureSliceShader;
} else if (item->useHighDefShader()) {
shader = m_volumeTextureShader;
@@ -1395,10 +1417,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
QVector3D cameraPos = m_cachedScene->activeCamera()->position();
cameraPos = MVPMatrix.inverted().map(cameraPos);
// Adjust camera position according to min/max bounds
- cameraPos = cameraPos
- + ((oneVector - cameraPos) * item->minBoundsNormal())
- - ((oneVector + cameraPos) * (oneVector - item->maxBoundsNormal()));
- shader->setUniformValue(shader->cameraPositionRelativeToModel(), -cameraPos);
+ cameraPos = -(cameraPos
+ + ((oneVector - cameraPos) * item->minBoundsNormal())
+ - ((oneVector + cameraPos) * (oneVector - item->maxBoundsNormal())));
+ shader->setUniformValue(shader->cameraPositionRelativeToModel(), cameraPos);
GLint color8Bit = (item->textureFormat() == QImage::Format_Indexed8) ? 1 : 0;
if (color8Bit) {
shader->setUniformValueArray(shader->colorIndex(),
@@ -1412,14 +1434,10 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
shader->setUniformValue(shader->minBounds(), item->minBounds());
shader->setUniformValue(shader->maxBounds(), item->maxBounds());
+ QVector3D slices;
if (shader == m_volumeTextureSliceShader) {
- 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);
+ shader->setUniformValue(shader->volumeSliceIndices(),
+ item->sliceFractions());
} else {
// Precalculate texture dimensions so we can optimize
// ray stepping to hit every texture layer.
@@ -1443,6 +1461,24 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
shader->setUniformValue(shader->textureDimensions(), textureDimensions);
shader->setUniformValue(shader->sampleCount(), sampleCount);
}
+ if (item->drawSliceFrames()) {
+ // Set up the slice frame shader
+ glDisable(GL_CULL_FACE);
+ m_volumeSliceFrameShader->bind();
+ m_volumeSliceFrameShader->setUniformValue(
+ m_volumeSliceFrameShader->color(), item->sliceFrameColor());
+
+ // Draw individual slice frames.
+ if (item->sliceIndexX() >= 0)
+ drawVolumeSliceFrame(item, Qt::XAxis, projectionViewMatrix);
+ if (item->sliceIndexY() >= 0)
+ drawVolumeSliceFrame(item, Qt::YAxis, projectionViewMatrix);
+ if (item->sliceIndexZ() >= 0)
+ drawVolumeSliceFrame(item, Qt::ZAxis, projectionViewMatrix);
+
+ glEnable(GL_CULL_FACE);
+ shader->bind();
+ }
m_drawer->drawObject(shader, item->mesh(), 0, 0, item->texture());
} else
#endif
@@ -1476,6 +1512,105 @@ void Abstract3DRenderer::drawCustomItems(RenderingState state,
}
}
+void Abstract3DRenderer::drawVolumeSliceFrame(const CustomRenderItem *item, Qt::Axis axis,
+ const QMatrix4x4 &projectionViewMatrix)
+{
+ QVector2D frameWidth;
+ QVector3D frameScaling;
+ QVector3D translation = item->translation();
+ QQuaternion rotation = item->rotation();
+ float fracTrans;
+ bool needRotate = !rotation.isIdentity();
+ QMatrix4x4 rotationMatrix;
+ if (needRotate)
+ rotationMatrix.rotate(rotation);
+
+ if (axis == Qt::XAxis) {
+ fracTrans = item->sliceFractions().x();
+ float range = item->maxBoundsNormal().x() - item->minBoundsNormal().x();
+ float minMult = item->minBoundsNormal().x() / range;
+ float maxMult = (1.0f - item->maxBoundsNormal().x()) / range;
+ fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult);
+ if (needRotate)
+ translation -= rotationMatrix.map(QVector3D(fracTrans * item->scaling().x(), 0.0f, 0.0f));
+ else
+ translation.setX(translation.x() + fracTrans * item->scaling().x());
+ frameScaling = QVector3D(item->scaling().z()
+ + (item->scaling().z() * item->sliceFrameGaps().z())
+ + (item->scaling().z() * item->sliceFrameWidths().z()),
+ item->scaling().y()
+ + (item->scaling().y() * item->sliceFrameGaps().y())
+ + (item->scaling().y() * item->sliceFrameWidths().y()),
+ item->scaling().x() * item->sliceFrameThicknesses().x());
+ frameWidth = QVector2D(item->scaling().z() * item->sliceFrameWidths().z(),
+ item->scaling().y() * item->sliceFrameWidths().y());
+ rotation *= m_yRightAngleRotation;
+ } else if (axis == Qt::YAxis) {
+ fracTrans = item->sliceFractions().y();
+ float range = item->maxBoundsNormal().y() - item->minBoundsNormal().y();
+ // Y axis is logically flipped, so we need to swam min and max bounds
+ float minMult = (1.0f - item->maxBoundsNormal().y()) / range;
+ float maxMult = item->minBoundsNormal().y() / range;
+ fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult);
+ if (needRotate)
+ translation -= rotationMatrix.map(QVector3D(0.0f, fracTrans * item->scaling().y(), 0.0f));
+ else
+ translation.setY(translation.y() - fracTrans * item->scaling().y());
+ frameScaling = QVector3D(item->scaling().x()
+ + (item->scaling().x() * item->sliceFrameGaps().x())
+ + (item->scaling().x() * item->sliceFrameWidths().x()),
+ item->scaling().z()
+ + (item->scaling().z() * item->sliceFrameGaps().z())
+ + (item->scaling().z() * item->sliceFrameWidths().z()),
+ item->scaling().y() * item->sliceFrameThicknesses().y());
+ frameWidth = QVector2D(item->scaling().x() * item->sliceFrameWidths().x(),
+ item->scaling().z() * item->sliceFrameWidths().z());
+ rotation *= m_xRightAngleRotation;
+ } else { // Z axis
+ fracTrans = item->sliceFractions().z();
+ float range = item->maxBoundsNormal().z() - item->minBoundsNormal().z();
+ // Z axis is logically flipped, so we need to swam min and max bounds
+ float minMult = (1.0f - item->maxBoundsNormal().z()) / range;
+ float maxMult = item->minBoundsNormal().z() / range;
+ fracTrans = fracTrans - ((1.0f - fracTrans) * minMult) + ((1.0f + fracTrans) * maxMult);
+ if (needRotate)
+ translation -= rotationMatrix.map(QVector3D(0.0f, 0.0f, fracTrans * item->scaling().z()));
+ else
+ translation.setZ(translation.z() - fracTrans * item->scaling().z());
+ frameScaling = QVector3D(item->scaling().x()
+ + (item->scaling().x() * item->sliceFrameGaps().x())
+ + (item->scaling().x() * item->sliceFrameWidths().x()),
+ item->scaling().y()
+ + (item->scaling().y() * item->sliceFrameGaps().y())
+ + (item->scaling().y() * item->sliceFrameWidths().y()),
+ item->scaling().z() * item->sliceFrameThicknesses().z());
+ frameWidth = QVector2D(item->scaling().x() * item->sliceFrameWidths().x(),
+ item->scaling().y() * item->sliceFrameWidths().y());
+ }
+
+ // If the slice is outside the shown area, don't show the frame
+ if (fracTrans < -1.0 || fracTrans > 1.0)
+ return;
+
+ // Shader needs the width of clear space in the middle.
+ frameWidth.setX(1.0f - (frameWidth.x() / frameScaling.x()));
+ frameWidth.setY(1.0f - (frameWidth.y() / frameScaling.y()));
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 mvpMatrix;
+
+ modelMatrix.translate(translation);
+ modelMatrix.rotate(rotation);
+ modelMatrix.scale(frameScaling);
+ mvpMatrix = projectionViewMatrix * modelMatrix;
+ m_volumeSliceFrameShader->setUniformValue(m_volumeSliceFrameShader->MVP(), mvpMatrix);
+ m_volumeSliceFrameShader->setUniformValue(m_volumeSliceFrameShader->sliceFrameWidth(),
+ frameWidth);
+
+ m_drawer->drawObject(m_volumeSliceFrameShader, item->mesh());
+
+}
+
void Abstract3DRenderer::calculatePolarXZ(const QVector3D &dataPos, float &x, float &z) const
{
// x is angular, z is radial
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
index c8bfa7af..b31cfbd3 100644
--- a/src/datavisualization/engine/abstract3drenderer_p.h
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -95,7 +95,9 @@ public:
virtual void initVolumeTextureShaders(const QString &vertexShader,
const QString &fragmentShader,
const QString &fragmentLowDefShader,
- const QString &sliceShader);
+ const QString &sliceShader,
+ const QString &sliceFrameVertexShader,
+ const QString &sliceFrameShader);
virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation,
QAbstract3DAxis::AxisType type);
virtual void updateAxisTitle(QAbstract3DAxis::AxisOrientation orientation,
@@ -207,6 +209,8 @@ protected:
void recalculateCustomItemScalingAndPos(CustomRenderItem *item);
virtual void getVisibleItemBounds(QVector3D &minBounds, QVector3D &maxBounds) = 0;
+ void drawVolumeSliceFrame(const CustomRenderItem *item, Qt::Axis axis,
+ const QMatrix4x4 &projectionViewMatrix);
bool m_hasNegativeValues;
Q3DTheme *m_cachedTheme;
@@ -248,6 +252,7 @@ protected:
ShaderHelper *m_volumeTextureShader;
ShaderHelper *m_volumeTextureLowDefShader;
ShaderHelper *m_volumeTextureSliceShader;
+ ShaderHelper *m_volumeSliceFrameShader;
bool m_useOrthoProjection;
bool m_xFlipped;
diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc
index eeddf92e..af759ba3 100644
--- a/src/datavisualization/engine/engine.qrc
+++ b/src/datavisualization/engine/engine.qrc
@@ -66,5 +66,7 @@
<file alias="vertexNoMatrices">shaders/defaultNoMatrices.vert</file>
<file alias="fragmentTexture3DLowDef">shaders/texture3dlowdef.frag</file>
<file alias="vertexPointES2_UV">shaders/point_ES2_UV.vert</file>
+ <file alias="fragment3DSliceFrames">shaders/3dsliceframes.frag</file>
+ <file alias="colorAndPosition">shaders/colorandposition.vert</file>
</qresource>
</RCC>
diff --git a/src/datavisualization/engine/shaders/3dsliceframes.frag b/src/datavisualization/engine/shaders/3dsliceframes.frag
new file mode 100644
index 00000000..44c080dc
--- /dev/null
+++ b/src/datavisualization/engine/shaders/3dsliceframes.frag
@@ -0,0 +1,15 @@
+#version 120
+
+uniform highp vec4 color_mdl;
+uniform highp vec2 sliceFrameWidth;
+
+varying highp vec3 pos;
+
+void main() {
+ highp vec2 absPos = min(vec2(1.0, 1.0), abs(pos.xy));
+ if (absPos.x > sliceFrameWidth.x || absPos.y > sliceFrameWidth.y)
+ gl_FragColor = color_mdl;
+ else
+ discard;
+}
+
diff --git a/src/datavisualization/engine/shaders/colorandposition.vert b/src/datavisualization/engine/shaders/colorandposition.vert
new file mode 100644
index 00000000..34849eae
--- /dev/null
+++ b/src/datavisualization/engine/shaders/colorandposition.vert
@@ -0,0 +1,10 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+
+varying highp vec3 pos;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ pos = vertexPosition_mdl;
+}
diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp
index b6dc1621..aa43c2df 100644
--- a/src/datavisualization/utils/shaderhelper.cpp
+++ b/src/datavisualization/utils/shaderhelper.cpp
@@ -103,6 +103,7 @@ void ShaderHelper::initialize()
m_preserveOpacityUniform = m_program->uniformLocation("preserveOpacity");
m_minBoundsUniform = m_program->uniformLocation("minBounds");
m_maxBoundsUniform = m_program->uniformLocation("maxBounds");
+ m_sliceFrameWidthUniform = m_program->uniformLocation("sliceFrameWidth");
m_initialized = true;
}
@@ -135,6 +136,11 @@ void ShaderHelper::release()
m_program->release();
}
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector2D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
void ShaderHelper::setUniformValue(GLuint uniform, const QVector3D &value)
{
m_program->setUniformValue(uniform, value);
@@ -340,6 +346,14 @@ GLuint ShaderHelper::minBounds()
return m_minBoundsUniform;
}
+GLuint ShaderHelper::sliceFrameWidth()
+{
+
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_sliceFrameWidthUniform;
+}
+
GLuint ShaderHelper::posAtt()
{
if (!m_initialized)
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
index 853fcc8f..da010cbd 100644
--- a/src/datavisualization/utils/shaderhelper_p.h
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -52,6 +52,7 @@ class ShaderHelper
bool testCompile();
void bind();
void release();
+ void setUniformValue(GLuint uniform, const QVector2D &value);
void setUniformValue(GLuint uniform, const QVector3D &value);
void setUniformValue(GLuint uniform, const QVector4D &value);
void setUniformValue(GLuint uniform, const QMatrix4x4 &value);
@@ -84,6 +85,7 @@ class ShaderHelper
GLuint preserveOpacity();
GLuint maxBounds();
GLuint minBounds();
+ GLuint sliceFrameWidth();
GLuint posAtt();
GLuint uvAtt();
@@ -128,6 +130,7 @@ class ShaderHelper
GLuint m_preserveOpacityUniform;
GLuint m_minBoundsUniform;
GLuint m_maxBoundsUniform;
+ GLuint m_sliceFrameWidthUniform;
GLboolean m_initialized;
};