summaryrefslogtreecommitdiffstats
path: root/src/datavisualization
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization')
-rw-r--r--src/datavisualization/axis/axis.pri12
-rw-r--r--src/datavisualization/axis/q3dabstractaxis.cpp373
-rw-r--r--src/datavisualization/axis/q3dabstractaxis.h100
-rw-r--r--src/datavisualization/axis/q3dabstractaxis_p.h77
-rw-r--r--src/datavisualization/axis/q3dcategoryaxis.cpp152
-rw-r--r--src/datavisualization/axis/q3dcategoryaxis.h50
-rw-r--r--src/datavisualization/axis/q3dcategoryaxis_p.h57
-rw-r--r--src/datavisualization/axis/q3dvalueaxis.cpp270
-rw-r--r--src/datavisualization/axis/q3dvalueaxis.h65
-rw-r--r--src/datavisualization/axis/q3dvalueaxis_p.h66
-rw-r--r--src/datavisualization/common.pri9
-rw-r--r--src/datavisualization/data/abstractitemmodelhandler.cpp250
-rw-r--r--src/datavisualization/data/abstractitemmodelhandler_p.h90
-rw-r--r--src/datavisualization/data/abstractrenderitem.cpp60
-rw-r--r--src/datavisualization/data/abstractrenderitem_p.h69
-rw-r--r--src/datavisualization/data/baritemmodelhandler.cpp148
-rw-r--r--src/datavisualization/data/baritemmodelhandler_p.h54
-rw-r--r--src/datavisualization/data/barrenderitem.cpp67
-rw-r--r--src/datavisualization/data/barrenderitem_p.h89
-rw-r--r--src/datavisualization/data/data.pri64
-rw-r--r--src/datavisualization/data/labelitem.cpp64
-rw-r--r--src/datavisualization/data/labelitem_p.h59
-rw-r--r--src/datavisualization/data/qabstractdatamapping.cpp71
-rw-r--r--src/datavisualization/data/qabstractdatamapping.h53
-rw-r--r--src/datavisualization/data/qabstractdatamapping_p.h50
-rw-r--r--src/datavisualization/data/qabstractdataproxy.cpp148
-rw-r--r--src/datavisualization/data/qabstractdataproxy.h73
-rw-r--r--src/datavisualization/data/qabstractdataproxy_p.h62
-rw-r--r--src/datavisualization/data/qbardataitem.cpp110
-rw-r--r--src/datavisualization/data/qbardataitem.h54
-rw-r--r--src/datavisualization/data/qbardataitem_p.h51
-rw-r--r--src/datavisualization/data/qbardataproxy.cpp707
-rw-r--r--src/datavisualization/data/qbardataproxy.h130
-rw-r--r--src/datavisualization/data/qbardataproxy_p.h75
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy.cpp489
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy.h75
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy_p.h69
-rw-r--r--src/datavisualization/data/qitemmodelbardatamapping.cpp407
-rw-r--r--src/datavisualization/data/qitemmodelbardatamapping.h90
-rw-r--r--src/datavisualization/data/qitemmodelbardatamapping_p.h63
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy.cpp198
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy.h62
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy_p.h58
-rw-r--r--src/datavisualization/data/qitemmodelscatterdatamapping.cpp200
-rw-r--r--src/datavisualization/data/qitemmodelscatterdatamapping.h62
-rw-r--r--src/datavisualization/data/qitemmodelscatterdatamapping_p.h56
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy.cpp196
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy.h62
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy_p.h58
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedatamapping.cpp411
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedatamapping.h90
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedatamapping_p.h63
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy.cpp198
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy.h62
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy_p.h58
-rw-r--r--src/datavisualization/data/qscatterdataitem.cpp153
-rw-r--r--src/datavisualization/data/qscatterdataitem.h63
-rw-r--r--src/datavisualization/data/qscatterdataitem_p.h51
-rw-r--r--src/datavisualization/data/qscatterdataproxy.cpp367
-rw-r--r--src/datavisualization/data/qscatterdataproxy.h86
-rw-r--r--src/datavisualization/data/qscatterdataproxy_p.h64
-rw-r--r--src/datavisualization/data/qsurfacedataitem.cpp143
-rw-r--r--src/datavisualization/data/qsurfacedataitem.h59
-rw-r--r--src/datavisualization/data/qsurfacedataitem_p.h51
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.cpp289
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.h66
-rw-r--r--src/datavisualization/data/qsurfacedataproxy_p.h63
-rw-r--r--src/datavisualization/data/scatteritemmodelhandler.cpp81
-rw-r--r--src/datavisualization/data/scatteritemmodelhandler_p.h53
-rw-r--r--src/datavisualization/data/scatterrenderitem.cpp42
-rw-r--r--src/datavisualization/data/scatterrenderitem_p.h76
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler.cpp144
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler_p.h53
-rw-r--r--src/datavisualization/datavisualization.pro27
-rw-r--r--src/datavisualization/doc/images/q3dbars-minimal.pngbin0 -> 8611 bytes
-rw-r--r--src/datavisualization/doc/images/q3dscatter-minimal.pngbin0 -> 7998 bytes
-rw-r--r--src/datavisualization/doc/images/q3dsurface-minimal.pngbin0 -> 16174 bytes
-rw-r--r--src/datavisualization/doc/qtdatavisualization.qdocconf51
-rw-r--r--src/datavisualization/doc/snippets/doc_src_q3dbars_construction.cpp46
-rw-r--r--src/datavisualization/doc/snippets/doc_src_q3dscatter_construction.cpp42
-rw-r--r--src/datavisualization/doc/snippets/doc_src_q3dsurface_construction.cpp50
-rw-r--r--src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp121
-rw-r--r--src/datavisualization/doc/snippets/doc_src_qtdatavisualization.cpp118
-rw-r--r--src/datavisualization/doc/snippets/doc_src_qtdatavisualization.pro21
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-index.qdoc78
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc81
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc136
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-colorgradient.qdoc81
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-scatter3d.qdoc105
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-surface3d.qdoc90
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization.qdoc209
-rw-r--r--src/datavisualization/engine/abstract3dcontroller.cpp1056
-rw-r--r--src/datavisualization/engine/abstract3dcontroller_p.h334
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp313
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h141
-rw-r--r--src/datavisualization/engine/axisrendercache.cpp186
-rw-r--r--src/datavisualization/engine/axisrendercache_p.h101
-rw-r--r--src/datavisualization/engine/bars3dcontroller.cpp428
-rw-r--r--src/datavisualization/engine/bars3dcontroller_p.h138
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp1880
-rw-r--r--src/datavisualization/engine/bars3drenderer_p.h170
-rw-r--r--src/datavisualization/engine/drawer.cpp369
-rw-r--r--src/datavisualization/engine/drawer_p.h104
-rw-r--r--src/datavisualization/engine/engine.pri53
-rw-r--r--src/datavisualization/engine/engine.qrc62
-rw-r--r--src/datavisualization/engine/meshes/backgroudFlat.obj32
-rw-r--r--src/datavisualization/engine/meshes/backgroudNegatives.obj37
-rw-r--r--src/datavisualization/engine/meshes/backgroudSmooth.obj36
-rw-r--r--src/datavisualization/engine/meshes/barFilledFlat.obj242
-rw-r--r--src/datavisualization/engine/meshes/barFilledSmooth.obj236
-rw-r--r--src/datavisualization/engine/meshes/barFlat.obj219
-rw-r--r--src/datavisualization/engine/meshes/barSmooth.obj214
-rw-r--r--src/datavisualization/engine/meshes/coneFilledFlat.obj128
-rw-r--r--src/datavisualization/engine/meshes/coneFilledSmooth.obj128
-rw-r--r--src/datavisualization/engine/meshes/coneFlat.obj89
-rw-r--r--src/datavisualization/engine/meshes/coneSmooth.obj90
-rw-r--r--src/datavisualization/engine/meshes/cubeFilledFlat.obj54
-rw-r--r--src/datavisualization/engine/meshes/cubeFilledSmooth.obj56
-rw-r--r--src/datavisualization/engine/meshes/cubeFlat.obj47
-rw-r--r--src/datavisualization/engine/meshes/cubeSmooth.obj50
-rw-r--r--src/datavisualization/engine/meshes/cylinderFilledFlat.obj361
-rw-r--r--src/datavisualization/engine/meshes/cylinderFilledSmooth.obj391
-rw-r--r--src/datavisualization/engine/meshes/cylinderFlat.obj299
-rw-r--r--src/datavisualization/engine/meshes/cylinderSmooth.obj330
-rw-r--r--src/datavisualization/engine/meshes/plane.obj15
-rw-r--r--src/datavisualization/engine/meshes/pyramidFilledFlat.obj36
-rw-r--r--src/datavisualization/engine/meshes/pyramidFilledSmooth.obj36
-rw-r--r--src/datavisualization/engine/meshes/pyramidFlat.obj22
-rw-r--r--src/datavisualization/engine/meshes/pyramidSmooth.obj23
-rw-r--r--src/datavisualization/engine/meshes/scatterdot.obj28
-rw-r--r--src/datavisualization/engine/meshes/scatterdotFlat.obj28
-rw-r--r--src/datavisualization/engine/meshes/sphere.obj1301
-rw-r--r--src/datavisualization/engine/meshes/sphereSmooth.obj1232
-rw-r--r--src/datavisualization/engine/q3dbars.cpp620
-rw-r--r--src/datavisualization/engine/q3dbars.h142
-rw-r--r--src/datavisualization/engine/q3dbars_p.h54
-rw-r--r--src/datavisualization/engine/q3dbox.cpp481
-rw-r--r--src/datavisualization/engine/q3dbox.h184
-rw-r--r--src/datavisualization/engine/q3dcamera.cpp698
-rw-r--r--src/datavisualization/engine/q3dcamera.h131
-rw-r--r--src/datavisualization/engine/q3dcamera_p.h87
-rw-r--r--src/datavisualization/engine/q3dlight.cpp79
-rw-r--r--src/datavisualization/engine/q3dlight.h50
-rw-r--r--src/datavisualization/engine/q3dlight_p.h59
-rw-r--r--src/datavisualization/engine/q3dobject.cpp121
-rw-r--r--src/datavisualization/engine/q3dobject.h65
-rw-r--r--src/datavisualization/engine/q3dobject_p.h53
-rw-r--r--src/datavisualization/engine/q3dscatter.cpp568
-rw-r--r--src/datavisualization/engine/q3dscatter.h128
-rw-r--r--src/datavisualization/engine/q3dscatter_p.h54
-rw-r--r--src/datavisualization/engine/q3dscene.cpp375
-rw-r--r--src/datavisualization/engine/q3dscene.h103
-rw-r--r--src/datavisualization/engine/q3dscene_p.h85
-rw-r--r--src/datavisualization/engine/q3dsurface.cpp542
-rw-r--r--src/datavisualization/engine/q3dsurface.h123
-rw-r--r--src/datavisualization/engine/q3dsurface_p.h53
-rw-r--r--src/datavisualization/engine/q3dwindow.cpp197
-rw-r--r--src/datavisualization/engine/q3dwindow.h65
-rw-r--r--src/datavisualization/engine/q3dwindow_p.h59
-rw-r--r--src/datavisualization/engine/scatter3dcontroller.cpp271
-rw-r--r--src/datavisualization/engine/scatter3dcontroller_p.h106
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp1623
-rw-r--r--src/datavisualization/engine/scatter3drenderer_p.h155
-rw-r--r--src/datavisualization/engine/selectionpointer.cpp275
-rw-r--r--src/datavisualization/engine/selectionpointer_p.h97
-rw-r--r--src/datavisualization/engine/shaders/ambient.frag32
-rw-r--r--src/datavisualization/engine/shaders/colorOnY.frag36
-rw-r--r--src/datavisualization/engine/shaders/colorOnY_ES2.frag37
-rw-r--r--src/datavisualization/engine/shaders/default.frag36
-rw-r--r--src/datavisualization/engine/shaders/default.vert28
-rw-r--r--src/datavisualization/engine/shaders/default_ES2.frag38
-rw-r--r--src/datavisualization/engine/shaders/default_ES2.vert26
-rw-r--r--src/datavisualization/engine/shaders/depth.frag3
-rw-r--r--src/datavisualization/engine/shaders/depth.vert8
-rw-r--r--src/datavisualization/engine/shaders/label.frag8
-rw-r--r--src/datavisualization/engine/shaders/label.vert11
-rw-r--r--src/datavisualization/engine/shaders/selection.frag7
-rw-r--r--src/datavisualization/engine/shaders/selection.vert7
-rw-r--r--src/datavisualization/engine/shaders/shadow.frag82
-rw-r--r--src/datavisualization/engine/shaders/shadow.vert37
-rw-r--r--src/datavisualization/engine/shaders/shadowNoTex.frag98
-rw-r--r--src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag82
-rw-r--r--src/datavisualization/engine/shaders/surface.frag36
-rw-r--r--src/datavisualization/engine/shaders/surface.vert25
-rw-r--r--src/datavisualization/engine/shaders/surfaceFlat.frag36
-rw-r--r--src/datavisualization/engine/shaders/surfaceFlat.vert27
-rw-r--r--src/datavisualization/engine/shaders/surfaceGrid.frag6
-rw-r--r--src/datavisualization/engine/shaders/surfaceGrid.vert6
-rw-r--r--src/datavisualization/engine/shaders/surface_ES2.frag39
-rw-r--r--src/datavisualization/engine/shaders/texture.frag35
-rw-r--r--src/datavisualization/engine/shaders/texture.vert26
-rw-r--r--src/datavisualization/engine/shaders/texture_ES2.frag37
-rw-r--r--src/datavisualization/engine/surface3dcontroller.cpp233
-rw-r--r--src/datavisualization/engine/surface3dcontroller_p.h108
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp2185
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h185
-rw-r--r--src/datavisualization/engine/theme.cpp250
-rw-r--r--src/datavisualization/engine/theme_p.h82
-rw-r--r--src/datavisualization/global/datavisualizationglobal_p.h54
-rw-r--r--src/datavisualization/global/global.pri4
-rw-r--r--src/datavisualization/global/qdatavisualizationenums.h126
-rw-r--r--src/datavisualization/global/qdatavisualizationglobal.h67
-rw-r--r--src/datavisualization/global/qtdatavisualizationenums.qdoc176
-rw-r--r--src/datavisualization/input/input.pri12
-rw-r--r--src/datavisualization/input/q3dinputhandler.cpp190
-rw-r--r--src/datavisualization/input/q3dinputhandler.h48
-rw-r--r--src/datavisualization/input/q3dinputhandler_p.h51
-rw-r--r--src/datavisualization/input/qabstract3dinputhandler.cpp210
-rw-r--r--src/datavisualization/input/qabstract3dinputhandler.h82
-rw-r--r--src/datavisualization/input/qabstract3dinputhandler_p.h70
-rw-r--r--src/datavisualization/input/qtouch3dinputhandler.cpp209
-rw-r--r--src/datavisualization/input/qtouch3dinputhandler.h47
-rw-r--r--src/datavisualization/input/qtouch3dinputhandler_p.h50
-rw-r--r--src/datavisualization/utils/abstractobjecthelper.cpp81
-rw-r--r--src/datavisualization/utils/abstractobjecthelper_p.h65
-rw-r--r--src/datavisualization/utils/camerahelper.cpp286
-rw-r--r--src/datavisualization/utils/camerahelper_p.h90
-rw-r--r--src/datavisualization/utils/meshloader.cpp125
-rw-r--r--src/datavisualization/utils/meshloader_p.h51
-rw-r--r--src/datavisualization/utils/objecthelper.cpp101
-rw-r--r--src/datavisualization/utils/objecthelper_p.h54
-rw-r--r--src/datavisualization/utils/shaderhelper.cpp241
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h111
-rw-r--r--src/datavisualization/utils/surfaceobject.cpp346
-rw-r--r--src/datavisualization/utils/surfaceobject_p.h76
-rw-r--r--src/datavisualization/utils/texturehelper.cpp376
-rw-r--r--src/datavisualization/utils/texturehelper_p.h70
-rw-r--r--src/datavisualization/utils/utils.cpp263
-rw-r--r--src/datavisualization/utils/utils.pri19
-rw-r--r--src/datavisualization/utils/utils_p.h79
-rw-r--r--src/datavisualization/utils/vertexindexer.cpp153
-rw-r--r--src/datavisualization/utils/vertexindexer_p.h88
232 files changed, 36777 insertions, 0 deletions
diff --git a/src/datavisualization/axis/axis.pri b/src/datavisualization/axis/axis.pri
new file mode 100644
index 00000000..4e96618b
--- /dev/null
+++ b/src/datavisualization/axis/axis.pri
@@ -0,0 +1,12 @@
+HEADERS += \
+ $$PWD/q3dabstractaxis.h \
+ $$PWD/q3dabstractaxis_p.h \
+ $$PWD/q3dvalueaxis.h \
+ $$PWD/q3dvalueaxis_p.h \
+ $$PWD/q3dcategoryaxis.h \
+ $$PWD/q3dcategoryaxis_p.h
+
+SOURCES += \
+ $$PWD/q3dabstractaxis.cpp \
+ $$PWD/q3dvalueaxis.cpp \
+ $$PWD/q3dcategoryaxis.cpp
diff --git a/src/datavisualization/axis/q3dabstractaxis.cpp b/src/datavisualization/axis/q3dabstractaxis.cpp
new file mode 100644
index 00000000..07761d0c
--- /dev/null
+++ b/src/datavisualization/axis/q3dabstractaxis.cpp
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dabstractaxis.h"
+#include "q3dabstractaxis_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DAbstractAxis
+ * \inmodule QtDataVisualization
+ * \brief Q3DAbstractAxis is base class for axes of a graph.
+ * \since 1.0.0
+ *
+ * You should not need to use this class directly, but one of its subclasses instead.
+ *
+ * \sa Q3DCategoryAxis, Q3DValueAxis
+ */
+
+/*!
+ * \qmltype AbstractAxis3D
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates Q3DAbstractAxis
+ * \brief AbstractAxis3D is base type for axes of a graph.
+ *
+ * This type is uncreatable, but contains properties that are exposed via subtypes.
+ */
+
+/*!
+ * \qmlproperty string AbstractAxis3D::title
+ * Defines the title for the axis.
+ */
+
+/*!
+ * \qmlproperty list AbstractAxis3D::labels
+ * Defines the labels for the axis.
+ */
+
+/*!
+ * \qmlproperty AbstractAxis3D.AxisOrientation AbstractAxis3D::orientation
+ * Defines the orientation of the axis.
+ */
+
+/*!
+ * \qmlproperty AbstractAxis3D.AxisType AbstractAxis3D::type
+ * Defines the type of the axis.
+ */
+
+/*!
+ * \qmlproperty real AbstractAxis3D::min
+ *
+ * Defines the minimum value on the axis.
+ * When setting this property the max is adjusted if necessary, to ensure that the range remains
+ * valid.
+ */
+
+/*!
+ * \qmlproperty real AbstractAxis3D::max
+ *
+ * Defines the maximum value on the axis.
+ * When setting this property the min is adjusted if necessary, to ensure that the range remains
+ * valid.
+ */
+
+/*!
+ * \qmlproperty bool AbstractAxis3D::autoAdjustRange
+ *
+ * If set, the axis will automatically adjust the range so that all data fits in it.
+ */
+
+
+/*!
+ * \enum Q3DAbstractAxis::AxisOrientation
+ *
+ * The orientation of the axis object.
+ *
+ * \value AxisOrientationNone
+ * \value AxisOrientationX
+ * \value AxisOrientationY
+ * \value AxisOrientationZ
+ */
+
+/*!
+ * \enum Q3DAbstractAxis::AxisType
+ *
+ * The type of the axis object.
+ *
+ * \value AxisTypeNone
+ * \value AxisTypeCategory
+ * \value AxisTypeValue
+ */
+
+/*!
+ * \internal
+ */
+Q3DAbstractAxis::Q3DAbstractAxis(Q3DAbstractAxisPrivate *d, QObject *parent) :
+ QObject(parent),
+ d_ptr(d)
+{
+}
+
+/*!
+ * Destroys Q3DAbstractAxis.
+ */
+Q3DAbstractAxis::~Q3DAbstractAxis()
+{
+}
+
+/*!
+ * \property Q3DAbstractAxis::title
+ *
+ * Defines the title for the axis.
+ */
+QString Q3DAbstractAxis::title() const
+{
+ return d_ptr->m_title;
+}
+
+/*!
+ * \property Q3DAbstractAxis::labels
+ *
+ * Defines the labels for the axis.
+ */
+QStringList Q3DAbstractAxis::labels() const
+{
+ d_ptr->updateLabels();
+ return d_ptr->m_labels;
+}
+
+/*!
+ * \property Q3DAbstractAxis::orientation
+ *
+ * Defines the orientation of the axis, one of \c Q3DAbstractAxis::AxisOrientation.
+ */
+Q3DAbstractAxis::AxisOrientation Q3DAbstractAxis::orientation() const
+{
+ return d_ptr->m_orientation;
+}
+
+/*!
+ * \property Q3DAbstractAxis::type
+ *
+ * Defines the type of the axis, one of \c Q3DAbstractAxis::AxisType.
+ */
+Q3DAbstractAxis::AxisType Q3DAbstractAxis::type() const
+{
+ return d_ptr->m_type;
+}
+
+void Q3DAbstractAxis::setTitle(QString title)
+{
+ if (d_ptr->m_title != title) {
+ d_ptr->m_title = title;
+ emit titleChanged(title);
+ }
+}
+
+/*!
+ * Sets value range of the axis from \a min to \a max.
+ * When setting the range, the max is adjusted if necessary, to ensure that the range remains valid.
+ * \note For Q3DCategoryAxis this specifies the index range of rows or columns to show.
+ */
+void Q3DAbstractAxis::setRange(qreal min, qreal max)
+{
+ d_ptr->setRange(min, max);
+ setAutoAdjustRange(false);
+}
+
+/*!
+ * \property Q3DAbstractAxis::min
+ *
+ * Defines the minimum value on the axis.
+ * When setting this property the max is adjusted if necessary, to ensure that the range remains
+ * valid.
+ * \note For Q3DCategoryAxis this specifies the index of the first row or column to show.
+ */
+void Q3DAbstractAxis::setMin(qreal min)
+{
+ d_ptr->setMin(min);
+ setAutoAdjustRange(false);
+}
+
+/*!
+ * \property Q3DAbstractAxis::max
+ *
+ * Defines the maximum value on the axis.
+ * When setting this property the min is adjusted if necessary, to ensure that the range remains
+ * valid.
+ * \note For Q3DCategoryAxis this specifies the index of the last row or column to show.
+ */
+void Q3DAbstractAxis::setMax(qreal max)
+{
+ d_ptr->setMax(max);
+ setAutoAdjustRange(false);
+}
+
+qreal Q3DAbstractAxis::min() const
+{
+ return d_ptr->m_min;
+}
+
+qreal Q3DAbstractAxis::max() const
+{
+ return d_ptr->m_max;
+}
+
+/*!
+ * \property Q3DAbstractAxis::autoAdjustRange
+ *
+ * If set, the axis will automatically adjust the range so that all data fits in it.
+ *
+ * \sa setRange(), setMin(), setMax()
+ */
+void Q3DAbstractAxis::setAutoAdjustRange(bool autoAdjust)
+{
+ if (d_ptr->m_autoAdjust != autoAdjust) {
+ d_ptr->m_autoAdjust = autoAdjust;
+ emit autoAdjustRangeChanged(autoAdjust);
+ }
+}
+
+bool Q3DAbstractAxis::isAutoAdjustRange() const
+{
+ return d_ptr->m_autoAdjust;
+}
+
+// Q3DAbstractAxisPrivate
+
+Q3DAbstractAxisPrivate::Q3DAbstractAxisPrivate(Q3DAbstractAxis *q, Q3DAbstractAxis::AxisType type)
+ : QObject(0),
+ q_ptr(q),
+ m_orientation(Q3DAbstractAxis::AxisOrientationNone),
+ m_type(type),
+ m_isDefaultAxis(false),
+ m_min(0.0),
+ m_max(10.0),
+ m_autoAdjust(true),
+ m_onlyPositiveValues(false),
+ m_allowMinMaxSame(false)
+{
+}
+
+Q3DAbstractAxisPrivate::~Q3DAbstractAxisPrivate()
+{
+}
+
+void Q3DAbstractAxisPrivate::setOrientation(Q3DAbstractAxis::AxisOrientation orientation)
+{
+ if (m_orientation == Q3DAbstractAxis::AxisOrientationNone)
+ m_orientation = orientation;
+ else
+ Q_ASSERT("Attempted to reset axis orientation.");
+}
+
+void Q3DAbstractAxisPrivate::updateLabels()
+{
+ // Default implementation does nothing
+}
+
+void Q3DAbstractAxisPrivate::setRange(qreal min, qreal max)
+{
+ bool adjusted = false;
+ if (m_onlyPositiveValues) {
+ if (min < 0.0) {
+ min = 0.0;
+ adjusted = true;
+ }
+ if (max < 0.0) {
+ max = 0.0;
+ adjusted = true;
+ }
+ }
+ // If min >= max, we adjust ranges so that
+ // m_max becomes (min + 1.0)
+ // as axes need some kind of valid range.
+ bool dirty = false;
+ if (m_min != min) {
+ m_min = min;
+ dirty = true;
+ }
+ if (m_max != max || min > max || (!m_allowMinMaxSame && min == max)) {
+ if (min > max || (!m_allowMinMaxSame && min == max)) {
+ m_max = min + 1.0;
+ adjusted = true;
+ } else {
+ m_max = max;
+ }
+ dirty = true;
+ }
+
+ if (dirty) {
+ if (adjusted) {
+ qWarning() << "Warning: Tried to set invalid range for axis."
+ " Range automatically adjusted to a valid one:"
+ << min << "-" << max << "-->" << m_min << "-" << m_max;
+ }
+ emit q_ptr->rangeChanged(m_min, m_max);
+ }
+}
+
+void Q3DAbstractAxisPrivate::setMin(qreal min)
+{
+ if (m_onlyPositiveValues) {
+ if (min < 0.0) {
+ min = 0.0;
+ qWarning() << "Warning: Tried to set negative minimum for an axis that only supports"
+ " positive values:" << min;
+ }
+ }
+
+ if (m_min != min) {
+ if (min > m_max || (!m_allowMinMaxSame && min == m_max)) {
+ qreal oldMax = m_max;
+ m_max = min + 1.0;
+ qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for"
+ " value axis. Maximum automatically adjusted to a valid one:"
+ << oldMax << "-->" << m_max;
+ }
+ m_min = min;
+
+ emit q_ptr->rangeChanged(m_min, m_max);
+ }
+}
+
+void Q3DAbstractAxisPrivate::setMax(qreal max)
+{
+ if (m_onlyPositiveValues) {
+ if (max < 0.0) {
+ max = 0.0;
+ qWarning() << "Warning: Tried to set negative maximum for an axis that only supports"
+ " positive values:" << max;
+ }
+ }
+
+ if (m_max != max) {
+ if (m_min > max || (!m_allowMinMaxSame && m_min == max)) {
+ qreal oldMin = m_min;
+ m_min = max - 1.0;
+ if (m_onlyPositiveValues && m_min < 0.0) {
+ m_min = 0.0;
+ if (!m_allowMinMaxSame && max == 0.0) {
+ m_min = oldMin;
+ qWarning() << "Unable to set maximum value to zero.";
+ return;
+ }
+ }
+ qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for"
+ " value axis. Minimum automatically adjusted to a valid one:"
+ << oldMin << "-->" << m_min;
+ }
+ m_max = max;
+ emit q_ptr->rangeChanged(m_min, m_max);
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/axis/q3dabstractaxis.h b/src/datavisualization/axis/q3dabstractaxis.h
new file mode 100644
index 00000000..9e5c426a
--- /dev/null
+++ b/src/datavisualization/axis/q3dabstractaxis.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DABSTRACTAXIS_H
+#define Q3DABSTRACTAXIS_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QObject>
+#include <QScopedPointer>
+#include <QVector>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DAbstractAxisPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DAbstractAxis : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(AxisOrientation)
+ Q_ENUMS(AxisType)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
+ Q_PROPERTY(QStringList labels READ labels NOTIFY labelsChanged)
+ Q_PROPERTY(AxisOrientation orientation READ orientation)
+ Q_PROPERTY(AxisType type READ type)
+ Q_PROPERTY(qreal min READ min WRITE setMin NOTIFY rangeChanged)
+ Q_PROPERTY(qreal max READ max WRITE setMax NOTIFY rangeChanged)
+ Q_PROPERTY(bool autoAdjustRange READ isAutoAdjustRange WRITE setAutoAdjustRange NOTIFY autoAdjustRangeChanged)
+
+public:
+ enum AxisOrientation {
+ AxisOrientationNone = 0,
+ AxisOrientationX = 1,
+ AxisOrientationY = 2,
+ AxisOrientationZ = 4
+ };
+
+ enum AxisType {
+ AxisTypeNone = 0,
+ AxisTypeCategory = 1,
+ AxisTypeValue = 2
+ //AxisTypeLogValue = 6 // inherits valueaxis (4 + 2) // TODO
+ };
+
+protected:
+ explicit Q3DAbstractAxis(Q3DAbstractAxisPrivate *d, QObject *parent = 0);
+
+public:
+ virtual ~Q3DAbstractAxis();
+
+ QString title() const;
+ QStringList labels() const;
+
+ AxisOrientation orientation() const;
+ AxisType type() const;
+
+ qreal min() const;
+ qreal max() const;
+ bool isAutoAdjustRange() const;
+
+ void setTitle(QString title);
+ void setRange(qreal min, qreal max);
+ void setMin(qreal min);
+ void setMax(qreal max);
+ void setAutoAdjustRange(bool autoAdjust);
+
+signals:
+ void titleChanged(QString newTitle);
+ void labelsChanged();
+ void rangeChanged(qreal min, qreal max);
+ void autoAdjustRangeChanged(bool autoAdjust);
+
+protected:
+ QScopedPointer<Q3DAbstractAxisPrivate> d_ptr;
+
+private:
+ Q_DISABLE_COPY(Q3DAbstractAxis)
+
+ friend class Abstract3DController;
+ friend class Bars3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACTAXIS_H
diff --git a/src/datavisualization/axis/q3dabstractaxis_p.h b/src/datavisualization/axis/q3dabstractaxis_p.h
new file mode 100644
index 00000000..902f65be
--- /dev/null
+++ b/src/datavisualization/axis/q3dabstractaxis_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "datavisualizationglobal_p.h"
+#include "q3dabstractaxis.h"
+#include "abstract3dcontroller_p.h"
+
+#ifndef Q3DABSTRACTAXIS_P_H
+#define Q3DABSTRACTAXIS_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DAbstractAxisPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ Q3DAbstractAxisPrivate(Q3DAbstractAxis *q, Q3DAbstractAxis::AxisType type);
+ virtual ~Q3DAbstractAxisPrivate();
+
+ void setOrientation(Q3DAbstractAxis::AxisOrientation orientation);
+
+ inline bool isDefaultAxis() { return m_isDefaultAxis; }
+ inline void setDefaultAxis(bool isDefault) { m_isDefaultAxis = isDefault; }
+
+ virtual void setRange(qreal min, qreal max);
+ virtual void setMin(qreal min);
+ virtual void setMax (qreal max);
+
+protected:
+ virtual void updateLabels();
+
+ Q3DAbstractAxis *q_ptr;
+
+ QString m_title;
+ QStringList m_labels;
+ Q3DAbstractAxis::AxisOrientation m_orientation;
+ Q3DAbstractAxis::AxisType m_type;
+ bool m_isDefaultAxis;
+ qreal m_min;
+ qreal m_max;
+ bool m_autoAdjust;
+ bool m_onlyPositiveValues;
+ bool m_allowMinMaxSame;
+
+ friend class Q3DAbstractAxis;
+ friend class Q3DValueAxis;
+ friend class Q3DCategoryAxis;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACTAXIS_P_H
diff --git a/src/datavisualization/axis/q3dcategoryaxis.cpp b/src/datavisualization/axis/q3dcategoryaxis.cpp
new file mode 100644
index 00000000..05f52cdc
--- /dev/null
+++ b/src/datavisualization/axis/q3dcategoryaxis.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dcategoryaxis.h"
+#include "q3dcategoryaxis_p.h"
+#include "bars3dcontroller_p.h"
+#include "qbardataproxy.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DCategoryAxis
+ * \inmodule QtDataVisualization
+ * \brief The Q3DCategoryAxis class is used for manipulating an axis of a graph.
+ * \since 1.0.0
+ *
+ * Q3DCategoryAxis provides an axis that can be given labels. The axis is divided into equal-sized
+ * categories based on the data window size defined by setting the axis range.
+ *
+ * Grid lines are drawn between categories, if visible. Labels are drawn to positions of categories
+ * if provided.
+ */
+
+/*!
+ * \qmltype CategoryAxis3D
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates Q3DCategoryAxis
+ * \inherits AbstractAxis3D
+ * \brief The CategoryAxis3D type is used for manipulating an axis of a graph.
+ *
+ * This type provides an axis that can be given labels.
+ */
+
+/*!
+ * \qmlproperty list CategoryAxis3D::categoryLabels
+ * Defines labels for axis applied to categories. If there are fewer labels than categories, the
+ * remaining ones do not have a label. If category labels are not explicitly defined, labels are
+ * generated from the data row and column labels.
+ */
+
+/*!
+ * Constructs Q3DCategoryAxis with \a parent.
+ */
+Q3DCategoryAxis::Q3DCategoryAxis(QObject *parent) :
+ Q3DAbstractAxis(new Q3DCategoryAxisPrivate(this), parent)
+{
+}
+
+/*!
+ * Destroys Q3DCategoryAxis.
+ */
+Q3DCategoryAxis::~Q3DCategoryAxis()
+{
+}
+
+/*!
+ * \property Q3DCategoryAxis::categoryLabels
+ *
+ * Defines labels for axis applied to categories. If there are fewer labels than categories, the
+ * remaining ones do not have a label. If category labels are not explicitly defined, labels are
+ * generated from the data row and column labels.
+ *
+ * \note CategoryLabels actually reads/writes the Q3DAbstractAxis::labels property,
+ * which is read only there. Since subclass cannot have property with same name,
+ * this partially duplicate property is necessary.
+ */
+QStringList Q3DCategoryAxis::categoryLabels() const
+{
+ return labels();
+}
+
+void Q3DCategoryAxis::setCategoryLabels(const QStringList &labels)
+{
+ dptr()->m_labelsExplicitlySet = !labels.isEmpty();
+ bool labelsFromData = false;
+
+ // Get labels from data proxy if axis is attached to a bar controller and an active axis there
+ if (labels.isEmpty()) {
+ Bars3DController *controller = qobject_cast<Bars3DController *>(parent());
+ if (controller) {
+ if (controller->axisX() == this) {
+ controller->handleDataRowLabelsChanged();
+ labelsFromData = true;
+ } else if (controller->axisZ() == this) {
+ controller->handleDataColumnLabelsChanged();
+ labelsFromData = true;
+ }
+ }
+ }
+
+ if (!labelsFromData && d_ptr->m_labels != labels) {
+ d_ptr->m_labels = labels;
+ emit labelsChanged();
+ }
+}
+
+/*!
+ * \internal
+ */
+Q3DCategoryAxisPrivate *Q3DCategoryAxis::dptr()
+{
+ return static_cast<Q3DCategoryAxisPrivate *>(d_ptr.data());
+}
+
+Q3DCategoryAxisPrivate::Q3DCategoryAxisPrivate(Q3DCategoryAxis *q)
+ : Q3DAbstractAxisPrivate(q, Q3DAbstractAxis::AxisTypeCategory),
+ m_labelsExplicitlySet(false)
+{
+ m_onlyPositiveValues = true;
+ m_allowMinMaxSame = true;
+}
+
+Q3DCategoryAxisPrivate::~Q3DCategoryAxisPrivate()
+{
+}
+
+/*!
+ * \internal
+ * Controller uses this function to set labels from data proxy as category labels.
+ * If the labels have been explicitly set by user, data proxy labels are not used.
+ */
+void Q3DCategoryAxisPrivate::setDataLabels(const QStringList &labels)
+{
+ if (!m_labelsExplicitlySet && m_labels != labels) {
+ m_labels = labels;
+ emit qptr()->labelsChanged();
+ }
+}
+
+Q3DCategoryAxis *Q3DCategoryAxisPrivate::qptr()
+{
+ return static_cast<Q3DCategoryAxis *>(q_ptr);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/axis/q3dcategoryaxis.h b/src/datavisualization/axis/q3dcategoryaxis.h
new file mode 100644
index 00000000..ef545950
--- /dev/null
+++ b/src/datavisualization/axis/q3dcategoryaxis.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DCATEGORYAXIS_H
+#define Q3DCATEGORYAXIS_H
+
+#include <QtDataVisualization/q3dabstractaxis.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCategoryAxisPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DCategoryAxis : public Q3DAbstractAxis
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList categoryLabels READ categoryLabels WRITE setCategoryLabels)
+
+public:
+ explicit Q3DCategoryAxis(QObject *parent = 0);
+ virtual ~Q3DCategoryAxis();
+
+ QStringList categoryLabels() const;
+ void setCategoryLabels(const QStringList &labels);
+
+protected:
+ Q3DCategoryAxisPrivate *dptr();
+
+private:
+ Q_DISABLE_COPY(Q3DCategoryAxis)
+ friend class Bars3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QCATEGORYAXIS_H
diff --git a/src/datavisualization/axis/q3dcategoryaxis_p.h b/src/datavisualization/axis/q3dcategoryaxis_p.h
new file mode 100644
index 00000000..9b66e48a
--- /dev/null
+++ b/src/datavisualization/axis/q3dcategoryaxis_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "q3dcategoryaxis.h"
+#include "q3dabstractaxis_p.h"
+#include "qbardataitem.h"
+
+#ifndef QCATEGORYAXIS_P_H
+#define QCATEGORYAXIS_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCategoryAxisPrivate : public Q3DAbstractAxisPrivate
+{
+ Q_OBJECT
+
+public:
+ Q3DCategoryAxisPrivate(Q3DCategoryAxis *q);
+ virtual ~Q3DCategoryAxisPrivate();
+
+ void setDataLabels(const QStringList &labels);
+
+private:
+ Q3DCategoryAxis *qptr();
+
+ bool m_labelsExplicitlySet;
+ friend class Q3DCategoryAxis;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QCATEGORYAXIS_P_H
diff --git a/src/datavisualization/axis/q3dvalueaxis.cpp b/src/datavisualization/axis/q3dvalueaxis.cpp
new file mode 100644
index 00000000..5e38e4ca
--- /dev/null
+++ b/src/datavisualization/axis/q3dvalueaxis.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dvalueaxis.h"
+#include "q3dvalueaxis_p.h"
+#include "utils_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DValueAxis
+ * \inmodule QtDataVisualization
+ * \brief The Q3DValueAxis class is used for manipulating an axis of a graph.
+ * \since 1.0.0
+ *
+ * Q3DValueAxis provides an axis that can be given a range of values and segment and subsegment
+ * counts to divide the range into.
+ *
+ * Labels are drawn between each segment. Grid lines are drawn between each segment and each
+ * subsegment. \note If visible, there will always be at least two grid lines and labels indicating
+ * the minimum and the maximum values of the range, as there is always at least one segment.
+ */
+
+/*!
+ * \qmltype ValueAxis3D
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates Q3DValueAxis
+ * \inherits AbstractAxis3D
+ * \brief The ValueAxis3D type is used for manipulating an axis of a graph.
+ *
+ * This type provides an axis that can be given a range of values and segment and subsegment
+ * counts to divide the range into.
+ */
+
+
+/*!
+ * \qmlproperty int ValueAxis3D::segmentCount
+ *
+ * Defines the number of segments on the axis. This indicates how many labels are drawn. The number
+ * of grid lines to be drawn is calculated with formula: \c {segments * subsegments + 1}.
+ * The preset default is \c 5, and it can not be below \c 1.
+ */
+
+/*!
+ * \qmlproperty int ValueAxis3D::subSegmentCount
+ *
+ * Defines the number of subsegments inside each segment on the axis. Grid lines are drawn between
+ * each subsegment, in addition to each segment.
+ * The preset default is \c 1, and it can not be below \c 1.
+ */
+
+/*!
+ * \qmlproperty string ValueAxis3D::labelFormat
+ *
+ * Defines the label format to be used for the labels on this axis. Supported specifiers are:
+ * \c {d, i, o, x, X, f, F, e, E, g, G, c}. See QString::sprintf() for additional details.
+ */
+
+/*!
+ * Constructs Q3DValueAxis with the given \a parent.
+ */
+Q3DValueAxis::Q3DValueAxis(QObject *parent) :
+ Q3DAbstractAxis(new Q3DValueAxisPrivate(this), parent)
+{
+}
+
+/*!
+ * Destroys Q3DValueAxis.
+ */
+Q3DValueAxis::~Q3DValueAxis()
+{
+}
+
+
+/*!
+ * \property Q3DValueAxis::segmentCount
+ *
+ * Defines the number of segments on the axis. This indicates how many labels are drawn. The number
+ * of grid lines to be drawn is calculated with formula: \c {segments * subsegments + 1}.
+ * The preset default is \c 5, and it can not be below \c 1.
+ *
+ * \sa setSubSegmentCount()
+ */
+void Q3DValueAxis::setSegmentCount(int count)
+{
+ if (count <= 0) {
+ qWarning() << "Warning: Illegal segment count automatically adjusted to a legal one:"
+ << count << "-> 1";
+ count = 1;
+ }
+ if (dptr()->m_segmentCount != count){
+ dptr()->m_segmentCount = count;
+ dptr()->emitLabelsChanged();
+ emit segmentCountChanged(count);
+ }
+}
+
+int Q3DValueAxis::segmentCount() const
+{
+ return dptrc()->m_segmentCount;
+}
+
+/*!
+ * \property Q3DValueAxis::subSegmentCount
+ *
+ * Defines the number of subsegments inside each segment on the axis. Grid lines are drawn between
+ * each subsegment, in addition to each segment.
+ * The preset default is \c 1, and it can not be below \c 1.
+ *
+ * \sa setSegmentCount()
+ */
+void Q3DValueAxis::setSubSegmentCount(int count)
+{
+ if (count <= 0) {
+ qWarning() << "Warning: Illegal subsegment count automatically adjusted to a legal one:"
+ << count << "-> 1";
+ count = 1;
+ }
+ if (dptr()->m_subSegmentCount != count) {
+ dptr()->m_subSegmentCount = count;
+ emit subSegmentCountChanged(count);
+ }
+}
+
+int Q3DValueAxis::subSegmentCount() const
+{
+ return dptrc()->m_subSegmentCount;
+}
+
+/*!
+ * \property Q3DValueAxis::labelFormat
+ *
+ * Defines the label format to be used for the labels on this axis. Supported specifiers are:
+ * \c {d, i, o, x, X, f, F, e, E, g, G, c}. See QString::sprintf() for additional details.
+ *
+ * Usage example:
+ *
+ * \c {axis->setLabelFormat("%.2f mm");}
+ */
+void Q3DValueAxis::setLabelFormat(const QString &format)
+{
+ if (dptr()->m_labelFormat != format) {
+ dptr()->m_labelFormat = format;
+ dptr()->emitLabelsChanged();
+ emit labelFormatChanged(format);
+ }
+}
+
+QString Q3DValueAxis::labelFormat() const
+{
+ return dptrc()->m_labelFormat;
+}
+
+/*!
+ * \internal
+ */
+Q3DValueAxisPrivate *Q3DValueAxis::dptr()
+{
+ return static_cast<Q3DValueAxisPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const Q3DValueAxisPrivate *Q3DValueAxis::dptrc() const
+{
+ return static_cast<const Q3DValueAxisPrivate *>(d_ptr.data());
+}
+
+Q3DValueAxisPrivate::Q3DValueAxisPrivate(Q3DValueAxis *q)
+ : Q3DAbstractAxisPrivate(q, Q3DAbstractAxis::AxisTypeValue),
+ m_segmentCount(5),
+ m_subSegmentCount(1),
+ m_labelFormat(Utils::defaultLabelFormat()),
+ m_labelsDirty(true)
+{
+}
+
+Q3DValueAxisPrivate::~Q3DValueAxisPrivate()
+{
+}
+
+void Q3DValueAxisPrivate::setRange(qreal min, qreal max)
+{
+ bool dirty = (min != m_min || max != m_max);
+
+ Q3DAbstractAxisPrivate::setRange(min, max);
+
+ if (dirty)
+ emitLabelsChanged();
+}
+
+void Q3DValueAxisPrivate::setMin(qreal min)
+{
+ bool dirty = (min != m_min);
+
+ Q3DAbstractAxisPrivate::setMin(min);
+
+ if (dirty)
+ emitLabelsChanged();
+}
+
+void Q3DValueAxisPrivate::setMax(qreal max)
+{
+ bool dirty = (max != m_max);
+
+ Q3DAbstractAxisPrivate::setMax(max);
+
+ if (dirty)
+ emitLabelsChanged();
+}
+
+void Q3DValueAxisPrivate::emitLabelsChanged()
+{
+ m_labelsDirty = true;
+ emit q_ptr->labelsChanged();
+}
+
+void Q3DValueAxisPrivate::updateLabels()
+{
+ if (!m_labelsDirty)
+ return;
+
+ m_labelsDirty = false;
+
+ QStringList newLabels;
+ newLabels.reserve(m_segmentCount + 1);
+
+ // First label is at axis min, which is an extra segment
+ qreal segmentStep = (m_max - m_min) / m_segmentCount;
+
+ QString formatString(m_labelFormat);
+ Utils::ParamType paramType = Utils::findFormatParamType(formatString);
+ QByteArray formatArray = formatString.toUtf8();
+
+ for (int i = 0; i < m_segmentCount; i++) {
+ qreal value = m_min + (segmentStep * i);
+ newLabels.append(Utils::formatLabel(formatArray, paramType, value));
+ }
+
+ // Ensure max label doesn't suffer from any rounding errors
+ newLabels.append(Utils::formatLabel(formatArray, paramType, m_max));
+
+ if (m_labels != newLabels)
+ m_labels = newLabels;
+}
+
+Q3DValueAxis *Q3DValueAxisPrivate::qptr()
+{
+ return static_cast<Q3DValueAxis *>(q_ptr);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/axis/q3dvalueaxis.h b/src/datavisualization/axis/q3dvalueaxis.h
new file mode 100644
index 00000000..f1280e25
--- /dev/null
+++ b/src/datavisualization/axis/q3dvalueaxis.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QVALUEAXIS_H
+#define QVALUEAXIS_H
+
+#include <QtDataVisualization/q3dabstractaxis.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DValueAxisPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DValueAxis : public Q3DAbstractAxis
+{
+ Q_OBJECT
+ Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged)
+ Q_PROPERTY(int subSegmentCount READ subSegmentCount WRITE setSubSegmentCount NOTIFY subSegmentCountChanged)
+ Q_PROPERTY(QString labelFormat READ labelFormat WRITE setLabelFormat NOTIFY labelFormatChanged)
+
+public:
+ explicit Q3DValueAxis(QObject *parent = 0);
+ virtual ~Q3DValueAxis();
+
+ int segmentCount() const;
+ int subSegmentCount() const;
+ QString labelFormat() const;
+
+ void setSegmentCount(int count);
+ void setSubSegmentCount(int count);
+ void setLabelFormat(const QString &format);
+
+signals:
+ void segmentCountChanged(int count);
+ void subSegmentCountChanged(int count);
+ void labelFormatChanged(QString format);
+
+protected:
+ Q3DValueAxisPrivate *dptr();
+ const Q3DValueAxisPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(Q3DValueAxis)
+ friend class Bars3DController;
+ friend class Scatter3DController;
+ friend class Surface3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QVALUEAXIS_H
diff --git a/src/datavisualization/axis/q3dvalueaxis_p.h b/src/datavisualization/axis/q3dvalueaxis_p.h
new file mode 100644
index 00000000..5d0084e6
--- /dev/null
+++ b/src/datavisualization/axis/q3dvalueaxis_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "q3dvalueaxis.h"
+#include "q3dabstractaxis_p.h"
+
+#ifndef QVALUEAXIS_P_H
+#define QVALUEAXIS_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DValueAxisPrivate : public Q3DAbstractAxisPrivate
+{
+ Q_OBJECT
+
+public:
+ Q3DValueAxisPrivate(Q3DValueAxis *q);
+ virtual ~Q3DValueAxisPrivate();
+
+ virtual void setRange(qreal min, qreal max);
+ virtual void setMin(qreal min);
+ virtual void setMax (qreal max);
+
+protected:
+ void emitLabelsChanged();
+ virtual void updateLabels();
+
+ int m_segmentCount;
+ int m_subSegmentCount;
+ QString m_labelFormat;
+ bool m_labelsDirty;
+
+private:
+ Q3DValueAxis *qptr();
+
+ friend class Q3DValueAxis;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QVALUEAXIS_P_H
diff --git a/src/datavisualization/common.pri b/src/datavisualization/common.pri
new file mode 100644
index 00000000..5b03ab98
--- /dev/null
+++ b/src/datavisualization/common.pri
@@ -0,0 +1,9 @@
+# This qmake file is included by all Patternist projects and contains common Qt defines,
+# compiler warnings, and include paths.
+
+INCLUDEPATH += $$PWD/engine \
+ $$PWD/global \
+ $$PWD/utils \
+ $$PWD/axis \
+ $$PWD/data \
+ $$PWD/input
diff --git a/src/datavisualization/data/abstractitemmodelhandler.cpp b/src/datavisualization/data/abstractitemmodelhandler.cpp
new file mode 100644
index 00000000..0ad0ac0b
--- /dev/null
+++ b/src/datavisualization/data/abstractitemmodelhandler.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstractitemmodelhandler_p.h"
+#include "qabstractdatamapping.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+AbstractItemModelHandler::AbstractItemModelHandler(QObject *parent)
+ : QObject(parent),
+ m_activeMapping(0),
+ resolvePending(0)
+{
+ m_resolveTimer.setSingleShot(true);
+ QObject::connect(&m_resolveTimer, &QTimer::timeout,
+ this, &AbstractItemModelHandler::handlePendingResolve);
+}
+
+AbstractItemModelHandler::~AbstractItemModelHandler()
+{
+}
+
+void AbstractItemModelHandler::setItemModel(const QAbstractItemModel *itemModel)
+{
+ if (!m_itemModel.isNull())
+ QObject::disconnect(m_itemModel, 0, this, 0);
+
+ m_itemModel = itemModel;
+
+ if (!m_itemModel.isNull()) {
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::columnsInserted,
+ this, &AbstractItemModelHandler::handleColumnsInserted);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::columnsMoved,
+ this, &AbstractItemModelHandler::handleColumnsMoved);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::columnsRemoved,
+ this, &AbstractItemModelHandler::handleColumnsRemoved);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::dataChanged,
+ this, &AbstractItemModelHandler::handleDataChanged);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::layoutChanged,
+ this, &AbstractItemModelHandler::handleLayoutChanged);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::modelReset,
+ this, &AbstractItemModelHandler::handleModelReset);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::rowsInserted,
+ this, &AbstractItemModelHandler::handleRowsInserted);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::rowsMoved,
+ this, &AbstractItemModelHandler::handleRowsMoved);
+ QObject::connect(m_itemModel.data(), &QAbstractItemModel::rowsRemoved,
+ this, &AbstractItemModelHandler::handleRowsRemoved);
+ }
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+}
+
+const QAbstractItemModel *AbstractItemModelHandler::itemModel() const
+{
+ return m_itemModel.data();
+}
+
+void AbstractItemModelHandler::setActiveMapping(QAbstractDataMapping *mapping)
+{
+ if (m_activeMapping)
+ QObject::disconnect(m_activeMapping, 0, this, 0);
+
+ if (mapping)
+ addMapping(mapping);
+
+ m_activeMapping = mapping;
+
+ if (m_activeMapping) {
+ QObject::connect(m_activeMapping, &QAbstractDataMapping::mappingChanged,
+ this, &AbstractItemModelHandler::handleMappingChanged);
+ }
+
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+}
+
+QAbstractDataMapping *AbstractItemModelHandler::activeMapping() const
+{
+ return m_activeMapping;
+}
+
+void AbstractItemModelHandler::addMapping(QAbstractDataMapping *mapping)
+{
+ Q_ASSERT(mapping);
+ AbstractItemModelHandler *owner = qobject_cast<AbstractItemModelHandler *>(mapping->parent());
+ if (owner != this) {
+ Q_ASSERT_X(!owner, "addMapping", "Mapping already attached to a proxy.");
+ mapping->setParent(this);
+ }
+ if (!m_mappings.contains(mapping))
+ m_mappings.append(mapping);
+}
+
+void AbstractItemModelHandler::releaseMapping(QAbstractDataMapping *mapping)
+{
+ if (mapping && m_mappings.contains(mapping)) {
+ // If the mapping is in use, clear the existing mapping
+ if (m_activeMapping == mapping)
+ setActiveMapping(0);
+
+ m_mappings.removeAll(mapping);
+ mapping->setParent(0);
+ }
+}
+
+QList<QAbstractDataMapping *> AbstractItemModelHandler::mappings() const
+{
+ return m_mappings;
+}
+
+void AbstractItemModelHandler::handleColumnsInserted(const QModelIndex &parent,
+ int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+
+ // Resolve new items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleColumnsMoved(const QModelIndex &sourceParent,
+ int sourceStart,
+ int sourceEnd,
+ const QModelIndex &destinationParent,
+ int destinationColumn)
+{
+ Q_UNUSED(sourceParent)
+ Q_UNUSED(sourceStart)
+ Q_UNUSED(sourceEnd)
+ Q_UNUSED(destinationParent)
+ Q_UNUSED(destinationColumn)
+
+ // Resolve moved items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleColumnsRemoved(const QModelIndex &parent,
+ int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+
+ // Remove old items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector<int> &roles)
+{
+ Q_UNUSED(topLeft)
+ Q_UNUSED(bottomRight)
+ Q_UNUSED(roles)
+
+ // Resolve changed items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleLayoutChanged(const QList<QPersistentModelIndex> &parents,
+ QAbstractItemModel::LayoutChangeHint hint)
+{
+ Q_UNUSED(parents)
+ Q_UNUSED(hint)
+
+ // Resolve moved items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleModelReset()
+{
+ // Data cleared, reset array
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+
+ // Resolve new items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleRowsMoved(const QModelIndex &sourceParent,
+ int sourceStart,
+ int sourceEnd,
+ const QModelIndex &destinationParent,
+ int destinationRow)
+{
+ Q_UNUSED(sourceParent)
+ Q_UNUSED(sourceStart)
+ Q_UNUSED(sourceEnd)
+ Q_UNUSED(destinationParent)
+ Q_UNUSED(destinationRow)
+
+ // Resolve moved items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleRowsRemoved(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+
+ // Resolve removed items
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0); // TODO Resolving entire model is inefficient
+}
+
+void AbstractItemModelHandler::handleMappingChanged()
+{
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+}
+
+void AbstractItemModelHandler::handlePendingResolve()
+{
+ resolveModel();
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/abstractitemmodelhandler_p.h b/src/datavisualization/data/abstractitemmodelhandler_p.h
new file mode 100644
index 00000000..fbaaa1f9
--- /dev/null
+++ b/src/datavisualization/data/abstractitemmodelhandler_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 ABSTRACTITEMMODELHANDLER_P_H
+#define ABSTRACTITEMMODELHANDLER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QAbstractItemModel>
+#include <QPointer>
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstractDataMapping;
+
+class AbstractItemModelHandler : public QObject
+{
+ Q_OBJECT
+public:
+ AbstractItemModelHandler(QObject *parent = 0);
+ virtual ~AbstractItemModelHandler();
+
+ virtual void setItemModel(const QAbstractItemModel *itemModel);
+ virtual const QAbstractItemModel *itemModel() const;
+ virtual void setActiveMapping(QAbstractDataMapping *mapping);
+ virtual QAbstractDataMapping *activeMapping() const;
+ virtual void addMapping(QAbstractDataMapping *mapping);
+ virtual void releaseMapping(QAbstractDataMapping *mapping);
+ virtual QList<QAbstractDataMapping *> mappings() const;
+
+public slots:
+ virtual void handleColumnsInserted(const QModelIndex &parent, int start, int end);
+ virtual void handleColumnsMoved(const QModelIndex &sourceParent, int sourceStart,
+ int sourceEnd, const QModelIndex &destinationParent,
+ int destinationColumn);
+ virtual void handleColumnsRemoved(const QModelIndex &parent, int start, int end);
+ virtual void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles = QVector<int> ());
+ virtual void handleLayoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
+ QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
+ virtual void handleModelReset();
+ virtual void handleRowsInserted(const QModelIndex &parent, int start, int end);
+ virtual void handleRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destinationParent, int destinationRow);
+ virtual void handleRowsRemoved(const QModelIndex &parent, int start, int end);
+
+ virtual void handleMappingChanged();
+ virtual void handlePendingResolve();
+
+protected:
+ virtual void resolveModel() = 0;
+
+ QPointer<const QAbstractItemModel> m_itemModel; // Not owned
+ QAbstractDataMapping *m_activeMapping;
+ bool resolvePending;
+ QTimer m_resolveTimer;
+ QList<QAbstractDataMapping *> m_mappings;
+
+private:
+ Q_DISABLE_COPY(AbstractItemModelHandler)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/abstractrenderitem.cpp b/src/datavisualization/data/abstractrenderitem.cpp
new file mode 100644
index 00000000..22a1c6de
--- /dev/null
+++ b/src/datavisualization/data/abstractrenderitem.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstractrenderitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+AbstractRenderItem::AbstractRenderItem()
+ : m_selectionLabelItem(0)
+{
+}
+
+AbstractRenderItem::AbstractRenderItem(const AbstractRenderItem &other)
+{
+ m_selectionLabel = other.m_selectionLabel;
+ m_translation = other.m_translation;
+ m_selectionLabelItem = 0;
+}
+
+AbstractRenderItem::~AbstractRenderItem()
+{
+ delete m_selectionLabelItem;
+}
+
+LabelItem &AbstractRenderItem::selectionLabelItem()
+{
+ if (!m_selectionLabelItem)
+ m_selectionLabelItem = new LabelItem;
+ return *m_selectionLabelItem;
+}
+
+void AbstractRenderItem::setSelectionLabel(const QString &label)
+{
+ if (m_selectionLabelItem)
+ m_selectionLabelItem->clear();
+ m_selectionLabel = label;
+}
+
+QString &AbstractRenderItem::selectionLabel()
+{
+ return m_selectionLabel;
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/abstractrenderitem_p.h b/src/datavisualization/data/abstractrenderitem_p.h
new file mode 100644
index 00000000..5f623c41
--- /dev/null
+++ b/src/datavisualization/data/abstractrenderitem_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 ABSTRACTRENDERITEM_P_H
+#define ABSTRACTRENDERITEM_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "labelitem_p.h"
+
+#include <QOpenGLFunctions>
+#include <QString>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class AbstractRenderItem
+{
+public:
+ AbstractRenderItem();
+ AbstractRenderItem(const AbstractRenderItem &other);
+ virtual ~AbstractRenderItem();
+
+ // Position in 3D scene
+ inline void setTranslation(const QVector3D &translation) { m_translation = translation; }
+ inline const QVector3D &translation() const {return m_translation; }
+
+ // Selection label item (containing special selection texture, if mode is activated)
+ LabelItem &selectionLabelItem();
+
+ // Formatted selection label for item.
+ void setSelectionLabel(const QString &label);
+ QString &selectionLabel(); // Formats selection label if not previously formatted
+
+protected:
+ QString m_selectionLabel;
+ QVector3D m_translation;
+ LabelItem *m_selectionLabelItem;
+
+ friend class QAbstractDataItem;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/baritemmodelhandler.cpp b/src/datavisualization/data/baritemmodelhandler.cpp
new file mode 100644
index 00000000..f7611668
--- /dev/null
+++ b/src/datavisualization/data/baritemmodelhandler.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "baritemmodelhandler_p.h"
+#include "qitemmodelbardatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+BarItemModelHandler::BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject *parent)
+ : AbstractItemModelHandler(parent),
+ m_proxy(proxy),
+ m_proxyArray(0),
+ m_columnCount(0)
+{
+}
+
+BarItemModelHandler::~BarItemModelHandler()
+{
+}
+
+// Resolve entire item model into QBarDataArray.
+void BarItemModelHandler::resolveModel()
+{
+ QItemModelBarDataMapping *mapping = static_cast<QItemModelBarDataMapping *>(m_activeMapping);
+ if (m_itemModel.isNull() || !mapping) {
+ m_proxy->resetArray(0);
+ return;
+ }
+
+ if (!mapping->useModelCategories()
+ && (mapping->rowRole().isEmpty() || mapping->columnRole().isEmpty())) {
+ m_proxy->resetArray(0);
+ return;
+ }
+
+ QStringList rowLabels;
+ QStringList columnLabels;
+
+ QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
+
+ // Default to display role if no mapping
+ int valueRole = roleHash.key(mapping->valueRole().toLatin1(), Qt::DisplayRole);
+ int rowCount = m_itemModel->rowCount();
+ int columnCount = m_itemModel->columnCount();
+
+ if (mapping->useModelCategories()) {
+ // If dimensions have changed, recreate the array
+ if (m_proxyArray != m_proxy->array() || columnCount != m_columnCount
+ || rowCount != m_proxyArray->size()) {
+ m_proxyArray = new QBarDataArray;
+ m_proxyArray->reserve(rowCount);
+ for (int i = 0; i < rowCount; i++)
+ m_proxyArray->append(new QBarDataRow(columnCount));
+ }
+ for (int i = 0; i < rowCount; i++) {
+ QBarDataRow &newProxyRow = *m_proxyArray->at(i);
+ for (int j = 0; j < columnCount; j++)
+ newProxyRow[j].setValue(m_itemModel->index(i, j).data(valueRole).toReal());
+ }
+ // Generate labels from headers if using model rows/columns
+ for (int i = 0; i < rowCount; i++)
+ rowLabels << m_itemModel->headerData(i, Qt::Vertical).toString();
+ for (int i = 0; i < columnCount; i++)
+ columnLabels << m_itemModel->headerData(i, Qt::Horizontal).toString();
+ m_columnCount = columnCount;
+ } else {
+ int rowRole = roleHash.key(mapping->rowRole().toLatin1());
+ int columnRole = roleHash.key(mapping->columnRole().toLatin1());
+
+ bool generateRows = mapping->autoRowCategories();
+ bool generateColumns = mapping->autoColumnCategories();
+ QStringList rowList;
+ QStringList columnList;
+ // For detecting duplicates in categories generation, using QHashes should be faster than
+ // simple QStringList::contains() check.
+ QHash<QString, bool> rowListHash;
+ QHash<QString, bool> columnListHash;
+
+ // Sort values into rows and columns
+ typedef QHash<QString, qreal> ColumnValueMap;
+ QHash <QString, ColumnValueMap> itemValueMap;
+ for (int i = 0; i < rowCount; i++) {
+ for (int j = 0; j < columnCount; j++) {
+ QModelIndex index = m_itemModel->index(i, j);
+ QString rowRoleStr = index.data(rowRole).toString();
+ QString columnRoleStr = index.data(columnRole).toString();
+ itemValueMap[rowRoleStr][columnRoleStr] = index.data(valueRole).toReal();
+ if (generateRows && !rowListHash.value(rowRoleStr, false)) {
+ rowListHash.insert(rowRoleStr, true);
+ rowList << rowRoleStr;
+ }
+ if (generateColumns && !columnListHash.value(columnRoleStr, false)) {
+ columnListHash.insert(columnRoleStr, true);
+ columnList << columnRoleStr;
+ }
+ }
+ }
+
+ if (generateRows)
+ mapping->dptr()->m_rowCategories = rowList;
+ else
+ rowList = mapping->rowCategories();
+
+ if (generateColumns)
+ mapping->dptr()->m_columnCategories = columnList;
+ else
+ columnList = mapping->columnCategories();
+
+ // If dimensions have changed, recreate the array
+ if (m_proxyArray != m_proxy->array() || columnList.size() != m_columnCount
+ || rowList.size() != m_proxyArray->size()) {
+ m_proxyArray = new QBarDataArray;
+ m_proxyArray->reserve(rowList.size());
+ for (int i = 0; i < rowList.size(); i++)
+ m_proxyArray->append(new QBarDataRow(columnList.size()));
+ }
+ // Create new data array from itemValueMap
+ for (int i = 0; i < rowList.size(); i++) {
+ QString rowKey = rowList.at(i);
+ QBarDataRow &newProxyRow = *m_proxyArray->at(i);
+ for (int j = 0; j < columnList.size(); j++)
+ newProxyRow[j].setValue(itemValueMap[rowKey][columnList.at(j)]);
+ }
+
+ rowLabels = rowList;
+ columnLabels = columnList;
+ m_columnCount = columnList.size();
+ }
+
+ m_proxy->resetArray(m_proxyArray, rowLabels, columnLabels);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/baritemmodelhandler_p.h b/src/datavisualization/data/baritemmodelhandler_p.h
new file mode 100644
index 00000000..54b45f2e
--- /dev/null
+++ b/src/datavisualization/data/baritemmodelhandler_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 BARITEMMODELHANDLER_P_H
+#define BARITEMMODELHANDLER_P_H
+
+#include "abstractitemmodelhandler_p.h"
+#include "qitemmodelbardataproxy.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class BarItemModelHandler : public AbstractItemModelHandler
+{
+ Q_OBJECT
+public:
+ BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject *parent = 0);
+ virtual ~BarItemModelHandler();
+
+protected:
+ void virtual resolveModel();
+
+ QItemModelBarDataProxy *m_proxy; // Not owned
+ QBarDataArray *m_proxyArray; // Not owned
+ int m_columnCount;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/barrenderitem.cpp b/src/datavisualization/data/barrenderitem.cpp
new file mode 100644
index 00000000..558e2f96
--- /dev/null
+++ b/src/datavisualization/data/barrenderitem.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "barrenderitem_p.h"
+#include "bars3drenderer_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+BarRenderItem::BarRenderItem()
+ : AbstractRenderItem(),
+ m_value(0),
+ m_height(0.0f),
+ m_sliceLabelItem(0)
+{
+}
+
+BarRenderItem::BarRenderItem(const BarRenderItem &other)
+ : AbstractRenderItem(other)
+{
+ m_value = other.m_value;
+ m_position = other.m_position;
+ m_height = other.m_height;
+ m_sliceLabel = other.m_sliceLabel;
+ m_sliceLabelItem = 0;
+}
+
+BarRenderItem::~BarRenderItem()
+{
+ delete m_sliceLabelItem;
+}
+
+LabelItem &BarRenderItem::sliceLabelItem()
+{
+ if (!m_sliceLabelItem)
+ m_sliceLabelItem = new LabelItem;
+ return *m_sliceLabelItem;
+}
+
+void BarRenderItem::setSliceLabel(const QString &label)
+{
+ if (m_sliceLabelItem)
+ m_sliceLabelItem->clear();
+ m_sliceLabel = label;
+}
+
+QString &BarRenderItem::sliceLabel()
+{
+ return m_sliceLabel;
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/barrenderitem_p.h b/src/datavisualization/data/barrenderitem_p.h
new file mode 100644
index 00000000..6cd2b0fa
--- /dev/null
+++ b/src/datavisualization/data/barrenderitem_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 BARRENDERITEM_P_H
+#define BARRENDERITEM_P_H
+
+#include "abstractrenderitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Bars3DRenderer;
+
+class BarRenderItem : public AbstractRenderItem
+{
+public:
+ BarRenderItem();
+ BarRenderItem(const BarRenderItem &other);
+ virtual ~BarRenderItem();
+
+ // Position relative to data window (for bar label generation)
+ inline void setPosition(const QPoint &pos) { m_position = pos; }
+ inline const QPoint &position() const { return m_position; }
+
+ // Actual cached data value of the bar (needed to trigger label reformats)
+ inline void setValue(qreal value);
+ inline qreal value() const { return m_value; }
+
+ // Normalized bar height
+ inline void setHeight(GLfloat height) { m_height = height; }
+ inline GLfloat height() const { return m_height; }
+
+ // Label item for formatted label
+ LabelItem &sliceLabelItem();
+
+ // Formatted label for item.
+ void setSliceLabel(const QString &label);
+ QString &sliceLabel(); // Formats label if not previously formatted
+
+protected:
+ qreal m_value;
+ QPoint m_position; // x = row, y = column
+ GLfloat m_height;
+ QString m_sliceLabel;
+ LabelItem *m_sliceLabelItem;
+
+ friend class QBarDataItem;
+};
+
+void BarRenderItem::setValue(qreal value)
+{
+ m_value = value;
+ // Force reformatting on next access by setting label string to null string
+ if (!m_sliceLabel.isNull())
+ setSliceLabel(QString());
+ if (!m_selectionLabel.isNull())
+ setSelectionLabel(QString());
+}
+
+typedef QVector<BarRenderItem> BarRenderItemRow;
+typedef QVector<BarRenderItemRow> BarRenderItemArray;
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri
new file mode 100644
index 00000000..770d2bd1
--- /dev/null
+++ b/src/datavisualization/data/data.pri
@@ -0,0 +1,64 @@
+HEADERS += \
+ $$PWD/labelitem_p.h \
+ $$PWD/qabstractdataproxy.h \
+ $$PWD/qabstractdataproxy_p.h \
+ $$PWD/qbardataproxy.h \
+ $$PWD/qbardataproxy_p.h \
+ $$PWD/abstractrenderitem_p.h \
+ $$PWD/barrenderitem_p.h \
+ $$PWD/qbardataitem.h \
+ $$PWD/qbardataitem_p.h \
+ $$PWD/qitemmodelbardatamapping.h \
+ $$PWD/qitemmodelbardatamapping_p.h \
+ $$PWD/qitemmodelbardataproxy_p.h \
+ $$PWD/qitemmodelbardataproxy.h \
+ $$PWD/scatterrenderitem_p.h \
+ $$PWD/qscatterdataitem.h \
+ $$PWD/qscatterdataitem_p.h \
+ $$PWD/qscatterdataproxy.h \
+ $$PWD/qscatterdataproxy_p.h \
+ $$PWD/qitemmodelscatterdatamapping.h \
+ $$PWD/qitemmodelscatterdatamapping_p.h \
+ $$PWD/qitemmodelscatterdataproxy.h \
+ $$PWD/qitemmodelscatterdataproxy_p.h \
+ $$PWD/abstractitemmodelhandler_p.h \
+ $$PWD/baritemmodelhandler_p.h \
+ $$PWD/qabstractdatamapping.h \
+ $$PWD/qabstractdatamapping_p.h \
+ $$PWD/scatteritemmodelhandler_p.h \
+ $$PWD/qsurfacedataproxy.h \
+ $$PWD/qsurfacedataproxy_p.h \
+ $$PWD/qheightmapsurfacedataproxy.h \
+ $$PWD/qheightmapsurfacedataproxy_p.h \
+ $$PWD/qitemmodelsurfacedatamapping.h \
+ $$PWD/qitemmodelsurfacedatamapping_p.h \
+ $$PWD/qitemmodelsurfacedataproxy.h \
+ $$PWD/qitemmodelsurfacedataproxy_p.h \
+ $$PWD/surfaceitemmodelhandler_p.h \
+ $$PWD/qsurfacedataitem.h \
+ $$PWD/qsurfacedataitem_p.h
+
+SOURCES += \
+ $$PWD/labelitem.cpp \
+ $$PWD/qabstractdataproxy.cpp \
+ $$PWD/qbardataproxy.cpp \
+ $$PWD/abstractrenderitem.cpp \
+ $$PWD/barrenderitem.cpp \
+ $$PWD/qbardataitem.cpp \
+ $$PWD/qitemmodelbardatamapping.cpp \
+ $$PWD/qitemmodelbardataproxy.cpp \
+ $$PWD/scatterrenderitem.cpp \
+ $$PWD/qscatterdataitem.cpp \
+ $$PWD/qscatterdataproxy.cpp \
+ $$PWD/qitemmodelscatterdatamapping.cpp \
+ $$PWD/qitemmodelscatterdataproxy.cpp \
+ $$PWD/abstractitemmodelhandler.cpp \
+ $$PWD/baritemmodelhandler.cpp \
+ $$PWD/qabstractdatamapping.cpp \
+ $$PWD/scatteritemmodelhandler.cpp \
+ $$PWD/qsurfacedataproxy.cpp \
+ $$PWD/qheightmapsurfacedataproxy.cpp \
+ $$PWD/qitemmodelsurfacedatamapping.cpp \
+ $$PWD/qitemmodelsurfacedataproxy.cpp \
+ $$PWD/surfaceitemmodelhandler.cpp \
+ $$PWD/qsurfacedataitem.cpp
diff --git a/src/datavisualization/data/labelitem.cpp b/src/datavisualization/data/labelitem.cpp
new file mode 100644
index 00000000..5e27a50e
--- /dev/null
+++ b/src/datavisualization/data/labelitem.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "labelitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+LabelItem::LabelItem()
+ : m_size(QSize(0, 0)),
+ m_textureId(0)
+{
+}
+
+LabelItem::~LabelItem()
+{
+ glDeleteTextures(1, &m_textureId);
+}
+
+void LabelItem::setSize(const QSize &size)
+{
+ m_size = size;
+}
+
+QSize LabelItem::size() const
+{
+ return m_size;
+}
+
+void LabelItem::setTextureId(GLuint textureId)
+{
+ glDeleteTextures(1, &m_textureId);
+ m_textureId = textureId;
+}
+
+GLuint LabelItem::textureId() const
+{
+ return m_textureId;
+}
+
+void LabelItem::clear()
+{
+ if (m_textureId) {
+ glDeleteTextures(1, &m_textureId);
+ m_textureId = 0;
+ }
+ m_size = QSize(0, 0);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/labelitem_p.h b/src/datavisualization/data/labelitem_p.h
new file mode 100644
index 00000000..c10c1f12
--- /dev/null
+++ b/src/datavisualization/data/labelitem_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 LABELITEM_P_H
+#define LABELITEM_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+#include <QSize>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class LabelItem
+{
+public:
+ explicit LabelItem();
+ ~LabelItem();
+
+ void setSize(const QSize &size);
+ QSize size() const;
+ void setTextureId(GLuint textureId);
+ GLuint textureId() const;
+ void clear();
+
+private:
+ Q_DISABLE_COPY(LabelItem);
+
+ QSize m_size;
+ GLuint m_textureId;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qabstractdatamapping.cpp b/src/datavisualization/data/qabstractdatamapping.cpp
new file mode 100644
index 00000000..892d2f94
--- /dev/null
+++ b/src/datavisualization/data/qabstractdatamapping.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qabstractdatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QAbstractDataMapping
+ * \inmodule QtDataVisualization
+ * \brief Abstract base class for QtDataVisualization data mapping classes.
+ * \since 1.0.0
+ *
+ * Data mapping classes provide a way to map data from an external data source to one of
+ * QtDataVisualization data proxies.
+ * \sa QItemModelBarDataMapping, QItemModelScatterDataMapping
+ */
+
+/*!
+ * \internal
+ */
+QAbstractDataMapping::QAbstractDataMapping(QAbstractDataMappingPrivate *d, QObject *parent)
+ : QObject(parent),
+ d_ptr(d)
+{
+}
+
+/*!
+ * Destroys QAbstractDataMapping.
+ */
+QAbstractDataMapping::~QAbstractDataMapping()
+{
+}
+
+/*!
+ * \fn void QAbstractDataMapping::mappingChanged()
+ *
+ * Emitted when any mapping has changed.
+ */
+
+// QItemModelBarDataMappingPrivate
+
+QAbstractDataMappingPrivate::QAbstractDataMappingPrivate(QAbstractDataMapping *q,
+ QAbstractDataProxy::DataType type)
+ : QObject(0),
+ q_ptr(q),
+ m_type(type)
+{
+}
+
+QAbstractDataMappingPrivate::~QAbstractDataMappingPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
diff --git a/src/datavisualization/data/qabstractdatamapping.h b/src/datavisualization/data/qabstractdatamapping.h
new file mode 100644
index 00000000..eb892cb7
--- /dev/null
+++ b/src/datavisualization/data/qabstractdatamapping.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QABSTRACTDATAMAPPING_H
+#define QABSTRACTDATAMAPPING_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/qabstractdataproxy.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstractDataMappingPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QAbstractDataMapping : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAbstractDataMapping(QAbstractDataMappingPrivate *d, QObject *parent = 0);
+ virtual ~QAbstractDataMapping();
+
+signals:
+ void mappingChanged();
+
+private:
+ QScopedPointer<QAbstractDataMappingPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QAbstractDataMapping)
+
+ friend class QItemModelBarDataMapping;
+ friend class QItemModelScatterDataMapping;
+ friend class QItemModelSurfaceDataMapping;
+};
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qabstractdatamapping_p.h b/src/datavisualization/data/qabstractdatamapping_p.h
new file mode 100644
index 00000000..39012237
--- /dev/null
+++ b/src/datavisualization/data/qabstractdatamapping_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "qabstractdatamapping.h"
+
+#ifndef QABSTRACTDATAMAPPING_P_H
+#define QABSTRACTDATAMAPPING_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstractDataMappingPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QAbstractDataMappingPrivate(QAbstractDataMapping *q, QAbstractDataProxy::DataType type);
+ virtual ~QAbstractDataMappingPrivate();
+
+private:
+ QAbstractDataMapping *q_ptr;
+ QAbstractDataProxy::DataType m_type;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qabstractdataproxy.cpp b/src/datavisualization/data/qabstractdataproxy.cpp
new file mode 100644
index 00000000..8ccb0d7a
--- /dev/null
+++ b/src/datavisualization/data/qabstractdataproxy.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qabstractdataproxy.h"
+#include "qabstractdataproxy_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QAbstractDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Base class for all QtDataVisualization data proxies.
+ * \since 1.0.0
+ *
+ * You use the visualization type specific inherited classes instead of the base class.
+ * \sa QBarDataProxy, QScatterDataProxy, QSurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype AbstractDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QAbstractDataProxy
+ * \brief Base type for all QtDataVisualization data proxies.
+ *
+ * This type is uncreatable, but contains properties that are exposed via subtypes.
+ * \sa BarDataProxy, ScatterDataProxy, SurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty AbstractDataProxy.DataType AbstractDataProxy::type
+ * The type of the proxy.
+ */
+
+/*!
+ * \qmlproperty string AbstractDataProxy::itemLabelFormat
+ *
+ * Label format for data items in this proxy. This format is used for single item labels,
+ * e.g. when an item is selected. How the format is interpreted depends on proxy type. See
+ * each proxy class documentation for more information.
+ */
+
+/*!
+ * \enum QAbstractDataProxy::DataType
+ *
+ * Data type of the proxy.
+ *
+ * \value DataTypeNone
+ * No data type.
+ * \value DataTypeBar
+ * Data type for Q3DBars.
+ * \value DataTypeScatter
+ * Data type for Q3DScatter.
+ * \value DataTypeSurface
+ * Data type for Q3DSurface.
+ */
+
+/*!
+ * \internal
+ */
+QAbstractDataProxy::QAbstractDataProxy(QAbstractDataProxyPrivate *d, QObject *parent) :
+ QObject(parent),
+ d_ptr(d)
+{
+}
+
+/*!
+ * Destroys QAbstractDataProxy.
+ */
+QAbstractDataProxy::~QAbstractDataProxy()
+{
+}
+
+/*!
+ * \property QAbstractDataProxy::type
+ *
+ * The type of the proxy.
+ */
+QAbstractDataProxy::DataType QAbstractDataProxy::type() const
+{
+ return d_ptr->m_type;
+}
+
+/*!
+ * \property QAbstractDataProxy::itemLabelFormat
+ *
+ * Sets label \a format for data items in this proxy. This format is used for single item labels,
+ * e.g. when an item is selected. How the format is interpreted depends on proxy type. See
+ * each proxy class documentation for more information.
+ *
+ * \sa QBarDataProxy, QScatterDataProxy, QSurfaceDataProxy
+ */
+void QAbstractDataProxy::setItemLabelFormat(const QString &format)
+{
+ d_ptr->setItemLabelFormat(format);
+ emit itemLabelFormatChanged();
+}
+
+/*!
+ * \return label format for data items in this proxy.
+ */
+QString QAbstractDataProxy::itemLabelFormat() const
+{
+ return d_ptr->m_itemLabelFormat;
+}
+
+/*!
+ * \fn void QAbstractDataProxy::itemLabelFormatChanged()
+ *
+ * Emitted when label format changes.
+ */
+
+// QAbstractDataProxyPrivate
+
+QAbstractDataProxyPrivate::QAbstractDataProxyPrivate(QAbstractDataProxy *q, QAbstractDataProxy::DataType type)
+ : QObject(0),
+ q_ptr(q),
+ m_type(type),
+ m_isDefaultProxy(false)
+{
+}
+
+QAbstractDataProxyPrivate::~QAbstractDataProxyPrivate()
+{
+}
+
+void QAbstractDataProxyPrivate::setItemLabelFormat(const QString &format)
+{
+ m_itemLabelFormat = format;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qabstractdataproxy.h b/src/datavisualization/data/qabstractdataproxy.h
new file mode 100644
index 00000000..db0e0863
--- /dev/null
+++ b/src/datavisualization/data/qabstractdataproxy.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QABSTRACTDATAPROXY_H
+#define QABSTRACTDATAPROXY_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QObject>
+#include <QScopedPointer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstractDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QAbstractDataProxy : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(DataType)
+ Q_PROPERTY(DataType type READ type)
+ Q_PROPERTY(QString itemLabelFormat READ itemLabelFormat WRITE setItemLabelFormat NOTIFY itemLabelFormatChanged)
+
+public:
+ enum DataType {
+ DataTypeNone = 0,
+ DataTypeBar = 1,
+ DataTypeScatter = 2,
+ DataTypeSurface = 4
+ };
+
+protected:
+ explicit QAbstractDataProxy(QAbstractDataProxyPrivate *d, QObject *parent = 0);
+
+public:
+ virtual ~QAbstractDataProxy();
+
+ DataType type() const;
+
+ void setItemLabelFormat(const QString &format);
+ QString itemLabelFormat() const;
+
+signals:
+ void itemLabelFormatChanged();
+
+protected:
+ QScopedPointer<QAbstractDataProxyPrivate> d_ptr;
+
+private:
+ Q_DISABLE_COPY(QAbstractDataProxy)
+
+ friend class Abstract3DController;
+ friend class Bars3DController;
+ friend class Scatter3DController;
+ friend class Surface3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACTDATAPROXY_H
diff --git a/src/datavisualization/data/qabstractdataproxy_p.h b/src/datavisualization/data/qabstractdataproxy_p.h
new file mode 100644
index 00000000..4aa1b678
--- /dev/null
+++ b/src/datavisualization/data/qabstractdataproxy_p.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "datavisualizationglobal_p.h"
+#include "qabstractdataproxy.h"
+#include <QString>
+
+#ifndef QABSTRACTDATAPROXY_P_H
+#define QABSTRACTDATAPROXY_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstractDataProxyPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QAbstractDataProxyPrivate(QAbstractDataProxy *q, QAbstractDataProxy::DataType type);
+ virtual ~QAbstractDataProxyPrivate();
+
+ void setItemLabelFormat(const QString &format);
+
+ inline bool isDefaultProxy() { return m_isDefaultProxy; }
+ inline void setDefaultProxy(bool isDefault) { m_isDefaultProxy = isDefault; }
+
+protected:
+ QAbstractDataProxy *q_ptr;
+ QAbstractDataProxy::DataType m_type;
+ QString m_itemLabelFormat;
+ bool m_isDefaultProxy;
+
+private:
+ friend class QAbstractDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACTDATAPROXY_P_H
diff --git a/src/datavisualization/data/qbardataitem.cpp b/src/datavisualization/data/qbardataitem.cpp
new file mode 100644
index 00000000..2803c01a
--- /dev/null
+++ b/src/datavisualization/data/qbardataitem.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qbardataitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QBarDataItem
+ * \inmodule QtDataVisualization
+ * \brief The QBarDataItem class provides a container for resolved data to be added to bar graphs.
+ * \since 1.0.0
+ *
+ * A QBarDataItem holds data for a single rendered bar in a graph.
+ * Bar data proxies parse data into QBarDataItem instances for visualizing.
+ *
+ * \sa QBarDataProxy, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs QBarDataItem.
+ */
+QBarDataItem::QBarDataItem()
+ : d_ptr(0), // private data doesn't exist by default (optimization)
+ m_value(0.0)
+{
+}
+
+/*!
+ * Constructs QBarDataItem with \a value.
+ */
+QBarDataItem::QBarDataItem(qreal value)
+ : d_ptr(0),
+ m_value(value)
+{
+}
+
+/*!
+ * Constructs a copy of \a other.
+ */
+QBarDataItem::QBarDataItem(const QBarDataItem &other)
+{
+ operator=(other);
+}
+
+/*!
+ * Destroys QBarDataItem.
+ */
+QBarDataItem::~QBarDataItem()
+{
+ delete d_ptr;
+}
+
+/*!
+ * Assigns a copy of \a other to this object.
+ */
+QBarDataItem &QBarDataItem::operator=(const QBarDataItem &other)
+{
+ m_value = other.m_value;
+ if (other.d_ptr)
+ createExtraData();
+ else
+ d_ptr = 0;
+ // TODO set extra data
+ return *this;
+}
+
+/*!
+ * \fn void QBarDataItem::setValue(qreal value)
+ * Sets \a value to this data item.
+ */
+
+/*!
+ * \fn qreal QBarDataItem::value() const
+ * \return value of this data item.
+ */
+
+/*!
+ * \internal
+ */
+void QBarDataItem::createExtraData()
+{
+ if (!d_ptr)
+ d_ptr = new QBarDataItemPrivate;
+}
+
+QBarDataItemPrivate::QBarDataItemPrivate()
+{
+}
+
+QBarDataItemPrivate::~QBarDataItemPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qbardataitem.h b/src/datavisualization/data/qbardataitem.h
new file mode 100644
index 00000000..68bbcedf
--- /dev/null
+++ b/src/datavisualization/data/qbardataitem.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QBARDATAITEM_H
+#define QBARDATAITEM_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QBarDataItemPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QBarDataItem
+{
+public:
+ QBarDataItem();
+ QBarDataItem(qreal value);
+ QBarDataItem(const QBarDataItem &other);
+ ~QBarDataItem();
+
+ QBarDataItem &operator=(const QBarDataItem &other);
+
+ void setValue(qreal value) { m_value = value; }
+ qreal value() const { return m_value; }
+
+ // TODO Set color, label format, ...?
+
+protected:
+ virtual void createExtraData();
+
+ QBarDataItemPrivate *d_ptr;
+
+private:
+ qreal m_value;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qbardataitem_p.h b/src/datavisualization/data/qbardataitem_p.h
new file mode 100644
index 00000000..20b7ea69
--- /dev/null
+++ b/src/datavisualization/data/qbardataitem_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QBARDATAITEM_P_H
+#define QBARDATAITEM_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qbardataitem.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QBarDataItemPrivate
+{
+public:
+ QBarDataItemPrivate();
+ virtual ~QBarDataItemPrivate();
+
+ // TODO stores other data for bars besides value
+
+protected:
+ friend class QBarDataItem;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qbardataproxy.cpp b/src/datavisualization/data/qbardataproxy.cpp
new file mode 100644
index 00000000..2ec38980
--- /dev/null
+++ b/src/datavisualization/data/qbardataproxy.cpp
@@ -0,0 +1,707 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qbardataproxy.h"
+#include "qbardataproxy_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QBarDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Base proxy class for Q3DBars.
+ * \since 1.0.0
+ *
+ * QBarDataProxy handles adding, inserting, changing and removing rows of data.
+ *
+ * The data array is a list of vectors (rows) of QBarDataItem instances.
+ * Each row can contain different amount of items or even be null.
+ *
+ * QBarDataProxy takes ownership of all QBarDataRows passed to it, whether directly or
+ * in a QBarDataArray container.
+ * If you use QBarDataRow pointers to directly modify data after adding the array to the proxy,
+ * you must also emit proper signal to make the graph update.
+ *
+ * QBarDataProxy optionally keeps track of row and column labels, which Q3DCategoryAxis can utilize
+ * to show axis labels. The row and column labels are stored in separate array from the data and
+ * row manipulation methods provide an alternate versions that don't affect the row labels.
+ * This enables the option of having row labels that relate to the position of the data in the
+ * array rather than the data itself.
+ *
+ * QBarDataProxy supports the following format tags for QAbstractDataProxy::setItemLabelFormat():
+ * \table
+ * \row
+ * \li @rowTitle \li Title from row axis
+ * \row
+ * \li @colTitle \li Title from column axis
+ * \row
+ * \li @valueTitle \li Title from value axis
+ * \row
+ * \li @rowIdx \li Visible row index
+ * \row
+ * \li @colIdx \li Visible Column index
+ * \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{Q3DValueAxis::setLabelFormat()} for more information.
+ * \row
+ * \li %<format spec> \li Item value in specified format.
+ * \endtable
+ *
+ * For example:
+ * \snippet doc_src_qtdatavisualization.cpp 1
+ *
+ * \sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype BarDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QBarDataProxy
+ * \inherits AbstractDataProxy
+ * \brief Base proxy type for Bars3D.
+ *
+ * This type handles adding, inserting, changing and removing rows of data with Qt Quick 2.
+ *
+ * This type is uncreatable, but contains properties that are exposed via subtypes.
+ *
+ * For more complete description, see QBarDataProxy.
+ *
+ * \sa ItemModelBarDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty int BarDataProxy::rowCount
+ * Row count in the array.
+ */
+
+/*!
+ * \qmlproperty list BarDataProxy::rowLabels
+ *
+ * Optional row labels for the array. Indexes in this array match row indexes in data array.
+ * If the list is shorter than row count, all rows will not get labels.
+ */
+
+/*!
+ * \qmlproperty list BarDataProxy::columnLabels
+ *
+ * Optional column labels for the array. Indexes in this array match column indexes in rows.
+ * If the list is shorter than the longest row, all columns will not get labels.
+ */
+
+/*!
+ * Constructs QBarDataProxy with the given \a parent.
+ */
+QBarDataProxy::QBarDataProxy(QObject *parent) :
+ QAbstractDataProxy(new QBarDataProxyPrivate(this), parent)
+{
+}
+
+/*!
+ * \internal
+ */
+QBarDataProxy::QBarDataProxy(QBarDataProxyPrivate *d, QObject *parent) :
+ QAbstractDataProxy(d, parent)
+{
+}
+
+/*!
+ * Destroys QBarDataProxy.
+ */
+QBarDataProxy::~QBarDataProxy()
+{
+}
+
+/*!
+ * Clears the existing array and row and column labels.
+ */
+void QBarDataProxy::resetArray()
+{
+ resetArray(0, QStringList(), QStringList());
+}
+
+/*!
+ * Takes ownership of the \a newArray. Clears the existing array and if the \a newArray is
+ * different than the existing array. If it's the same array, this just triggers arrayReset()
+ * signal.
+ * Passing null array deletes the old array and creates a new empty array.
+ * Row and column labels are not affected.
+ */
+void QBarDataProxy::resetArray(QBarDataArray *newArray)
+{
+ dptr()->resetArray(newArray, 0, 0);
+ emit arrayReset();
+}
+
+/*!
+ * Takes ownership of the \a newArray. Clears the existing array and if the \a newArray is
+ * different than the existing array. If it's the same array, this just triggers arrayReset()
+ * signal.
+ * Passing null array deletes the old array and creates a new empty array.
+ * The \a rowLabels and \a columnLabels lists specify the new labels for rows and columns.
+ */
+void QBarDataProxy::resetArray(QBarDataArray *newArray, const QStringList &rowLabels,
+ const QStringList &columnLabels)
+{
+ dptr()->resetArray(newArray, &rowLabels, &columnLabels);
+ emit arrayReset();
+}
+
+/*!
+ * Changes existing rows by replacing a row at \a rowIndex with \a row. The \a row can be
+ * the same as the existing row already stored at the \a rowIndex.
+ * Existing row labels are not affected.
+ */
+void QBarDataProxy::setRow(int rowIndex, QBarDataRow *row)
+{
+ dptr()->setRow(rowIndex, row, 0);
+ emit rowsChanged(rowIndex, 1);
+}
+
+/*!
+ * Changes existing rows by replacing a row at \a rowIndex with \a row. The \a row can be
+ * the same as the existing row already stored at the \a rowIndex.
+ * Changes the row label to the \a label.
+ */
+void QBarDataProxy::setRow(int rowIndex, QBarDataRow *row, const QString &label)
+{
+ dptr()->setRow(rowIndex, row, &label);
+ emit rowsChanged(rowIndex, 1);
+}
+
+/*!
+ * Changes existing rows by replacing a rows starting at \a rowIndex with \a rows.
+ * Existing row labels are not affected. The rows in the \a rows array can be
+ * the same as the existing rows already stored at the \a rowIndex.
+ */
+void QBarDataProxy::setRows(int rowIndex, const QBarDataArray &rows)
+{
+ dptr()->setRows(rowIndex, rows, 0);
+ emit rowsChanged(rowIndex, rows.size());
+}
+
+/*!
+ * Changes existing rows by replacing a rows starting at \a rowIndex with \a rows.
+ * The row labels are changed to \a labels. The rows in the \a rows array can be
+ * the same as the existing rows already stored at the \a rowIndex.
+ */
+void QBarDataProxy::setRows(int rowIndex, const QBarDataArray &rows, const QStringList &labels)
+{
+ dptr()->setRows(rowIndex, rows, &labels);
+ emit rowsChanged(rowIndex, rows.size());
+}
+
+/*!
+ * Changes a single item at \a rowIndex, \a columnIndex to the \a item.
+ */
+void QBarDataProxy::setItem(int rowIndex, int columnIndex, const QBarDataItem &item)
+{
+ dptr()->setItem(rowIndex, columnIndex, item);
+ emit itemChanged(rowIndex, columnIndex);
+}
+
+/*!
+ * Adds a new \a row to the end of array.
+ * Existing row labels are not affected.
+ *
+ * \return index of the added row.
+ */
+int QBarDataProxy::addRow(QBarDataRow *row)
+{
+ int addIndex = dptr()->addRow(row, 0);
+ emit rowsAdded(addIndex, 1);
+ return addIndex;
+}
+
+/*!
+ * Adds a new \a row with the \a label to the end of array.
+ *
+ * \return index of the added row.
+ */
+int QBarDataProxy::addRow(QBarDataRow *row, const QString &label)
+{
+ int addIndex = dptr()->addRow(row, &label);
+ emit rowsAdded(addIndex, 1);
+ return addIndex;
+}
+
+/*!
+ * Adds new \a rows to the end of array.
+ * Existing row labels are not affected.
+ *
+ * \return index of the first added row.
+ */
+int QBarDataProxy::addRows(const QBarDataArray &rows)
+{
+ int addIndex = dptr()->addRows(rows, 0);
+ emit rowsAdded(addIndex, rows.size());
+ return addIndex;
+}
+
+/*!
+ * Adds new \a rows with \a labels to the end of array.
+ *
+ * \return index of the first added row.
+ */
+int QBarDataProxy::addRows(const QBarDataArray &rows, const QStringList &labels)
+{
+ int addIndex = dptr()->addRows(rows, &labels);
+ emit rowsAdded(addIndex, rows.size());
+ return addIndex;
+}
+
+/*!
+ * Inserts a new \a row into \a rowIndex.
+ * If rowIndex is equal to array size, rows are added to end of the array.
+ * Any existing row labels are not affected.
+ * \note Row labels array will be out of sync with row array after this call,
+ * if there were labeled rows beyond the inserted row.
+ */
+void QBarDataProxy::insertRow(int rowIndex, QBarDataRow *row)
+{
+ dptr()->insertRow(rowIndex, row, 0);
+ emit rowsInserted(rowIndex, 1);
+}
+
+/*!
+ * Inserts a new \a row with the \a label into \a rowIndex.
+ * If rowIndex is equal to array size, rows are added to end of the array.
+ */
+void QBarDataProxy::insertRow(int rowIndex, QBarDataRow *row, const QString &label)
+{
+ dptr()->insertRow(rowIndex, row, &label);
+ emit rowsInserted(rowIndex, 1);
+}
+
+/*!
+ * Inserts new \a rows into \a rowIndex.
+ * If rowIndex is equal to array size, rows are added to end of the array.
+ * Any existing row labels are not affected.
+ * \note Row labels array will be out of sync with row array after this call,
+ * if there were labeled rows beyond the inserted rows.
+ */
+void QBarDataProxy::insertRows(int rowIndex, const QBarDataArray &rows)
+{
+ dptr()->insertRows(rowIndex, rows, 0);
+ emit rowsInserted(rowIndex, rows.size());
+}
+
+/*!
+ * Inserts new \a rows with \a labels into \a rowIndex.
+ * If rowIndex is equal to array size, rows are added to end of the array.
+ */
+void QBarDataProxy::insertRows(int rowIndex, const QBarDataArray &rows, const QStringList &labels)
+{
+ dptr()->insertRows(rowIndex, rows, &labels);
+ emit rowsInserted(rowIndex, rows.size());
+}
+
+/*!
+ * Removes \a removeCount rows staring at \a rowIndex. Attempting to remove rows past the end of the
+ * array does nothing. If \a removeLabels is true, corresponding row labels are also removed. Otherwise
+ * the row labels are not affected.
+ * \note If \a removeLabels is false, the row labels array will be out of sync with the row array
+ * if there are labeled rows beyond the removed rows.
+ */
+void QBarDataProxy::removeRows(int rowIndex, int removeCount, bool removeLabels)
+{
+ if (rowIndex < rowCount() && removeCount >= 1) {
+ dptr()->removeRows(rowIndex, removeCount, removeLabels);
+ emit rowsRemoved(rowIndex, removeCount);
+ }
+}
+
+/*!
+ * \property QBarDataProxy::rowCount
+ *
+ * Row count in the array.
+ */
+int QBarDataProxy::rowCount() const
+{
+ return dptrc()->m_dataArray->size();
+}
+
+/*!
+ * \property QBarDataProxy::rowLabels
+ *
+ * Optional row labels for the array. Indexes in this array match row indexes in data array.
+ * If the list is shorter than row count, all rows will not get labels.
+ */
+QStringList QBarDataProxy::rowLabels() const
+{
+ return dptrc()->m_rowLabels;
+}
+
+void QBarDataProxy::setRowLabels(const QStringList &labels)
+{
+ if (dptr()->m_rowLabels != labels) {
+ dptr()->m_rowLabels = labels;
+ emit rowLabelsChanged();
+ }
+}
+
+/*!
+ * \property QBarDataProxy::columnLabels
+ *
+ * Optional column labels for the array. Indexes in this array match column indexes in rows.
+ * If the list is shorter than the longest row, all columns will not get labels.
+ */
+QStringList QBarDataProxy::columnLabels() const
+{
+ return dptrc()->m_columnLabels;
+}
+
+void QBarDataProxy::setColumnLabels(const QStringList &labels)
+{
+ if (dptr()->m_columnLabels != labels) {
+ dptr()->m_columnLabels = labels;
+ emit columnLabelsChanged();
+ }
+}
+
+/*!
+ * \return pointer to the data array.
+ */
+const QBarDataArray *QBarDataProxy::array() const
+{
+ return dptrc()->m_dataArray;
+}
+
+/*!
+ * \return pointer to the row at \a rowIndex. It is guaranteed to be valid only until next call
+ * that modifies data.
+ */
+const QBarDataRow *QBarDataProxy::rowAt(int rowIndex) const
+{
+ const QBarDataArray &dataArray = *dptrc()->m_dataArray;
+ Q_ASSERT(rowIndex >= 0 && rowIndex < dataArray.size());
+ return dataArray[rowIndex];
+}
+
+/*!
+ * \return pointer to the item at \a rowIndex, \a columnIndex. It is guaranteed to be valid only
+ * until next call that modifies data.
+ */
+const QBarDataItem *QBarDataProxy::itemAt(int rowIndex, int columnIndex) const
+{
+ const QBarDataArray &dataArray = *dptrc()->m_dataArray;
+ Q_ASSERT(rowIndex >= 0 && rowIndex < dataArray.size());
+ const QBarDataRow &dataRow = *dataArray[rowIndex];
+ Q_ASSERT(columnIndex >= 0 && columnIndex < dataRow.size());
+ return &dataRow.at(columnIndex);
+}
+
+/*!
+ * \internal
+ */
+QBarDataProxyPrivate *QBarDataProxy::dptr()
+{
+ return static_cast<QBarDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QBarDataProxyPrivate *QBarDataProxy::dptrc() const
+{
+ return static_cast<const QBarDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \fn void QBarDataProxy::arrayReset()
+ *
+ * Emitted when data array is reset.
+ * If you change the whole array contents without calling resetArray(), you need to
+ * emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QBarDataProxy::rowsAdded(int startIndex, int count)
+ *
+ * Emitted when rows have been added. Provides \a startIndex and \a count of rows added.
+ * If you add rows directly to the array without calling addRow() or addRows(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QBarDataProxy::rowsChanged(int startIndex, int count)
+ *
+ * Emitted when rows have changed. Provides \a startIndex and \a count of changed rows.
+ * If you change rows directly in the array without calling setRow() or setRows(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QBarDataProxy::rowsRemoved(int startIndex, int count)
+ *
+ * Emitted when rows have been removed. Provides \a startIndex and \a count of rows removed.
+ * Index is the current array size if rows were removed from the end of the array.
+ * If you remove rows directly from the array without calling removeRows(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QBarDataProxy::rowsInserted(int startIndex, int count)
+ *
+ * Emitted when rows have been inserted. Provides \a startIndex and \a count of inserted rows.
+ * If you insert rows directly into the array without calling insertRow() or insertRows(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QBarDataProxy::itemChanged(int rowIndex, int columnIndex)
+ *
+ * Emitted when an item has changed. Provides \a rowIndex and \a columnIndex of changed item.
+ * If you change an item directly in the array without calling setItem(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+// QBarDataProxyPrivate
+
+QBarDataProxyPrivate::QBarDataProxyPrivate(QBarDataProxy *q)
+ : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeBar),
+ m_dataArray(new QBarDataArray)
+{
+ m_itemLabelFormat = QStringLiteral("@valueTitle: @valueLabel");
+}
+
+QBarDataProxyPrivate::~QBarDataProxyPrivate()
+{
+ clearArray();
+}
+
+void QBarDataProxyPrivate::resetArray(QBarDataArray *newArray, const QStringList *rowLabels,
+ const QStringList *columnLabels)
+{
+ if (rowLabels)
+ qptr()->setRowLabels(*rowLabels);
+ if (columnLabels)
+ qptr()->setColumnLabels(*columnLabels);
+
+ if (!newArray)
+ newArray = new QBarDataArray;
+
+ if (newArray != m_dataArray) {
+ clearArray();
+ m_dataArray = newArray;
+ }
+}
+
+void QBarDataProxyPrivate::setRow(int rowIndex, QBarDataRow *row, const QString *label)
+{
+ Q_ASSERT(rowIndex >= 0 && rowIndex < m_dataArray->size());
+
+ if (label)
+ fixRowLabels(rowIndex, 1, QStringList(*label), false);
+ if (row != m_dataArray->at(rowIndex)) {
+ clearRow(rowIndex);
+ (*m_dataArray)[rowIndex] = row;
+ }
+}
+
+void QBarDataProxyPrivate::setRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels)
+{
+ QBarDataArray &dataArray = *m_dataArray;
+ Q_ASSERT(rowIndex >= 0 && (rowIndex + rows.size()) <= dataArray.size());
+ if (labels)
+ fixRowLabels(rowIndex, rows.size(), *labels, false);
+ for (int i = 0; i < rows.size(); i++) {
+ if (rows.at(i) != dataArray.at(rowIndex)) {
+ clearRow(rowIndex);
+ dataArray[rowIndex] = rows.at(i);
+ }
+ rowIndex++;
+ }
+}
+
+void QBarDataProxyPrivate::setItem(int rowIndex, int columnIndex, const QBarDataItem &item)
+{
+ Q_ASSERT(rowIndex >= 0 && rowIndex < m_dataArray->size());
+ QBarDataRow &row = *(*m_dataArray)[rowIndex];
+ Q_ASSERT(columnIndex < row.size());
+ row[columnIndex] = item;
+}
+
+int QBarDataProxyPrivate::addRow(QBarDataRow *row, const QString *label)
+{
+ int currentSize = m_dataArray->size();
+ if (label)
+ fixRowLabels(currentSize, 1, QStringList(*label), false);
+ m_dataArray->append(row);
+ return currentSize;
+}
+
+int QBarDataProxyPrivate::addRows(const QBarDataArray &rows, const QStringList *labels)
+{
+ int currentSize = m_dataArray->size();
+ if (labels)
+ fixRowLabels(currentSize, rows.size(), *labels, false);
+ for (int i = 0; i < rows.size(); i++)
+ m_dataArray->append(rows.at(i));
+ return currentSize;
+}
+
+void QBarDataProxyPrivate::insertRow(int rowIndex, QBarDataRow *row, const QString *label)
+{
+ Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray->size());
+ if (label)
+ fixRowLabels(rowIndex, 1, QStringList(*label), true);
+ m_dataArray->insert(rowIndex, row);
+}
+
+void QBarDataProxyPrivate::insertRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels)
+{
+ Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray->size());
+ if (labels)
+ fixRowLabels(rowIndex, rows.size(), *labels, true);
+ for (int i = 0; i < rows.size(); i++)
+ m_dataArray->insert(rowIndex++, rows.at(i));
+}
+
+void QBarDataProxyPrivate::removeRows(int rowIndex, int removeCount, bool removeLabels)
+{
+ Q_ASSERT(rowIndex >= 0);
+ int maxRemoveCount = m_dataArray->size() - rowIndex;
+ removeCount = qMin(removeCount, maxRemoveCount);
+ bool labelsChanged = false;
+ for (int i = 0; i < removeCount; i++) {
+ clearRow(rowIndex);
+ m_dataArray->removeAt(rowIndex);
+ if (removeLabels && m_rowLabels.size() > rowIndex) {
+ m_rowLabels.removeAt(rowIndex);
+ labelsChanged = true;
+ }
+ }
+ if (labelsChanged)
+ emit qptr()->rowLabelsChanged();
+}
+
+QBarDataProxy *QBarDataProxyPrivate::qptr()
+{
+ return static_cast<QBarDataProxy *>(q_ptr);
+}
+
+void QBarDataProxyPrivate::clearRow(int rowIndex)
+{
+ if (m_dataArray->at(rowIndex)) {
+ delete m_dataArray->at(rowIndex);
+ (*m_dataArray)[rowIndex] = 0;
+ }
+}
+
+void QBarDataProxyPrivate::clearArray()
+{
+ for (int i = 0; i < m_dataArray->size(); i++)
+ clearRow(i);
+ m_dataArray->clear();
+ delete m_dataArray;
+}
+
+/*!
+ * \internal
+ * Fixes the row label array to include specified labels.
+ */
+void QBarDataProxyPrivate::fixRowLabels(int startIndex, int count, const QStringList &newLabels, bool isInsert)
+{
+ bool changed = false;
+ int currentSize = m_rowLabels.size();
+
+ int newSize = newLabels.size();
+ if (startIndex >= currentSize) {
+ // Adding labels past old label array, create empty strings to fill intervening space
+ if (newSize) {
+ for (int i = currentSize; i < startIndex; i++)
+ m_rowLabels << QString();
+ // Doesn't matter if insert, append, or just change when there were no existing
+ // strings, just append new strings.
+ m_rowLabels << newLabels;
+ changed = true;
+ }
+ } else {
+ if (isInsert) {
+ int insertIndex = startIndex;
+ if (count)
+ changed = true;
+ for (int i = 0; i < count; i++) {
+ if (i < newSize)
+ m_rowLabels.insert(insertIndex++, newLabels.at(i));
+ else
+ m_rowLabels.insert(insertIndex++, QString());
+ }
+ } else {
+ // Either append or change, replace labels up to array end and then add new ones
+ int lastChangeIndex = count + startIndex;
+ int newIndex = 0;
+ for (int i = startIndex; i < lastChangeIndex; i++) {
+ if (i >= currentSize) {
+ // Label past the current size, so just append the new label
+ if (newSize < newIndex) {
+ changed = true;
+ m_rowLabels << newLabels.at(newIndex);
+ } else {
+ break; // No point appending empty strings, so just exit
+ }
+ } else if (newSize > newIndex) {
+ // Replace existing label
+ if (m_rowLabels.at(i) != newLabels.at(newIndex)) {
+ changed = true;
+ m_rowLabels[i] = newLabels.at(newIndex);
+ }
+ } else {
+ // No more new labels, so clear existing label
+ if (!m_rowLabels.at(i).isEmpty()) {
+ changed = true;
+ m_rowLabels[i] = QString();
+ }
+ }
+ newIndex++;
+ }
+ }
+ }
+ if (changed)
+ emit qptr()->rowLabelsChanged();
+}
+
+QPair<GLfloat, GLfloat> QBarDataProxyPrivate::limitValues(int startRow, int endRow,
+ int startColumn, int endColumn) const
+{
+ QPair<GLfloat, GLfloat> limits = qMakePair(0.0f, 0.0f);
+ endRow = qMin(endRow, m_dataArray->size() - 1);
+ for (int i = startRow; i <= endRow; i++) {
+ QBarDataRow *row = m_dataArray->at(i);
+ if (row) {
+ endColumn = qMin(endColumn, row->size() - 1);
+ for (int j = startColumn; j <= endColumn; j++) {
+ const QBarDataItem &item = m_dataArray->at(i)->at(j);
+ qreal itemValue = item.value();
+ if (limits.second < itemValue)
+ limits.second = itemValue;
+ if (limits.first > itemValue)
+ limits.first = itemValue;
+ }
+ }
+ }
+ return limits;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qbardataproxy.h b/src/datavisualization/data/qbardataproxy.h
new file mode 100644
index 00000000..758700df
--- /dev/null
+++ b/src/datavisualization/data/qbardataproxy.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QBARDATAPROXY_H
+#define QBARDATAPROXY_H
+
+#include <QtDataVisualization/qabstractdataproxy.h>
+#include <QtDataVisualization/qbardataitem.h>
+#include <QVector>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+typedef QVector<QBarDataItem> QBarDataRow;
+typedef QList<QBarDataRow *> QBarDataArray;
+
+class QBarDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QBarDataProxy : public QAbstractDataProxy
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int rowCount READ rowCount)
+ Q_PROPERTY(QStringList rowLabels READ rowLabels WRITE setRowLabels NOTIFY rowLabelsChanged)
+ Q_PROPERTY(QStringList columnLabels READ columnLabels WRITE setColumnLabels NOTIFY columnLabelsChanged)
+public:
+ explicit QBarDataProxy(QObject *parent = 0);
+ virtual ~QBarDataProxy();
+
+ // TODO: Replace first part of class description in docs with this once all TODOs are done:
+ /*
+ * QBarDataProxy is optimized for adding, inserting, and removing rows of data.
+ * Adding a column essentially means modifying every row, which is comparatively very inefficient.
+ * Proxy is also optimized to use cases where the only defining characteristic of an individual
+ * bar is its value. Modifying other data that might be added in the future such as color of
+ * individual bar requires allocating additional data object for the bar.
+ */
+
+ int rowCount() const;
+
+ QStringList rowLabels() const;
+ void setRowLabels(const QStringList &labels);
+ QStringList columnLabels() const;
+ void setColumnLabels(const QStringList &labels);
+
+ const QBarDataArray *array() const;
+ const QBarDataRow *rowAt(int rowIndex) const;
+ const QBarDataItem *itemAt(int rowIndex, int columnIndex) const;
+
+ void resetArray();
+ void resetArray(QBarDataArray *newArray);
+ void resetArray(QBarDataArray *newArray, const QStringList &rowLabels,
+ const QStringList &columnLabels);
+
+ void setRow(int rowIndex, QBarDataRow *row);
+ void setRow(int rowIndex, QBarDataRow *row, const QString &label);
+ void setRows(int rowIndex, const QBarDataArray &rows);
+ void setRows(int rowIndex, const QBarDataArray &rows, const QStringList &labels);
+
+ // Setting a column is comparatively inefficient as it changes all rows.
+ // Can resize rows that are shorter than columnIndex.
+ // TODO void setColumn(int columnIndex, const QBarDataRow &column);
+ // TODO void setColumns(int columnIndex, const QBarDataArray &columns);
+
+ void setItem(int rowIndex, int columnIndex, const QBarDataItem &item);
+ // Change block of items
+ // TODO setItems(int rowIndex, int columnIndex, QBarDataArray *items);
+
+ int addRow(QBarDataRow *row);
+ int addRow(QBarDataRow *row, const QString &label);
+ int addRows(const QBarDataArray &rows);
+ int addRows(const QBarDataArray &rows, const QStringList &labels);
+ // TODO int addColumn(const QBarDataRow &column); // returns the index of the added column
+ // TODO int addColumns(const QBarDataArray &columns); // returns the index of the first added column
+
+ void insertRow(int rowIndex, QBarDataRow *row);
+ void insertRow(int rowIndex, QBarDataRow *row, const QString &label);
+ void insertRows(int rowIndex, const QBarDataArray &rows);
+ void insertRows(int rowIndex, const QBarDataArray &rows, const QStringList &labels);
+ // TODO void insertColumn(int columnIndex, const QBarDataRow &column);
+ // TODO void insertColumns(int columnIndex, const QBarDataArray &columns);
+
+ void removeRows(int rowIndex, int removeCount, bool removeLabels = true);
+ // TODO void removeColumns(int columnIndex, int removeCount);
+
+signals:
+ void arrayReset();
+ void rowsAdded(int startIndex, int count);
+ void rowsChanged(int startIndex, int count);
+ void rowsRemoved(int startIndex, int count);
+ void rowsInserted(int startIndex, int count);
+ // TODO void columnsChanged(int startIndex, int count);
+ // TODO void columnsAdded(int startIndex, int count);
+ // TODO void columnsRemoved(int startIndex, int count);
+ // TODO void columnsInserted(int startIndex, int count);
+ void itemChanged(int rowIndex, int columnIndex); // TODO remove once itemsChanged is added?
+ // TODO void itemsChanged(int rowIndex, int columnIndex, int rowCount, int columnCount);
+
+ void rowLabelsChanged();
+ void columnLabelsChanged();
+
+protected:
+ explicit QBarDataProxy(QBarDataProxyPrivate *d, QObject *parent = 0);
+ QBarDataProxyPrivate *dptr();
+ const QBarDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QBarDataProxy)
+
+ friend class Bars3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QBARDATAPROXY_H
diff --git a/src/datavisualization/data/qbardataproxy_p.h b/src/datavisualization/data/qbardataproxy_p.h
new file mode 100644
index 00000000..4d51bd5b
--- /dev/null
+++ b/src/datavisualization/data/qbardataproxy_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QBARDATAPROXY_P_H
+#define QBARDATAPROXY_P_H
+
+#include "qbardataproxy.h"
+#include "qabstractdataproxy_p.h"
+#include "qbardataitem.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QBarDataProxyPrivate : public QAbstractDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QBarDataProxyPrivate(QBarDataProxy *q);
+ virtual ~QBarDataProxyPrivate();
+
+ void resetArray(QBarDataArray *newArray, const QStringList *rowLabels,
+ const QStringList *columnLabels);
+ void setRow(int rowIndex, QBarDataRow *row, const QString *label);
+ void setRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels);
+ void setItem(int rowIndex, int columnIndex, const QBarDataItem &item);
+ int addRow(QBarDataRow *row, const QString *label);
+ int addRows(const QBarDataArray &rows, const QStringList *labels);
+ void insertRow(int rowIndex, QBarDataRow *row, const QString *label);
+ void insertRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels);
+ void removeRows(int rowIndex, int removeCount, bool removeLabels);
+
+ QPair<GLfloat, GLfloat> limitValues(int startRow, int startColumn, int rowCount,
+ int columnCount) const;
+
+private:
+ QBarDataProxy *qptr();
+ void clearRow(int rowIndex);
+ void clearArray();
+ void fixRowLabels(int startIndex, int count, const QStringList &newLabels, bool isInsert);
+
+ QBarDataArray *m_dataArray;
+ QStringList m_rowLabels;
+ QStringList m_columnLabels;
+
+private:
+ friend class QBarDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QBARDATAPROXY_P_H
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
new file mode 100644
index 00000000..518e69eb
--- /dev/null
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qheightmapsurfacedataproxy_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+// Default ranges correspond value axis defaults
+const float defaultMinValue = 0.0f;
+const float defaultMaxValue = 10.0f;
+
+/*!
+ * \class QHeightMapSurfaceDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Base proxy class for Q3DSurface.
+ * \since 1.0.0
+ *
+ * QHeightMapSurfaceDataProxy takes care of surface related height map data handling. It provides a
+ * way for giving the surface plot a height map to be visualized.
+ *
+ * Since height maps do not contain values for X or Z axes, those values need to be given
+ * separately using minXValue, maxXValue, minZValue, and maxZValue properties. X-value corresponds
+ * to image horizontal direction and Z-value to the vertical. Setting any of these
+ * properties triggers asynchronous re-resolving of any existing height map.
+ *
+ * \sa QSurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype HeightMapSurfaceDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QHeightMapSurfaceDataProxy
+ * \inherits SurfaceDataProxy
+ * \brief Base proxy type for Surface3D.
+ *
+ * HeightMapSurfaceDataProxy takes care of surface related height map data handling. It provides a
+ * way for giving the surface plot a height map to be visualized.
+ *
+ * For more complete description, see QHeightMapSurfaceDataProxy.
+ *
+ * \sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty image HeightMapSurfaceDataProxy::heightMap
+ *
+ * A height map to be visualized. Setting this property replaces current data with height map data.
+ *
+ * There are several formats the image can be given in, but if it is not in a directly usable
+ * format, a conversion is made. \note If the result seems wrong, the automatic conversion failed
+ * and you should try converting the image yourself before setting it. Preferred format is
+ * QImage::Format_RGB32 in grayscale.
+ *
+ * The height of the image is read from the red component of the pixels if the image is in grayscale,
+ * otherwise it is an average calculated from red, green and blue components of the pixels. Using
+ * grayscale images may improve data conversion speed for large images.
+ *
+ * Since height maps do not contain values for X or Z axes, those values need to be given
+ * separately using minXValue, maxXValue, minZValue, and maxZValue properties. X-value corresponds
+ * to image horizontal direction and Z-value to the vertical. Setting any of these
+ * properties triggers asynchronous re-resolving of any existing height map.
+ *
+ * Not recommended formats: all mono formats (for example QImage::Format_Mono).
+ */
+
+/*!
+ * \qmlproperty string HeightMapSurfaceDataProxy::heightMapFile
+ *
+ * A file with a height map image to be visualized. Setting this property replaces current data
+ * with height map data.
+ *
+ * \sa heightMap
+ */
+
+/*!
+ * \qmlproperty qreal HeightMapSurfaceDataProxy::minXValue
+ *
+ * The minimum X value for the generated surface points.
+ * When setting this property the corresponding maximum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+
+/*!
+ * \qmlproperty qreal HeightMapSurfaceDataProxy::maxXValue
+ *
+ * The maximum X value for the generated surface points.
+ * When setting this property the corresponding minimum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+
+/*!
+ * \qmlproperty qreal HeightMapSurfaceDataProxy::minZValue
+ *
+ * The minimum Z value for the generated surface points.
+ * When setting this property the corresponding maximum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+
+/*!
+ * \qmlproperty qreal HeightMapSurfaceDataProxy::maxZValue
+ *
+ * The maximum Z value for the generated surface points.
+ * When setting this property the corresponding minimum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+
+/*!
+ * Constructs QHeightMapSurfaceDataProxy with the given \a parent.
+ */
+QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(QObject *parent) :
+ QSurfaceDataProxy(new QHeightMapSurfaceDataProxyPrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QHeightMapSurfaceDataProxy with the given \a image and \a parent. Height map is set
+ * by calling setHeighMap() with \a image.
+ *
+ * \sa heightMap
+ */
+QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(const QImage &image, QObject *parent) :
+ QSurfaceDataProxy(new QHeightMapSurfaceDataProxyPrivate(this), parent)
+{
+ setHeightMap(image);
+}
+
+/*!
+ * \internal
+ */
+QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(
+ QHeightMapSurfaceDataProxyPrivate *d, QObject *parent) :
+ QSurfaceDataProxy(d, parent)
+{
+}
+
+/*!
+ * Destroys QHeightMapSurfaceDataProxy.
+ */
+QHeightMapSurfaceDataProxy::~QHeightMapSurfaceDataProxy()
+{
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::heightMap
+ *
+ * A height map to be visualized. Setting this property replaces current data with height map data.
+ *
+ * There are several formats the image can be given in, but if it is not in a directly usable
+ * format, a conversion is made. \note If the result seems wrong, the automatic conversion failed
+ * and you should try converting the image yourself before setting it. Preferred format is
+ * QImage::Format_RGB32 in grayscale.
+ *
+ * The height of the image is read from the red component of the pixels if the image is in grayscale,
+ * otherwise it is an average calculated from red, green and blue components of the pixels. Using
+ * grayscale images may improve data conversion speed for large images.
+ *
+ * Not recommended formats: all mono formats (for example QImage::Format_Mono).
+ *
+ * The height map is resolved asynchronously. QSurfaceDataProxy::arrayReset() is emitted when the
+ * data has been resolved.
+ */
+void QHeightMapSurfaceDataProxy::setHeightMap(const QImage &image)
+{
+ dptr()->m_heightMap = image;
+
+ // We do resolving asynchronously to make qml onArrayReset handlers actually get the initial reset
+ if (!dptr()->m_resolveTimer.isActive())
+ dptr()->m_resolveTimer.start(0);
+}
+
+QImage QHeightMapSurfaceDataProxy::heightMap() const
+{
+ return dptrc()->m_heightMap;
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::heightMapFile
+ *
+ * A file with a height map image to be visualized. Setting this property replaces current data
+ * with height map data.
+ *
+ * \sa heightMap
+ */
+void QHeightMapSurfaceDataProxy::setHeightMapFile(const QString &filename)
+{
+ dptr()->m_heightMapFile = filename;
+ setHeightMap(QImage(filename));
+}
+
+QString QHeightMapSurfaceDataProxy::heightMapFile() const
+{
+ return dptrc()->m_heightMapFile;
+}
+
+/*!
+ * A convenience function for setting all minimum (\a minX and \a minZ) and maximum
+ * (\a maxX and \a maxZ) values at the same time. The minimum values must be smaller than the
+ * corresponding maximum value. Otherwise the values get adjusted so that they are valid.
+ */
+void QHeightMapSurfaceDataProxy::setValueRanges(float minX, float maxX, float minZ, float maxZ)
+{
+ dptr()->setValueRanges(minX, maxX, minZ, maxZ);
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::minXValue
+ *
+ * The minimum X value for the generated surface points.
+ * When setting this property the corresponding maximum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+void QHeightMapSurfaceDataProxy::setMinXValue(float min)
+{
+ dptr()->setMinXValue(min);
+}
+
+float QHeightMapSurfaceDataProxy::minXValue() const
+{
+ return dptrc()->m_minXValue;
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::maxXValue
+ *
+ * The maximum X value for the generated surface points.
+ * When setting this property the corresponding minimum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+void QHeightMapSurfaceDataProxy::setMaxXValue(float max)
+{
+ dptr()->setMaxXValue(max);
+}
+
+float QHeightMapSurfaceDataProxy::maxXValue() const
+{
+ return dptrc()->m_maxXValue;
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::minZValue
+ *
+ * The minimum Z value for the generated surface points.
+ * When setting this property the corresponding maximum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+void QHeightMapSurfaceDataProxy::setMinZValue(float min)
+{
+ dptr()->setMinZValue(min);
+}
+
+float QHeightMapSurfaceDataProxy::minZValue() const
+{
+ return dptrc()->m_minZValue;
+}
+
+/*!
+ * \property QHeightMapSurfaceDataProxy::maxZValue
+ *
+ * The maximum Z value for the generated surface points.
+ * When setting this property the corresponding minimum value is adjusted if necessary,
+ * to ensure that the range remains valid.
+ */
+void QHeightMapSurfaceDataProxy::setMaxZValue(float max)
+{
+ dptr()->setMaxZValue(max);
+}
+
+float QHeightMapSurfaceDataProxy::maxZValue() const
+{
+ return dptrc()->m_maxZValue;
+}
+
+/*!
+ * \internal
+ */
+QHeightMapSurfaceDataProxyPrivate *QHeightMapSurfaceDataProxy::dptr()
+{
+ return static_cast<QHeightMapSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QHeightMapSurfaceDataProxyPrivate *QHeightMapSurfaceDataProxy::dptrc() const
+{
+ return static_cast<const QHeightMapSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+//
+// QHeightMapSurfaceDataProxyPrivate
+//
+
+QHeightMapSurfaceDataProxyPrivate::QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q)
+ : QSurfaceDataProxyPrivate(q),
+ m_minXValue(defaultMinValue),
+ m_maxXValue(defaultMaxValue),
+ m_minZValue(defaultMinValue),
+ m_maxZValue(defaultMaxValue)
+{
+ m_resolveTimer.setSingleShot(true);
+ QObject::connect(&m_resolveTimer, &QTimer::timeout,
+ this, &QHeightMapSurfaceDataProxyPrivate::handlePendingResolve);
+}
+
+QHeightMapSurfaceDataProxyPrivate::~QHeightMapSurfaceDataProxyPrivate()
+{
+}
+
+QHeightMapSurfaceDataProxy *QHeightMapSurfaceDataProxyPrivate::qptr()
+{
+ return static_cast<QHeightMapSurfaceDataProxy *>(q_ptr);
+}
+
+void QHeightMapSurfaceDataProxyPrivate::setValueRanges(float minX, float maxX, float minZ, float maxZ)
+{
+ bool changed = false;
+ if (m_minXValue != minX || m_minZValue != minZ) {
+ m_minXValue = minX;
+ m_minZValue = minZ;
+ changed = true;
+ }
+ if (m_maxXValue != maxX || minX >= maxX) {
+ if (minX >= maxX) {
+ m_maxXValue = minX + 1.0;
+ qWarning() << "Warning: Tried to set invalid range for X value range."
+ " Range automatically adjusted to a valid one:"
+ << minX << "-" << maxX << "-->" << m_minXValue << "-" << m_maxXValue;
+ } else {
+ m_maxXValue = maxX;
+ }
+ changed = true;
+ }
+ if (m_maxZValue != maxZ || minZ >= maxZ) {
+ if (minZ >= maxZ) {
+ m_maxZValue = minZ + 1.0;
+ qWarning() << "Warning: Tried to set invalid range for Z value range."
+ " Range automatically adjusted to a valid one:"
+ << minZ << "-" << maxZ << "-->" << m_minZValue << "-" << m_maxZValue;
+ } else {
+ m_maxZValue = maxZ;
+ }
+ changed = true;
+ }
+
+ if (changed && !m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+}
+
+void QHeightMapSurfaceDataProxyPrivate::setMinXValue(float min)
+{
+ if (min != m_minXValue) {
+ if (min >= m_maxXValue) {
+ qreal oldMax = m_maxXValue;
+ m_maxXValue = min + 1.0;
+ qWarning() << "Warning: Tried to set minimum X to equal or larger than maximum X for"
+ " value range. Maximum automatically adjusted to a valid one:"
+ << oldMax << "-->" << m_maxXValue;
+ }
+ m_minXValue = min;
+
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+ }
+}
+
+void QHeightMapSurfaceDataProxyPrivate::setMaxXValue(float max)
+{
+ if (m_maxXValue != max) {
+ if (max <= m_minXValue) {
+ qreal oldMin = m_minXValue;
+ m_minXValue = max - 1.0;
+ qWarning() << "Warning: Tried to set maximum X to equal or smaller than minimum X for"
+ " value range. Minimum automatically adjusted to a valid one:"
+ << oldMin << "-->" << m_minXValue;
+ }
+ m_maxXValue = max;
+
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+ }
+}
+
+void QHeightMapSurfaceDataProxyPrivate::setMinZValue(float min)
+{
+ if (min != m_minZValue) {
+ if (min >= m_maxZValue) {
+ qreal oldMax = m_maxZValue;
+ m_maxZValue = min + 1.0;
+ qWarning() << "Warning: Tried to set minimum Z to equal or larger than maximum Z for"
+ " value range. Maximum automatically adjusted to a valid one:"
+ << oldMax << "-->" << m_maxZValue;
+ }
+ m_minZValue = min;
+
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+ }
+}
+
+void QHeightMapSurfaceDataProxyPrivate::setMaxZValue(float max)
+{
+ if (m_maxZValue != max) {
+ if (max <= m_minZValue) {
+ qreal oldMin = m_minZValue;
+ m_minZValue = max - 1.0;
+ qWarning() << "Warning: Tried to set maximum Z to equal or smaller than minimum Z for"
+ " value range. Minimum automatically adjusted to a valid one:"
+ << oldMin << "-->" << m_minZValue;
+ }
+ m_maxZValue = max;
+
+ if (!m_resolveTimer.isActive())
+ m_resolveTimer.start(0);
+ }
+}
+
+void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve()
+{
+ QImage heightImage = m_heightMap;
+ // Convert to RGB32 to be sure we're reading the right bytes
+ if (heightImage.format() != QImage::Format_RGB32)
+ heightImage = heightImage.convertToFormat(QImage::Format_RGB32);
+
+ uchar *bits = heightImage.bits();
+
+ int imageHeight = heightImage.height();
+ int imageWidth = heightImage.width();
+ int bitCount = imageWidth * 4 * (imageHeight - 1);
+ int widthBits = imageWidth * 4;
+ float height = 0;
+
+ // Do not recreate array if dimensions have not changed
+ QSurfaceDataArray *dataArray = m_dataArray;
+ if (imageWidth != qptr()->columnCount() || imageHeight != dataArray->size()) {
+ dataArray = new QSurfaceDataArray;
+ dataArray->reserve(imageHeight);
+ for (int i = 0; i < imageHeight; i++) {
+ QSurfaceDataRow *newProxyRow = new QSurfaceDataRow(imageWidth);
+ dataArray->append(newProxyRow);
+ }
+ }
+
+ float xMul = (m_maxXValue - m_minXValue) / float(imageWidth - 1);
+ float zMul = (m_maxZValue - m_minZValue) / float(imageHeight - 1);
+
+ if (heightImage.isGrayscale()) {
+ // Grayscale, it's enough to read Red byte
+ for (int i = 0; i < imageHeight; i++, bitCount -= widthBits) {
+ QSurfaceDataRow &newRow = *dataArray->at(i);
+ for (int j = 0; j < imageWidth; j++)
+ newRow[j].setPosition(QVector3D((float(j) * xMul) + m_minXValue, float(bits[bitCount + (j * 4)]),
+ (float(i) * zMul) + m_minZValue));
+ }
+ } else {
+ // Not grayscale, we'll need to calculate height from RGB
+ for (int i = 0; i < imageHeight; i++, bitCount -= widthBits) {
+ QSurfaceDataRow &newRow = *dataArray->at(i);
+ for (int j = 0; j < imageWidth; j++) {
+ int nextpixel = j * 4;
+ height = (float(bits[bitCount + nextpixel])
+ + float(bits[1 + bitCount + nextpixel])
+ + float(bits[2 + bitCount + nextpixel]));
+ newRow[j].setPosition(QVector3D((float(j) * xMul) + m_minXValue, height / 3.0f,
+ (float(i) * zMul) + m_minZValue));
+ }
+ }
+ }
+
+ qptr()->resetArray(dataArray);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.h b/src/datavisualization/data/qheightmapsurfacedataproxy.h
new file mode 100644
index 00000000..3306059f
--- /dev/null
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QHEIGHTMAPSURFACEDATAPROXY_H
+#define QHEIGHTMAPSURFACEDATAPROXY_H
+
+#include <QtDataVisualization/qsurfacedataproxy.h>
+
+#include <QImage>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QHeightMapSurfaceDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QHeightMapSurfaceDataProxy : public QSurfaceDataProxy
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QImage heightMap READ heightMap WRITE setHeightMap)
+ Q_PROPERTY(QString heightMapFile READ heightMapFile WRITE setHeightMapFile)
+ Q_PROPERTY(float minXValue READ minXValue WRITE setMinXValue)
+ Q_PROPERTY(float maxXValue READ maxXValue WRITE setMaxXValue)
+ Q_PROPERTY(float minZValue READ minZValue WRITE setMinZValue)
+ Q_PROPERTY(float maxZValue READ maxZValue WRITE setMaxZValue)
+
+public:
+ explicit QHeightMapSurfaceDataProxy(QObject *parent = 0);
+ explicit QHeightMapSurfaceDataProxy(const QImage &image, QObject *parent = 0);
+ virtual ~QHeightMapSurfaceDataProxy();
+
+ void setHeightMap(const QImage &image);
+ QImage heightMap() const;
+
+ void setHeightMapFile(const QString &filename);
+ QString heightMapFile() const;
+
+ void setValueRanges(float minX, float maxX, float minZ, float maxZ);
+ void setMinXValue(float min);
+ float minXValue() const;
+ void setMaxXValue(float max);
+ float maxXValue() const;
+ void setMinZValue(float min);
+ float minZValue() const;
+ void setMaxZValue(float max);
+ float maxZValue() const;
+
+protected:
+ explicit QHeightMapSurfaceDataProxy(QHeightMapSurfaceDataProxyPrivate *d, QObject *parent = 0);
+ QHeightMapSurfaceDataProxyPrivate *dptr();
+ const QHeightMapSurfaceDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QHeightMapSurfaceDataProxy)
+
+ friend class Surface3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy_p.h b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h
new file mode 100644
index 00000000..2d773344
--- /dev/null
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QHEIGHTMAPSURFACEDATAPROXY_P_H
+#define QHEIGHTMAPSURFACEDATAPROXY_P_H
+
+#include "qheightmapsurfacedataproxy.h"
+#include "qsurfacedataproxy_p.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QHeightMapSurfaceDataProxyPrivate : public QSurfaceDataProxyPrivate
+{
+ Q_OBJECT
+
+public:
+ QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q);
+ virtual ~QHeightMapSurfaceDataProxyPrivate();
+
+ void setValueRanges(float minX, float maxX, float minZ, float maxZ);
+ void setMinXValue(float min);
+ void setMaxXValue(float max);
+ void setMinZValue(float min);
+ void setMaxZValue(float max);
+private:
+ QHeightMapSurfaceDataProxy *qptr();
+ void handlePendingResolve();
+
+ QImage m_heightMap;
+ QString m_heightMapFile;
+ QTimer m_resolveTimer;
+
+ float m_minXValue;
+ float m_maxXValue;
+ float m_minZValue;
+ float m_maxZValue;
+
+ friend class QHeightMapSurfaceDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelbardatamapping.cpp b/src/datavisualization/data/qitemmodelbardatamapping.cpp
new file mode 100644
index 00000000..fc6f8f54
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardatamapping.cpp
@@ -0,0 +1,407 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelbardatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QItemModelBarDataMapping
+ * \inmodule QtDataVisualization
+ * \brief Item model mapping for Q3DBars.
+ * \since 1.0.0
+ *
+ * QItemModelBarDataMapping is used to map roles of QAbstractItemModel to rows, columns, and values
+ * of Q3DBars. There are three ways to use QItemModelBarDataMapping:
+ *
+ * 1) If useModelCategories property is set to true, QItemModelBarDataMapping will map rows and
+ * columns of QAbstractItemModel to rows and columns of Q3DBars, and uses the value returned for
+ * Qt::DisplayRole as bar value by default.
+ * The value role to be used can be redefined if Qt::DisplayRole is not suitable.
+ *
+ * 2) For models that do not have data already neatly sorted into rows and columns, such as
+ * QAbstractListModel based models, you can define a role from the model to map for each of row,
+ * column and value.
+ *
+ * 3) If you do not want to include all data contained in the model, or the autogenerated rows and
+ * columns are not ordered as you wish, you can specify which rows and columns should be included
+ * and in which order by defining an explicit list of categories for either or both of rows and
+ * columns.
+ *
+ * For example, assume that you have a custom QAbstractItemModel for storing various monthly values
+ * related to a business.
+ * Each item in the model has roles "year", "month", "income", and "expenses".
+ * You could do the following to display the data in a bar graph:
+ *
+ * \snippet doc_src_qtdatavisualization.cpp 3
+ *
+ * \sa QItemModelBarDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype BarDataMapping
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelBarDataMapping
+ * \brief Item model mapping for Bars3D.
+ *
+ * This type is used to map roles of AbstractItemModel to rows, columns, and values of Bars3D. For
+ * more complete description, see QItemModelBarDataMapping.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 4
+ *
+ * \sa ItemModelBarDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty string BarDataMapping::rowRole
+ * The row role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string BarDataMapping::columnRole
+ * The column role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string BarDataMapping::valueRole
+ * The value role of the mapping.
+ */
+
+/*!
+ * \qmlproperty list BarDataMapping::rowCategories
+ * The row categories of the mapping. Only items with row roles that are found in this list are
+ * included when data is resolved. The rows are ordered in the same order as they are in this list.
+ */
+
+/*!
+ * \qmlproperty list BarDataMapping::columnCategories
+ * The column categories of the mapping. Only items with column roles that are found in this list are
+ * included when data is resolved. The columns are ordered in the same order as they are in this list.
+ */
+
+/*!
+ * \qmlproperty list BarDataMapping::useModelCategories
+ * When set to true, the mapping ignores row and column roles and categories, and uses
+ * the rows and columns from the model instead. Defaults to false.
+ */
+
+/*!
+ * \qmlproperty list BarDataMapping::autoRowCategories
+ * When set to true, the mapping ignores any explicitly set row categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Defaults to true.
+ */
+
+/*!
+ * \qmlproperty list BarDataMapping::autoColumnCategories
+ * When set to true, the mapping ignores any explicitly set column categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Defaults to true.
+ */
+
+/*!
+ * Constructs QItemModelBarDataMapping with the given \a parent.
+ */
+QItemModelBarDataMapping::QItemModelBarDataMapping(QObject *parent)
+ : QAbstractDataMapping(new QItemModelBarDataMappingPrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QItemModelBarDataMapping with \a valueRole and the given \a parent.
+ * This constructor is meant to be used with models that have data properly sorted
+ * in rows and columns already, so it also sets useModelCategories property to true.
+ */
+QItemModelBarDataMapping::QItemModelBarDataMapping(const QString &valueRole, QObject *parent)
+ : QAbstractDataMapping(new QItemModelBarDataMappingPrivate(this), parent)
+{
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_useModelCategories = true;
+}
+
+/*!
+ * Constructs QItemModelBarDataMapping with \a rowRole, \a columnRole, \a valueRole
+ * and the given \a parent.
+ */
+QItemModelBarDataMapping::QItemModelBarDataMapping(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ QObject *parent)
+ : QAbstractDataMapping(new QItemModelBarDataMappingPrivate(this), parent)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+}
+
+/*!
+ * Constructs QItemModelBarDataMapping with \a rowRole, \a columnRole, \a valueRole,
+ * \a rowCategories, \a columnCategories and the given \a parent. This constructor
+ * also sets autoRowCategories and autoColumnCategories to false.
+ */
+QItemModelBarDataMapping::QItemModelBarDataMapping(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories,
+ QObject *parent)
+ : QAbstractDataMapping(new QItemModelBarDataMappingPrivate(this), parent)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_rowCategories = rowCategories;
+ dptr()->m_columnCategories = columnCategories;
+ dptr()->m_autoRowCategories = false;
+ dptr()->m_autoColumnCategories = false;
+}
+
+/*!
+ * Destroys QItemModelBarDataMapping.
+ */
+QItemModelBarDataMapping::~QItemModelBarDataMapping()
+{
+}
+
+/*!
+ * \property QItemModelBarDataMapping::rowRole
+ *
+ * Defines the row role for the mapping.
+ */
+void QItemModelBarDataMapping::setRowRole(const QString &role)
+{
+ if (dptr()->m_rowRole != role) {
+ dptr()->m_rowRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelBarDataMapping::rowRole() const
+{
+ return dptrc()->m_rowRole;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::columnRole
+ *
+ * Defines the column role for the mapping.
+ */
+void QItemModelBarDataMapping::setColumnRole(const QString &role)
+{
+ if (dptr()->m_columnRole != role) {
+ dptr()->m_columnRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelBarDataMapping::columnRole() const
+{
+ return dptrc()->m_columnRole;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::valueRole
+ *
+ * Defines the value role for the mapping.
+ */
+void QItemModelBarDataMapping::setValueRole(const QString &role)
+{
+ if (dptr()->m_valueRole != role) {
+ dptr()->m_valueRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelBarDataMapping::valueRole() const
+{
+ return dptrc()->m_valueRole;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::rowCategories
+ *
+ * Defines the row categories for the mapping.
+ */
+void QItemModelBarDataMapping::setRowCategories(const QStringList &categories)
+{
+ if (dptr()->m_rowCategories != categories) {
+ dptr()->m_rowCategories = categories;
+ emit mappingChanged();
+ }
+}
+
+QStringList QItemModelBarDataMapping::rowCategories() const
+{
+ return dptrc()->m_rowCategories;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::columnCategories
+ *
+ * Defines the column categories for the mapping.
+ */
+void QItemModelBarDataMapping::setColumnCategories(const QStringList &categories)
+{
+ if (dptr()->m_columnCategories != categories) {
+ dptr()->m_columnCategories = categories;
+ emit mappingChanged();
+ }
+}
+
+QStringList QItemModelBarDataMapping::columnCategories() const
+{
+ return dptrc()->m_columnCategories;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::useModelCategories
+ *
+ * When set to true, the mapping ignores row and column roles and categories, and uses
+ * the rows and columns from the model instead. Defaults to false.
+ */
+void QItemModelBarDataMapping::setUseModelCategories(bool enable)
+{
+ if (dptr()->m_useModelCategories != enable) {
+ dptr()->m_useModelCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelBarDataMapping::useModelCategories() const
+{
+ return dptrc()->m_useModelCategories;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::autoRowCategories
+ *
+ * When set to true, the mapping ignores any explicitly set row categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Defaults to true.
+ */
+void QItemModelBarDataMapping::setAutoRowCategories(bool enable)
+{
+ if (dptr()->m_autoRowCategories != enable) {
+ dptr()->m_autoRowCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelBarDataMapping::autoRowCategories() const
+{
+ return dptrc()->m_autoRowCategories;
+}
+
+/*!
+ * \property QItemModelBarDataMapping::autoColumnCategories
+ *
+ * When set to true, the mapping ignores any explicitly set column categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Defaults to true.
+ */
+void QItemModelBarDataMapping::setAutoColumnCategories(bool enable)
+{
+ if (dptr()->m_autoColumnCategories != enable) {
+ dptr()->m_autoColumnCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelBarDataMapping::autoColumnCategories() const
+{
+ return dptrc()->m_autoColumnCategories;
+}
+
+/*!
+ * Changes \a rowRole, \a columnRole, \a valueRole, \a rowCategories and \a columnCategories to the
+ * mapping.
+ */
+void QItemModelBarDataMapping::remap(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_rowCategories = rowCategories;
+ dptr()->m_columnCategories = columnCategories;
+
+ emit mappingChanged();
+}
+
+/*!
+ * /return index of the specified \a category in row categories list.
+ * If the row categories list is empty, -1 is returned.
+ * \note If the automatic row categories generation is in use, this method will
+ * not return valid index before the data in the model is resolved for the first time.
+ */
+int QItemModelBarDataMapping::rowCategoryIndex(const QString &category)
+{
+ return dptr()->m_rowCategories.indexOf(category);
+}
+
+/*!
+ * /return index of the specified \a category in column categories list.
+ * If the category is not found, -1 is returned.
+ * \note If the automatic column categories generation is in use, this method will
+ * not return valid index before the data in the model is resolved for the first time.
+ */
+int QItemModelBarDataMapping::columnCategoryIndex(const QString &category)
+{
+ return dptr()->m_columnCategories.indexOf(category);
+}
+
+/*!
+ * \internal
+ */
+QItemModelBarDataMappingPrivate *QItemModelBarDataMapping::dptr()
+{
+ return static_cast<QItemModelBarDataMappingPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelBarDataMappingPrivate *QItemModelBarDataMapping::dptrc() const
+{
+ return static_cast<const QItemModelBarDataMappingPrivate *>(d_ptr.data());
+}
+
+// QItemModelBarDataMappingPrivate
+
+QItemModelBarDataMappingPrivate::QItemModelBarDataMappingPrivate(QItemModelBarDataMapping *q)
+ : QAbstractDataMappingPrivate(q, QAbstractDataProxy::DataTypeBar),
+ m_useModelCategories(false),
+ m_autoRowCategories(true),
+ m_autoColumnCategories(true)
+{
+}
+
+QItemModelBarDataMappingPrivate::~QItemModelBarDataMappingPrivate()
+{
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
diff --git a/src/datavisualization/data/qitemmodelbardatamapping.h b/src/datavisualization/data/qitemmodelbardatamapping.h
new file mode 100644
index 00000000..a5ef33b8
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardatamapping.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELBARDATAMAPPING_H
+#define QITEMMODELBARDATAMAPPING_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/qabstractdatamapping.h>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelBarDataMappingPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataMapping : public QAbstractDataMapping
+{
+ Q_OBJECT
+ Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole)
+ Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole)
+ Q_PROPERTY(QString valueRole READ valueRole WRITE setValueRole)
+ Q_PROPERTY(QStringList rowCategories READ rowCategories WRITE setRowCategories)
+ Q_PROPERTY(QStringList columnCategories READ columnCategories WRITE setColumnCategories)
+ Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories)
+ Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories)
+ Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories)
+
+public:
+ explicit QItemModelBarDataMapping(QObject *parent = 0);
+ QItemModelBarDataMapping(const QString &valueRole, QObject *parent = 0);
+ QItemModelBarDataMapping(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, QObject *parent = 0);
+ QItemModelBarDataMapping(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, const QStringList &rowCategories,
+ const QStringList &columnCategories, QObject *parent = 0);
+ virtual ~QItemModelBarDataMapping();
+
+ void setRowRole(const QString &role);
+ QString rowRole() const;
+ void setColumnRole(const QString &role);
+ QString columnRole() const;
+ void setValueRole(const QString &role);
+ QString valueRole() const;
+
+ void setRowCategories(const QStringList &categories);
+ QStringList rowCategories() const;
+ void setColumnCategories(const QStringList &categories);
+ QStringList columnCategories() const;
+
+ void setUseModelCategories(bool enable);
+ bool useModelCategories() const;
+ void setAutoRowCategories(bool enable);
+ bool autoRowCategories() const;
+ void setAutoColumnCategories(bool enable);
+ bool autoColumnCategories() const;
+
+ void remap(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, const QStringList &rowCategories,
+ const QStringList &columnCategories);
+
+ Q_INVOKABLE int rowCategoryIndex(const QString& category);
+ Q_INVOKABLE int columnCategoryIndex(const QString& category);
+
+protected:
+ QItemModelBarDataMappingPrivate *dptr();
+ const QItemModelBarDataMappingPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelBarDataMapping)
+
+ friend class BarItemModelHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelbardatamapping_p.h b/src/datavisualization/data/qitemmodelbardatamapping_p.h
new file mode 100644
index 00000000..90a17fdb
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardatamapping_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "qitemmodelbardatamapping.h"
+#include "qabstractdatamapping_p.h"
+
+#ifndef QITEMMODELBARDATAMAPPING_P_H
+#define QITEMMODELBARDATAMAPPING_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelBarDataMappingPrivate : public QAbstractDataMappingPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelBarDataMappingPrivate(QItemModelBarDataMapping *q);
+ virtual ~QItemModelBarDataMappingPrivate();
+
+private:
+ QString m_rowRole;
+ QString m_columnRole;
+ QString m_valueRole;
+
+ // For row/column items, sort items into these categories. Other categories are ignored.
+ QStringList m_rowCategories;
+ QStringList m_columnCategories;
+
+ bool m_useModelCategories;
+ bool m_autoRowCategories;
+ bool m_autoColumnCategories;
+
+ friend class QItemModelBarDataMapping;
+ friend class BarItemModelHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelbardataproxy.cpp b/src/datavisualization/data/qitemmodelbardataproxy.cpp
new file mode 100644
index 00000000..b0fa74b6
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardataproxy.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelbardataproxy_p.h"
+#include "baritemmodelhandler_p.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QItemModelBarDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Proxy class for presenting data in item models with Q3DBars.
+ * \since 1.0.0
+ *
+ * QItemModelBarDataProxy allows you to use QAbstractItemModel derived models as a data source
+ * for Q3DBars. It uses QItemModelBarDataMapping instance to map data from the model to Q3DBars
+ * graph.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * \sa QItemModelBarDataMapping, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype ItemModelBarDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelBarDataProxy
+ * \inherits BarDataProxy
+ * \brief Proxy class for presenting data in item models with Bars3D.
+ *
+ * This type allows you to use AbstractItemModel derived models as a data source for Bars3D.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 7
+ *
+ * \sa BarDataProxy, BarDataMapping, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty list ItemModelBarDataProxy::itemModel
+ * The item model.
+ */
+
+/*!
+ * \qmlproperty list ItemModelBarDataProxy::activeMapping
+ * The active mapping. Modifying a mapping that is set to the proxy will trigger data set
+ * re-resolving.
+ */
+
+/*!
+ * Constructs QItemModelBarDataProxy.
+ */
+QItemModelBarDataProxy::QItemModelBarDataProxy() :
+ QBarDataProxy(new QItemModelBarDataProxyPrivate(this))
+{
+}
+
+/*!
+ * Constructs QItemModelBarDataProxy with \a itemModel and \a mapping. Proxy takes ownership of the
+ * \a mapping, but doesn't take ownership of the \a itemModel, as typically item models are owned
+ * by other controls.
+ */
+QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelBarDataMapping *mapping) :
+ QBarDataProxy(new QItemModelBarDataProxyPrivate(this))
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+/*!
+ * Destroys QItemModelBarDataProxy.
+ */
+QItemModelBarDataProxy::~QItemModelBarDataProxy()
+{
+}
+
+/*!
+ * \property QItemModelBarDataProxy::itemModel
+ *
+ * Defines item model. Does not take ownership of the model, but does connect to it to listen for
+ * changes.
+ */
+void QItemModelBarDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+}
+
+const QAbstractItemModel *QItemModelBarDataProxy::itemModel() const
+{
+ return dptrc()->m_itemModelHandler->itemModel();
+}
+
+/*!
+ * \property QItemModelBarDataProxy::activeMapping
+ *
+ * Defines data mapping. Proxy takes ownership of the \a mapping.
+ * Modifying a mapping that is set to the proxy will trigger data set re-resolving.
+ */
+void QItemModelBarDataProxy::setActiveMapping(QItemModelBarDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+QItemModelBarDataMapping *QItemModelBarDataProxy::activeMapping() const
+{
+ return static_cast<QItemModelBarDataMapping *>(dptrc()->m_itemModelHandler->activeMapping());
+}
+
+/*!
+ * Transfers the ownership of the \a mapping to this proxy. The mapping is not taken to use yet.
+ * \sa setActiveMapping(), releaseMapping()
+ */
+void QItemModelBarDataProxy::addMapping(QItemModelBarDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->addMapping(mapping);
+}
+
+/*!
+ * Releases the ownership of the \a mapping back to the caller. If the mapping was the currently
+ * active one, no mapping remains active after this call.
+ */
+void QItemModelBarDataProxy::releaseMapping(QItemModelBarDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->releaseMapping(mapping);
+}
+
+/*!
+ * \return list of mappings owned by the proxy.
+ */
+QList<QItemModelBarDataMapping *> QItemModelBarDataProxy::mappings() const
+{
+ QList<QItemModelBarDataMapping *> retList;
+ QList<QAbstractDataMapping *> abstractList = dptrc()->m_itemModelHandler->mappings();
+ foreach (QAbstractDataMapping *mapping, abstractList)
+ retList.append(static_cast<QItemModelBarDataMapping *>(mapping));
+
+ return retList;
+}
+
+/*!
+ * \internal
+ */
+QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptr()
+{
+ return static_cast<QItemModelBarDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptrc() const
+{
+ return static_cast<const QItemModelBarDataProxyPrivate *>(d_ptr.data());
+}
+
+// QItemModelBarDataProxyPrivate
+
+QItemModelBarDataProxyPrivate::QItemModelBarDataProxyPrivate(QItemModelBarDataProxy *q)
+ : QBarDataProxyPrivate(q),
+ m_itemModelHandler(new BarItemModelHandler(q))
+{
+}
+
+QItemModelBarDataProxyPrivate::~QItemModelBarDataProxyPrivate()
+{
+ delete m_itemModelHandler;
+}
+
+QItemModelBarDataProxy *QItemModelBarDataProxyPrivate::qptr()
+{
+ return static_cast<QItemModelBarDataProxy *>(q_ptr);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qitemmodelbardataproxy.h b/src/datavisualization/data/qitemmodelbardataproxy.h
new file mode 100644
index 00000000..2a96f0c8
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardataproxy.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELBARDATAPROXY_H
+#define QITEMMODELBARDATAPROXY_H
+
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QtDataVisualization/qitemmodelbardatamapping.h>
+#include <QAbstractItemModel>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelBarDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataProxy : public QBarDataProxy
+{
+ Q_OBJECT
+ Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel)
+ Q_PROPERTY(QItemModelBarDataMapping* activeMapping READ activeMapping WRITE setActiveMapping)
+
+public:
+ explicit QItemModelBarDataProxy();
+ explicit QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelBarDataMapping *mapping);
+ virtual ~QItemModelBarDataProxy();
+
+ void setItemModel(const QAbstractItemModel *itemModel);
+ const QAbstractItemModel *itemModel() const;
+
+ void setActiveMapping(QItemModelBarDataMapping *mapping);
+ QItemModelBarDataMapping *activeMapping() const;
+ void addMapping(QItemModelBarDataMapping *mapping);
+ void releaseMapping(QItemModelBarDataMapping *mapping);
+ QList<QItemModelBarDataMapping *> mappings() const;
+
+protected:
+ QItemModelBarDataProxyPrivate *dptr();
+ const QItemModelBarDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelBarDataProxy)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelbardataproxy_p.h b/src/datavisualization/data/qitemmodelbardataproxy_p.h
new file mode 100644
index 00000000..fc646f0d
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelbardataproxy_p.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELBARDATAPROXY_P_H
+#define QITEMMODELBARDATAPROXY_P_H
+
+#include "qitemmodelbardataproxy.h"
+#include "qbardataproxy_p.h"
+#include <QPointer>
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class BarItemModelHandler;
+
+class QItemModelBarDataProxyPrivate : public QBarDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelBarDataProxyPrivate(QItemModelBarDataProxy *q);
+ virtual ~QItemModelBarDataProxyPrivate();
+
+private:
+ QItemModelBarDataProxy *qptr();
+
+ BarItemModelHandler *m_itemModelHandler;
+
+ friend class QItemModelBarDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelscatterdatamapping.cpp b/src/datavisualization/data/qitemmodelscatterdatamapping.cpp
new file mode 100644
index 00000000..f9ef6d04
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdatamapping.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelscatterdatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QItemModelScatterDataMapping
+ * \inmodule QtDataVisualization
+ * \brief Item model mapping for Q3DScatter.
+ * \since 1.0.0
+ *
+ * QItemModelScatterDataMapping is used to map roles of QAbstractItemModel to the XYZ-values
+ * of Q3DScatter points.
+ *
+ * QItemModelScatterDataMapping ignores rows and columns of the QAbstractItemModel and treats
+ * all items equally. It requires the model to provide at least three roles for the data items
+ * that can be mapped to X, Y, and Z-values for the scatter points.
+ *
+ * For example, assume that you have a custom QAbstractItemModel for storing various measurements
+ * done on material samples, providing data for roles such as "density", "hardness" and
+ * "conductivity". You could visualize these properties on a scatter graph:
+ *
+ * \snippet doc_src_qtdatavisualization.cpp 4
+ *
+ * \sa QItemModelScatterDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype ScatterDataMapping
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelScatterDataMapping
+ * \brief Item model mapping for Scatter3D.
+ *
+ * This type is used to map roles of AbstractItemModel to the XYZ-values of Scatter3D points. For
+ * more complete description, see QItemModelScatterDataMapping.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 5
+ *
+ * \sa ItemModelScatterDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty string ScatterDataMapping::xPosRole
+ * The X position role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string ScatterDataMapping::yPosRole
+ * The Y position role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string ScatterDataMapping::zPosRole
+ * The Z position role of the mapping.
+ */
+
+/*!
+ * Constructs QItemModelScatterDataMapping with the given \a parent.
+ */
+QItemModelScatterDataMapping::QItemModelScatterDataMapping(QObject *parent)
+ : QAbstractDataMapping(new QItemModelScatterDataMappingPrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QItemModelScatterDataMapping with \a xPosRole, \a yPosRole, \a zPosRole
+ * and the given \a parent.
+ */
+QItemModelScatterDataMapping::QItemModelScatterDataMapping(const QString &xPosRole,
+ const QString &yPosRole,
+ const QString &zPosRole,
+ QObject *parent)
+ : QAbstractDataMapping(new QItemModelScatterDataMappingPrivate(this), parent)
+{
+ dptr()->m_xPosRole = xPosRole;
+ dptr()->m_yPosRole = yPosRole;
+ dptr()->m_zPosRole = zPosRole;
+}
+
+/*!
+ * Destroys QItemModelScatterDataMapping.
+ */
+QItemModelScatterDataMapping::~QItemModelScatterDataMapping()
+{
+}
+
+/*!
+ * \property QItemModelScatterDataMapping::xPosRole
+ *
+ * Defines the X position role for the mapping.
+ */
+void QItemModelScatterDataMapping::setXPosRole(const QString &role)
+{
+ dptr()->m_xPosRole = role;
+ emit mappingChanged();
+}
+
+QString QItemModelScatterDataMapping::xPosRole() const
+{
+ return dptrc()->m_xPosRole;
+}
+
+/*!
+ * \property QItemModelScatterDataMapping::yPosRole
+ *
+ * Defines the Y position role for the mapping.
+ */
+void QItemModelScatterDataMapping::setYPosRole(const QString &role)
+{
+ dptr()->m_yPosRole = role;
+ emit mappingChanged();
+}
+
+QString QItemModelScatterDataMapping::yPosRole() const
+{
+ return dptrc()->m_yPosRole;
+}
+
+/*!
+ * \property QItemModelScatterDataMapping::zPosRole
+ *
+ * Defines the Z position role for the mapping.
+ */
+void QItemModelScatterDataMapping::setZPosRole(const QString &role)
+{
+ dptr()->m_zPosRole = role;
+ emit mappingChanged();
+}
+
+QString QItemModelScatterDataMapping::zPosRole() const
+{
+ return dptrc()->m_zPosRole;
+}
+
+/*!
+ * Changes \a xPosRole, \a yPosRole and \a zPosRole to the mapping.
+ *
+ * Emits mappingChanged() signal after remapping.
+ */
+void QItemModelScatterDataMapping::remap(const QString &xPosRole, const QString &yPosRole,
+ const QString &zPosRole)
+{
+ dptr()->m_xPosRole = xPosRole;
+ dptr()->m_yPosRole = yPosRole;
+ dptr()->m_zPosRole = zPosRole;
+
+ emit mappingChanged();
+}
+
+/*!
+ * \internal
+ */
+QItemModelScatterDataMappingPrivate *QItemModelScatterDataMapping::dptr()
+{
+ return static_cast<QItemModelScatterDataMappingPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelScatterDataMappingPrivate *QItemModelScatterDataMapping::dptrc() const
+{
+ return static_cast<const QItemModelScatterDataMappingPrivate *>(d_ptr.data());
+}
+
+// QItemModelScatterDataMappingPrivate
+
+QItemModelScatterDataMappingPrivate::QItemModelScatterDataMappingPrivate(
+ QItemModelScatterDataMapping *q)
+ : QAbstractDataMappingPrivate(q, QAbstractDataProxy::DataTypeScatter)
+{
+}
+
+QItemModelScatterDataMappingPrivate::~QItemModelScatterDataMappingPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
diff --git a/src/datavisualization/data/qitemmodelscatterdatamapping.h b/src/datavisualization/data/qitemmodelscatterdatamapping.h
new file mode 100644
index 00000000..62f2fefc
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdatamapping.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSCATTERDATAMAPPING_H
+#define QITEMMODELSCATTERDATAMAPPING_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/qabstractdatamapping.h>
+#include <QObject>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelScatterDataMappingPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelScatterDataMapping : public QAbstractDataMapping
+{
+ Q_OBJECT
+ Q_PROPERTY(QString xPosRole READ xPosRole WRITE setXPosRole)
+ Q_PROPERTY(QString yPosRole READ yPosRole WRITE setYPosRole)
+ Q_PROPERTY(QString zPosRole READ zPosRole WRITE setZPosRole)
+
+public:
+ explicit QItemModelScatterDataMapping(QObject *parent = 0);
+ QItemModelScatterDataMapping(const QString &xPosRole, const QString &yPosRole,
+ const QString &zPosRole, QObject *parent = 0);
+ virtual ~QItemModelScatterDataMapping();
+
+ void setXPosRole(const QString &role);
+ QString xPosRole() const;
+ void setYPosRole(const QString &role);
+ QString yPosRole() const;
+ void setZPosRole(const QString &role);
+ QString zPosRole() const;
+
+ void remap(const QString &xPosRole, const QString &yPosRole, const QString &zPosRole);
+
+protected:
+ QItemModelScatterDataMappingPrivate *dptr();
+ const QItemModelScatterDataMappingPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelScatterDataMapping)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelscatterdatamapping_p.h b/src/datavisualization/data/qitemmodelscatterdatamapping_p.h
new file mode 100644
index 00000000..62ff42b4
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdatamapping_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSCATTERDATAMAPPING_P_H
+#define QITEMMODELSCATTERDATAMAPPING_P_H
+
+#include "qitemmodelscatterdatamapping.h"
+#include "qabstractdatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelScatterDataMappingPrivate : public QAbstractDataMappingPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelScatterDataMappingPrivate(QItemModelScatterDataMapping *q);
+ virtual ~QItemModelScatterDataMappingPrivate();
+
+private:
+ //QString m_labelRole;
+ QString m_xPosRole;
+ QString m_yPosRole;
+ QString m_zPosRole;
+ //QString m_valueRole;
+
+ friend class QItemModelScatterDataMapping;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.cpp b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp
new file mode 100644
index 00000000..b037d4d1
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelscatterdataproxy_p.h"
+#include "scatteritemmodelhandler_p.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QItemModelScatterDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Proxy class for presenting data in item models with Q3DScatter.
+ * \since 1.0.0
+ *
+ * QItemModelScatterDataProxy allows you to use QAbstractItemModel derived models as a data source
+ * for Q3DScatter. It maps roles defined in QItemModelScatterDataMapping to roles in the model.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QScatterDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * /sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype ItemModelScatterDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelScatterDataProxy
+ * \inherits ScatterDataProxy
+ * \brief Proxy class for presenting data in item models with Scatter3D.
+ *
+ * This type allows you to use AbstractItemModel derived models as a data source for Scatter3D.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QScatterDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 8
+ *
+ * \sa ScatterDataProxy, ScatterDataMapping, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty list ItemModelScatterDataProxy::itemModel
+ * The item model.
+ */
+
+/*!
+ * \qmlproperty list ItemModelScatterDataProxy::activeMapping
+ * The active mapping. Modifying a mapping that is set to the proxy will trigger data set
+ * re-resolving.
+ */
+
+/*!
+ * Constructs QItemModelScatterDataProxy.
+ */
+QItemModelScatterDataProxy::QItemModelScatterDataProxy() :
+ QScatterDataProxy(new QItemModelScatterDataProxyPrivate(this))
+{
+}
+
+/*!
+ * Constructs QItemModelScatterDataProxy with \a itemModel and \a mapping. Does not take ownership
+ * of the model or the mapping, but does connect to them to listen for changes.
+ */
+QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelScatterDataMapping *mapping) :
+ QScatterDataProxy(new QItemModelScatterDataProxyPrivate(this))
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+/*!
+ * Destroys QItemModelScatterDataProxy.
+ */
+QItemModelScatterDataProxy::~QItemModelScatterDataProxy()
+{
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::itemModel
+ *
+ * Defines item model. Does not take ownership of the model, but does connect to it to listen for
+ * changes.
+ */
+void QItemModelScatterDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+}
+
+const QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const
+{
+ return dptrc()->m_itemModelHandler->itemModel();
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::activeMapping
+ *
+ * Defines data mapping. Proxy takes ownership of the \a mapping.
+ * Modifying a mapping that is set to the proxy will trigger data set re-resolving.
+ */
+void QItemModelScatterDataProxy::setActiveMapping(QItemModelScatterDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+QItemModelScatterDataMapping *QItemModelScatterDataProxy::activeMapping() const
+{
+ return static_cast<QItemModelScatterDataMapping *>(dptrc()->m_itemModelHandler->activeMapping());
+}
+
+/*!
+ * Transfers the ownership of the \a mapping to this proxy. The mapping is not taken to use yet.
+ * \sa setActiveMapping(), releaseMapping()
+ */
+void QItemModelScatterDataProxy::addMapping(QItemModelScatterDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->addMapping(mapping);
+}
+
+/*!
+ * Releases the ownership of the \a mapping back to the caller. If the mapping was the currently
+ * active one, no mapping remains active after this call.
+ */
+void QItemModelScatterDataProxy::releaseMapping(QItemModelScatterDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->releaseMapping(mapping);
+}
+
+/*!
+ * \return list of mappings owned by the proxy.
+ */
+QList<QItemModelScatterDataMapping *> QItemModelScatterDataProxy::mappings() const
+{
+ QList<QItemModelScatterDataMapping *> retList;
+ QList<QAbstractDataMapping *> abstractList = dptrc()->m_itemModelHandler->mappings();
+ foreach (QAbstractDataMapping *mapping, abstractList)
+ retList.append(static_cast<QItemModelScatterDataMapping *>(mapping));
+
+ return retList;
+}
+
+/*!
+ * \internal
+ */
+QItemModelScatterDataProxyPrivate *QItemModelScatterDataProxy::dptr()
+{
+ return static_cast<QItemModelScatterDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelScatterDataProxyPrivate *QItemModelScatterDataProxy::dptrc() const
+{
+ return static_cast<const QItemModelScatterDataProxyPrivate *>(d_ptr.data());
+}
+
+// QItemModelScatterDataProxyPrivate
+
+QItemModelScatterDataProxyPrivate::QItemModelScatterDataProxyPrivate(QItemModelScatterDataProxy *q)
+ : QScatterDataProxyPrivate(q),
+ m_itemModelHandler(new ScatterItemModelHandler(q))
+{
+}
+
+QItemModelScatterDataProxyPrivate::~QItemModelScatterDataProxyPrivate()
+{
+ delete m_itemModelHandler;
+}
+
+QItemModelScatterDataProxy *QItemModelScatterDataProxyPrivate::qptr()
+{
+ return static_cast<QItemModelScatterDataProxy *>(q_ptr);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.h b/src/datavisualization/data/qitemmodelscatterdataproxy.h
new file mode 100644
index 00000000..891950c1
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSCATTERDATAPROXY_H
+#define QITEMMODELSCATTERDATAPROXY_H
+
+#include <QtDataVisualization/qscatterdataproxy.h>
+#include <QtDataVisualization/qitemmodelscatterdatamapping.h>
+#include <QAbstractItemModel>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelScatterDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelScatterDataProxy : public QScatterDataProxy
+{
+ Q_OBJECT
+ Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel)
+ Q_PROPERTY(QItemModelScatterDataMapping* activeMapping READ activeMapping WRITE setActiveMapping)
+
+public:
+ explicit QItemModelScatterDataProxy();
+ explicit QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelScatterDataMapping *mapping);
+ virtual ~QItemModelScatterDataProxy();
+
+ void setItemModel(const QAbstractItemModel *itemModel);
+ const QAbstractItemModel *itemModel() const;
+
+ void setActiveMapping(QItemModelScatterDataMapping *mapping);
+ QItemModelScatterDataMapping *activeMapping() const;
+ void addMapping(QItemModelScatterDataMapping *mapping);
+ void releaseMapping(QItemModelScatterDataMapping *mapping);
+ QList<QItemModelScatterDataMapping *> mappings() const;
+
+protected:
+ QItemModelScatterDataProxyPrivate *dptr();
+ const QItemModelScatterDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelScatterDataProxy)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy_p.h b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h
new file mode 100644
index 00000000..854062a3
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSCATTERDATAPROXY_P_H
+#define QITEMMODELSCATTERDATAPROXY_P_H
+
+#include "qitemmodelscatterdataproxy.h"
+#include "qscatterdataproxy_p.h"
+#include <QPointer>
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ScatterItemModelHandler;
+
+class QItemModelScatterDataProxyPrivate : public QScatterDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelScatterDataProxyPrivate(QItemModelScatterDataProxy *q);
+ virtual ~QItemModelScatterDataProxyPrivate();
+
+private:
+ QItemModelScatterDataProxy *qptr();
+
+ ScatterItemModelHandler *m_itemModelHandler;
+
+ friend class QItemModelScatterDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelsurfacedatamapping.cpp b/src/datavisualization/data/qitemmodelsurfacedatamapping.cpp
new file mode 100644
index 00000000..5388ec18
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedatamapping.cpp
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelsurfacedatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QItemModelSurfaceDataMapping
+ * \inmodule QtDataVisualization
+ * \brief Item model mapping for Q3DSurface.
+ * \since 1.0.0
+ *
+ * QItemModelSurfaceDataMapping is used to map roles of QAbstractItemModel to rows, columns, and values
+ * of Q3DSurface. There are three ways to use QItemModelSurfaceDataMapping:
+ *
+ * 1) If useModelCategories property is set to true, QItemModelSurfaceDataMapping will map rows and
+ * columns of QAbstractItemModel to rows and columns of Q3DSurface, and uses the value returned for
+ * Qt::DisplayRole as bar value by default.
+ * The value role to be used can be redefined if Qt::DisplayRole is not suitable.
+ *
+ * 2) For models that do not have data already neatly sorted into rows and columns, such as
+ * QAbstractListModel based models, you can define a role from the model to map for each of row,
+ * column and value.
+ *
+ * 3) If you do not want to include all data contained in the model, or the autogenerated rows and
+ * columns are not ordered as you wish, you can specify which rows and columns should be included
+ * and in which order by defining an explicit list of categories for either or both of rows and
+ * columns.
+ *
+ * For example, assume that you have a custom QAbstractItemModel storing surface topography data.
+ * Each item in the model has roles "longitude", "latitude" and "height". The item model already
+ * contains the data properly sorted so that longitudes and latitudes are first encountered in
+ * correct order, which enables us to utilize the row and column category autogeneration.
+ * You could do the following to display the data in a surface graph:
+ *
+ * \snippet doc_src_qtdatavisualization.cpp 5
+ *
+ * \sa QItemModelSurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype SurfaceDataMapping
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelSurfaceDataMapping
+ * \brief Item model mapping for Surface3D.
+ *
+ * This type is used to map roles of AbstractItemModel to rows, columns, and values of Surface3D.
+ * For more complete description, see QItemModelSurfaceDataMapping.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 6
+ *
+ * \sa ItemModelSurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty string SurfaceDataMapping::rowRole
+ * The row role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string SurfaceDataMapping::columnRole
+ * The column role of the mapping.
+ */
+
+/*!
+ * \qmlproperty string SurfaceDataMapping::valueRole
+ * The value role of the mapping.
+ */
+
+/*!
+ * \qmlproperty list SurfaceDataMapping::rowCategories
+ * The row categories of the mapping. Only items with row roles that are found in this list are
+ * included when data is resolved. The rows are ordered in the same order as they are in this list.
+ */
+
+/*!
+ * \qmlproperty list SurfaceDataMapping::columnCategories
+ * The column categories of the mapping. Only items with column roles that are found in this list are
+ * included when data is resolved. The columns are ordered in the same order as they are in this list.
+ */
+
+/*!
+ * \qmlproperty list SurfaceDataMapping::useModelCategories
+ * When set to true, the mapping ignores row and column roles and categories, and uses
+ * the rows and columns from the model instead. Defaults to false.
+ */
+
+/*!
+ * \qmlproperty list SurfaceDataMapping::autoRowCategories
+ * When set to true, the mapping ignores any explicitly set row categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Proxy minimum and maximum row values are also
+ * autogenerated from data when this is set to true. Defaults to true.
+ */
+
+/*!
+ * \qmlproperty list SurfaceDataMapping::autoColumnCategories
+ * When set to true, the mapping ignores any explicitly set column categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Proxy minimum and maximum column values are also
+ * autogenerated from data when this is set to true. Defaults to true.
+ */
+
+/*!
+ * Constructs QItemModelSurfaceDataMapping with the given \a parent.
+ */
+QItemModelSurfaceDataMapping::QItemModelSurfaceDataMapping(QObject *parent)
+ : QAbstractDataMapping(new QItemModelSurfaceDataMappingPrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QItemModelSurfaceDataMapping with \a valueRole and the given \a parent.
+ * This constructor is meant to be used with models that have data properly sorted
+ * in rows and columns already, so it also sets useModelCategories property to true.
+ */
+QItemModelSurfaceDataMapping::QItemModelSurfaceDataMapping(const QString &valueRole, QObject *parent)
+ : QAbstractDataMapping(new QItemModelSurfaceDataMappingPrivate(this), parent)
+{
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_useModelCategories = true;
+}
+
+/*!
+ * Constructs QItemModelSurfaceDataMapping with \a rowRole, \a columnRole, \a valueRole
+ * and the given \a parent.
+ */
+QItemModelSurfaceDataMapping::QItemModelSurfaceDataMapping(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ QObject *parent)
+ : QAbstractDataMapping(new QItemModelSurfaceDataMappingPrivate(this), parent)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+}
+
+/*!
+ * Constructs QItemModelSurfaceDataMapping with \a rowRole, \a columnRole, \a valueRole,
+ * \a rowCategories, \a columnCategories and the given \a parent. This constructor
+ * also sets autoRowCategories and autoColumnCategories to false.
+ */
+QItemModelSurfaceDataMapping::QItemModelSurfaceDataMapping(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories,
+ QObject *parent)
+ : QAbstractDataMapping(new QItemModelSurfaceDataMappingPrivate(this), parent)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_rowCategories = rowCategories;
+ dptr()->m_columnCategories = columnCategories;
+ dptr()->m_autoRowCategories = false;
+ dptr()->m_autoColumnCategories = false;
+}
+
+/*!
+ * Destroys QItemModelSurfaceDataMapping.
+ */
+QItemModelSurfaceDataMapping::~QItemModelSurfaceDataMapping()
+{
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::rowRole
+ *
+ * Defines the row role for the mapping.
+ */
+void QItemModelSurfaceDataMapping::setRowRole(const QString &role)
+{
+ if (dptr()->m_rowRole != role) {
+ dptr()->m_rowRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelSurfaceDataMapping::rowRole() const
+{
+ return dptrc()->m_rowRole;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::columnRole
+ *
+ * Defines the column role for the mapping.
+ */
+void QItemModelSurfaceDataMapping::setColumnRole(const QString &role)
+{
+ if (dptr()->m_columnRole != role) {
+ dptr()->m_columnRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelSurfaceDataMapping::columnRole() const
+{
+ return dptrc()->m_columnRole;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::valueRole
+ *
+ * Defines the value role for the mapping.
+ */
+void QItemModelSurfaceDataMapping::setValueRole(const QString &role)
+{
+ if (dptr()->m_valueRole != role) {
+ dptr()->m_valueRole = role;
+ emit mappingChanged();
+ }
+}
+
+QString QItemModelSurfaceDataMapping::valueRole() const
+{
+ return dptrc()->m_valueRole;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::rowCategories
+ *
+ * Defines the row categories for the mapping.
+ */
+void QItemModelSurfaceDataMapping::setRowCategories(const QStringList &categories)
+{
+ if (dptr()->m_rowCategories != categories) {
+ dptr()->m_rowCategories = categories;
+ emit mappingChanged();
+ }
+}
+
+QStringList QItemModelSurfaceDataMapping::rowCategories() const
+{
+ return dptrc()->m_rowCategories;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::columnCategories
+ *
+ * Defines the column categories for the mapping.
+ */
+void QItemModelSurfaceDataMapping::setColumnCategories(const QStringList &categories)
+{
+ if (dptr()->m_columnCategories != categories) {
+ dptr()->m_columnCategories = categories;
+ emit mappingChanged();
+ }
+}
+
+QStringList QItemModelSurfaceDataMapping::columnCategories() const
+{
+ return dptrc()->m_columnCategories;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::useModelCategories
+ *
+ * When set to true, the mapping ignores row and column roles and categories, and uses
+ * the rows and columns from the model instead. Defaults to false.
+ */
+void QItemModelSurfaceDataMapping::setUseModelCategories(bool enable)
+{
+ if (dptr()->m_useModelCategories != enable) {
+ dptr()->m_useModelCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelSurfaceDataMapping::useModelCategories() const
+{
+ return dptrc()->m_useModelCategories;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::autoRowCategories
+ *
+ * When set to true, the mapping ignores any explicitly set row categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Proxy minimum and maximum row values are also
+ * autogenerated from data when this is set to true. Defaults to true.
+ */
+void QItemModelSurfaceDataMapping::setAutoRowCategories(bool enable)
+{
+ if (dptr()->m_autoRowCategories != enable) {
+ dptr()->m_autoRowCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelSurfaceDataMapping::autoRowCategories() const
+{
+ return dptrc()->m_autoRowCategories;
+}
+
+/*!
+ * \property QItemModelSurfaceDataMapping::autoColumnCategories
+ *
+ * When set to true, the mapping ignores any explicitly set column categories
+ * and overwrites them with automatically generated ones whenever the
+ * data from model is resolved. Proxy minimum and maximum column values are also
+ * autogenerated from data when this is set to true. Defaults to true.
+ */
+void QItemModelSurfaceDataMapping::setAutoColumnCategories(bool enable)
+{
+ if (dptr()->m_autoColumnCategories != enable) {
+ dptr()->m_autoColumnCategories = enable;
+ emit mappingChanged();
+ }
+}
+
+bool QItemModelSurfaceDataMapping::autoColumnCategories() const
+{
+ return dptrc()->m_autoColumnCategories;
+}
+
+/*!
+ * Changes \a rowRole, \a columnRole, \a valueRole, \a rowCategories and \a columnCategories to the
+ * mapping.
+ */
+void QItemModelSurfaceDataMapping::remap(const QString &rowRole,
+ const QString &columnRole,
+ const QString &valueRole,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories)
+{
+ dptr()->m_rowRole = rowRole;
+ dptr()->m_columnRole = columnRole;
+ dptr()->m_valueRole = valueRole;
+ dptr()->m_rowCategories = rowCategories;
+ dptr()->m_columnCategories = columnCategories;
+
+ emit mappingChanged();
+}
+
+/*!
+ * /return index of the specified \a category in row categories list.
+ * If the row categories list is empty, -1 is returned.
+ * \note If the automatic row categories generation is in use, this method will
+ * not return valid index before the data in the model is resolved for the first time.
+ */
+int QItemModelSurfaceDataMapping::rowCategoryIndex(const QString &category)
+{
+ return dptr()->m_rowCategories.indexOf(category);
+}
+
+/*!
+ * /return index of the specified \a category in column categories list.
+ * \note If the automatic column categories generation is in use, this method will
+ * not return valid index before the data in the model is resolved for the first time.
+ */
+int QItemModelSurfaceDataMapping::columnCategoryIndex(const QString &category)
+{
+ return dptr()->m_columnCategories.indexOf(category);
+}
+
+/*!
+ * \internal
+ */
+QItemModelSurfaceDataMappingPrivate *QItemModelSurfaceDataMapping::dptr()
+{
+ return static_cast<QItemModelSurfaceDataMappingPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelSurfaceDataMappingPrivate *QItemModelSurfaceDataMapping::dptrc() const
+{
+ return static_cast<const QItemModelSurfaceDataMappingPrivate *>(d_ptr.data());
+}
+
+// QItemModelSurfaceDataMappingPrivate
+
+QItemModelSurfaceDataMappingPrivate::QItemModelSurfaceDataMappingPrivate(QItemModelSurfaceDataMapping *q)
+ : QAbstractDataMappingPrivate(q, QAbstractDataProxy::DataTypeSurface),
+ m_useModelCategories(false),
+ m_autoRowCategories(true),
+ m_autoColumnCategories(true)
+{
+}
+
+QItemModelSurfaceDataMappingPrivate::~QItemModelSurfaceDataMappingPrivate()
+{
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
diff --git a/src/datavisualization/data/qitemmodelsurfacedatamapping.h b/src/datavisualization/data/qitemmodelsurfacedatamapping.h
new file mode 100644
index 00000000..7e8817bf
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedatamapping.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSURFACEDATAMAPPING_H
+#define QITEMMODELSURFACEDATAMAPPING_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/qabstractdatamapping.h>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelSurfaceDataMappingPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataMapping : public QAbstractDataMapping
+{
+ Q_OBJECT
+ Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole)
+ Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole)
+ Q_PROPERTY(QString valueRole READ valueRole WRITE setValueRole)
+ Q_PROPERTY(QStringList rowCategories READ rowCategories WRITE setRowCategories)
+ Q_PROPERTY(QStringList columnCategories READ columnCategories WRITE setColumnCategories)
+ Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories)
+ Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories)
+ Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories)
+
+public:
+ explicit QItemModelSurfaceDataMapping(QObject *parent = 0);
+ QItemModelSurfaceDataMapping(const QString &valueRole, QObject *parent = 0);
+ QItemModelSurfaceDataMapping(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, QObject *parent = 0);
+ QItemModelSurfaceDataMapping(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, const QStringList &rowCategories,
+ const QStringList &columnCategories, QObject *parent = 0);
+ virtual ~QItemModelSurfaceDataMapping();
+
+ void setRowRole(const QString &role);
+ QString rowRole() const;
+ void setColumnRole(const QString &role);
+ QString columnRole() const;
+ void setValueRole(const QString &role);
+ QString valueRole() const;
+
+ void setRowCategories(const QStringList &categories);
+ QStringList rowCategories() const;
+ void setColumnCategories(const QStringList &categories);
+ QStringList columnCategories() const;
+
+ void setUseModelCategories(bool enable);
+ bool useModelCategories() const;
+ void setAutoRowCategories(bool enable);
+ bool autoRowCategories() const;
+ void setAutoColumnCategories(bool enable);
+ bool autoColumnCategories() const;
+
+ void remap(const QString &rowRole, const QString &columnRole,
+ const QString &valueRole, const QStringList &rowCategories,
+ const QStringList &columnCategories);
+
+ Q_INVOKABLE int rowCategoryIndex(const QString& category);
+ Q_INVOKABLE int columnCategoryIndex(const QString& category);
+
+protected:
+ QItemModelSurfaceDataMappingPrivate *dptr();
+ const QItemModelSurfaceDataMappingPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelSurfaceDataMapping)
+
+ friend class SurfaceItemModelHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelsurfacedatamapping_p.h b/src/datavisualization/data/qitemmodelsurfacedatamapping_p.h
new file mode 100644
index 00000000..9896f868
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedatamapping_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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.
+
+#include "qitemmodelsurfacedatamapping.h"
+#include "qabstractdatamapping_p.h"
+
+#ifndef QITEMMODELSURFACEDATAMAPPING_P_H
+#define QITEMMODELSURFACEDATAMAPPING_P_H
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelSurfaceDataMappingPrivate : public QAbstractDataMappingPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelSurfaceDataMappingPrivate(QItemModelSurfaceDataMapping *q);
+ virtual ~QItemModelSurfaceDataMappingPrivate();
+
+private:
+ QString m_rowRole;
+ QString m_columnRole;
+ QString m_valueRole;
+
+ // For row/column items, sort items into these categories. Other categories are ignored.
+ QStringList m_rowCategories;
+ QStringList m_columnCategories;
+
+ bool m_useModelCategories;
+ bool m_autoRowCategories;
+ bool m_autoColumnCategories;
+
+ friend class QItemModelSurfaceDataMapping;
+ friend class SurfaceItemModelHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp
new file mode 100644
index 00000000..f6403e9b
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qitemmodelsurfacedataproxy_p.h"
+#include "surfaceitemmodelhandler_p.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+// TODO: CHECK DOCUMENTATION!
+
+/*!
+ * \class QItemModelSurfaceDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Proxy class for presenting data in item models with Q3DSurface.
+ * \since 1.0.0
+ *
+ * QItemModelSurfaceDataProxy allows you to use QAbstractItemModel derived models as a data source
+ * for Q3DSurface. It maps roles defined in QItemModelSurfaceDataMapping to roles in the model.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * /sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype ItemModelSurfaceDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QItemModelSurfaceDataProxy
+ * \inherits SurfaceDataProxy
+ * \brief Proxy class for presenting data in item models with Surface3D.
+ *
+ * This type allows you to use AbstractItemModel derived models as a data source for Surface3D.
+ *
+ * Data is resolved asynchronously whenever the mapping or the model changes.
+ * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved.
+ *
+ * Usage example:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 9
+ *
+ * \sa SurfaceDataProxy, SurfaceDataMapping, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty list ItemModelSurfaceDataProxy::itemModel
+ * The item model.
+ */
+
+/*!
+ * \qmlproperty list ItemModelSurfaceDataProxy::activeMapping
+ * The active mapping. Modifying a mapping that is set to the proxy will trigger data set
+ * re-resolving.
+ */
+
+/*!
+ * Constructs QItemModelSurfaceDataProxy.
+ */
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy() :
+ QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this))
+{
+}
+
+/*!
+ * Constructs QItemModelSurfaceDataProxy with \a itemModel and \a mapping. Does not take ownership
+ * of the model or the mapping, but does connect to them to listen for changes.
+ */
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelSurfaceDataMapping *mapping) :
+ QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this))
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+/*!
+ * Destroys QItemModelSurfaceDataProxy.
+ */
+QItemModelSurfaceDataProxy::~QItemModelSurfaceDataProxy()
+{
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::itemModel
+ *
+ * Defines item model. Does not take ownership of the model, but does connect to it to listen for
+ * changes.
+ */
+void QItemModelSurfaceDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+{
+ dptr()->m_itemModelHandler->setItemModel(itemModel);
+}
+
+const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const
+{
+ return dptrc()->m_itemModelHandler->itemModel();
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::activeMapping
+ *
+ * Defines data mapping. Proxy takes ownership of the \a mapping.
+ * Modifying a mapping that is set to the proxy will trigger data set re-resolving.
+ */
+void QItemModelSurfaceDataProxy::setActiveMapping(QItemModelSurfaceDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->setActiveMapping(mapping);
+}
+
+QItemModelSurfaceDataMapping *QItemModelSurfaceDataProxy::activeMapping() const
+{
+ return static_cast<QItemModelSurfaceDataMapping *>(dptrc()->m_itemModelHandler->activeMapping());
+}
+
+/*!
+ * Transfers the ownership of the \a mapping to this proxy. The mapping is not taken to use yet.
+ * \sa setActiveMapping(), releaseMapping()
+ */
+void QItemModelSurfaceDataProxy::addMapping(QItemModelSurfaceDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->addMapping(mapping);
+}
+
+/*!
+ * Releases the ownership of the \a mapping back to the caller. If the mapping was the currently
+ * active one, no mapping remains active after this call.
+ */
+void QItemModelSurfaceDataProxy::releaseMapping(QItemModelSurfaceDataMapping *mapping)
+{
+ dptr()->m_itemModelHandler->releaseMapping(mapping);
+}
+
+/*!
+ * \return list of mappings owned by the proxy.
+ */
+QList<QItemModelSurfaceDataMapping *> QItemModelSurfaceDataProxy::mappings() const
+{
+ QList<QItemModelSurfaceDataMapping *> retList;
+ QList<QAbstractDataMapping *> abstractList = dptrc()->m_itemModelHandler->mappings();
+ foreach (QAbstractDataMapping *mapping, abstractList)
+ retList.append(static_cast<QItemModelSurfaceDataMapping *>(mapping));
+
+ return retList;
+}
+
+/*!
+ * \internal
+ */
+QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptr()
+{
+ return static_cast<QItemModelSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptrc() const
+{
+ return static_cast<const QItemModelSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+// QItemModelSurfaceDataProxyPrivate
+
+QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelSurfaceDataProxy *q)
+ : QSurfaceDataProxyPrivate(q),
+ m_itemModelHandler(new SurfaceItemModelHandler(q))
+{
+}
+
+QItemModelSurfaceDataProxyPrivate::~QItemModelSurfaceDataProxyPrivate()
+{
+ delete m_itemModelHandler;
+}
+
+QItemModelSurfaceDataProxy *QItemModelSurfaceDataProxyPrivate::qptr()
+{
+ return static_cast<QItemModelSurfaceDataProxy *>(q_ptr);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.h b/src/datavisualization/data/qitemmodelsurfacedataproxy.h
new file mode 100644
index 00000000..080bf54b
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSURFACEDATAPROXY_H
+#define QITEMMODELSURFACEDATAPROXY_H
+
+#include <QtDataVisualization/qsurfacedataproxy.h>
+#include <QtDataVisualization/qitemmodelsurfacedatamapping.h>
+#include <QAbstractItemModel>
+#include <QStringList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QItemModelSurfaceDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataProxy : public QSurfaceDataProxy
+{
+ Q_OBJECT
+ Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel)
+ Q_PROPERTY(QItemModelSurfaceDataMapping* activeMapping READ activeMapping WRITE setActiveMapping)
+
+public:
+ explicit QItemModelSurfaceDataProxy();
+ explicit QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelSurfaceDataMapping *mapping);
+ virtual ~QItemModelSurfaceDataProxy();
+
+ void setItemModel(const QAbstractItemModel *itemModel);
+ const QAbstractItemModel *itemModel() const;
+
+ void setActiveMapping(QItemModelSurfaceDataMapping *mapping);
+ QItemModelSurfaceDataMapping *activeMapping() const;
+ void addMapping(QItemModelSurfaceDataMapping *mapping);
+ void releaseMapping(QItemModelSurfaceDataMapping *mapping);
+ QList<QItemModelSurfaceDataMapping *> mappings() const;
+
+protected:
+ QItemModelSurfaceDataProxyPrivate *dptr();
+ const QItemModelSurfaceDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QItemModelSurfaceDataProxy)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h
new file mode 100644
index 00000000..ff9d13de
--- /dev/null
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QITEMMODELSURFACEDATAPROXY_P_H
+#define QITEMMODELSURFACEDATAPROXY_P_H
+
+#include "qitemmodelsurfacedataproxy.h"
+#include "qsurfacedataproxy_p.h"
+#include <QPointer>
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class SurfaceItemModelHandler;
+
+class QItemModelSurfaceDataProxyPrivate : public QSurfaceDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QItemModelSurfaceDataProxyPrivate(QItemModelSurfaceDataProxy *q);
+ virtual ~QItemModelSurfaceDataProxyPrivate();
+
+private:
+ QItemModelSurfaceDataProxy *qptr();
+
+ SurfaceItemModelHandler *m_itemModelHandler;
+
+ friend class QItemModelSurfaceDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qscatterdataitem.cpp b/src/datavisualization/data/qscatterdataitem.cpp
new file mode 100644
index 00000000..055a9dad
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataitem.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qscatterdataitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QScatterDataItem
+ * \inmodule QtDataVisualization
+ * \brief The QScatterDataItem class provides a container for resolved data to be added to scatter
+ * graphs.
+ * \since 1.0.0
+ *
+ * A QScatterDataItem holds data for a single rendered item in a scatter graph.
+ * Scatter data proxies parse data into QScatterDataItem instances for visualizing.
+ *
+ * \sa QScatterDataProxy, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs QScatterDataItem.
+ */
+QScatterDataItem::QScatterDataItem()
+ : d_ptr(0) // private data doesn't exist by default (optimization)
+
+{
+}
+
+/*!
+ * Constructs QScatterDataItem with \a position.
+ */
+QScatterDataItem::QScatterDataItem(const QVector3D &position)
+ : d_ptr(0),
+ m_position(position)
+{
+}
+
+/*!
+ * Constructs a copy of \a other.
+ */
+QScatterDataItem::QScatterDataItem(const QScatterDataItem &other)
+{
+ operator=(other);
+}
+
+/*!
+ * Destroys QScatterDataItem.
+ */
+QScatterDataItem::~QScatterDataItem()
+{
+}
+
+/*!
+ * Assigns a copy of \a other to this object.
+ */
+QScatterDataItem &QScatterDataItem::operator=(const QScatterDataItem &other)
+{
+ m_position = other.m_position;
+ //m_size = other.m_size;
+
+ if (other.d_ptr)
+ createExtraData();
+ else
+ d_ptr = 0;
+ // TODO set extra data
+
+ return *this;
+}
+
+/*!
+ * \fn void QScatterDataItem::setPosition(const QVector3D &position)
+ * Sets \a position to this data item.
+ */
+
+/*!
+ * \fn QVector3D QScatterDataItem::position() const
+ * \return position of this data item.
+ */
+
+/*!
+ * \fn void QScatterDataItem::setX(float value)
+ * Sets the X component of the item position to the \a value.
+ */
+
+/*!
+ * \fn void QScatterDataItem::setY(float value)
+ * Sets the Y component of the item position to the \a value.
+ */
+
+/*!
+ * \fn void QScatterDataItem::setZ(float value)
+ * Sets the Z component of the item position to the \a value.
+ */
+
+/*!
+ * \fn float QScatterDataItem::x() const
+ * \return the X component of the position of this data item.
+ */
+
+/*!
+ * \fn float QScatterDataItem::y() const
+ * \return the Y component of the position of this data item.
+ */
+
+/*!
+ * \fn float QScatterDataItem::z() const
+ * \return the Z component of the position of this data item.
+ */
+
+//void QScatterDataItem::setSize(qreal size)
+//{
+// m_size = size;
+//}
+
+//const qreal &QScatterDataItem::size() const
+//{
+// return m_size;
+//}
+
+/*!
+ * \internal
+ */
+void QScatterDataItem::createExtraData()
+{
+ if (!d_ptr)
+ d_ptr = new QScatterDataItemPrivate;
+}
+
+QScatterDataItemPrivate::QScatterDataItemPrivate()
+{
+}
+
+QScatterDataItemPrivate::~QScatterDataItemPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qscatterdataitem.h b/src/datavisualization/data/qscatterdataitem.h
new file mode 100644
index 00000000..29154259
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataitem.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSCATTERDATAITEM_H
+#define QSCATTERDATAITEM_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QScatterDataItemPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QScatterDataItem
+{
+public:
+ QScatterDataItem();
+ QScatterDataItem(const QVector3D &position);
+ QScatterDataItem(const QScatterDataItem &other);
+ ~QScatterDataItem();
+
+ QScatterDataItem &operator=(const QScatterDataItem &other);
+
+ inline void setPosition(const QVector3D &position) { m_position = position; }
+ inline QVector3D position() const { return m_position; }
+ inline void setX(float value) { m_position.setX(value); }
+ inline void setY(float value) { m_position.setY(value); }
+ inline void setZ(float value) { m_position.setZ(value); }
+ inline float x() const { return m_position.x(); }
+ inline float y() const { return m_position.y(); }
+ inline float z() const { return m_position.z(); }
+
+ //void setSize(qreal size);
+ //qreal size() const;
+
+protected:
+ virtual void createExtraData();
+
+ QScatterDataItemPrivate *d_ptr;
+
+private:
+ QVector3D m_position;
+ //qreal m_size;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qscatterdataitem_p.h b/src/datavisualization/data/qscatterdataitem_p.h
new file mode 100644
index 00000000..acc67347
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataitem_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSCATTERDATAITEM_P_H
+#define QSCATTERDATAITEM_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qscatterdataitem.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QScatterDataItemPrivate
+{
+public:
+ QScatterDataItemPrivate();
+ virtual ~QScatterDataItemPrivate();
+
+ // TODO stores other data for scatter items besides position
+
+protected:
+ friend class QScatterDataItem;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qscatterdataproxy.cpp b/src/datavisualization/data/qscatterdataproxy.cpp
new file mode 100644
index 00000000..4d83da8d
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataproxy.cpp
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qscatterdataproxy.h"
+#include "qscatterdataproxy_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QScatterDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Base proxy class for Q3DScatter.
+ * \since 1.0.0
+ *
+ * QScatterDataProxy handles adding, inserting, changing and removing data items.
+ *
+ * QScatterDataProxy takes ownership of all QScatterDataArrays and QScatterDataItems passed to it.
+ *
+ * QScatterDataProxy supports the following format tags for QAbstractDataProxy::setItemLabelFormat():
+ * \table
+ * \row
+ * \li @xTitle \li Title from X axis
+ * \row
+ * \li @yTitle \li Title from Y axis
+ * \row
+ * \li @zTitle \li Title from Z axis
+ * \row
+ * \li @xLabel \li Item value formatted using the same format the X axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \row
+ * \li @yLabel \li Item value formatted using the same format the Y axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \row
+ * \li @zLabel \li Item value formatted using the same format the Z axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \endtable
+ *
+ * For example:
+ * \snippet doc_src_qtdatavisualization.cpp 2
+ *
+ * /sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype ScatterDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QScatterDataProxy
+ * \inherits AbstractDataProxy
+ * \brief Base proxy class for Scatter3D.
+ *
+ * This type handles adding, inserting, changing and removing data items.
+ *
+ * This type is uncreatable, but contains properties that are exposed via subtypes.
+ *
+ * For more complete description, see QScatterDataProxy.
+ *
+ * \sa ItemModelScatterDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty int ScatterDataProxy::itemCount
+ * Item count in the array.
+ */
+
+/*!
+ * Constructs QScatterDataProxy with the given \a parent.
+ */
+QScatterDataProxy::QScatterDataProxy(QObject *parent) :
+ QAbstractDataProxy(new QScatterDataProxyPrivate(this), parent)
+{
+}
+
+/*!
+ * \internal
+ */
+QScatterDataProxy::QScatterDataProxy(QScatterDataProxyPrivate *d, QObject *parent) :
+ QAbstractDataProxy(d, parent)
+{
+}
+
+/*!
+ * Destroys QScatterDataProxy.
+ */
+QScatterDataProxy::~QScatterDataProxy()
+{
+}
+
+/*!
+ * Takes ownership of the \a newArray. Clears the existing array and if the \a newArray is
+ * different than the existing array. If it's the same array, this just triggers arrayReset()
+ * signal.
+ * Passing null array deletes the old array and creates a new empty array.
+ */
+void QScatterDataProxy::resetArray(QScatterDataArray *newArray)
+{
+ if (dptr()->m_dataArray != newArray)
+ dptr()->resetArray(newArray);
+
+ emit arrayReset();
+}
+
+/*!
+ * Changes a single item at \a index with \a item.
+ */
+void QScatterDataProxy::setItem(int index, const QScatterDataItem &item)
+{
+ dptr()->setItem(index, item);
+ emit itemsChanged(index, 1);
+}
+
+/*!
+ * Changes items starting from \a index with \a items.
+ */
+void QScatterDataProxy::setItems(int index, const QScatterDataArray &items)
+{
+ dptr()->setItems(index, items);
+ emit itemsChanged(index, items.size());
+}
+
+/*!
+ * Adds a single \a item to the end of the array.
+ *
+ * \return index of the added item.
+ */
+int QScatterDataProxy::addItem(const QScatterDataItem &item)
+{
+ int addIndex = dptr()->addItem(item);
+ emit itemsAdded(addIndex, 1);
+ return addIndex;
+}
+
+/*!
+ * Adds \a items to the end of the array.
+ *
+ * \return index of the first added item.
+ */
+int QScatterDataProxy::addItems(const QScatterDataArray &items)
+{
+ int addIndex = dptr()->addItems(items);
+ emit itemsAdded(addIndex, items.size());
+ return addIndex;
+}
+
+/*!
+ * Inserts a single \a item to \a index. If index is equal to data array size, item is added to
+ * the array.
+ */
+void QScatterDataProxy::insertItem(int index, const QScatterDataItem &item)
+{
+ dptr()->insertItem(index, item);
+ emit itemsInserted(index, 1);
+}
+
+/*!
+ * Inserts \a items to \a index. If index is equal to data array size, items are added to the array.
+ */
+void QScatterDataProxy::insertItems(int index, const QScatterDataArray &items)
+{
+ dptr()->insertItems(index, items);
+ emit itemsInserted(index, items.size());
+}
+
+/*!
+ * Removes \a removeCount items starting from \a index. Attempting to remove items past the end of
+ * the array does nothing.
+ */
+void QScatterDataProxy::removeItems(int index, int removeCount)
+{
+ dptr()->removeItems(index, removeCount);
+ emit itemsRemoved(index, removeCount);
+}
+
+/*!
+ * \property QScatterDataProxy::itemCount
+ *
+ * \return item count in the array.
+ */
+int QScatterDataProxy::itemCount() const
+{
+ return dptrc()->m_dataArray->size();
+}
+
+/*!
+ * \return pointer to the data array.
+ */
+const QScatterDataArray *QScatterDataProxy::array() const
+{
+ return dptrc()->m_dataArray;
+}
+
+/*!
+ * \return pointer to the item at \a index. It is guaranteed to be valid only until next call
+ * that modifies data.
+ */
+const QScatterDataItem *QScatterDataProxy::itemAt(int index) const
+{
+ return &dptrc()->m_dataArray->at(index);
+}
+
+/*!
+ * \internal
+ */
+QScatterDataProxyPrivate *QScatterDataProxy::dptr()
+{
+ return static_cast<QScatterDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QScatterDataProxyPrivate *QScatterDataProxy::dptrc() const
+{
+ return static_cast<const QScatterDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \fn void QScatterDataProxy::arrayReset()
+ *
+ * Emitted when data array is reset.
+ * If you change the whole array contents without calling resetArray(), you need to
+ * emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QScatterDataProxy::itemsAdded(int startIndex, int count)
+ *
+ * Emitted when items have been added. Provides \a startIndex and \a count of items added.
+ * If you add items directly to the array without calling addItem() or addItems(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QScatterDataProxy::itemsChanged(int startIndex, int count)
+ *
+ * Emitted when items have changed. Provides \a startIndex and \a count of changed items.
+ * If you change items directly in the array without calling setItem() or setItems(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QScatterDataProxy::itemsRemoved(int startIndex, int count)
+ *
+ * Emitted when items have been removed. Provides \a startIndex and \a count of items removed.
+ * Index may be over current array size if removed from end.
+ * If you remove items directly from the array without calling removeItems(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+/*!
+ * \fn void QScatterDataProxy::itemsInserted(int startIndex, int count)
+ *
+ * Emitted when items have been inserted. Provides \a startIndex and \a count of inserted items.
+ * If you insert items directly into the array without calling insertItem() or insertItems(), you
+ * need to emit this signal yourself or the graph won't get updated.
+ */
+
+// QScatterDataProxyPrivate
+
+QScatterDataProxyPrivate::QScatterDataProxyPrivate(QScatterDataProxy *q)
+ : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeScatter),
+ m_dataArray(new QScatterDataArray)
+{
+ m_itemLabelFormat = QStringLiteral("(@xLabel, @yLabel, @zLabel)");
+}
+
+QScatterDataProxyPrivate::~QScatterDataProxyPrivate()
+{
+ m_dataArray->clear();
+ delete m_dataArray;
+}
+
+void QScatterDataProxyPrivate::resetArray(QScatterDataArray *newArray)
+{
+ if (!newArray)
+ newArray = new QScatterDataArray;
+
+ if (newArray != m_dataArray) {
+ m_dataArray->clear();
+ delete m_dataArray;
+ m_dataArray = newArray;
+ }
+}
+
+void QScatterDataProxyPrivate::setItem(int index, const QScatterDataItem &item)
+{
+ Q_ASSERT(index >= 0 && index < m_dataArray->size());
+ (*m_dataArray)[index] = item;
+}
+
+void QScatterDataProxyPrivate::setItems(int index, const QScatterDataArray &items)
+{
+ Q_ASSERT(index >= 0 && (index + items.size()) <= m_dataArray->size());
+ for (int i = 0; i < items.size(); i++)
+ (*m_dataArray)[index++] = items[i];
+}
+
+int QScatterDataProxyPrivate::addItem(const QScatterDataItem &item)
+{
+ int currentSize = m_dataArray->size();
+ m_dataArray->append(item);
+ return currentSize;
+}
+
+int QScatterDataProxyPrivate::addItems(const QScatterDataArray &items)
+{
+ int currentSize = m_dataArray->size();
+ (*m_dataArray) += items;
+ return currentSize;
+}
+
+void QScatterDataProxyPrivate::insertItem(int index, const QScatterDataItem &item)
+{
+ Q_ASSERT(index >= 0 && index <= m_dataArray->size());
+ m_dataArray->insert(index, item);
+}
+
+void QScatterDataProxyPrivate::insertItems(int index, const QScatterDataArray &items)
+{
+ Q_ASSERT(index >= 0 && index <= m_dataArray->size());
+ for (int i = 0; i < items.size(); i++)
+ m_dataArray->insert(index++, items.at(i));
+}
+
+void QScatterDataProxyPrivate::removeItems(int index, int removeCount)
+{
+ Q_ASSERT(index >= 0);
+ int maxRemoveCount = m_dataArray->size() - index;
+ removeCount = qMin(removeCount, maxRemoveCount);
+ m_dataArray->remove(index, removeCount);
+}
+
+QVector3D QScatterDataProxyPrivate::limitValues()
+{
+ QVector3D limits;
+ for (int i = 0; i < m_dataArray->size(); i++) {
+ const QScatterDataItem &item = m_dataArray->at(i);
+ float xValue = qAbs(item.position().x());
+ if (limits.x() < xValue)
+ limits.setX(xValue);
+ float yValue = qAbs(item.position().y());
+ if (limits.y() < yValue)
+ limits.setY(yValue);
+ float zValue = qAbs(item.position().z());
+ if (limits.z() < zValue)
+ limits.setZ(zValue);
+ }
+ return limits;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qscatterdataproxy.h b/src/datavisualization/data/qscatterdataproxy.h
new file mode 100644
index 00000000..178bc900
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataproxy.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSCATTERDATAPROXY_H
+#define QSCATTERDATAPROXY_H
+
+#include <QtDataVisualization/qabstractdataproxy.h>
+#include <QtDataVisualization/qscatterdataitem.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+typedef QVector<QScatterDataItem> QScatterDataArray;
+
+class QScatterDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QScatterDataProxy : public QAbstractDataProxy
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int itemCount READ itemCount)
+
+public:
+ explicit QScatterDataProxy(QObject *parent = 0);
+ virtual ~QScatterDataProxy();
+
+ // TODO: Replace first part of class description in docs with this once all TODOs are done:
+ /*
+ * QScatterDataProxy handles adding, inserting, changing and removing data items.
+ * QScatterDataProxy is optimized to use cases where the only defining characteristics of an
+ * individual scatter item are it's position and size. Modifying other data that might be
+ * added in the future such as color requires allocating additional data object for the bar.
+ */
+
+ int itemCount() const;
+ const QScatterDataArray *array() const;
+ const QScatterDataItem *itemAt(int index) const;
+
+ void resetArray(QScatterDataArray *newArray);
+
+ void setItem(int index, const QScatterDataItem &item);
+ void setItems(int index, const QScatterDataArray &items);
+
+ int addItem(const QScatterDataItem &item);
+ int addItems(const QScatterDataArray &items);
+
+ void insertItem(int index, const QScatterDataItem &item);
+ void insertItems(int index, const QScatterDataArray &items);
+
+ void removeItems(int index, int removeCount);
+
+signals:
+ void arrayReset();
+ void itemsAdded(int startIndex, int count);
+ void itemsChanged(int startIndex, int count);
+ void itemsRemoved(int startIndex, int count);
+ void itemsInserted(int startIndex, int count);
+
+protected:
+ explicit QScatterDataProxy(QScatterDataProxyPrivate *d, QObject *parent = 0);
+ QScatterDataProxyPrivate *dptr();
+ const QScatterDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QScatterDataProxy)
+
+ friend class Scatter3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qscatterdataproxy_p.h b/src/datavisualization/data/qscatterdataproxy_p.h
new file mode 100644
index 00000000..9920e3a7
--- /dev/null
+++ b/src/datavisualization/data/qscatterdataproxy_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSCATTERDATAPROXY_P_H
+#define QSCATTERDATAPROXY_P_H
+
+#include "qscatterdataproxy.h"
+#include "qabstractdataproxy_p.h"
+#include "qscatterdataitem.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QScatterDataProxyPrivate : public QAbstractDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QScatterDataProxyPrivate(QScatterDataProxy *q);
+ virtual ~QScatterDataProxyPrivate();
+
+ void resetArray(QScatterDataArray *newArray);
+ void setItem(int index, const QScatterDataItem &item);
+ void setItems(int index, const QScatterDataArray &items);
+ int addItem(const QScatterDataItem &item);
+ int addItems(const QScatterDataArray &items);
+ void insertItem(int index, const QScatterDataItem &item);
+ void insertItems(int index, const QScatterDataArray &items);
+ void removeItems(int index, int removeCount);
+
+ QVector3D limitValues();
+
+private:
+ QScatterDataArray *m_dataArray;
+
+ friend class QScatterDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QBARDATAPROXY_P_H
diff --git a/src/datavisualization/data/qsurfacedataitem.cpp b/src/datavisualization/data/qsurfacedataitem.cpp
new file mode 100644
index 00000000..19f8f347
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataitem.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qsurfacedataitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QSurfaceDataItem
+ * \inmodule QtDataVisualization
+ * \brief The QSurfaceDataItem class provides a container for resolved data to be added to surface
+ * graphs.
+ * \since 1.0.0
+ *
+ * A QSurfaceDataItem holds data for a single vertex in surface graph.
+ * Surface data proxies parse data into QSurfaceDataItem instances for visualizing.
+ *
+ * \sa QSurfaceDataProxy, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs QSurfaceDataItem.
+ */
+QSurfaceDataItem::QSurfaceDataItem()
+ : d_ptr(0) // private data doesn't exist by default (optimization)
+
+{
+}
+
+/*!
+ * Constructs QSurfaceDataItem with \a position.
+ */
+QSurfaceDataItem::QSurfaceDataItem(const QVector3D &position)
+ : d_ptr(0),
+ m_position(position)
+{
+}
+
+/*!
+ * Constructs a copy of \a other.
+ */
+QSurfaceDataItem::QSurfaceDataItem(const QSurfaceDataItem &other)
+{
+ operator=(other);
+}
+
+/*!
+ * Destroys QSurfaceDataItem.
+ */
+QSurfaceDataItem::~QSurfaceDataItem()
+{
+}
+
+/*!
+ * Assigns a copy of \a other to this object.
+ */
+QSurfaceDataItem &QSurfaceDataItem::operator=(const QSurfaceDataItem &other)
+{
+ m_position = other.m_position;
+ //m_size = other.m_size;
+
+ if (other.d_ptr)
+ createExtraData();
+ else
+ d_ptr = 0;
+ // TODO set extra data
+
+ return *this;
+}
+
+/*!
+ * \fn void QSurfaceDataItem::setPosition(const QVector3D &position)
+ * Sets \a position to this data item.
+ */
+
+/*!
+ * \fn QVector3D QSurfaceDataItem::position() const
+ * \return position of this data item.
+ */
+
+/*!
+ * \fn void QSurfaceDataItem::setX(float value)
+ * Sets the X component of the item position to the \a value.
+ */
+
+/*!
+ * \fn void QSurfaceDataItem::setY(float value)
+ * Sets the Y component of the item position to the \a value.
+ */
+
+/*!
+ * \fn void QSurfaceDataItem::setZ(float value)
+ * Sets the Z component of the item position to the \a value.
+ */
+
+/*!
+ * \fn float QSurfaceDataItem::x() const
+ * \return the X component of the position of this data item.
+ */
+
+/*!
+ * \fn float QSurfaceDataItem::y() const
+ * \return the Y component of the position of this data item.
+ */
+
+/*!
+ * \fn float QSurfaceDataItem::z() const
+ * \return the Z component of the position of this data item.
+ */
+
+/*!
+ * \internal
+ */
+void QSurfaceDataItem::createExtraData()
+{
+ if (!d_ptr)
+ d_ptr = new QSurfaceDataItemPrivate;
+}
+
+QSurfaceDataItemPrivate::QSurfaceDataItemPrivate()
+{
+}
+
+QSurfaceDataItemPrivate::~QSurfaceDataItemPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qsurfacedataitem.h b/src/datavisualization/data/qsurfacedataitem.h
new file mode 100644
index 00000000..dbc849d3
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataitem.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSURFACEDATAITEM_H
+#define QSURFACEDATAITEM_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QSurfaceDataItemPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QSurfaceDataItem
+{
+public:
+ QSurfaceDataItem();
+ QSurfaceDataItem(const QVector3D &position);
+ QSurfaceDataItem(const QSurfaceDataItem &other);
+ ~QSurfaceDataItem();
+
+ QSurfaceDataItem &operator=(const QSurfaceDataItem &other);
+
+ inline void setPosition(const QVector3D &position) { m_position = position; }
+ inline QVector3D position() const { return m_position; }
+ inline void setX(float value) { m_position.setX(value); }
+ inline void setY(float value) { m_position.setY(value); }
+ inline void setZ(float value) { m_position.setZ(value); }
+ inline float x() const { return m_position.x(); }
+ inline float y() const { return m_position.y(); }
+ inline float z() const { return m_position.z(); }
+
+protected:
+ virtual void createExtraData();
+
+ QSurfaceDataItemPrivate *d_ptr;
+
+private:
+ QVector3D m_position;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qsurfacedataitem_p.h b/src/datavisualization/data/qsurfacedataitem_p.h
new file mode 100644
index 00000000..d13679a8
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataitem_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSURFACEDATAITEM_P_H
+#define QSURFACEDATAITEM_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qsurfacedataitem.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QSurfaceDataItemPrivate
+{
+public:
+ QSurfaceDataItemPrivate();
+ virtual ~QSurfaceDataItemPrivate();
+
+ // TODO stores other data for surface items besides position
+
+protected:
+ friend class QSurfaceDataItem;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp
new file mode 100644
index 00000000..72f33de7
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataproxy.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qsurfacedataproxy.h"
+#include "qsurfacedataproxy_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class QSurfaceDataProxy
+ * \inmodule QtDataVisualization
+ * \brief Base proxy class for Q3DSurface.
+ * \since 1.0.0
+ *
+ * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the data
+ * in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for
+ * controlling the rows. For rows there is a QVector QSurfaceDataRow which contains QSurfaceDataItem
+ * objects. See Q3DSurface documentation and basic sample code there how to feed the data for the
+ * QSurfaceDataProxy.
+ *
+ * All rows must have same number of items.
+ *
+ * When determining what rows and columns are visible, the first item in each row and the first item in
+ * each column determine if the whole row or column is visible, even if other items in the row or column
+ * individually have different X- or Z-coordinates.
+ *
+ * \note Surfaces with less than two rows or columns are not considered valid surfaces and will
+ * not get rendered.
+ *
+ * QSurfaceDataProxy supports the following format tags for QAbstractDataProxy::setItemLabelFormat():
+ * \table
+ * \row
+ * \li @xTitle \li Title from X axis
+ * \row
+ * \li @yTitle \li Title from Y axis
+ * \row
+ * \li @zTitle \li Title from Z axis
+ * \row
+ * \li @xLabel \li Item value formatted using the same format as the X axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \row
+ * \li @yLabel \li Item value formatted using the same format as the Y axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \row
+ * \li @zLabel \li Item value formatted using the same format as the Z axis attached to the graph uses,
+ * see \l{Q3DValueAxis::setLabelFormat()} for more information.
+ * \endtable
+ *
+ * \sa {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmltype SurfaceDataProxy
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \instantiates QSurfaceDataProxy
+ * \inherits AbstractDataProxy
+ * \brief Base proxy class for Surface3D.
+ *
+ * This type handles surface data items. The data is arranged into rows and columns, and all rows must have
+ * the same number of columns.
+ *
+ * This type is uncreatable, but contains properties that are exposed via subtypes.
+ *
+ * For more complete description, see QSurfaceDataProxy.
+ *
+ * \sa ItemModelSurfaceDataProxy, {Qt Data Visualization Data Handling}
+ */
+
+/*!
+ * \qmlproperty int SurfaceDataProxy::rowCount
+ * Number of the rows in the array.
+ */
+
+/*!
+ * \qmlproperty int SurfaceDataProxy::columnCount
+ * Number of the columns in the array.
+ */
+
+/*!
+ * Constructs QSurfaceDataProxy with the given \a parent.
+ */
+QSurfaceDataProxy::QSurfaceDataProxy(QObject *parent) :
+ QAbstractDataProxy(new QSurfaceDataProxyPrivate(this), parent)
+{
+}
+
+/*!
+ * \internal
+ */
+QSurfaceDataProxy::QSurfaceDataProxy(QSurfaceDataProxyPrivate *d, QObject *parent) :
+ QAbstractDataProxy(d, parent)
+{
+}
+
+/*!
+ * Destroys QSurfaceDataProxy.
+ */
+QSurfaceDataProxy::~QSurfaceDataProxy()
+{
+}
+
+/*!
+ * Takes ownership of the \a newArray. Clears the existing array and if the \a newArray is
+ * different than the existing array. If it's the same array, this just triggers arrayReset()
+ * signal.
+ * Passing null array deletes the old array and creates a new empty array.
+ * All rows in \a newArray must be of same length.
+ */
+void QSurfaceDataProxy::resetArray(QSurfaceDataArray *newArray)
+{
+ if (dptr()->m_dataArray != newArray) {
+ dptr()->resetArray(newArray);
+ }
+ emit arrayReset();
+}
+
+/*!
+ * \return pointer to the data array.
+ */
+const QSurfaceDataArray *QSurfaceDataProxy::array() const
+{
+ return dptrc()->m_dataArray;
+}
+
+/*!
+ * \property QSurfaceDataProxy::rowCount
+ *
+ * \return number of rows in the data.
+ */
+int QSurfaceDataProxy::rowCount() const
+{
+ return dptrc()->m_dataArray->size();
+}
+
+/*!
+ * \property QSurfaceDataProxy::columnCount
+ *
+ * \return number of items in the columns.
+ */
+int QSurfaceDataProxy::columnCount() const
+{
+ if (dptrc()->m_dataArray->size() > 0)
+ return dptrc()->m_dataArray->at(0)->size();
+ else
+ return 0;
+}
+
+/*!
+ * \return pointer to the item at \a index. It is guaranteed to be valid only until next call that
+ * modifies data.
+ */
+const QSurfaceDataItem *QSurfaceDataProxy::itemAt(int index) const
+{
+ return &dptrc()->m_dataArray->at(index)->at(2);
+}
+
+/*!
+ * \internal
+ */
+QSurfaceDataProxyPrivate *QSurfaceDataProxy::dptr()
+{
+ return static_cast<QSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QSurfaceDataProxyPrivate *QSurfaceDataProxy::dptrc() const
+{
+ return static_cast<const QSurfaceDataProxyPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \fn void QSurfaceDataProxy::arrayReset()
+ *
+ * Emitted when data array is reset.
+ * If you change the whole array contents without calling resetArray(), you need to
+ * emit this signal yourself or the graph won't get updated.
+ */
+
+//
+// QSurfaceDataProxyPrivate
+//
+
+QSurfaceDataProxyPrivate::QSurfaceDataProxyPrivate(QSurfaceDataProxy *q)
+ : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeSurface),
+ m_dataArray(new QSurfaceDataArray)
+{
+ m_itemLabelFormat = QStringLiteral("@yLabel (@xLabel, @zLabel)");
+}
+
+QSurfaceDataProxyPrivate::~QSurfaceDataProxyPrivate()
+{
+ clearArray();
+}
+
+void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray *newArray)
+{
+ if (!newArray)
+ newArray = new QSurfaceDataArray;
+
+ if (newArray != m_dataArray) {
+ clearArray();
+ m_dataArray = newArray;
+ }
+}
+
+QSurfaceDataProxy *QSurfaceDataProxyPrivate::qptr()
+{
+ return static_cast<QSurfaceDataProxy *>(q_ptr);
+}
+
+void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxValues)
+{
+ qreal min = 0.0;
+ qreal max = 0.0;
+
+ int rows = m_dataArray->size();
+ int columns = 0;
+ if (rows)
+ columns = m_dataArray->at(0)->size();
+
+ if (rows && columns) {
+ min = m_dataArray->at(0)->at(0).y();
+ max = m_dataArray->at(0)->at(0).y();
+ }
+
+ for (int i = 0; i < rows; i++) {
+ QSurfaceDataRow *row = m_dataArray->at(i);
+ if (row) {
+ for (int j = 0; j < columns; j++) {
+ qreal itemValue = m_dataArray->at(i)->at(j).y();
+ if (min > itemValue)
+ min = itemValue;
+ if (max < itemValue)
+ max = itemValue;
+ }
+ }
+ }
+
+ minValues.setY(min);
+ maxValues.setY(max);
+ if (columns) {
+ minValues.setX(m_dataArray->at(0)->at(0).x());
+ minValues.setZ(m_dataArray->at(0)->at(0).z());
+ maxValues.setX(m_dataArray->at(0)->last().x());
+ maxValues.setZ(m_dataArray->last()->at(0).z());
+ } else {
+ minValues.setX(0.0f);
+ minValues.setZ(0.0f);
+ maxValues.setX(0.0f);
+ maxValues.setZ(0.0f);
+ }
+}
+
+void QSurfaceDataProxyPrivate::clearRow(int rowIndex)
+{
+ if (m_dataArray->at(rowIndex)) {
+ delete m_dataArray->at(rowIndex);
+ (*m_dataArray)[rowIndex] = 0;
+ }
+}
+
+void QSurfaceDataProxyPrivate::clearArray()
+{
+ for (int i = 0; i < m_dataArray->size(); i++)
+ clearRow(i);
+ m_dataArray->clear();
+ delete m_dataArray;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qsurfacedataproxy.h b/src/datavisualization/data/qsurfacedataproxy.h
new file mode 100644
index 00000000..460fa437
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataproxy.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSURFACEDATAPROXY_H
+#define QSURFACEDATAPROXY_H
+
+#include <QtDataVisualization/qabstractdataproxy.h>
+#include <QtDataVisualization/qsurfacedataitem.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+typedef QVector<QSurfaceDataItem> QSurfaceDataRow;
+typedef QList<QSurfaceDataRow *> QSurfaceDataArray;
+
+class QSurfaceDataProxyPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QSurfaceDataProxy : public QAbstractDataProxy
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int rowCount READ rowCount)
+ Q_PROPERTY(int columnCount READ columnCount)
+
+public:
+ explicit QSurfaceDataProxy(QObject *parent = 0);
+ virtual ~QSurfaceDataProxy();
+
+ int rowCount() const;
+ int columnCount() const;
+ const QSurfaceDataArray *array() const;
+ const QSurfaceDataItem *itemAt(int index) const;
+
+ void resetArray(QSurfaceDataArray *newArray);
+
+signals:
+ void arrayReset();
+
+protected:
+ explicit QSurfaceDataProxy(QSurfaceDataProxyPrivate *d, QObject *parent = 0);
+ QSurfaceDataProxyPrivate *dptr();
+ const QSurfaceDataProxyPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QSurfaceDataProxy)
+
+ friend class Surface3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QSURFACEDATAPROXY_H
diff --git a/src/datavisualization/data/qsurfacedataproxy_p.h b/src/datavisualization/data/qsurfacedataproxy_p.h
new file mode 100644
index 00000000..4c8c2820
--- /dev/null
+++ b/src/datavisualization/data/qsurfacedataproxy_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QSURFACEDATAPROXY_P_H
+#define QSURFACEDATAPROXY_P_H
+
+#include "qsurfacedataproxy.h"
+#include "qabstractdataproxy_p.h"
+
+#include <QSize>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QSurfaceDataProxyPrivate : public QAbstractDataProxyPrivate
+{
+ Q_OBJECT
+public:
+ QSurfaceDataProxyPrivate(QSurfaceDataProxy *q);
+ virtual ~QSurfaceDataProxyPrivate();
+
+ void resetArray(QSurfaceDataArray *newArray);
+
+ void limitValues(QVector3D &minValues, QVector3D &maxValues);
+
+protected:
+ QSurfaceDataArray *m_dataArray;
+
+private:
+ QSurfaceDataProxy *qptr();
+ void clearRow(int rowIndex);
+ void clearArray();
+
+ friend class QSurfaceDataProxy;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QSURFACEDATAPROXY_P_H
diff --git a/src/datavisualization/data/scatteritemmodelhandler.cpp b/src/datavisualization/data/scatteritemmodelhandler.cpp
new file mode 100644
index 00000000..34230ae0
--- /dev/null
+++ b/src/datavisualization/data/scatteritemmodelhandler.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "scatteritemmodelhandler_p.h"
+#include <QTimer>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ScatterItemModelHandler::ScatterItemModelHandler(QItemModelScatterDataProxy *proxy, QObject *parent)
+ : AbstractItemModelHandler(parent),
+ m_proxy(proxy),
+ m_proxyArray(0)
+{
+}
+
+ScatterItemModelHandler::~ScatterItemModelHandler()
+{
+}
+
+// Resolve entire item model into QScatterDataArray.
+void ScatterItemModelHandler::resolveModel()
+{
+ QItemModelScatterDataMapping *mapping = static_cast<QItemModelScatterDataMapping *>(m_activeMapping);
+ if (m_itemModel.isNull() || !mapping) {
+ m_proxy->resetArray(0);
+ m_proxyArray = 0;
+ return;
+ }
+
+ static const int noRoleIndex = -1;
+
+ QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
+ const int xPosRole = roleHash.key(mapping->xPosRole().toLatin1(), noRoleIndex);
+ const int yPosRole = roleHash.key(mapping->yPosRole().toLatin1(), noRoleIndex);
+ const int zPosRole = roleHash.key(mapping->zPosRole().toLatin1(), noRoleIndex);
+ const int columnCount = m_itemModel->columnCount();
+ const int rowCount = m_itemModel->rowCount();
+ const int totalCount = rowCount * columnCount;
+ int runningCount = 0;
+
+ // If dimensions have changed, recreate the array
+ if (m_proxyArray != m_proxy->array() || totalCount != m_proxyArray->size())
+ m_proxyArray = new QScatterDataArray(totalCount);
+
+ // Parse data into newProxyArray
+ for (int i = 0; i < rowCount; i++) {
+ for (int j = 0; j < columnCount; j++) {
+ QModelIndex index = m_itemModel->index(i, j);
+ float xPos(0.0f);
+ float yPos(0.0f);
+ float zPos(0.0f);
+ if (xPosRole != noRoleIndex)
+ xPos = index.data(xPosRole).toFloat();
+ if (yPosRole != noRoleIndex)
+ yPos = index.data(yPosRole).toFloat();
+ if (zPosRole != noRoleIndex)
+ zPos = index.data(zPosRole).toFloat();
+ (*m_proxyArray)[runningCount].setPosition(QVector3D(xPos, yPos, zPos));
+ runningCount++;
+ }
+ }
+
+ m_proxy->resetArray(m_proxyArray);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/scatteritemmodelhandler_p.h b/src/datavisualization/data/scatteritemmodelhandler_p.h
new file mode 100644
index 00000000..9b8a19a2
--- /dev/null
+++ b/src/datavisualization/data/scatteritemmodelhandler_p.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SCATTERITEMMODELHANDLER_P_H
+#define SCATTERITEMMODELHANDLER_P_H
+
+#include "abstractitemmodelhandler_p.h"
+#include "qitemmodelscatterdataproxy.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ScatterItemModelHandler : public AbstractItemModelHandler
+{
+ Q_OBJECT
+public:
+ ScatterItemModelHandler(QItemModelScatterDataProxy *proxy, QObject *parent = 0);
+ virtual ~ScatterItemModelHandler();
+
+protected:
+ void virtual resolveModel();
+
+ QItemModelScatterDataProxy *m_proxy; // Not owned
+ QScatterDataArray *m_proxyArray; // Not owned
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/scatterrenderitem.cpp b/src/datavisualization/data/scatterrenderitem.cpp
new file mode 100644
index 00000000..83c66583
--- /dev/null
+++ b/src/datavisualization/data/scatterrenderitem.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "scatterrenderitem_p.h"
+#include "scatter3drenderer_p.h"
+#include "qscatterdataproxy.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ScatterRenderItem::ScatterRenderItem()
+ : AbstractRenderItem(),
+ m_visible(false)
+{
+}
+
+ScatterRenderItem::ScatterRenderItem(const ScatterRenderItem &other)
+ : AbstractRenderItem(other),
+ m_visible(false)
+{
+ m_position = other.m_position;
+}
+
+ScatterRenderItem::~ScatterRenderItem()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/scatterrenderitem_p.h b/src/datavisualization/data/scatterrenderitem_p.h
new file mode 100644
index 00000000..58e91e96
--- /dev/null
+++ b/src/datavisualization/data/scatterrenderitem_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SCATTERRENDERITEM_P_H
+#define SCATTERRENDERITEM_P_H
+
+#include "abstractrenderitem_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Scatter3DRenderer;
+
+class ScatterRenderItem : public AbstractRenderItem
+{
+public:
+ ScatterRenderItem();
+ ScatterRenderItem(const ScatterRenderItem &other);
+ virtual ~ScatterRenderItem();
+
+ inline const QVector3D &position() const { return m_position; }
+ inline void setPosition(const QVector3D &pos);
+
+ inline bool isVisible() const { return m_visible; }
+ inline void setVisible(bool visible) { m_visible = visible; }
+
+ //inline void setSize(qreal size);
+ //inline qreal size() const { return m_size; }
+
+protected:
+ QVector3D m_position;
+ bool m_visible;
+ //qreal m_size; // TODO in case we need a fourth variable that adjusts scatter item size
+
+ friend class QScatterDataItem;
+};
+
+void ScatterRenderItem::setPosition(const QVector3D &pos)
+{
+ if (m_position != pos) {
+ m_position = pos;
+ // Force reformatting on next access by setting label string to null string
+ if (!m_selectionLabel.isNull())
+ setSelectionLabel(QString());
+ }
+}
+
+typedef QVector<ScatterRenderItem> ScatterRenderItemArray;
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/data/surfaceitemmodelhandler.cpp b/src/datavisualization/data/surfaceitemmodelhandler.cpp
new file mode 100644
index 00000000..70482162
--- /dev/null
+++ b/src/datavisualization/data/surfaceitemmodelhandler.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "surfaceitemmodelhandler_p.h"
+#include "qitemmodelsurfacedatamapping_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+SurfaceItemModelHandler::SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent)
+ : AbstractItemModelHandler(parent),
+ m_proxy(proxy),
+ m_proxyArray(0)
+{
+}
+
+SurfaceItemModelHandler::~SurfaceItemModelHandler()
+{
+}
+
+// Resolve entire item model into QSurfaceDataArray.
+void SurfaceItemModelHandler::resolveModel()
+{
+ QItemModelSurfaceDataMapping *mapping = static_cast<QItemModelSurfaceDataMapping *>(m_activeMapping);
+ if (m_itemModel.isNull() || !mapping) {
+ m_proxy->resetArray(0);
+ m_proxyArray = 0;
+ return;
+ }
+
+ if (!mapping->useModelCategories()
+ && (mapping->rowRole().isEmpty() || mapping->columnRole().isEmpty())) {
+ m_proxy->resetArray(0);
+ m_proxyArray = 0;
+ return;
+ }
+
+ QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
+
+ // Default to display role if no mapping
+ int valueRole = roleHash.key(mapping->valueRole().toLatin1(), Qt::DisplayRole);
+ int rowCount = m_itemModel->rowCount();
+ int columnCount = m_itemModel->columnCount();
+
+ if (mapping->useModelCategories()) {
+ // If dimensions have changed, recreate the array
+ if (m_proxyArray != m_proxy->array() || columnCount != m_proxy->columnCount()
+ || rowCount != m_proxyArray->size()) {
+ m_proxyArray = new QSurfaceDataArray;
+ m_proxyArray->reserve(rowCount);
+ for (int i = 0; i < rowCount; i++)
+ m_proxyArray->append(new QSurfaceDataRow(columnCount));
+ }
+ for (int i = 0; i < rowCount; i++) {
+ QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i);
+ for (int j = 0; j < columnCount; j++) {
+ newProxyRow[j].setPosition(
+ QVector3D(m_itemModel->headerData(j, Qt::Horizontal).toFloat(),
+ m_itemModel->index(i, j).data(valueRole).toFloat(),
+ m_itemModel->headerData(i, Qt::Vertical).toFloat()));
+ }
+ }
+ } else {
+ int rowRole = roleHash.key(mapping->rowRole().toLatin1());
+ int columnRole = roleHash.key(mapping->columnRole().toLatin1());
+
+ bool generateRows = mapping->autoRowCategories();
+ bool generateColumns = mapping->autoColumnCategories();
+
+ QStringList rowList;
+ QStringList columnList;
+ // For detecting duplicates in categories generation, using QHashes should be faster than
+ // simple QStringList::contains() check.
+ QHash<QString, bool> rowListHash;
+ QHash<QString, bool> columnListHash;
+
+ // Sort values into rows and columns
+ typedef QHash<QString, qreal> ColumnValueMap;
+ QHash <QString, ColumnValueMap> itemValueMap;
+ for (int i = 0; i < rowCount; i++) {
+ for (int j = 0; j < columnCount; j++) {
+ QModelIndex index = m_itemModel->index(i, j);
+ QString rowRoleStr = index.data(rowRole).toString();
+ QString columnRoleStr = index.data(columnRole).toString();
+ itemValueMap[rowRoleStr][columnRoleStr] = index.data(valueRole).toReal();
+ if (generateRows && !rowListHash.value(rowRoleStr, false)) {
+ rowListHash.insert(rowRoleStr, true);
+ rowList << rowRoleStr;
+ }
+ if (generateColumns && !columnListHash.value(columnRoleStr, false)) {
+ columnListHash.insert(columnRoleStr, true);
+ columnList << columnRoleStr;
+ }
+ }
+ }
+
+ if (generateRows)
+ mapping->dptr()->m_rowCategories = rowList;
+ else
+ rowList = mapping->rowCategories();
+
+ if (generateColumns)
+ mapping->dptr()->m_columnCategories = columnList;
+ else
+ columnList = mapping->columnCategories();
+
+ // If dimensions have changed, recreate the array
+ if (m_proxyArray != m_proxy->array() || columnList.size() != m_proxy->columnCount()
+ || rowList.size() != m_proxyArray->size()) {
+ m_proxyArray = new QSurfaceDataArray;
+ m_proxyArray->reserve(rowList.size());
+ for (int i = 0; i < rowList.size(); i++)
+ m_proxyArray->append(new QSurfaceDataRow(columnList.size()));
+ }
+ // Create data array from itemValueMap
+ for (int i = 0; i < rowList.size(); i++) {
+ QString rowKey = rowList.at(i);
+ QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i);
+ for (int j = 0; j < columnList.size(); j++) {
+ newProxyRow[j].setPosition(QVector3D(columnList.at(j).toFloat(),
+ itemValueMap[rowKey][columnList.at(j)],
+ rowList.at(i).toFloat()));
+ }
+ }
+ }
+
+ m_proxy->resetArray(m_proxyArray);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/surfaceitemmodelhandler_p.h b/src/datavisualization/data/surfaceitemmodelhandler_p.h
new file mode 100644
index 00000000..bcf642c5
--- /dev/null
+++ b/src/datavisualization/data/surfaceitemmodelhandler_p.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SURFACEITEMMODELHANDLER_P_H
+#define SURFACEITEMMODELHANDLER_P_H
+
+#include "abstractitemmodelhandler_p.h"
+#include "qitemmodelsurfacedataproxy.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class SurfaceItemModelHandler : public AbstractItemModelHandler
+{
+ Q_OBJECT
+public:
+ SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent = 0);
+ virtual ~SurfaceItemModelHandler();
+
+protected:
+ void virtual resolveModel();
+
+ QItemModelSurfaceDataProxy *m_proxy; // Not owned
+ QSurfaceDataArray *m_proxyArray; // Not owned
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/datavisualization.pro b/src/datavisualization/datavisualization.pro
new file mode 100644
index 00000000..87857062
--- /dev/null
+++ b/src/datavisualization/datavisualization.pro
@@ -0,0 +1,27 @@
+TARGET = QtDataVisualization
+QT = core gui
+
+DEFINES += QT_DATAVISUALIZATION_LIBRARY
+
+QMAKE_DOCS = $$PWD/doc/qtdatavisualization.qdocconf
+
+load(qt_module)
+
+include($$PWD/common.pri)
+include($$PWD/engine/engine.pri)
+include($$PWD/global/global.pri)
+include($$PWD/utils/utils.pri)
+include($$PWD/axis/axis.pri)
+include($$PWD/data/data.pri)
+include($$PWD/input/input.pri)
+
+android {
+ CONFIG += static
+}
+
+OTHER_FILES += doc/qtdatavisualization.qdocconf \
+ doc/src/* \
+ doc/images/* \
+ doc/snippets/* \
+ global/*.qdoc
+
diff --git a/src/datavisualization/doc/images/q3dbars-minimal.png b/src/datavisualization/doc/images/q3dbars-minimal.png
new file mode 100644
index 00000000..fff8d415
--- /dev/null
+++ b/src/datavisualization/doc/images/q3dbars-minimal.png
Binary files differ
diff --git a/src/datavisualization/doc/images/q3dscatter-minimal.png b/src/datavisualization/doc/images/q3dscatter-minimal.png
new file mode 100644
index 00000000..1c3290b3
--- /dev/null
+++ b/src/datavisualization/doc/images/q3dscatter-minimal.png
Binary files differ
diff --git a/src/datavisualization/doc/images/q3dsurface-minimal.png b/src/datavisualization/doc/images/q3dsurface-minimal.png
new file mode 100644
index 00000000..119cdfb9
--- /dev/null
+++ b/src/datavisualization/doc/images/q3dsurface-minimal.png
Binary files differ
diff --git a/src/datavisualization/doc/qtdatavisualization.qdocconf b/src/datavisualization/doc/qtdatavisualization.qdocconf
new file mode 100644
index 00000000..e3189604
--- /dev/null
+++ b/src/datavisualization/doc/qtdatavisualization.qdocconf
@@ -0,0 +1,51 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+
+project = QtDataVisualization
+description = Qt Data Visualization Reference Documentation
+version = 1.0.0
+
+exampledirs += ../../../examples \
+ snippets
+
+headerdirs += ..
+imagedirs += ../images \
+ images
+sourcedirs += ..
+
+depends += qtcore \
+ qtgui
+
+qhp.projects = qtdatavisualization
+
+qhp.qtdatavisualization.file = qtdatavisualization.qhp
+qhp.qtdatavisualization.namespace = org.qt-project.qtdatavisualization.1.0.0
+qhp.qtdatavisualization.virtualFolder = qtdatavisualization
+qhp.qtdatavisualization.indexTitle = Qt Data Visualization
+qhp.qtdatavisualization.indexRoot =
+
+qhp.qtdatavisualization.filterAttributes = qtdatavisualization 1.0.0 qtrefdoc
+qhp.qtdatavisualization.customFilters.Qt.name = QtDataVisualization 1.0.0
+qhp.qtdatavisualization.customFilters.Qt.filterAttributes = qtdatavisualization 1.0.0
+qhp.qtdatavisualization.subprojects = classes
+qhp.qtdatavisualization.subprojects.classes.title = C++ Classes
+qhp.qtdatavisualization.subprojects.classes.indexTitle = Qt Data Visualization C++ Classes
+qhp.qtdatavisualization.subprojects.classes.selectors = class fake:headerfile
+qhp.qtdatavisualization.subprojects.classes.sortPages = true
+
+
+HTML.footer = \
+ "<div class=\"footer\">\n" \
+ " <p>\n" \
+ " <acronym title=\"Copyright\">&copy;</acronym> 2013 Digia. Qt and Qt logos are\n" \
+ " trademarks of of Digia Corporation in Finland and/or other countries worldwide.\n" \
+ " </p>\n" \
+ " All other trademarks are property of their respective owners.\n" \
+ " <br />\n" \
+ " <p>\n" \
+ " Licensees holding valid Qt Enterprise licenses may use this document in accordance\n" \
+ " with the Qt Enterprise License Agreement provided with the Software or,\n" \
+ " alternatively, in accordance with the terms contained in a written agreement\n" \
+ " between you and Digia.\n" \
+ " </p>\n" \
+ "</div>\n"
+
diff --git a/src/datavisualization/doc/snippets/doc_src_q3dbars_construction.cpp b/src/datavisualization/doc/snippets/doc_src_q3dbars_construction.cpp
new file mode 100644
index 00000000..a5615601
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_q3dbars_construction.cpp
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+//! [3]
+#include <QtDataVisualization>
+
+using namespace QtDataVisualization;
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ //! [4]
+ Q3DBars *bars = new Q3DBars();
+ //! [4]
+ //! [0]
+ bars->rowAxis()->setRange(0, 4);
+ bars->columnAxis()->setRange(0, 4);
+ //! [0]
+ //! [1]
+ QBarDataRow data;
+ data << 1.0 << 3.0 << 7.5 << 5.0 << 2.2;
+ bars->activeDataProxy()->addRow(&data);
+ //! [1]
+ //! [2]
+ bars->show();
+ //! [2]
+
+ return app.exec();
+}
+//! [3]
diff --git a/src/datavisualization/doc/snippets/doc_src_q3dscatter_construction.cpp b/src/datavisualization/doc/snippets/doc_src_q3dscatter_construction.cpp
new file mode 100644
index 00000000..b2f48921
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_q3dscatter_construction.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+//! [3]
+#include <QtDataVisualization>
+
+using namespace QtDataVisualization;
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ //! [0]
+ Q3DScatter *scatter = new Q3DScatter();
+ //! [0]
+ //! [1]
+ QScatterDataArray data;
+ data << QVector3D(1.0f, 0.5f, 1.0f) << QVector3D(-1.0f, -0.5f, -1.0f) << QVector3D(0.5f, 0.0f, 0.0f);
+ scatter->activeDataProxy()->addItems(data);
+ //! [1]
+ //! [2]
+ scatter->show();
+ //! [2]
+
+ return app.exec();
+}
+//! [3]
diff --git a/src/datavisualization/doc/snippets/doc_src_q3dsurface_construction.cpp b/src/datavisualization/doc/snippets/doc_src_q3dsurface_construction.cpp
new file mode 100644
index 00000000..33b6cf37
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_q3dsurface_construction.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+//! [5]
+#include <QtDataVisualization>
+
+using namespace QtDataVisualization;
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ //! [0]
+ Q3DSurface surface;
+ //! [0]
+ //! [1]
+ QSurfaceDataArray *data = new QSurfaceDataArray;
+ QSurfaceDataRow *dataRow = new QSurfaceDataRow;
+ //! [1]
+
+ //! [2]
+ *dataRow << 0.1 << 1.8 << 0.4;
+ *data << dataRow;
+ //! [2]
+
+ //! [3]
+ surface.activeDataProxy()->resetArray(data);
+ //! [3]
+ //! [4]
+ surface.show();
+ //! [4]
+
+ return app.exec();
+}
+//! [5]
diff --git a/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp b/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp
new file mode 100644
index 00000000..f4446e17
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+//! [0]
+import com.digia.QtDataVisualization 1.0
+//! [0]
+
+//! [1]
+Bars3D {
+ rows: 4
+ columns: 4
+ dataProxy: barProxy // an ItemModelBarDataProxy
+ barSpacing: Qt.size(0.5, 0.5)
+ barSpacingRelative: false
+ itemLabelFormat: "@valueTitle for @colLabel, @rowLabel: @valueLabel"
+}
+//! [1]
+
+//! [2]
+Scatter3D {
+ dataProxy: scatterProxy // an ItemModelScatterDataProxy
+ itemLabelFormat: "X:@xLabel Y:@yLabel Z:@zLabel"
+ axisX.segmentCount: 2
+ axisX.subSegmentCount: 2
+ axisX.labelFormat: "%.2f"
+ axisZ.segmentCount: 2
+ axisZ.subSegmentCount: 2
+ axisZ.labelFormat: "%.2f"
+ axisY.segmentCount: 3
+ axisY.subSegmentCount: 2
+ axisY.labelFormat: "%.2f"
+}
+//! [2]
+
+//! [3]
+Surface3D {
+ dataProxy: surfaceProxy // an ItemModelSurfaceDataProxy
+ axisX.min: 0.0
+ axisX.max: 10.0
+ axisZ.min: 0.0
+ axisZ.max: 10.0
+ axisY.min: 0.0
+ axisY.max: 5.0
+ axisX.segmentCount: 5
+ axisX.subSegmentCount: 2
+ axisX.labelFormat: "%i"
+ axisZ.segmentCount: 5
+ axisZ.subSegmentCount: 2
+ axisZ.labelFormat: "%i"
+ axisY.segmentCount: 5
+ axisY.labelFormat: "%.1f"
+}
+//! [3]
+
+//! [4]
+BarDataMapping {
+ id: barMapping
+ rowRole: "year"
+ columnRole: "city"
+ valueRole: "expenses"
+ rowCategories: ["2010", "2011", "2012", "2013"]
+ columnCategories: ["Oulu", "Rauma", "Helsinki", "Tampere"]
+}
+//! [4]
+
+//! [5]
+ScatterDataMapping {
+ id: scatterMapping
+ xPosRole: "xPos"
+ yPosRole: "yPos"
+ zPosRole: "zPos"
+}
+//! [5]
+
+//! [6]
+SurfaceDataMapping {
+ id: surfaceMapping
+ rowRole: "latitude"
+ columnRole: "longitude"
+ valueRole: "population"
+}
+//! [6]
+
+//! [7]
+ItemModelBarDataProxy {
+ id: barProxy
+ activeMapping: barMapping // a BarDataMapping
+ itemModel: dataModel // a ListModel
+}
+//! [7]
+
+//! [8]
+ItemModelScatterDataProxy {
+ id: scatterProxy
+ activeMapping: scatterMapping // a ScatterDataMapping
+ itemModel: dataModel // a ListModel
+}
+//! [8]
+
+//! [9]
+ItemModelSurfaceDataProxy {
+ id: surfaceProxy
+ activeMapping: surfaceMapping // a SurfaceDataMapping
+ itemModel: dataModel // a ListModel
+}
+//! [9]
diff --git a/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.cpp b/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.cpp
new file mode 100644
index 00000000..2f3d6a98
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+//! [0]
+#include <QtDataVisualization>
+
+using namespace QtDataVisualization;
+//! [0]
+
+//! [1]
+proxy->setItemLabelFormat(QStringLiteral("@valueTitle for (@rowLabel, @colLabel): %.1f"));
+//! [1]
+
+//! [2]
+proxy->setItemLabelFormat(QStringLiteral("@xTitle: @xValue, @yTitle: @yValue, @zTitle: @zValue"));
+//! [2]
+
+//! [3]
+// By defining row and column categories, you tell the mapping which row and column each item
+// belongs to. The categories must match the data stored in the model in the roles you define
+// for row and column mapping. In this example we expect "year" role to return four digit year
+// and "month" to return three letter designation for the month.
+//
+// An example of an item in model would be:
+// Requested role -> Returned data
+// "year" -> "2006" // Matches the first row category, so this item is added to the first row.
+// "month" -> "jan" // Matches the first column category, so this item is added as first item in the row.
+// "income" -> "12.1"
+// "expenses" -> "9.2"
+QStringList years;
+QStringList months;
+years << "2006" << "2007" << "2008" << "2009" << "2010" << "2011" << "2012";
+months << "jan" << "feb" << "mar" << "apr" << "may" << "jun" << "jul" << "aug" << "sep" << "oct" << "nov" << "dec";
+
+QItemModelBarDataMapping *mapping = new QItemModelBarDataMapping(QStringLiteral("year"), // Row role
+ QStringLiteral("month"), // Column role
+ QStringLiteral("income"), // Value role
+ years, // Row categories
+ months); // Column categories
+
+QItemModelBarDataProxy *proxy = new QItemModelBarDataProxy(customModel, mapping);
+
+//...
+
+// To display different data later, you can simply change the mapping of the current
+// mapping object, or set another mapping object.
+proxy->activeMapping()->setValueRole(QStringLiteral("expenses"));
+//! [3]
+
+//! [4]
+// Map "density" value to X-axis, "hardness" to Y-axis and "conductivity" to Z-axis.
+QItemModelScatterDataMapping *mapping = new QItemModelScatterDataMapping(QStringLiteral("density"),
+ QStringLiteral("hardness"),
+ QStringLiteral("conductivity"))
+
+QItemModelScatterDataProxy *proxy = new QItemModelScatterDataProxy(customModel, mapping);
+//! [4]
+
+//! [5]
+QItemModelSurfaceDataMapping *mapping = new QItemModelSurfaceDataMapping(QStringLiteral("longitude"), // Row role
+ QStringLiteral("latitude"), // Column role
+ QStringLiteral("height")); // value role
+
+QItemModelSurfaceDataProxy *proxy = new QItemModelSurfaceDataProxy(customModel, mapping);
+//! [5]
+
+//! [6]
+qmake
+make
+//! [6]
+
+//! [7]
+qmake CONFIG+=static
+make
+//! [7]
+
+//! [8]
+qmake
+make
+./qmlsurface
+//! [8]
+
+//! [9]
+Q3DBars *graph = new Q3DBars();
+QWidget *container = QWidget::createWindowContainer(graph);
+//! [9]
+
+//! [10]
+Q3DBars graph;
+QBarDataProxy *newProxy = new QBarDataProxy;
+
+QBarDataArray *dataArray = new QBarDataArray;
+dataArray->reserve(10);
+for (int i = 0; i < 10; i++) {
+ QBarDataRow *dataRow = new QBarDataRow(5);
+ for (int j = 0; j < 5; j++)
+ (*dataRow)[j].setValue(myData->getValue(i, j));
+ dataArray->append(dataRow);
+}
+
+newProxy->resetArray(dataArray);
+graph->setActiveDataProxy(newProxy);
+//! [10]
diff --git a/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.pro b/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.pro
new file mode 100644
index 00000000..81555f88
--- /dev/null
+++ b/src/datavisualization/doc/snippets/doc_src_qtdatavisualization.pro
@@ -0,0 +1,21 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+#! [0]
+QT += datavisualization
+#! [0]
diff --git a/src/datavisualization/doc/src/qtdatavisualization-index.qdoc b/src/datavisualization/doc/src/qtdatavisualization-index.qdoc
new file mode 100644
index 00000000..f2245c12
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-index.qdoc
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \title Qt Data Visualization
+ \page qtdatavisualization-index.html
+ \brief QtDataVisualization module provides functionality for 3D visualization.
+
+ Qt Data Visualization module provides a way to visualize data in 3D.
+
+ \section1 Features
+
+ \list
+ \li Multiple data visualization options: 3D Bars, 3D Scatter, and 3D Surface
+ \li 2D slice views of the 3D data
+ \li Interactive data: Rotate, zoom, and highlight data using mouse or touch
+ \li Uses OpenGL for rendering the data
+ \li QML2 support
+ \li Customizable axes for data - control viewable data window with axis ranges
+ \li Customizable input handling (upcoming feature - not supported in technology preview)
+ \li Customizable scene handling - full control of cameras and lights (upcoming feature -
+ not supported in technology preview)
+ \li Customizable themes (upcoming feature - not supported in technology preview)
+ \endlist
+
+ \section1 Getting Started
+
+ To import Qt Data Visualization QML types, add the following import statement to your \c .qml
+ file:
+
+ \snippet doc_src_qmldatavisualization.cpp 0
+
+ If you intend to use Qt Data Visualization C++ classes in your application, use the
+ following include and using directives:
+
+ \snippet doc_src_qtdatavisualization.cpp 0
+
+ \note If you are using a few classes from this module, we recommend including those specific
+ classes only instead of the whole module.
+
+ To link against Qt Data Visualization module, add this line to your \c qmake project file:
+
+ \snippet doc_src_qtdatavisualization.pro 0
+
+ See \l{Qt Data Visualization Getting Started}{Getting started} page for further information
+ how to use Qt Data Visualization in your application.
+
+ \section1 Articles
+ \list
+ \li \l{Qt Data Visualization Data Handling}{Data input}
+ \li \l{Qt Data Visualization Interacting with Data}{Interacting with visualized data}
+ \endlist
+
+ \section1 References
+ \list
+ \li \l{Qt Data Visualization C++ Classes}
+ \li \l{Qt Data Visualization QML Types}
+ \endlist
+
+ Qt Data Visualization comes with the following examples:
+
+ \annotatedlist qtdatavisualization_examples
+*/
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc
new file mode 100644
index 00000000..7a0d2c4a
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \qmltype AbstractGraph3D
+ \inqmlmodule com.digia.QtDataVisualization 1.0
+ \since com.digia.QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief Base type for 3D visualizations.
+
+ This type is the base type for all 3D visualizations in QtDataVisualization.
+
+ It resides in the data visualization module that can be imported like this:
+
+ \snippet doc_src_qmldatavisualization.cpp 0
+
+ Note that this type is uncreatable, but contains properties that are shared between
+ the 3D visualizations.
+
+ \sa Bars3D, Scatter3D, Surface3D, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ \qmlproperty AbstractGraph3D.SelectionMode AbstractGraph3D::selectionMode
+ Active selection mode in the visualization.
+ */
+/*!
+ \qmlproperty AbstractGraph3D.LabelStyle AbstractGraph3D::labelStyle
+ Label style.
+ */
+
+/*!
+ \qmlproperty AbstractGraph3D.ShadowQuality AbstractGraph3D::shadowQuality
+ Shadow quality.
+ */
+
+/*!
+ \qmlproperty AbstractGraph3D.CameraPreset AbstractGraph3D::cameraPreset
+ Camera preset.
+ */
+
+/*!
+ \qmlproperty AbstractGraph3D.Theme AbstractGraph3D::theme
+ Theme of the graph. Theme affects visualization colors, label colors, text color, background color, window
+ color and grid color. Lighting is also adjusted by themes.
+ */
+
+/*!
+ \qmlproperty font AbstractGraph3D::font
+ Font used for labels.
+ */
+
+/*!
+ \qmlproperty bool AbstractGraph3D::gridVisible
+ Grid visibility. If false, grid lines are not drawn.
+ */
+
+/*!
+ \qmlproperty bool AbstractGraph3D::backgroundVisible
+ Background visibility. If false, background is not drawn.
+ */
+
+/*!
+ \qmlproperty string AbstractGraph3D::itemLabelFormat
+ Label format of single item labels, e.g. a selected datapoint.
+ */
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc
new file mode 100644
index 00000000..213542b9
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-bars3d.qdoc
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ * \qmltype Bars3D
+ * \inherits AbstractGraph3D
+ * \inqmlmodule com.digia.QtDataVisualization 1.0
+ * \since com.digia.QtDataVisualization 1.0
+ * \ingroup datavisualization_qml
+ * \brief 3D bar graph.
+ *
+ * This type enables developers to render bar graphs in 3D with Qt Quick 2.
+ *
+ * You will need to import data visualization module to use this type:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 0
+ *
+ * After that you can use Bars3D in your qml files:
+ *
+ * \snippet doc_src_qmldatavisualization.cpp 1
+ *
+ * See \l{Qt Quick 2 Bars Example} for more thorough usage example.
+ *
+ * \sa ItemModelBarDataProxy, Scatter3D, Surface3D, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * \qmlmethod void Bars3D::setBarColor(const QColor &baseColor, bool uniform)
+ * Set bar color using your own color. \a baseColor sets the base color of a bar. The \a uniform
+ * -flag is used to define if color needs to be uniform throughout bar's length, or will the colors
+ * be applied by height, starting with dark at the bottom. It is \c true by default.
+ *
+ * Calling this method overrides colors from theme.
+ *
+ * \sa AbstractGraph3D::theme
+ *
+ * \warning This method is subject to change.
+ */
+
+/*!
+ * \qmlproperty BarDataProxy Bars3D::dataProxy
+ * The active data proxy.
+ *
+ * If a proxy is not given, a temporary default proxy is created and activated.
+ * This temporary proxy is destroyed if another proxy is explicitly set active via this property.
+ */
+
+/*!
+ * \qmlproperty CategoryAxis3D Bars3D::rowAxis
+ * A user-defined row axis.
+ *
+ * If an axis is not given, a temporary default axis with no labels is created.
+ * This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ * \qmlproperty ValueAxis3D Bars3D::valueAxis
+ * A user-defined value axis.
+ *
+ * If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ * \qmlproperty CategoryAxis3D Bars3D::columnAxis
+ * A user-defined column axis.
+ *
+ * If an axis is not given, a temporary default axis with no labels is created.
+ * This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+
+/*!
+ * \qmlproperty Bars3D.MeshStyle Bars3D::barType
+ * Bar object type.
+ */
+
+/*!
+ * \qmlproperty real Bars3D::barThickness
+ * Bar thickness ratio between X and Z dimensions. 1.0 means bars are as wide as they are deep, 0.5
+ * makes them twice as deep as they are wide.
+ */
+
+/*!
+ * \qmlproperty size Bars3D::barSpacing
+ * Bar spacing in X and Z dimensions.
+ */
+
+/*!
+ * \qmlproperty bool Bars3D::barSpacingRelative
+ * Relative or absolute bar spacing.
+ */
+
+/*!
+ * \qmlproperty bool Bars3D::barSmoothingEnabled
+ * Bar smoothing. If false, bar shading is flat.
+ */
+
+/*!
+ * \qmlproperty string Bars3D::meshFileName
+ * Override bar type with a mesh object.
+ * \note Object needs to be in Wavefront obj format and include vertices, normals and UVs.
+ * It also needs to be in triangles.
+ */
+
+/*!
+ * \qmlproperty int Bars3D::rows
+ * Row count of data window.
+ */
+
+/*!
+ * \qmlproperty int Bars3D::columns
+ * Column count of data window.
+ */
+
+/*!
+ * \qmlproperty point Bars3D::selectedBarPos
+ * Position of the selected bar in data window. Only one bar can be selected at a time.
+ * To clear selection, specify an illegal position, e.g. Qt.point(-1.0, -1.0).
+ */
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-colorgradient.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-colorgradient.qdoc
new file mode 100644
index 00000000..f8edf492
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-colorgradient.qdoc
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \qmltype ColorGradientStop
+ \inqmlmodule com.digia.QtDataVisualization 1.0
+ \since com.digia.QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief Defines the color at a position in ColorGradient.
+
+ Defines the color at a position in a ColorGradient.
+
+ \sa ColorGradient
+*/
+
+/*!
+ \qmlproperty real ColorGradientStop::position
+
+ The position property describes the position of this gradient stop.
+
+ The default position is 0.0.
+
+ \sa ColorGradient
+*/
+
+/*!
+ \qmlproperty color ColorGradientStop::color
+
+ The color property describes the color color of this gradient stop.
+
+ The default color is black.
+
+ \sa ColorGradient
+*/
+
+/*!
+ \qmltype ColorGradient
+ \inqmlmodule com.digia.QtDataVisualization 1.0
+ \since com.digia.QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief Defines a color gradient.
+
+ A gradient is defined by two or more colors, which will be blended seamlessly.
+
+ The colors are specified as a set of ColorGradientStop child items, each of
+ which defines a position on the gradient from 0.0 to 1.0 and a color.
+ The position of each ColorGradientStop is defined by setting its
+ \l{ColorGradientStop::}{position} property; its color is defined using its
+ \l{ColorGradientStop::}{color} property.
+
+ A gradient without any gradient stops falls back to QLinearGradient default,
+ which is black at 0.0 and white at 1.0.
+
+ \sa ColorGradientStop
+*/
+
+/*!
+ \qmlproperty list<ColorGradientStop> ColorGradient::stops
+ \default
+
+ This property holds the gradient stops describing the gradient.
+
+ By default, this property contains an empty list.
+
+ To set the gradient stops, define them as children of the ColorGradient.
+*/
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-scatter3d.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-scatter3d.qdoc
new file mode 100644
index 00000000..2839468e
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-scatter3d.qdoc
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \qmltype Scatter3D
+ \inherits AbstractGraph3D
+ \inqmlmodule com.digia.QtDataVisualization 1.0
+ \since com.digia.QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief 3D scatter graph.
+
+ This type enables developers to render scatter graphs in 3D with Qt Quick 2.
+
+ You will need to import data visualization module to use this type:
+
+ \snippet doc_src_qmldatavisualization.cpp 0
+
+ After that you can use Scatter3D in your qml files:
+
+ \snippet doc_src_qmldatavisualization.cpp 2
+
+ See \l{Qt Quick 2 Scatter Example} for more thorough usage example.
+
+ \sa ItemModelScatterDataProxy, Bars3D, Surface3D, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * \qmlmethod void Scatter3D::setObjectColor(const QColor &baseColor, bool uniform)
+ * Set item color using your own colors. \a baseColor sets the base color of a item. The \a uniform
+ * -flag is used to define if color needs to be uniform throughout item's length, or will the colors
+ * be applied by height. It is \c true by default.
+ *
+ * Calling this method overrides colors from theme.
+ *
+ * \sa AbstractGraph3D::theme
+ *
+ * \warning This method is subject to change.
+ */
+
+/*!
+ \qmlproperty ScatterDataProxy Scatter3D::dataProxy
+ The active data proxy.
+
+ If a proxy is not given, a temporary default proxy is created and activated.
+ This temporary proxy is destroyed if another proxy is explicitly set active via this property.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Scatter3D::axisX
+ A user-defined X axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Scatter3D::axisY
+ A user-defined Y axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Scatter3D::axisZ
+ A user-defined Z axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty Scatter3D.MeshStyle Scatter3D::objectType
+ Dot object type.
+ */
+
+/*!
+ \qmlproperty bool Scatter3D::objectSmoothingEnabled
+ Dot smoothing. If false, dot shading is flat.
+ */
+
+/*!
+ \qmlproperty string Scatter3D::meshFileName
+ Override object type with a mesh object.
+ \note Object needs to be in Wavefront obj format and include vertices, normals and UVs.
+ It also needs to be in triangles.
+ */
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-surface3d.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-surface3d.qdoc
new file mode 100644
index 00000000..3669c1cd
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-surface3d.qdoc
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \qmltype Surface3D
+ \inherits AbstractGraph3D
+ \inqmlmodule com.digia.QtDataVisualization 1.0
+ \since com.digia.QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief 3D surface graph.
+
+ This type enables developers to render surface plots in 3D with Qt Quick 2.
+
+ You will need to import data visualization module to use this type:
+
+ \snippet doc_src_qmldatavisualization.cpp 0
+
+ After that you can use Surface3D in your qml files:
+
+ \snippet doc_src_qmldatavisualization.cpp 3
+
+ See \l{Qt Quick 2 Surface Example} for more thorough usage example.
+
+ \sa ItemModelSurfaceDataProxy, Bars3D, Scatter3D, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ \qmlproperty SurfaceDataProxy Surface3D::dataProxy
+ The active data proxy.
+
+ If a proxy is not given, a temporary default proxy is created and activated.
+ This temporary proxy is destroyed if another proxy is explicitly set active via this property.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Surface3D::axisX
+ A user-defined X axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Surface3D::axisY
+ A user-defined Y axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty ValueAxis3D Surface3D::axisZ
+ A user-defined Z axis.
+
+ If an axis is not given, a temporary default axis with no labels and automatically adjusting
+ range is created.
+ This temporary axis is destroyed if another axis is explicitly set to same orientation.
+ */
+
+/*!
+ \qmlproperty bool Surface3D::smoothSurfaceEnabled
+ Smoothing of surface. If false, shading of the surface is flat.
+ */
+
+/*!
+ \qmlproperty bool Surface3D::surfaceGridEnabled
+ Surface grid visibility. If false, no surface grid is drawn.
+ */
+
+/*!
+ \qmlproperty ColorGradient Surface3D::gradient
+ The current surface gradient. Setting this property replaces the previous gradient.
+ */
diff --git a/src/datavisualization/doc/src/qtdatavisualization.qdoc b/src/datavisualization/doc/src/qtdatavisualization.qdoc
new file mode 100644
index 00000000..45087e9d
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization.qdoc
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \module QtDataVisualization
+ \title Qt Data Visualization C++ Classes
+ \ingroup modules
+
+ \brief The QtDataVisualization module provides functionality for 3D visualization.
+*/
+
+/*!
+ \group datavisualization_qml
+ \title Qt Data Visualization QML Types
+
+ \brief QML types for the Qt Data Visualization API.
+
+ Qt Data Visualization functionality can be accessed via these QML types.
+
+ \section1 QML Types
+*/
+
+/*!
+ \page qtdatavisualization_getting_started.html
+ \title Qt Data Visualization Getting Started
+
+ \section1 Building Qt Data Visualization
+
+ To build Qt Data Visualization module, set up a command prompt with an environment for
+ building Qt applications, navigate to the directory containing \c qtdatavisualization.pro,
+ and give the following commands:
+
+ \snippet doc_src_qtdatavisualization.cpp 6
+
+ \note The \c make tool name may vary depending on your target platform.
+ E.g. make/nmake/mingw32-make/...
+
+ To build a statically linked version of the Qt Data Visualization module, give the following
+ commands:
+
+ \snippet doc_src_qtdatavisualization.cpp 7
+
+ \section1 Running examples
+
+ Qt Data Visualization examples are found under \c examples subdirectory. To build and run a
+ single example, e.g. the qmlsurface example, navigate to the example directory and give the
+ following commands:
+
+ \snippet doc_src_qtdatavisualization.cpp 8
+
+ \note On some platforms, such as Windows, the executable can be generated under debug or
+ release folders, depending on your build.
+
+ \section1 Creating a simple application
+
+ To create a simple application, start by creating a new Qt Gui Application project in Qt
+ Creator and add this line to the \c .pro file of the project:
+
+ \snippet doc_src_qtdatavisualization.pro 0
+
+ In the \c main.cpp file, include the module headers and declare namespace usage:
+
+ \snippet doc_src_qtdatavisualization.cpp 0
+
+ Then, add the sample code found in one of the following pages, depending on what kind of
+ visualization you are interested in: \l{How to construct a minimal Q3DBars graph},
+ \l{How to construct a minimal Q3DScatter graph}, or
+ \l{How to construct a minimal Q3DSurface graph}.
+
+ To use Qt Data Visualization graphs in widget based applications, you can use
+ QWidget::createWindowContainer() function to wrap the graph into a widget:
+
+ \snippet doc_src_qtdatavisualization.cpp 9
+
+ For further code examples, see one of the Qt Data Visualization examples:
+
+ \annotatedlist qtdatavisualization_examples
+*/
+
+/*!
+ \page qtdatavisualization_data_handling.html
+ \title Qt Data Visualization Data Handling
+
+ \section1 Data proxies
+
+ The data users wish to visualize comes in many formats, all of which cannot obviously be
+ directly supported. Therefore Qt Data Visualization implements data proxies into which
+ user can feed their data in a known format. Each visualization type has a basic proxy type,
+ which takes data in a format suitable for that visualization.
+ For example, the basic proxy for Q3DBars is QBarDataProxy, which stores rows of QBarDataItem
+ objects. Each QBarDataItem stores a single bar value. Additional typedefs are provided for
+ QBarDataArray and QBarDataRow containers.
+
+ This code snipped shows how to use basic proxy when your data is stored in some hypothetical
+ \c myData object:
+
+ \snippet doc_src_qtdatavisualization.cpp 10
+
+ \note The graph objects can own more than one data proxy, but only one proxy can be
+ active at a time. If you need to switch back and forth between two different sets of data,
+ it may be more efficient to store each set in different proxy and just change the active
+ proxy, rather than reset the data in one proxy every time you need to switch.
+
+ \section1 Item models and data mapping
+
+ For common use cases, Qt Data Visualization offers specialized proxies. One such case is having
+ data in an item model (QAbstractItemModel subclass), which is a common way to store data in
+ Qt applications. Each of the visualization types offers a special proxy and a corresponding mapping
+ class for this purpose, e.g. QItemModelBarDataProxy and QItemModelBarDataMapping for Q3DBars.
+ These proxies are simple to use - just give them a pointer to the item model containing the
+ data and the mapping object containing rules how to map the data into format the basic proxy can
+ digest.
+
+ Mapping objects work with item model roles. Each data item in the model can have different
+ values for different roles. For example, with QItemModelBarDataMapping you can specify which
+ role is used to determine which row the item belongs to, which role does the same for columns,
+ and which role specifies the value of the item. When the proxy resolves the data from the model,
+ it uses these mappings to generate the rows and columns of the bar graph.
+
+ Depending on the visualization type, mapping classes may support other functionality as well,
+ such as QItemModelBarDataMapping optionally mapping QAbstractItemModel rows and columns directly
+ into bar graph rows and columns. See individual mapping classes for more information and examples
+ how to use them: QItemModelBarDataMapping, QItemModelScatterDataMapping, and
+ QItemModelSurfaceDataMapping.
+
+ \section1 Other custom proxies
+
+ QHeightMapSurfaceDataProxy is a specialized proxy for generating a surface graph from a
+ heightmap image. See QHeightMapSurfaceDataProxy documentation for more information.
+
+ The \l{Custom Proxy Example}{Custom Proxy} example shows how a custom proxy can be created. It
+ defines a custom data set based on variant lists and an extension of the basic proxy to resolve
+ that data with an associated mapper.
+
+ \section1 Dealing with real-time data
+
+ When you have a data set that updates rapidly, it is important to handle data properly to
+ ensure good performance. Since memory allocation is a costly operation, always use
+ QList::reserve() and QVector::resize() where possible to avoid reallocations when constructing
+ the array to give to the proxy. If you need to change the entire data set for each frame,
+ it is in most cases best to re-use the existing array - especially if the array dimensions do not
+ change. If you need to add, insert, remove, or change several rows or items for each frame, it
+ is always more efficient to do it with one method call instead of multiple calls affecting
+ a single row or item each. For example, adding ten rows with a single QBarDataProxy::addRows() call
+ is much more efficient than ten separate QBarDataProxy::addRow() calls.
+
+ Bars renderer is optimized to access only data that is within data window and thus should not
+ suffer noticeable slowdown even if more data is continually added to the proxy.
+
+ Due to the unsorted nature of the scatter data, any change in the data window ranges requires
+ all data points to be checked for visibility, which can cause increasing slowdown if data is
+ continually added to the proxy.
+
+ Surface data, while on item level similar to scatter data, is already assigned into rows and
+ columns, so the surface renderer can do some optimization by making assumption that the data in
+ rows and columns is sorted along their respective axes, but it is nowhere near as efficient
+ as in bars case. Surface rendering can suffer significant slowdown if the data size grows unchecked.
+
+ For the best performance with the scatter and surface graphs, only keep the data you need in the
+ proxy.
+
+ \note Data handling is not yet fully optimized in the technology preview version.
+*/
+
+/*!
+ \page qtdatavisualization_interacting_with_data.html
+ \title Qt Data Visualization Interacting with Data
+
+ \section1 Interacting with data
+
+ You can interact with the rendered graph with either mouse or touch to rotate, zoom, or select
+ data. For the mouse controls, see Q3DInputHandler documentation, and for the touch controls,
+ see QTouch3DInputHandler documentation.
+
+ \note In the technology preview version, default input handlers cannot be replaced or even accessed
+ via public API. This feature is planned for the final release.
+
+ \section1 Data selection modes
+
+ All visualization types support selecting single data item - a bar, a scatter item, or a surface
+ vertex - using mouse, touch, and programmatically via the graph APIs. The selected item is highlighted
+ in the rendered graph, and selecting causes emission of a graph specific signal for this purpose,
+ e.g. Q3DBars::selectedBarPosChanged(), which the application can handle.
+
+ \note Surface graph doesn't have fully implemented selection API yet, it only supports
+ selection with mouse and touch in the technology preview version.
+
+ Bar and surface graphs support slice selection modes, where the selected row or column is drawn
+ in a separate viewport as a pseudo-2D graph. This makes it easier to see the actual values of
+ single row or column.
+
+ Bar graph additionally supports simply highlighting the whole row and/or column of the selected bar
+ without opening the slice view.
+*/
diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp
new file mode 100644
index 00000000..bfdc375e
--- /dev/null
+++ b/src/datavisualization/engine/abstract3dcontroller.cpp
@@ -0,0 +1,1056 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstract3dcontroller_p.h"
+#include "camerahelper_p.h"
+#include "q3dabstractaxis_p.h"
+#include "q3dvalueaxis.h"
+#include "q3dcategoryaxis.h"
+#include "abstract3drenderer_p.h"
+#include "q3dcamera.h"
+#include "q3dlight.h"
+#include "qabstractdataproxy_p.h"
+#include "qabstract3dinputhandler_p.h"
+#include "qtouch3dinputhandler.h"
+
+#include <QThread>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) :
+ QObject(parent),
+ m_boundingRect(boundRect.x(), boundRect.y(), boundRect.width(), boundRect.height()),
+ m_theme(),
+ m_font(QFont(QStringLiteral("Arial"))),
+ m_selectionMode(QDataVis::SelectionModeItem),
+ m_shadowQuality(QDataVis::ShadowQualityMedium),
+ m_labelStyle(QDataVis::LabelStyleTransparent),
+ m_isBackgroundEnabled(true),
+ m_isGridEnabled(true),
+ m_scene(new Q3DScene()),
+ m_activeInputHandler(0),
+ m_axisX(0),
+ m_axisY(0),
+ m_axisZ(0),
+ m_renderer(0),
+ m_isDataDirty(true),
+ m_data(0),
+ m_renderPending(false)
+{
+ m_theme.useTheme(QDataVis::ThemeQt);
+
+ // Populate the scene
+ m_scene->activeLight()->setPosition(defaultLightPos);
+
+ // Create initial default input handler
+ QAbstract3DInputHandler *inputHandler;
+ inputHandler = new QTouch3DInputHandler();
+ inputHandler->d_ptr->m_isDefaultHandler = true;
+ setActiveInputHandler(inputHandler);
+ connect(inputHandler, &QAbstract3DInputHandler::inputStateChanged, this,
+ &Abstract3DController::emitNeedRender);
+ connect(m_scene, &Q3DScene::needRender, this,
+ &Abstract3DController::emitNeedRender);
+}
+
+Abstract3DController::~Abstract3DController()
+{
+ // Renderer can be in another thread, don't delete it directly in that case
+ if (m_renderer && m_renderer->thread() != QThread::currentThread())
+ m_renderer->deleteLater();
+ else
+ delete m_renderer;
+ delete m_scene;
+}
+
+void Abstract3DController::setRenderer(Abstract3DRenderer *renderer)
+{
+ m_renderer = renderer;
+}
+
+void Abstract3DController::synchDataToRenderer()
+{
+ // If we don't have a renderer, don't do anything
+ if (!m_renderer)
+ return;
+
+ if (m_changeTracker.boundingRectChanged || m_changeTracker.sizeChanged) {
+ m_renderer->updateBoundingRect(m_boundingRect);
+ m_changeTracker.boundingRectChanged = false;
+ m_changeTracker.sizeChanged = false;
+ }
+
+ if (m_changeTracker.positionChanged) {
+ m_renderer->updatePosition(m_boundingRect);
+ m_changeTracker.positionChanged = false;
+ }
+
+ m_renderer->updateScene(m_scene);
+
+ if (m_changeTracker.themeChanged) {
+ m_renderer->updateTheme(m_theme);
+ m_changeTracker.themeChanged = false;
+ }
+
+ if (m_changeTracker.fontChanged) {
+ m_renderer->updateFont(m_font);
+ m_changeTracker.fontChanged = false;
+ }
+
+ if (m_changeTracker.labelStyleChanged) {
+ m_renderer->updateLabelStyle(m_labelStyle);
+ m_changeTracker.labelStyleChanged = false;
+ }
+
+ if (m_changeTracker.shadowQualityChanged) {
+ m_renderer->updateShadowQuality(m_shadowQuality);
+ m_changeTracker.shadowQualityChanged = false;
+ }
+
+ if (m_changeTracker.selectionModeChanged) {
+ m_renderer->updateSelectionMode(m_selectionMode);
+ m_changeTracker.selectionModeChanged = false;
+ }
+
+ if (m_changeTracker.objFileChanged) {
+ m_renderer->updateMeshFileName(m_objFile);
+ m_changeTracker.objFileChanged = false;
+ }
+
+ if (m_changeTracker.gridEnabledChanged) {
+ m_renderer->updateGridEnabled(m_isGridEnabled);
+ m_changeTracker.gridEnabledChanged = false;
+ }
+
+ if (m_changeTracker.backgroundEnabledChanged) {
+ m_renderer->updateBackgroundEnabled(m_isBackgroundEnabled);
+ m_changeTracker.backgroundEnabledChanged = false;
+ }
+
+ if (m_changeTracker.axisXTypeChanged) {
+ m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationX, m_axisX->type());
+ m_changeTracker.axisXTypeChanged = false;
+ }
+
+ if (m_changeTracker.axisYTypeChanged) {
+ m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationY, m_axisY->type());
+ m_changeTracker.axisYTypeChanged = false;
+ }
+
+ if (m_changeTracker.axisZTypeChanged) {
+ m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->type());
+ m_changeTracker.axisZTypeChanged = false;
+ }
+
+ if (m_changeTracker.axisXTitleChanged) {
+ m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationX, m_axisX->title());
+ m_changeTracker.axisXTitleChanged = false;
+ }
+
+ if (m_changeTracker.axisYTitleChanged) {
+ m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationY, m_axisY->title());
+ m_changeTracker.axisYTitleChanged = false;
+ }
+
+ if (m_changeTracker.axisZTitleChanged) {
+ m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->title());
+ m_changeTracker.axisZTitleChanged = false;
+ }
+
+ if (m_changeTracker.axisXLabelsChanged) {
+ m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationX, m_axisX->labels());
+ m_changeTracker.axisXLabelsChanged = false;
+ }
+
+ if (m_changeTracker.axisYLabelsChanged) {
+ m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationY, m_axisY->labels());
+ m_changeTracker.axisYLabelsChanged = false;
+ }
+ if (m_changeTracker.axisZLabelsChanged) {
+ m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->labels());
+ m_changeTracker.axisZLabelsChanged = false;
+ }
+
+ if (m_changeTracker.axisXRangeChanged) {
+ m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationX, m_axisX->min(),
+ m_axisX->max());
+ m_changeTracker.axisXRangeChanged = false;
+ }
+
+ if (m_changeTracker.axisYRangeChanged) {
+ m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationY, m_axisY->min(),
+ m_axisY->max());
+ m_changeTracker.axisYRangeChanged = false;
+ }
+
+ if (m_changeTracker.axisZRangeChanged) {
+ m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->min(),
+ m_axisZ->max());
+ m_changeTracker.axisZRangeChanged = false;
+ }
+
+ if (m_changeTracker.axisXSegmentCountChanged) {
+ m_changeTracker.axisXSegmentCountChanged = false;
+ if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX);
+ m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationX,
+ valueAxisX->segmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisYSegmentCountChanged) {
+ m_changeTracker.axisYSegmentCountChanged = false;
+ if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY);
+ m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationY,
+ valueAxisY->segmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisZSegmentCountChanged) {
+ m_changeTracker.axisZSegmentCountChanged = false;
+ if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ);
+ m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationZ,
+ valueAxisZ->segmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisXSubSegmentCountChanged) {
+ m_changeTracker.axisXSubSegmentCountChanged = false;
+ if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX);
+ m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationX,
+ valueAxisX->subSegmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisYSubSegmentCountChanged) {
+ m_changeTracker.axisYSubSegmentCountChanged = false;
+ if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY);
+ m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationY,
+ valueAxisY->subSegmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisZSubSegmentCountChanged) {
+ m_changeTracker.axisZSubSegmentCountChanged = false;
+ if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ);
+ m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationZ,
+ valueAxisZ->subSegmentCount());
+ }
+ }
+
+ if (m_changeTracker.axisXLabelFormatChanged) {
+ m_changeTracker.axisXLabelFormatChanged = false;
+ if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX);
+ m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationX,
+ valueAxisX->labelFormat());
+ }
+ }
+
+ if (m_changeTracker.axisYLabelFormatChanged) {
+ m_changeTracker.axisYLabelFormatChanged = false;
+ if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY);
+ m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationY,
+ valueAxisY->labelFormat());
+ }
+ }
+
+ if (m_changeTracker.axisZLabelFormatChanged) {
+ m_changeTracker.axisZLabelFormatChanged = false;
+ if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ);
+ m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationZ,
+ valueAxisZ->labelFormat());
+ }
+ }
+}
+
+void Abstract3DController::render(const GLuint defaultFboHandle)
+{
+ m_renderPending = false;
+
+ // If not initialized, do nothing.
+ if (!m_renderer)
+ return;
+
+ m_renderer->render(defaultFboHandle);
+
+#ifdef DISPLAY_RENDER_SPEED
+ // To get meaningful framerate, don't just do render on demand.
+ emitNeedRender();
+#endif
+}
+
+void Abstract3DController::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->mouseDoubleClickEvent(event);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::touchEvent(QTouchEvent *event)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->touchEvent(event);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->mousePressEvent(event, mousePos);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->mouseReleaseEvent(event, mousePos);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->mouseMoveEvent(event, mousePos);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::wheelEvent(QWheelEvent *event)
+{
+ if (m_activeInputHandler)
+ m_activeInputHandler->wheelEvent(event);
+
+ emitNeedRender();
+}
+
+void Abstract3DController::setSize(const int width, const int height)
+{
+ m_boundingRect.setWidth(width);
+ m_boundingRect.setHeight(height);
+ m_scene->setViewportSize(width, height);
+
+ m_changeTracker.boundingRectChanged = true;
+ emitNeedRender();
+}
+
+const QSize Abstract3DController::size()
+{
+ return m_boundingRect.size();
+}
+
+const QRect Abstract3DController::boundingRect()
+{
+ return m_boundingRect;
+}
+
+void Abstract3DController::setBoundingRect(const QRect boundingRect)
+{
+ m_boundingRect = boundingRect;
+ m_scene->setViewport(boundingRect);
+
+ m_changeTracker.boundingRectChanged = true;
+ emitNeedRender();
+}
+
+void Abstract3DController::setWidth(const int width)
+{
+ m_boundingRect.setWidth(width);
+ m_scene->setViewportSize(width, m_scene->viewport().height());
+
+ m_changeTracker.sizeChanged = true;
+ emitNeedRender();
+}
+
+int Abstract3DController::width()
+{
+ return m_boundingRect.width();
+}
+
+void Abstract3DController::setHeight(const int height)
+{
+ m_boundingRect.setHeight(height);
+ m_scene->setViewportSize(m_scene->viewport().width(), height);
+
+ m_changeTracker.sizeChanged = true;
+ emitNeedRender();
+}
+
+int Abstract3DController::height()
+{
+ return m_boundingRect.height();
+}
+
+void Abstract3DController::setX(const int x)
+{
+ m_boundingRect.setX(x);
+
+ m_changeTracker.positionChanged = true;
+ emitNeedRender();
+}
+
+int Abstract3DController::x()
+{
+ return m_boundingRect.x();
+}
+
+void Abstract3DController::setY(const int y)
+{
+ m_boundingRect.setY(y);
+
+ m_changeTracker.positionChanged = true;
+ emitNeedRender();
+}
+
+int Abstract3DController::y()
+{
+ return m_boundingRect.y();
+}
+
+QRect Abstract3DController::primarySubViewport() const
+{
+ return m_scene->primarySubViewport();
+}
+
+void Abstract3DController::setPrimarySubViewport(const QRect &primarySubViewport)
+{
+ m_scene->setPrimarySubViewport(primarySubViewport);
+}
+
+QRect Abstract3DController::secondarySubViewport() const
+{
+ return m_scene->secondarySubViewport();
+}
+
+void Abstract3DController::setSecondarySubViewport(const QRect &secondarySubViewport)
+{
+ m_scene->setSecondarySubViewport(secondarySubViewport);
+}
+
+void Abstract3DController::updateDevicePixelRatio(qreal ratio)
+{
+ m_scene->setDevicePixelRatio(ratio);
+}
+
+void Abstract3DController::setAxisX(Q3DAbstractAxis *axis)
+{
+ setAxisHelper(Q3DAbstractAxis::AxisOrientationX, axis, &m_axisX);
+}
+
+Q3DAbstractAxis *Abstract3DController::axisX()
+{
+ return m_axisX;
+}
+
+void Abstract3DController::setAxisY(Q3DAbstractAxis *axis)
+{
+ setAxisHelper(Q3DAbstractAxis::AxisOrientationY, axis, &m_axisY);
+}
+
+Q3DAbstractAxis *Abstract3DController::axisY()
+{
+ return m_axisY;
+}
+
+void Abstract3DController::setAxisZ(Q3DAbstractAxis *axis)
+{
+ setAxisHelper(Q3DAbstractAxis::AxisOrientationZ, axis, &m_axisZ);
+}
+
+Q3DAbstractAxis *Abstract3DController::axisZ()
+{
+ return m_axisZ;
+}
+
+void Abstract3DController::addAxis(Q3DAbstractAxis *axis)
+{
+ Q_ASSERT(axis);
+ Abstract3DController *owner = qobject_cast<Abstract3DController *>(axis->parent());
+ if (owner != this) {
+ Q_ASSERT_X(!owner, "addAxis", "Axis already attached to a graph.");
+ axis->setParent(this);
+ }
+ if (!m_axes.contains(axis))
+ m_axes.append(axis);
+}
+
+void Abstract3DController::releaseAxis(Q3DAbstractAxis *axis)
+{
+ if (axis && m_axes.contains(axis)) {
+ // Clear the default status from released default axes
+ if (axis->d_ptr->isDefaultAxis())
+ axis->d_ptr->setDefaultAxis(false);
+
+ // If the axis is in use, replace it with a temporary one
+ switch (axis->orientation()) {
+ case Q3DAbstractAxis::AxisOrientationX:
+ setAxisX(0);
+ break;
+ case Q3DAbstractAxis::AxisOrientationY:
+ setAxisY(0);
+ break;
+ case Q3DAbstractAxis::AxisOrientationZ:
+ setAxisZ(0);
+ break;
+ default:
+ break;
+ }
+
+ m_axes.removeAll(axis);
+ axis->setParent(0);
+ }
+}
+
+QList<Q3DAbstractAxis *> Abstract3DController::axes() const
+{
+ return m_axes;
+}
+
+QAbstractDataProxy *Abstract3DController::activeDataProxy() const
+{
+ return m_data;
+}
+
+void Abstract3DController::addDataProxy(QAbstractDataProxy *proxy)
+{
+ Q_ASSERT(proxy);
+ Abstract3DController *owner = qobject_cast<Abstract3DController *>(proxy->parent());
+ if (owner != this) {
+ Q_ASSERT_X(!owner, "addDataProxy", "Proxy already attached to a graph.");
+ proxy->setParent(this);
+ }
+ if (!m_dataProxies.contains(proxy))
+ m_dataProxies.append(proxy);
+}
+
+void Abstract3DController::releaseDataProxy(QAbstractDataProxy *proxy)
+{
+ if (proxy && m_dataProxies.contains(proxy)) {
+ // Clear the default status from released default proxies
+ if (proxy->d_ptr->isDefaultProxy())
+ proxy->d_ptr->setDefaultProxy(false);
+
+ // If the proxy is in use, replace it with a temporary one
+ if (m_data == proxy)
+ setActiveDataProxy(0);
+
+ m_dataProxies.removeAll(proxy);
+ proxy->setParent(0);
+ }
+}
+
+QList<QAbstractDataProxy *> Abstract3DController::dataProxies() const
+{
+ return m_dataProxies;
+}
+
+void Abstract3DController::setActiveDataProxy(QAbstractDataProxy *proxy)
+{
+ // If existing proxy is the default proxy, delete it
+ if (m_data) {
+ if (m_data->d_ptr->isDefaultProxy()) {
+ m_dataProxies.removeAll(m_data);
+ delete m_data;
+ } else {
+ // Disconnect the old proxy from use
+ QObject::disconnect(m_data, 0, this, 0);
+ }
+ }
+
+ // Assume ownership and activate
+ addDataProxy(proxy);
+ m_data = proxy;
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Abstract3DController::addInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ Q_ASSERT(inputHandler);
+ Abstract3DController *owner = qobject_cast<Abstract3DController *>(inputHandler->parent());
+ if (owner != this) {
+ Q_ASSERT_X(!owner, "addInputHandler", "Input handler already attached to another component.");
+ inputHandler->setParent(this);
+ }
+
+ if (!m_inputHandlers.contains(inputHandler))
+ m_inputHandlers.append(inputHandler);
+}
+
+void Abstract3DController::releaseInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ if (inputHandler && m_inputHandlers.contains(inputHandler)) {
+ // Clear the default status from released default input handler
+ if (inputHandler->d_ptr->m_isDefaultHandler)
+ inputHandler->d_ptr->m_isDefaultHandler = false;
+
+ // If the input handler is in use, remove it
+ if (m_activeInputHandler == inputHandler)
+ setActiveInputHandler(0);
+
+ m_inputHandlers.removeAll(inputHandler);
+ inputHandler->setParent(0);
+ }
+}
+
+void Abstract3DController::setActiveInputHandler(QAbstract3DInputHandler *inputHandler)
+{
+ if (inputHandler == m_activeInputHandler)
+ return;
+
+ // If existing input handler is the default input handler, delete it
+ if (m_activeInputHandler) {
+ if (m_activeInputHandler->d_ptr->m_isDefaultHandler) {
+ m_inputHandlers.removeAll(m_activeInputHandler);
+ delete m_activeInputHandler;
+ } else {
+ // Disconnect the old input handler from the scene
+ m_activeInputHandler->setScene(0);
+ }
+ }
+
+ // Assume ownership and connect to this controller's scene
+ if (inputHandler)
+ addInputHandler(inputHandler);
+
+ m_activeInputHandler = inputHandler;
+ if (m_activeInputHandler)
+ m_activeInputHandler->setScene(m_scene);
+
+ // Notify change of input handler
+ emit activeInputHandlerChanged(m_activeInputHandler);
+}
+
+QAbstract3DInputHandler* Abstract3DController::activeInputHandler()
+{
+ return m_activeInputHandler;
+}
+
+int Abstract3DController::zoomLevel()
+{
+ return m_scene->activeCamera()->zoomLevel();
+}
+
+void Abstract3DController::setZoomLevel(int zoomLevel)
+{
+ m_scene->activeCamera()->setZoomLevel(zoomLevel);
+
+ m_changeTracker.zoomLevelChanged = true;
+ emitNeedRender();
+}
+
+void Abstract3DController::setObjectColor(const QColor &baseColor, bool uniform)
+{
+ m_theme.m_baseColor = baseColor;
+ m_theme.m_uniformColor = uniform;
+
+ m_changeTracker.themeChanged = true;
+ emitNeedRender();
+}
+
+QColor Abstract3DController::objectColor() const
+{
+ return m_theme.m_baseColor;
+}
+
+void Abstract3DController::setTheme(QDataVis::Theme theme)
+{
+ m_theme.useTheme(theme);
+
+ m_changeTracker.themeChanged = true;
+ emitNeedRender();
+}
+
+Theme Abstract3DController::theme()
+{
+ return m_theme;
+}
+
+void Abstract3DController::setFont(const QFont &font)
+{
+ m_font = font;
+
+ m_changeTracker.fontChanged = true;
+ emitNeedRender();
+}
+
+QFont Abstract3DController::font()
+{
+ return m_font;
+}
+
+void Abstract3DController::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ m_selectionMode = mode;
+ m_changeTracker.selectionModeChanged = true;
+ emitNeedRender();
+}
+
+QDataVis::SelectionMode Abstract3DController::selectionMode()
+{
+ return m_selectionMode;
+}
+
+void Abstract3DController::setShadowQuality(QDataVis::ShadowQuality quality)
+{
+ m_shadowQuality = quality;
+
+ m_changeTracker.shadowQualityChanged = true;
+ emit shadowQualityChanged(m_shadowQuality);
+ emitNeedRender();
+}
+
+QDataVis::ShadowQuality Abstract3DController::shadowQuality()
+{
+ return m_shadowQuality;
+}
+
+void Abstract3DController::setLabelStyle(QDataVis::LabelStyle style)
+{
+ m_labelStyle = style;
+
+ m_changeTracker.labelStyleChanged = true;
+ emitNeedRender();
+}
+
+QDataVis::LabelStyle Abstract3DController::labelStyle()
+{
+ return m_labelStyle;
+}
+
+void Abstract3DController::setBackgroundEnabled(bool enable)
+{
+ m_isBackgroundEnabled = enable;
+ m_changeTracker.backgroundEnabledChanged = true;
+ emitNeedRender();
+}
+
+bool Abstract3DController::backgroundEnabled()
+{
+ return m_isBackgroundEnabled;
+}
+
+void Abstract3DController::setGridEnabled(bool enable)
+{
+ m_isGridEnabled = enable;
+ m_changeTracker.gridEnabledChanged = true;
+ emitNeedRender();
+}
+
+bool Abstract3DController::gridEnabled()
+{
+ return m_isGridEnabled;
+}
+
+bool Abstract3DController::isSlicingActive()
+{
+ return m_scene->isSlicingActive();
+}
+
+void Abstract3DController::setSlicingActive(bool isSlicing)
+{
+ m_scene->setSlicingActive(isSlicing);
+ emitNeedRender();
+}
+
+QDataVis::InputState Abstract3DController::inputState()
+{
+ if (m_activeInputHandler)
+ return m_activeInputHandler->inputState();
+ else
+ return QDataVis::InputStateNone;
+}
+
+QPoint Abstract3DController::inputPosition()
+{
+ if (m_activeInputHandler)
+ return m_activeInputHandler->inputPosition();
+ else
+ return QPoint(0,0);
+}
+
+void Abstract3DController::setMeshFileName(const QString &fileName)
+{
+ m_objFile = fileName;
+ m_changeTracker.objFileChanged = true;
+ emitNeedRender();
+}
+
+QString Abstract3DController::meshFileName()
+{
+ return m_objFile;
+}
+
+Q3DScene *Abstract3DController::scene()
+{
+ return m_scene;
+}
+
+void Abstract3DController::handleAxisTitleChanged(const QString &title)
+{
+ Q_UNUSED(title)
+ handleAxisTitleChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisTitleChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXTitleChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYTitleChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZTitleChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisLabelsChanged()
+{
+ handleAxisLabelsChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisLabelsChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXLabelsChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYLabelsChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZLabelsChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisRangeChanged(qreal min, qreal max)
+{
+ Q_UNUSED(min)
+ Q_UNUSED(max)
+ handleAxisRangeChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisRangeChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX) {
+ m_isDataDirty = true;
+ m_changeTracker.axisXRangeChanged = true;
+ } else if (sender == m_axisY) {
+ m_isDataDirty = true;
+ m_changeTracker.axisYRangeChanged = true;
+ } else if (sender == m_axisZ) {
+ m_isDataDirty = true;
+ m_changeTracker.axisZRangeChanged = true;
+ } else {
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ }
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisSegmentCountChanged(int count)
+{
+ Q_UNUSED(count)
+ handleAxisSegmentCountChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisSegmentCountChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXSegmentCountChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYSegmentCountChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZSegmentCountChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisSubSegmentCountChanged(int count)
+{
+ Q_UNUSED(count)
+ handleAxisSubSegmentCountChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisSubSegmentCountChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXSubSegmentCountChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYSubSegmentCountChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZSubSegmentCountChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisAutoAdjustRangeChanged(bool autoAdjust)
+{
+ QObject *sender = QObject::sender();
+ if (sender != m_axisX && sender != m_axisY && sender != m_axisZ)
+ return;
+
+ Q3DAbstractAxis *axis = static_cast<Q3DAbstractAxis*>(sender);
+ handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(), autoAdjust);
+}
+
+void Abstract3DController::handleAxisLabelFormatChanged(const QString &format)
+{
+ Q_UNUSED(format)
+ handleAxisLabelFormatChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender)
+{
+ // Label format changing needs to dirty the data so that labels are reset.
+ if (sender == m_axisX) {
+ m_isDataDirty = true;
+ m_changeTracker.axisXLabelFormatChanged = true;
+ } else if (sender == m_axisY) {
+ m_isDataDirty = true;
+ m_changeTracker.axisYLabelFormatChanged = true;
+ } else if (sender == m_axisZ) {
+ m_isDataDirty = true;
+ m_changeTracker.axisZLabelFormatChanged = true;
+ } else {
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ }
+ emitNeedRender();
+}
+
+void Abstract3DController::setAxisHelper(Q3DAbstractAxis::AxisOrientation orientation,
+ Q3DAbstractAxis *axis, Q3DAbstractAxis **axisPtr)
+{
+ // Setting null axis indicates using default axis
+ if (!axis)
+ axis = createDefaultAxis(orientation);
+
+ // If old axis is default axis, delete it
+ Q3DAbstractAxis *oldAxis = *axisPtr;
+ if (oldAxis) {
+ if (oldAxis->d_ptr->isDefaultAxis()) {
+ m_axes.removeAll(oldAxis);
+ delete oldAxis;
+ oldAxis = 0;
+ } else {
+ // Disconnect the old axis from use
+ QObject::disconnect(oldAxis, 0, this, 0);
+ oldAxis->d_ptr->setOrientation(Q3DAbstractAxis::AxisOrientationNone);
+ }
+ }
+
+ // Assume ownership
+ addAxis(axis);
+
+ // Connect the new axis
+ *axisPtr = axis;
+
+ axis->d_ptr->setOrientation(orientation);
+
+ QObject::connect(axis, &Q3DAbstractAxis::titleChanged,
+ this, &Abstract3DController::handleAxisTitleChanged);
+ QObject::connect(axis, &Q3DAbstractAxis::labelsChanged,
+ this, &Abstract3DController::handleAxisLabelsChanged);
+ QObject::connect(axis, &Q3DAbstractAxis::rangeChanged,
+ this, &Abstract3DController::handleAxisRangeChanged);
+ QObject::connect(axis, &Q3DAbstractAxis::autoAdjustRangeChanged,
+ this, &Abstract3DController::handleAxisAutoAdjustRangeChanged);
+
+ if (orientation == Q3DAbstractAxis::AxisOrientationX)
+ m_changeTracker.axisXTypeChanged = true;
+ else if (orientation == Q3DAbstractAxis::AxisOrientationY)
+ m_changeTracker.axisYTypeChanged = true;
+ else if (orientation == Q3DAbstractAxis::AxisOrientationZ)
+ m_changeTracker.axisZTypeChanged = true;
+
+ handleAxisTitleChangedBySender(axis);
+ handleAxisLabelsChangedBySender(axis);
+ handleAxisRangeChangedBySender(axis);
+ handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(),
+ axis->isAutoAdjustRange());
+
+ if (axis->type() & Q3DAbstractAxis::AxisTypeValue) {
+ Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(axis);
+ QObject::connect(valueAxis, &Q3DValueAxis::segmentCountChanged,
+ this, &Abstract3DController::handleAxisSegmentCountChanged);
+ QObject::connect(valueAxis, &Q3DValueAxis::subSegmentCountChanged,
+ this, &Abstract3DController::handleAxisSubSegmentCountChanged);
+ QObject::connect(valueAxis, &Q3DValueAxis::labelFormatChanged,
+ this, &Abstract3DController::handleAxisLabelFormatChanged);
+
+ handleAxisSegmentCountChangedBySender(valueAxis);
+ handleAxisSubSegmentCountChangedBySender(valueAxis);
+ handleAxisLabelFormatChangedBySender(valueAxis);
+ }
+}
+
+Q3DAbstractAxis *Abstract3DController::createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation)
+{
+ Q_UNUSED(orientation)
+
+ // The default default axis is a value axis. If the graph type has a different default axis
+ // for some orientation, this function needs to be overridden.
+ Q3DAbstractAxis *defaultAxis = createDefaultValueAxis();
+ return defaultAxis;
+}
+
+Q3DValueAxis *Abstract3DController::createDefaultValueAxis()
+{
+ // Default value axis has single segment, empty label format, and auto scaling
+ // TODO: Grid should be also hidden, but that is not currently controlled by axis
+ Q3DValueAxis *defaultAxis = new Q3DValueAxis;
+ defaultAxis->setSegmentCount(1);
+ defaultAxis->setSubSegmentCount(1);
+ defaultAxis->setAutoAdjustRange(true);
+ defaultAxis->setLabelFormat(QString());
+ defaultAxis->d_ptr->setDefaultAxis(true);
+
+ return defaultAxis;
+}
+
+Q3DCategoryAxis *Abstract3DController::createDefaultCategoryAxis()
+{
+ // Default category axis has no labels
+ // TODO: Grid should be also hidden, but that is not currently controlled by axis.
+ Q3DCategoryAxis *defaultAxis = new Q3DCategoryAxis;
+ defaultAxis->setAutoAdjustRange(true);
+ defaultAxis->d_ptr->setDefaultAxis(true);
+ return defaultAxis;
+}
+
+void Abstract3DController::emitNeedRender()
+{
+ if (!m_renderPending) {
+ emit needRender();
+ m_renderPending = true;
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h
new file mode 100644
index 00000000..f17c6c4d
--- /dev/null
+++ b/src/datavisualization/engine/abstract3dcontroller_p.h
@@ -0,0 +1,334 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 CONTROLLER3DBASE_H
+#define CONTROLLER3DBASE_H
+
+#include "datavisualizationglobal_p.h"
+#include "theme_p.h"
+#include "q3dabstractaxis.h"
+#include "drawer_p.h"
+#include "qabstract3dinputhandler.h"
+#include "qabstractdataproxy.h"
+#include "q3dscene.h"
+#include "q3dbox.h"
+
+#include <QObject>
+
+class QFont;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class CameraHelper;
+class Abstract3DRenderer;
+
+struct Abstract3DChangeBitField {
+ bool positionChanged : 1;
+ bool zoomLevelChanged : 1;
+ bool themeChanged : 1;
+ bool fontChanged : 1;
+ bool labelStyleChanged : 1;
+ bool boundingRectChanged : 1;
+ bool sizeChanged : 1;
+ bool shadowQualityChanged : 1;
+ bool selectionModeChanged : 1;
+ bool objFileChanged : 1;
+ bool gridEnabledChanged : 1;
+ bool backgroundEnabledChanged : 1;
+ bool axisXTypeChanged : 1;
+ bool axisYTypeChanged : 1;
+ bool axisZTypeChanged : 1;
+ bool axisXTitleChanged : 1;
+ bool axisYTitleChanged : 1;
+ bool axisZTitleChanged : 1;
+ bool axisXLabelsChanged : 1;
+ bool axisYLabelsChanged : 1;
+ bool axisZLabelsChanged : 1;
+ bool axisXRangeChanged : 1;
+ bool axisYRangeChanged : 1;
+ bool axisZRangeChanged : 1;
+ bool axisXSegmentCountChanged : 1;
+ bool axisYSegmentCountChanged : 1;
+ bool axisZSegmentCountChanged : 1;
+ bool axisXSubSegmentCountChanged : 1;
+ bool axisYSubSegmentCountChanged : 1;
+ bool axisZSubSegmentCountChanged : 1;
+ bool axisXLabelFormatChanged : 1;
+ bool axisYLabelFormatChanged : 1;
+ bool axisZLabelFormatChanged : 1;
+
+ Abstract3DChangeBitField() :
+ positionChanged(true),
+ zoomLevelChanged(true),
+ themeChanged(true),
+ fontChanged(true),
+ labelStyleChanged(true),
+ boundingRectChanged(true),
+ sizeChanged(true),
+ shadowQualityChanged(true),
+ selectionModeChanged(true),
+ objFileChanged(true),
+ gridEnabledChanged(true),
+ backgroundEnabledChanged(true),
+ axisXTypeChanged(true),
+ axisYTypeChanged(true),
+ axisZTypeChanged(true),
+ axisXTitleChanged(true),
+ axisYTitleChanged(true),
+ axisZTitleChanged(true),
+ axisXLabelsChanged(true),
+ axisYLabelsChanged(true),
+ axisZLabelsChanged(true),
+ axisXRangeChanged(true),
+ axisYRangeChanged(true),
+ axisZRangeChanged(true),
+ axisXSegmentCountChanged(true),
+ axisYSegmentCountChanged(true),
+ axisZSegmentCountChanged(true),
+ axisXSubSegmentCountChanged(true),
+ axisYSubSegmentCountChanged(true),
+ axisZSubSegmentCountChanged(true),
+ axisXLabelFormatChanged(true),
+ axisYLabelFormatChanged(true),
+ axisZLabelFormatChanged(true)
+ {
+ }
+};
+
+class QT_DATAVISUALIZATION_EXPORT Abstract3DController : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum SelectionType {
+ SelectionNone = 0,
+ SelectionItem,
+ SelectionRow,
+ SelectionColumn
+ };
+
+ enum MouseState {
+ MouseNone = 0,
+ MouseOnScene,
+ MouseOnOverview,
+ MouseOnZoom,
+ MouseRotating,
+ MouseOnPinch
+ };
+
+private:
+ Abstract3DChangeBitField m_changeTracker;
+ QRect m_boundingRect;
+ GLfloat m_horizontalRotation;
+ GLfloat m_verticalRotation;
+ Theme m_theme;
+ QFont m_font;
+ QDataVis::SelectionMode m_selectionMode;
+ QDataVis::ShadowQuality m_shadowQuality;
+ QDataVis::LabelStyle m_labelStyle;
+ bool m_isBackgroundEnabled;
+ bool m_isGridEnabled;
+ QString m_objFile;
+
+ Q3DScene *m_scene;
+
+protected:
+ QList<QAbstract3DInputHandler *> m_inputHandlers; // List of all added input handlers
+ QAbstract3DInputHandler *m_activeInputHandler;
+ CameraHelper *m_cameraHelper;
+ // Active axes
+ Q3DAbstractAxis *m_axisX;
+ Q3DAbstractAxis *m_axisY;
+ Q3DAbstractAxis *m_axisZ;
+
+ QList<Q3DAbstractAxis *> m_axes; // List of all added axes
+ Abstract3DRenderer *m_renderer;
+ bool m_isDataDirty;
+
+ QAbstractDataProxy *m_data;
+ QList<QAbstractDataProxy *> m_dataProxies;
+
+ bool m_renderPending;
+
+ explicit Abstract3DController(QRect boundRect, QObject *parent = 0);
+ virtual ~Abstract3DController();
+
+public:
+
+ inline bool isInitialized() { return (m_renderer != 0); }
+
+ /**
+ * @brief synchDataToRenderer Called on the render thread while main GUI thread is blocked before rendering.
+ */
+ virtual void synchDataToRenderer();
+
+ virtual void render(const GLuint defaultFboHandle = 0);
+
+ /**
+ * @brief setRenderer Sets the renderer to be used. isInitialized returns true from this point onwards.
+ * @param renderer Renderer to be used.
+ */
+ void setRenderer(Abstract3DRenderer *renderer);
+
+ // Size
+ virtual void setSize(const int width, const int height);
+ virtual const QSize size();
+ virtual const QRect boundingRect();
+ virtual void setBoundingRect(const QRect boundingRect);
+ virtual void setWidth(const int width);
+ virtual int width();
+ virtual void setHeight(const int height);
+ virtual int height();
+ virtual void setX(const int x);
+ virtual int x();
+ virtual void setY(const int y);
+ virtual int y();
+
+ virtual QRect primarySubViewport() const;
+ virtual void setPrimarySubViewport(const QRect &primarySubViewport);
+
+ virtual QRect secondarySubViewport() const;
+ virtual void setSecondarySubViewport(const QRect &secondarySubViewport);
+
+ virtual void setAxisX(Q3DAbstractAxis *axis);
+ virtual Q3DAbstractAxis *axisX();
+ virtual void setAxisY(Q3DAbstractAxis *axis);
+ virtual Q3DAbstractAxis *axisY();
+ virtual void setAxisZ(Q3DAbstractAxis *axis);
+ virtual Q3DAbstractAxis *axisZ();
+ virtual void addAxis(Q3DAbstractAxis *axis);
+ virtual void releaseAxis(Q3DAbstractAxis *axis);
+ virtual QList<Q3DAbstractAxis *> axes() const; // Omits default axes
+
+ virtual void addInputHandler(QAbstract3DInputHandler *inputHandler);
+ virtual void releaseInputHandler(QAbstract3DInputHandler *inputHandler);
+ virtual void setActiveInputHandler(QAbstract3DInputHandler *inputHandler);
+ virtual QAbstract3DInputHandler *activeInputHandler();
+
+ virtual QAbstractDataProxy *activeDataProxy() const;
+ virtual void addDataProxy(QAbstractDataProxy *proxy);
+ virtual void releaseDataProxy(QAbstractDataProxy *proxy);
+ virtual QList<QAbstractDataProxy *> dataProxies() const;
+ virtual void setActiveDataProxy(QAbstractDataProxy *proxy);
+ virtual void updateDevicePixelRatio(qreal ratio);
+
+ virtual int zoomLevel();
+ virtual void setZoomLevel(int zoomLevel);
+
+ // Set color if you don't want to use themes.
+ virtual void setObjectColor(const QColor &baseColor, bool uniform = true);
+ virtual QColor objectColor() const;
+
+ // Set theme (bar colors, shaders, window color, background colors, light intensity and text
+ // colors are affected)
+ virtual void setTheme(QDataVis::Theme theme);
+ virtual Theme theme();
+
+ // Set font
+ virtual void setFont(const QFont &font);
+ virtual QFont font();
+
+ // Selection mode
+ virtual void setSelectionMode(QDataVis::SelectionMode mode);
+ virtual QDataVis::SelectionMode selectionMode();
+
+ // Adjust shadow quality
+ virtual void setShadowQuality(QDataVis::ShadowQuality quality);
+ virtual QDataVis::ShadowQuality shadowQuality();
+
+ // Label style adjustment
+ virtual void setLabelStyle(QDataVis::LabelStyle style);
+ virtual QDataVis::LabelStyle labelStyle();
+
+ // Enable or disable background mesh
+ virtual void setBackgroundEnabled(bool enable);
+ virtual bool backgroundEnabled();
+
+ // Enable or disable background grid
+ virtual void setGridEnabled(bool enable);
+ virtual bool gridEnabled();
+
+ // Query input state and position
+ QDataVis::InputState inputState();
+ QPoint inputPosition();
+
+ // Enable or disable slicing mode
+ bool isSlicingActive();
+ void setSlicingActive(bool isSlicing);
+
+
+ // override bar type with own mesh
+ virtual void setMeshFileName(const QString &fileName);
+ virtual QString meshFileName();
+
+ Q3DScene *scene();
+
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+ virtual void touchEvent(QTouchEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void wheelEvent(QWheelEvent *event);
+
+ virtual void handleAxisTitleChangedBySender(QObject *sender);
+ virtual void handleAxisLabelsChangedBySender(QObject *sender);
+ virtual void handleAxisRangeChangedBySender(QObject *sender);
+ virtual void handleAxisSegmentCountChangedBySender(QObject *sender);
+ virtual void handleAxisSubSegmentCountChangedBySender(QObject *sender);
+ virtual void handleAxisAutoAdjustRangeChangedInOrientation(
+ Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) = 0;
+ virtual void handleAxisLabelFormatChangedBySender(QObject *sender);
+
+public slots:
+ void handleAxisTitleChanged(const QString &title);
+ void handleAxisLabelsChanged();
+ void handleAxisRangeChanged(qreal min, qreal max);
+ void handleAxisSegmentCountChanged(int count);
+ void handleAxisSubSegmentCountChanged(int count);
+ void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
+ void handleAxisLabelFormatChanged(const QString &format);
+
+signals:
+ void shadowQualityChanged(QDataVis::ShadowQuality quality);
+ void activeInputHandlerChanged(QAbstract3DInputHandler *inputHandler);
+ void needRender();
+
+protected:
+ virtual Q3DAbstractAxis *createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation);
+ Q3DValueAxis *createDefaultValueAxis();
+ Q3DCategoryAxis *createDefaultCategoryAxis();
+ void emitNeedRender();
+
+private:
+ void setAxisHelper(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis *axis,
+ Q3DAbstractAxis **axisPtr);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // CONTROLLER3DBASE_H
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
new file mode 100644
index 00000000..eef810df
--- /dev/null
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstract3drenderer_p.h"
+#include "q3dvalueaxis.h"
+#include "texturehelper_p.h"
+#include "utils_p.h"
+#include "q3dscene_p.h"
+#include "q3dcamera_p.h"
+#include "q3dlight_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
+ : QObject(0),
+ m_controller(controller),
+ m_hasNegativeValues(false),
+ m_cachedTheme(),
+ m_cachedFont(QFont(QStringLiteral("Arial"))),
+ m_cachedLabelStyle(QDataVis::LabelStyleFromTheme),
+ m_drawer(new Drawer(m_cachedTheme, m_cachedFont, m_cachedLabelStyle)),
+ m_cachedBoundingRect(QRect(0,0,0,0)),
+ m_cachedShadowQuality(QDataVis::ShadowQualityMedium),
+ m_autoScaleAdjustment(1.0f),
+ m_cachedSelectionMode(QDataVis::SelectionModeNone),
+ m_cachedIsGridEnabled(false),
+ m_cachedIsBackgroundEnabled(false),
+ m_cachedScene(new Q3DScene())
+ #ifdef DISPLAY_RENDER_SPEED
+ , m_isFirstFrame(true),
+ m_numFrames(0)
+ #endif
+
+{
+ QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Abstract3DRenderer::updateTextures);
+ QObject::connect(this, &Abstract3DRenderer::needRender, m_controller,
+ &Abstract3DController::needRender, Qt::QueuedConnection);
+}
+
+Abstract3DRenderer::~Abstract3DRenderer()
+{
+ delete m_drawer;
+ delete m_textureHelper;
+ delete m_cachedScene;
+}
+
+void Abstract3DRenderer::initializeOpenGL()
+{
+ // Set OpenGL features
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
+#if !defined(QT_OPENGL_ES_2)
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+#endif
+
+ m_textureHelper = new TextureHelper();
+ m_drawer->initializeOpenGL();
+
+ axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationX).setDrawer(m_drawer);
+ axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationY).setDrawer(m_drawer);
+ axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationZ).setDrawer(m_drawer);
+}
+
+void Abstract3DRenderer::render(const GLuint defaultFboHandle)
+{
+#ifdef DISPLAY_RENDER_SPEED
+ // For speed computation
+ if (m_isFirstFrame) {
+ m_lastFrameTime.start();
+ m_isFirstFrame = false;
+ }
+
+ // Measure speed (as milliseconds per frame)
+ m_numFrames++;
+ if (m_lastFrameTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago
+ qDebug() << qreal(m_lastFrameTime.elapsed()) / qreal(m_numFrames) << "ms/frame (=" << qreal(m_numFrames) << "fps)";
+ m_numFrames = 0;
+ m_lastFrameTime.restart();
+ }
+#endif
+
+ if (defaultFboHandle) {
+ glDepthMask(true);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glDisable(GL_BLEND); // For QtQuick2 blending is enabled by default, but we don't want it to be
+ }
+
+ glViewport(m_cachedScene->viewport().x(),
+ m_cachedScene->viewport().y(),
+ m_cachedScene->viewport().width(),
+ m_cachedScene->viewport().height());
+
+ QVector3D clearColor = Utils::vectorFromColor(m_cachedTheme.m_windowColor);
+ glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+QString Abstract3DRenderer::generateValueLabel(const QString &format, qreal value)
+{
+ QString valueLabelFormat = format;
+ Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat);
+ QByteArray valueFormatArray = valueLabelFormat.toUtf8();
+ return Utils::formatLabel(valueFormatArray, valueParamType, value);
+}
+
+void Abstract3DRenderer::updateDataModel(QAbstractDataProxy *dataProxy)
+{
+ m_cachedItemLabelFormat = dataProxy->itemLabelFormat();
+}
+
+QString Abstract3DRenderer::itemLabelFormat() const
+{
+ return m_cachedItemLabelFormat;
+}
+
+void Abstract3DRenderer::updateBoundingRect(const QRect &boundingRect)
+{
+ m_cachedBoundingRect = boundingRect;
+ handleResize();
+}
+
+void Abstract3DRenderer::updatePosition(const QRect &boundingRect)
+{
+ m_cachedBoundingRect = boundingRect;
+}
+
+void Abstract3DRenderer::updateTheme(Theme theme)
+{
+ m_cachedTheme.setFromTheme(theme);
+
+ m_drawer->setTheme(m_cachedTheme);
+ // Re-initialize shaders
+ handleShadowQualityChange();
+}
+
+void Abstract3DRenderer::updateScene(Q3DScene *scene)
+{
+ // Synchronize the controller scene to that of the renderer, and vice versa.
+ // Controller scene had priority if both have changed same values.
+ scene->d_ptr->sync(*m_cachedScene->d_ptr);
+ m_cachedScene->d_ptr->sync(*scene->d_ptr);
+}
+
+void Abstract3DRenderer::handleShadowQualityChange()
+{
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ if (!m_cachedTheme.m_uniformColor) {
+ initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ } else {
+ if (!m_cachedTheme.m_uniformColor) {
+ initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragmentColorOnY"));
+ } else {
+ initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ initBackgroundShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+#else
+ if (!m_cachedTheme.m_uniformColor) {
+ initShaders(QStringLiteral(":/shaders/vertexES2"),
+ QStringLiteral(":/shaders/fragmentColorOnYES2"));
+ } else {
+ initShaders(QStringLiteral(":/shaders/vertexES2"),
+ QStringLiteral(":/shaders/fragmentES2"));
+ }
+ initBackgroundShaders(QStringLiteral(":/shaders/vertexES2"),
+ QStringLiteral(":/shaders/fragmentES2"));
+#endif
+}
+
+void Abstract3DRenderer::updateFont(const QFont &font)
+{
+ m_cachedFont = font;
+ m_drawer->setFont(font);
+}
+
+void Abstract3DRenderer::updateLabelStyle(QDataVis::LabelStyle style)
+{
+ m_cachedLabelStyle = style;
+ m_drawer->setStyle(style);
+}
+
+void Abstract3DRenderer::updateMeshFileName(const QString &objFileName)
+{
+ if (objFileName != m_cachedObjFile) {
+ m_cachedObjFile = objFileName;
+ loadMeshFile();
+ }
+}
+
+void Abstract3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode)
+{
+ m_cachedSelectionMode = mode;
+}
+
+void Abstract3DRenderer::updateGridEnabled(bool enable)
+{
+ m_cachedIsGridEnabled = enable;
+}
+
+void Abstract3DRenderer::updateBackgroundEnabled(bool enable)
+{
+ m_cachedIsBackgroundEnabled = enable;
+}
+
+void Abstract3DRenderer::handleResize()
+{
+ if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0)
+ return;
+ // Calculate zoom level based on aspect ratio
+ GLfloat div;
+ GLfloat zoomAdjustment;
+ div = qMin(m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+ zoomAdjustment = defaultRatio * ((m_cachedBoundingRect.width() / div)
+ / (m_cachedBoundingRect.height() / div));
+ m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f
+
+ // Re-init selection buffer
+ initSelectionBuffer();
+
+#if !defined(QT_OPENGL_ES_2)
+ // Re-init depth buffer
+ updateDepthBuffer();
+#endif
+}
+
+void Abstract3DRenderer::updateAxisType(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis::AxisType type)
+{
+ axisCacheForOrientation(orientation).setType(type);
+}
+
+void Abstract3DRenderer::updateAxisTitle(Q3DAbstractAxis::AxisOrientation orientation, const QString &title)
+{
+ axisCacheForOrientation(orientation).setTitle(title);
+}
+
+void Abstract3DRenderer::updateAxisLabels(Q3DAbstractAxis::AxisOrientation orientation, const QStringList &labels)
+{
+ axisCacheForOrientation(orientation).setLabels(labels);
+}
+
+void Abstract3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max)
+{
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ cache.setMin(min);
+ cache.setMax(max);
+}
+
+void Abstract3DRenderer::updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count)
+{
+ axisCacheForOrientation(orientation).setSegmentCount(count);
+}
+
+void Abstract3DRenderer::updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count)
+{
+ axisCacheForOrientation(orientation).setSubSegmentCount(count);
+}
+
+void Abstract3DRenderer::updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientation orientation, const QString &format)
+{
+ axisCacheForOrientation(orientation).setLabelFormat(format);
+}
+
+AxisRenderCache &Abstract3DRenderer::axisCacheForOrientation(Q3DAbstractAxis::AxisOrientation orientation)
+{
+ switch (orientation) {
+ case Q3DAbstractAxis::AxisOrientationX:
+ return m_axisCacheX;
+ case Q3DAbstractAxis::AxisOrientationY:
+ return m_axisCacheY;
+ case Q3DAbstractAxis::AxisOrientationZ:
+ return m_axisCacheZ;
+ default:
+ qFatal("Abstract3DRenderer::axisCacheForOrientation");
+ return m_axisCacheX;
+ }
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
new file mode 100644
index 00000000..1c61ac07
--- /dev/null
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 ABSTRACT3DRENDERER_P_H
+#define ABSTRACT3DRENDERER_P_H
+
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QFont>
+#include <QTime>
+
+#include "datavisualizationglobal_p.h"
+#include "abstract3dcontroller_p.h"
+#include "axisrendercache_p.h"
+#include "qabstractdataproxy.h"
+
+//#define DISPLAY_RENDER_SPEED
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class TextureHelper;
+class Theme;
+class Drawer;
+
+class Abstract3DRenderer : public QObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+private:
+ Abstract3DController *m_controller;
+
+protected:
+ bool m_hasNegativeValues;
+ Theme m_cachedTheme;
+ QFont m_cachedFont;
+ QDataVis::LabelStyle m_cachedLabelStyle;
+ Drawer *m_drawer;
+ QRect m_cachedBoundingRect;
+ QDataVis::ShadowQuality m_cachedShadowQuality;
+ GLfloat m_autoScaleAdjustment;
+
+ QString m_cachedItemLabelFormat;
+ QString m_cachedObjFile;
+ QDataVis::SelectionMode m_cachedSelectionMode;
+ bool m_cachedIsGridEnabled;
+ bool m_cachedIsBackgroundEnabled;
+
+ AxisRenderCache m_axisCacheX;
+ AxisRenderCache m_axisCacheY;
+ AxisRenderCache m_axisCacheZ;
+ TextureHelper *m_textureHelper;
+ Q3DBox m_boundingBox;
+
+ Q3DScene *m_cachedScene;
+
+#ifdef DISPLAY_RENDER_SPEED
+ bool m_isFirstFrame;
+ QTime m_lastFrameTime;
+ GLint m_numFrames;
+#endif
+
+ QString generateValueLabel(const QString &format, qreal value);
+
+public:
+ virtual ~Abstract3DRenderer();
+
+ void updateDataModel(QAbstractDataProxy *dataProxy);
+
+ virtual void render(GLuint defaultFboHandle);
+
+ virtual void updateBoundingRect(const QRect &boundingRect);
+ virtual void updatePosition(const QRect &boundingRect);
+
+ virtual void updateTheme(Theme theme);
+ virtual void updateFont(const QFont &font);
+ virtual void updateLabelStyle(QDataVis::LabelStyle style);
+ virtual void updateSelectionMode(QDataVis::SelectionMode newMode);
+ virtual void updateGridEnabled(bool enable);
+ virtual void updateBackgroundEnabled(bool enable);
+ virtual void updateMeshFileName(const QString &objFileName);
+ virtual void updateScene(Q3DScene *scene);
+ virtual QString itemLabelFormat() const;
+ virtual void updateTextures() = 0;
+ virtual void initSelectionBuffer() = 0;
+
+#if !defined(QT_OPENGL_ES_2)
+ virtual void updateDepthBuffer() = 0;
+#endif
+ virtual void updateShadowQuality(QDataVis::ShadowQuality quality) = 0;
+ virtual void initShaders(const QString &vertexShader, const QString &fragmentShader) = 0;
+ virtual void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader) = 0;
+ virtual void updateAxisType(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis::AxisType type);
+ virtual void updateAxisTitle(Q3DAbstractAxis::AxisOrientation orientation, const QString &title);
+ virtual void updateAxisLabels(Q3DAbstractAxis::AxisOrientation orientation, const QStringList &labels);
+ virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
+ virtual void updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count);
+ virtual void updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count);
+ virtual void updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientation orientation, const QString &format);
+
+signals:
+ void needRender(); // Emit this if something in renderer causes need for another render pass.
+
+protected:
+ Abstract3DRenderer(Abstract3DController *controller);
+
+ virtual void initializeOpenGL();
+
+ virtual void handleShadowQualityChange();
+ virtual void handleResize();
+ virtual void loadMeshFile() = 0;
+
+ AxisRenderCache &axisCacheForOrientation(Q3DAbstractAxis::AxisOrientation orientation);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // ABSTRACT3DRENDERER_P_H
diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp
new file mode 100644
index 00000000..55ac0765
--- /dev/null
+++ b/src/datavisualization/engine/axisrendercache.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "axisrendercache_p.h"
+#include "qmath.h"
+#include <QFontMetrics>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+AxisRenderCache::AxisRenderCache()
+ : m_type(Q3DAbstractAxis::AxisTypeNone),
+ m_min(0.0),
+ m_max(10.0),
+ m_segmentCount(5),
+ m_subSegmentCount(1),
+ m_font(QFont(QStringLiteral("Arial"))),
+ m_drawer(0),
+ m_segmentStep(10.0f),
+ m_subSegmentStep(10.0f)
+{
+}
+
+AxisRenderCache::~AxisRenderCache()
+{
+ foreach (LabelItem *label, m_labelItems)
+ delete label;
+}
+
+void AxisRenderCache::setDrawer(Drawer *drawer)
+{
+ m_drawer = drawer;
+ m_font = m_drawer->font();
+ if (m_drawer) {
+ QObject::connect(m_drawer, &Drawer::drawerChanged, this, &AxisRenderCache::updateTextures);
+ updateTextures();
+ }
+}
+
+void AxisRenderCache::setType(Q3DAbstractAxis::AxisType type)
+{
+ m_type = type;
+
+ // If type is set, it means completely new axis instance, so clear all old data
+ m_labels.clear();
+ m_title.clear();
+ m_min = 0.0;
+ m_max = 10.0;
+ m_segmentCount = 5;
+ m_subSegmentCount = 1;
+ m_labelFormat.clear();
+
+ m_titleItem.clear();
+ foreach (LabelItem *label, m_labelItems)
+ delete label;
+ m_labelItems.clear();
+ m_segmentStep = 10.0f;
+ m_subSegmentStep = 10.0f;
+}
+
+void AxisRenderCache::setTitle(const QString &title)
+{
+ if (m_title != title) {
+ m_title = title;
+ // Generate axis label texture
+ if (m_drawer)
+ m_drawer->generateLabelItem(m_titleItem, title);
+ }
+}
+
+void AxisRenderCache::setLabels(const QStringList &labels)
+{
+ if (m_labels != labels) {
+ int newSize(labels.size());
+ int oldSize(m_labels.size());
+
+ for (int i = newSize; i < oldSize; i++)
+ delete m_labelItems.takeLast();
+
+ m_labelItems.reserve(newSize);
+
+ int widest = maxLabelWidth(labels);
+
+ for (int i = 0; i < newSize; i++) {
+ if (i >= oldSize)
+ m_labelItems.append(new LabelItem);
+ if (m_drawer) {
+ if (labels.at(i).isEmpty())
+ m_labelItems[i]->clear();
+ else if (i >= oldSize || labels.at(i) != m_labels.at(i))
+ m_drawer->generateLabelItem(*m_labelItems[i], labels.at(i), widest);
+ }
+ }
+ m_labels = labels;
+ }
+}
+
+void AxisRenderCache::setMin(qreal min)
+{
+ m_min = min;
+ updateSegmentStep();
+}
+
+void AxisRenderCache::setMax(qreal max)
+{
+ m_max = max;
+ updateSegmentStep();
+}
+
+void AxisRenderCache::setSegmentCount(int count)
+{
+ m_segmentCount = count;
+ updateSegmentStep();
+}
+
+void AxisRenderCache::setSubSegmentCount(int count)
+{
+ m_subSegmentCount = count;
+ updateSubSegmentStep();
+}
+
+void AxisRenderCache::updateTextures()
+{
+ m_font = m_drawer->font();
+
+ if (m_title.isEmpty())
+ m_titleItem.clear();
+ else
+ m_drawer->generateLabelItem(m_titleItem, m_title);
+
+ int widest = maxLabelWidth(m_labels);
+
+ for (int i = 0; i < m_labels.size(); i++) {
+ if (m_labels.at(i).isEmpty())
+ m_labelItems[i]->clear();
+ else
+ m_drawer->generateLabelItem(*m_labelItems[i], m_labels.at(i), widest);
+ }
+}
+
+void AxisRenderCache::updateSegmentStep()
+{
+ if (m_segmentCount > 0)
+ m_segmentStep = qFabs((m_max - m_min) / m_segmentCount);
+ else
+ m_segmentStep = 0.0f; // Irrelevant
+ updateSubSegmentStep();
+}
+
+void AxisRenderCache::updateSubSegmentStep()
+{
+ if (m_subSegmentCount > 1)
+ m_subSegmentStep = m_segmentStep / m_subSegmentCount;
+ else
+ m_subSegmentStep = m_segmentStep;
+}
+
+int AxisRenderCache::maxLabelWidth(const QStringList &labels) const
+{
+ int labelWidth = 0;
+ QFont labelFont = m_font;
+ labelFont.setPointSize(textureFontSize);
+ QFontMetrics labelFM(labelFont);
+ for (int i = 0; i < labels.size(); i++) {
+ int newWidth = labelFM.width(labels.at(i));
+ if (labelWidth < newWidth)
+ labelWidth = newWidth;
+ }
+ return labelWidth;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h
new file mode 100644
index 00000000..0bb1cf92
--- /dev/null
+++ b/src/datavisualization/engine/axisrendercache_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 AXISRENDERCACHE_P_H
+#define AXISRENDERCACHE_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "labelitem_p.h"
+#include "q3dabstractaxis_p.h"
+#include "drawer_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class AxisRenderCache : public QObject
+{
+ Q_OBJECT
+public:
+ AxisRenderCache();
+ virtual ~AxisRenderCache();
+
+ void setDrawer(Drawer *drawer);
+
+ void setType(Q3DAbstractAxis::AxisType type);
+ inline Q3DAbstractAxis::AxisType type() const { return m_type; }
+ void setTitle(const QString &title);
+ inline const QString &title() { return m_title; }
+ void setLabels(const QStringList &labels);
+ inline const QStringList &labels() { return m_labels; }
+ void setMin(qreal min);
+ inline qreal min() { return m_min; }
+ void setMax(qreal max);
+ inline qreal max() { return m_max; }
+ void setSegmentCount(int count);
+ inline int segmentCount() const { return m_segmentCount; }
+ void setSubSegmentCount(int count);
+ inline int subSegmentCount() const { return m_subSegmentCount; }
+ inline void setLabelFormat(const QString &format) { m_labelFormat = format; }
+ inline const QString &labelFormat() { return m_labelFormat; }
+
+ inline LabelItem &titleItem() { return m_titleItem; }
+ inline QList<LabelItem *> &labelItems() { return m_labelItems; }
+ inline GLfloat segmentStep() const { return m_segmentStep; }
+ inline GLfloat subSegmentStep() const { return m_subSegmentStep; }
+
+public slots:
+ void updateTextures();
+
+private:
+ void updateSegmentStep();
+ void updateSubSegmentStep();
+ int maxLabelWidth(const QStringList &labels) const;
+
+ // Cached axis values
+ Q3DAbstractAxis::AxisType m_type;
+ QString m_title;
+ QStringList m_labels;
+ qreal m_min;
+ qreal m_max;
+ int m_segmentCount;
+ int m_subSegmentCount;
+ QString m_labelFormat;
+ QFont m_font;
+
+ // Renderer items
+ Drawer *m_drawer; // Not owned
+ LabelItem m_titleItem;
+ QList<LabelItem *> m_labelItems;
+ GLfloat m_segmentStep;
+ GLfloat m_subSegmentStep;
+
+ Q_DISABLE_COPY(AxisRenderCache)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp
new file mode 100644
index 00000000..50d8d030
--- /dev/null
+++ b/src/datavisualization/engine/bars3dcontroller.cpp
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "bars3dcontroller_p.h"
+#include "bars3drenderer_p.h"
+#include "camerahelper_p.h"
+#include "q3dabstractaxis_p.h"
+#include "q3dvalueaxis_p.h"
+#include "q3dcategoryaxis_p.h"
+#include "qbardataproxy_p.h"
+
+#include <QMatrix4x4>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Bars3DController::Bars3DController(QRect boundRect)
+ : Abstract3DController(boundRect),
+ m_selectedBarPos(noSelectionPoint()),
+ m_isBarSpecRelative(true),
+ m_barThicknessRatio(1.0f),
+ m_barSpacing(QSizeF(1.0, 1.0)),
+ m_renderer(0)
+{
+ // Default bar type; specific to bars
+ setBarType(QDataVis::MeshStyleBevelBars, false);
+
+ setActiveDataProxy(0);
+
+ // Setting a null axis creates a new default axis according to orientation and graph type.
+ // Note: These cannot be set in Abstract3DController constructor, as they will call virtual
+ // functions implemented by subclasses.
+ setAxisX(0);
+ setAxisY(0);
+ setAxisZ(0);
+}
+
+Bars3DController::~Bars3DController()
+{
+}
+
+void Bars3DController::initializeOpenGL()
+{
+ // Initialization is called multiple times when Qt Quick components are used
+ if (isInitialized())
+ return;
+
+ m_renderer = new Bars3DRenderer(this);
+
+ setRenderer(m_renderer);
+ synchDataToRenderer();
+
+ QObject::connect(m_renderer, &Bars3DRenderer::selectedBarPosChanged, this,
+ &Bars3DController::handleSelectedBarPosChanged, Qt::QueuedConnection);
+ emitNeedRender();
+}
+
+void Bars3DController::synchDataToRenderer()
+{
+ Abstract3DController::synchDataToRenderer();
+
+ if (!isInitialized())
+ return;
+
+ // Notify changes to renderer
+ if (m_changeTracker.barSpecsChanged) {
+ m_renderer->updateBarSpecs(m_barThicknessRatio, m_barSpacing, m_isBarSpecRelative);
+ m_changeTracker.barSpecsChanged = false;
+ }
+
+ if (m_changeTracker.selectedBarPosChanged) {
+ m_renderer->updateSelectedBarPos(m_selectedBarPos);
+ m_changeTracker.selectedBarPosChanged = false;
+ }
+
+ if (m_isDataDirty) {
+ m_renderer->updateDataModel(static_cast<QBarDataProxy *>(m_data));
+ m_isDataDirty = false;
+ }
+}
+
+void Bars3DController::setActiveDataProxy(QAbstractDataProxy *proxy)
+{
+ // Setting null proxy indicates default proxy
+ if (!proxy) {
+ proxy = new QBarDataProxy;
+ proxy->d_ptr->setDefaultProxy(true);
+ }
+
+ Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeBar);
+
+ Abstract3DController::setActiveDataProxy(proxy);
+
+ QBarDataProxy *barDataProxy = static_cast<QBarDataProxy *>(m_data);
+
+ QObject::connect(barDataProxy, &QBarDataProxy::arrayReset, this,
+ &Bars3DController::handleArrayReset);
+ QObject::connect(barDataProxy, &QBarDataProxy::rowsAdded, this,
+ &Bars3DController::handleRowsAdded);
+ QObject::connect(barDataProxy, &QBarDataProxy::rowsChanged, this,
+ &Bars3DController::handleRowsChanged);
+ QObject::connect(barDataProxy, &QBarDataProxy::rowsRemoved, this,
+ &Bars3DController::handleRowsRemoved);
+ QObject::connect(barDataProxy, &QBarDataProxy::rowsInserted, this,
+ &Bars3DController::handleRowsInserted);
+ QObject::connect(barDataProxy, &QBarDataProxy::itemChanged, this,
+ &Bars3DController::handleItemChanged);
+ QObject::connect(barDataProxy, &QBarDataProxy::rowLabelsChanged, this,
+ &Bars3DController::handleDataRowLabelsChanged);
+ QObject::connect(barDataProxy, &QBarDataProxy::columnLabelsChanged, this,
+ &Bars3DController::handleDataColumnLabelsChanged);
+
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+
+ // Always clear selection on proxy change
+ setSelectedBarPos(noSelectionPoint());
+
+ handleDataRowLabelsChanged();
+ handleDataColumnLabelsChanged();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Bars3DController::handleArrayReset()
+{
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+ // Clear selection unless still valid
+ setSelectedBarPos(m_selectedBarPos);
+ emitNeedRender();
+}
+
+void Bars3DController::handleRowsAdded(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should update slice instead of deactivating?
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Bars3DController::handleRowsChanged(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should update slice instead of deactivating?
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Bars3DController::handleRowsRemoved(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should update slice instead of deactivating?
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+
+ // Clear selection unless still valid
+ setSelectedBarPos(m_selectedBarPos);
+
+ emitNeedRender();
+}
+
+void Bars3DController::handleRowsInserted(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should update slice instead of deactivating?
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Bars3DController::handleItemChanged(int rowIndex, int columnIndex)
+{
+ Q_UNUSED(rowIndex)
+ Q_UNUSED(columnIndex)
+ // TODO should update slice instead of deactivating?
+ scene()->setSlicingActive(false);
+ adjustAxisRanges();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Bars3DController::handleDataRowLabelsChanged()
+{
+ if (m_axisX && m_data) {
+ // Grab a sublist equal to data window (no need to have more labels in axis)
+ int min = int(m_axisX->min());
+ int count = int(m_axisX->max()) - min + 1;
+ QStringList subList = static_cast<QBarDataProxy *>(m_data)->rowLabels().mid(min, count);
+ static_cast<Q3DCategoryAxis *>(m_axisX)->dptr()->setDataLabels(subList);
+ }
+}
+
+void Bars3DController::handleDataColumnLabelsChanged()
+{
+ if (m_axisZ && m_data) {
+ // Grab a sublist equal to data window (no need to have more labels in axis)
+ int min = int(m_axisZ->min());
+ int count = int(m_axisZ->max()) - min + 1;
+ QStringList subList = static_cast<QBarDataProxy *>(m_data)->columnLabels().mid(min, count);
+ static_cast<Q3DCategoryAxis *>(m_axisZ)->dptr()->setDataLabels(subList);
+ }
+}
+
+void Bars3DController::handleSelectedBarPosChanged(const QPoint &position)
+{
+ QPoint pos = position;
+ if (pos == QPoint(255, 255))
+ pos = noSelectionPoint();
+ if (pos != m_selectedBarPos) {
+ m_selectedBarPos = pos;
+ emit selectedBarPosChanged(pos);
+ emitNeedRender();
+ }
+}
+
+void Bars3DController::handleAxisAutoAdjustRangeChangedInOrientation(
+ Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust)
+{
+ Q_UNUSED(orientation)
+ Q_UNUSED(autoAdjust)
+ adjustAxisRanges();
+}
+
+QPoint Bars3DController::noSelectionPoint()
+{
+ static QPoint noSelectionPos(-1, -1);
+ return noSelectionPos;
+}
+
+void Bars3DController::setAxisX(Q3DAbstractAxis *axis)
+{
+ Abstract3DController::setAxisX(axis);
+ handleDataRowLabelsChanged();
+}
+
+void Bars3DController::setAxisZ(Q3DAbstractAxis *axis)
+{
+ Abstract3DController::setAxisZ(axis);
+ handleDataColumnLabelsChanged();
+}
+
+void Bars3DController::handleAxisRangeChangedBySender(QObject *sender)
+{
+ // Data window changed
+ if (sender == m_axisX || sender == m_axisZ) {
+ // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted)
+ scene()->setSlicingActive(false);
+
+ // Clear selection unless still valid
+ setSelectedBarPos(m_selectedBarPos);
+
+ if (sender == m_axisX)
+ handleDataRowLabelsChanged();
+ if (sender == m_axisZ)
+ handleDataColumnLabelsChanged();
+ }
+
+ Abstract3DController::handleAxisRangeChangedBySender(sender);
+}
+
+void Bars3DController::setBarSpecs(GLfloat thicknessRatio, const QSizeF &spacing, bool relative)
+{
+ m_barThicknessRatio = thicknessRatio;
+ m_barSpacing = spacing;
+ m_isBarSpecRelative = relative;
+
+ m_changeTracker.barSpecsChanged = true;
+ emitNeedRender();
+}
+
+GLfloat Bars3DController::barThickness()
+{
+ return m_barThicknessRatio;
+}
+
+QSizeF Bars3DController::barSpacing()
+{
+ return m_barSpacing;
+}
+
+bool Bars3DController::isBarSpecRelative()
+{
+ return m_isBarSpecRelative;
+}
+
+void Bars3DController::setBarType(QDataVis::MeshStyle style, bool smooth)
+{
+ QString objFile;
+ if (style == QDataVis::MeshStyleBars)
+ objFile = QStringLiteral(":/defaultMeshes/bar");
+ else if (style == QDataVis::MeshStylePyramids)
+ objFile = QStringLiteral(":/defaultMeshes/pyramid");
+ else if (style == QDataVis::MeshStyleCones)
+ objFile = QStringLiteral(":/defaultMeshes/cone");
+ else if (style == QDataVis::MeshStyleCylinders)
+ objFile = QStringLiteral(":/defaultMeshes/cylinder");
+ else if (style == QDataVis::MeshStyleBevelBars)
+ objFile = QStringLiteral(":/defaultMeshes/bevelbar");
+
+ if (smooth)
+ objFile += QStringLiteral("Smooth");
+
+ Abstract3DController::setMeshFileName(objFile);
+}
+
+void Bars3DController::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ // Disable zoom if selection mode changes
+ scene()->setSlicingActive(false);
+ Abstract3DController::setSelectionMode(mode);
+}
+
+void Bars3DController::setSelectedBarPos(const QPoint &position)
+{
+ // If the selection is outside data window or targets non-existent
+ // bar, clear selection instead.
+ QPoint pos = position;
+
+ if (pos != noSelectionPoint()) {
+ int minRow = int(m_axisX->min());
+ int maxRow = int(m_axisX->max());
+ int minCol = int(m_axisZ->min());
+ int maxCol = int(m_axisZ->max());
+
+ if (pos.x() < minRow || pos.x() > maxRow || pos.y() < minCol || pos.y() > maxCol
+ || pos.x() + minRow >= static_cast<QBarDataProxy *>(m_data)->rowCount()
+ || pos.y() + minCol >= static_cast<QBarDataProxy *>(m_data)->rowAt(pos.x())->size()) {
+ pos = noSelectionPoint();
+ }
+ }
+
+ if (pos != m_selectedBarPos) {
+ m_selectedBarPos = pos;
+ m_changeTracker.selectedBarPosChanged = true;
+ emit selectedBarPosChanged(pos);
+ emitNeedRender();
+ }
+}
+
+QPoint Bars3DController::selectedBarPos() const
+{
+ return m_selectedBarPos;
+}
+
+void Bars3DController::adjustAxisRanges()
+{
+ const QBarDataProxy *proxy = static_cast<QBarDataProxy *>(m_data);
+ const QBarDataArray *array = proxy->array();
+
+ Q3DCategoryAxis *categoryAxisX = static_cast<Q3DCategoryAxis *>(m_axisX);
+ if (categoryAxisX && categoryAxisX->isAutoAdjustRange() && proxy) {
+ int rowCount = proxy->rowCount();
+ if (rowCount)
+ rowCount--;
+ categoryAxisX->dptr()->setRange(0.0, qreal(rowCount));
+ }
+
+ Q3DCategoryAxis *categoryAxisZ = static_cast<Q3DCategoryAxis *>(m_axisZ);
+ if (categoryAxisZ && categoryAxisZ->isAutoAdjustRange() && proxy) {
+ int columnCount = 0;
+ for (int i = 0; i < array->size(); i++) {
+ if (columnCount < array->at(i)->size())
+ columnCount = array->at(i)->size();
+ }
+ if (columnCount)
+ columnCount--;
+ categoryAxisZ->dptr()->setRange(0.0, qreal(columnCount));
+ }
+
+ Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisY);
+ if (valueAxis && categoryAxisX && categoryAxisZ && valueAxis->isAutoAdjustRange() && proxy) {
+ QPair<GLfloat, GLfloat> limits = proxy->dptrc()->limitValues(categoryAxisX->min(),
+ categoryAxisX->max(),
+ categoryAxisZ->min(),
+ categoryAxisZ->max());
+ if (limits.first < 0) {
+ // TODO: Currently we only support symmetric y-axis for bar graph if there are negative values
+ qreal maxAbs = qMax(qFabs(limits.first), qFabs(limits.second));
+ // Call private implementation to avoid unsetting auto adjust flag
+ valueAxis->dptr()->setRange(-maxAbs, maxAbs);
+ } else if (limits.second == 0.0) {
+ valueAxis->dptr()->setRange(0.0, 1.0); // Only zero value values in data set, set range to something.
+ } else {
+ valueAxis->dptr()->setRange(0.0, limits.second);
+ }
+ }
+}
+
+Q3DAbstractAxis *Bars3DController::createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation)
+{
+ Q3DAbstractAxis *defaultAxis = 0;
+
+ if (orientation == Q3DAbstractAxis::AxisOrientationY)
+ defaultAxis = createDefaultValueAxis();
+ else
+ defaultAxis = createDefaultCategoryAxis();
+
+ return defaultAxis;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/bars3dcontroller_p.h b/src/datavisualization/engine/bars3dcontroller_p.h
new file mode 100644
index 00000000..8398dd81
--- /dev/null
+++ b/src/datavisualization/engine/bars3dcontroller_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DBARSCONTROLLER_p_H
+#define Q3DBARSCONTROLLER_p_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstract3dcontroller_p.h"
+
+//#define DISPLAY_RENDER_SPEED
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Bars3DRenderer;
+class QBarDataProxy;
+
+struct Bars3DChangeBitField {
+ bool slicingActiveChanged : 1;
+ bool barSpecsChanged : 1;
+ bool selectedBarPosChanged : 1;
+
+ Bars3DChangeBitField() :
+ slicingActiveChanged(true),
+ barSpecsChanged(true),
+ selectedBarPosChanged(true)
+ {
+ }
+};
+
+class QT_DATAVISUALIZATION_EXPORT Bars3DController : public Abstract3DController
+{
+ Q_OBJECT
+
+private:
+ Bars3DChangeBitField m_changeTracker;
+
+ // Interaction
+ QPoint m_selectedBarPos; // Points to row & column in data window.
+
+ // Look'n'feel
+ bool m_isBarSpecRelative;
+ GLfloat m_barThicknessRatio;
+ QSizeF m_barSpacing;
+
+ // Rendering
+ Bars3DRenderer *m_renderer;
+
+public:
+ explicit Bars3DController(QRect rect);
+ ~Bars3DController();
+
+ void initializeOpenGL();
+ virtual void synchDataToRenderer();
+
+ // bar thickness, spacing between bars, and is spacing relative to thickness or absolute
+ // y -component sets the thickness/spacing of z -direction
+ // With relative 0.0f means side-to-side, 1.0f = one thickness in between
+ void setBarSpecs(GLfloat thicknessRatio = 1.0f,
+ const QSizeF &spacing = QSizeF(1.0, 1.0),
+ bool relative = true);
+ GLfloat barThickness();
+ QSizeF barSpacing();
+ bool isBarSpecRelative();
+
+ // bar type; bars (=cubes), pyramids, cones, cylinders, etc.
+ void setBarType(QDataVis::MeshStyle style, bool smooth = false);
+
+ // Change selection mode; single bar, bar and row, bar and column, or all
+ void setSelectionMode(QDataVis::SelectionMode mode);
+
+ void setSelectedBarPos(const QPoint &position);
+ QPoint selectedBarPos() const;
+
+ virtual void setActiveDataProxy(QAbstractDataProxy *proxy);
+
+ virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust);
+
+ static QPoint noSelectionPoint();
+
+ virtual void setAxisX(Q3DAbstractAxis *axis);
+ virtual void setAxisZ(Q3DAbstractAxis *axis);
+
+ virtual void handleAxisRangeChangedBySender(QObject *sender);
+
+public slots:
+ void handleArrayReset();
+ void handleRowsAdded(int startIndex, int count);
+ void handleRowsChanged(int startIndex, int count);
+ void handleRowsRemoved(int startIndex, int count);
+ void handleRowsInserted(int startIndex, int count);
+ void handleItemChanged(int rowIndex, int columnIndex);
+ void handleDataRowLabelsChanged();
+ void handleDataColumnLabelsChanged();
+
+ void handleSelectedBarPosChanged(const QPoint &position);
+
+signals:
+ void selectedBarPosChanged(QPoint position);
+
+protected:
+ virtual Q3DAbstractAxis *createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation);
+
+private:
+ void adjustAxisRanges();
+
+ Q_DISABLE_COPY(Bars3DController)
+
+};
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
new file mode 100644
index 00000000..74c1a99b
--- /dev/null
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -0,0 +1,1880 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "bars3drenderer_p.h"
+#include "bars3dcontroller_p.h"
+#include "q3dcamera_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "texturehelper_p.h"
+#include "theme_p.h"
+#include "utils_p.h"
+#include "drawer_p.h"
+#include "qbardataitem.h"
+#include "q3dlight.h"
+
+#include <QMatrix4x4>
+#include <QMouseEvent>
+#include <QThread>
+#include <qmath.h>
+#include <QDebug>
+
+// You can verify that depth buffer drawing works correctly by uncommenting this.
+// You should see the scene from where the light is
+//#define SHOW_DEPTH_TEXTURE_SCENE
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+const GLfloat labelMargin = 0.05f;
+const GLfloat gridLineWidth = 0.005f;
+static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color
+
+Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
+ : Abstract3DRenderer(controller),
+ m_controller(controller),
+ m_cachedIsSlicingActivated(false),
+ m_cachedRowCount(0),
+ m_cachedColumnCount(0),
+ m_selectedBar(0),
+ m_sliceSelection(0),
+ m_sliceCache(0),
+ m_sliceTitleItem(0),
+ m_xFlipped(false),
+ m_zFlipped(false),
+ m_yFlipped(false),
+ m_updateLabels(false),
+ m_barShader(0),
+ m_depthShader(0),
+ m_selectionShader(0),
+ m_backgroundShader(0),
+ m_labelShader(0),
+ m_barObj(0),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_bgrTexture(0),
+ m_depthTexture(0),
+ m_selectionTexture(0),
+ m_depthFrameBuffer(0),
+ m_selectionFrameBuffer(0),
+ m_selectionDepthBuffer(0),
+ m_shadowQualityToShader(100.0f),
+ m_shadowQualityMultiplier(3),
+ m_heightNormalizer(1.0f),
+ m_yAdjustment(0.0f),
+ m_rowWidth(0),
+ m_columnDepth(0),
+ m_maxDimension(0),
+ m_scaleX(0),
+ m_scaleZ(0),
+ m_scaleFactor(0),
+ m_maxSceneSize(40.0),
+ m_selection(selectionSkipColor),
+ m_previousSelection(selectionSkipColor),
+ m_hasHeightAdjustmentChanged(true)
+{
+ initializeOpenGLFunctions();
+ initializeOpenGL();
+}
+
+Bars3DRenderer::~Bars3DRenderer()
+{
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->deleteTexture(&m_bgrTexture);
+ if (m_sliceSelection) {
+ m_sliceSelection->clear(); // Slice doesn't own its items
+ delete m_sliceSelection;
+ }
+ delete m_barShader;
+ delete m_depthShader;
+ delete m_selectionShader;
+ delete m_backgroundShader;
+ delete m_barObj;
+ delete m_backgroundObj;
+ delete m_gridLineObj;
+ delete m_labelObj;
+ delete m_labelShader;
+}
+
+void Bars3DRenderer::initializeOpenGL()
+{
+ Abstract3DRenderer::initializeOpenGL();
+
+ // Initialize shaders
+ handleShadowQualityChange();
+
+ initLabelShaders(QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+
+#if !defined(QT_OPENGL_ES_2)
+ // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api.
+ initDepthShader();
+#endif
+
+ // Init selection shader
+ initSelectionShader();
+
+ // Load grid line mesh
+ loadGridLineMesh();
+
+ // Load label mesh
+ loadLabelMesh();
+
+ // Set view port
+ glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(),
+ m_sliceViewPort.width(), m_sliceViewPort.height());
+
+ // Load background mesh (we need to be initialized first)
+ loadBackgroundMesh();
+}
+
+void Bars3DRenderer::updateDataModel(QBarDataProxy *dataProxy)
+{
+ int minRow = m_axisCacheX.min();
+ int maxRow = m_axisCacheX.max();
+ int minCol = m_axisCacheZ.min();
+ int maxCol = m_axisCacheZ.max();
+ int newRows = maxRow - minRow + 1;
+ int newColumns = maxCol - minCol + 1;
+ if (newRows != m_renderItemArray.size() || newColumns != m_renderItemArray.at(0).size()) {
+ // Destroy old render items and reallocate new array
+ m_renderItemArray.clear();
+ m_renderItemArray.resize(newRows);
+ for (int i = 0; i < newRows; i++)
+ m_renderItemArray[i].resize(newColumns);
+
+ // Force update for selection related items
+ m_sliceCache = 0;
+ m_sliceTitleItem = 0;
+ if (m_sliceSelection)
+ m_sliceSelection->clear();
+
+ m_cachedColumnCount = newColumns;
+ m_cachedRowCount = newRows;
+ // TODO: Invent foolproof max scene size formula
+ // This seems to work ok if spacing is not negative (and row/column or column/row ratio is not too high)
+ m_maxSceneSize = 2 * qSqrt(newColumns * newRows);
+ // Calculate here and at setting bar specs
+ calculateSceneScalingFactors();
+ }
+
+ // Update cached data window
+ int dataRowCount = dataProxy->rowCount();
+ int dataRowIndex = minRow;
+ for (int i = 0; i < newRows; i++) {
+ int j = 0;
+ if (dataRowIndex < dataRowCount) {
+ const QBarDataRow *dataRow = dataProxy->rowAt(dataRowIndex);
+ int updateSize = qMin((dataRow->size() - minCol), m_renderItemArray[i].size());
+ if (dataRow) {
+ int dataColIndex = minCol;
+ for (; j < updateSize ; j++) {
+ qreal value = dataRow->at(dataColIndex).value();
+ m_renderItemArray[i][j].setValue(value);
+ m_renderItemArray[i][j].setHeight(GLfloat(value) / m_heightNormalizer);
+ dataColIndex++;
+ }
+ }
+ }
+ for (; j < m_renderItemArray[i].size(); j++) {
+ m_renderItemArray[i][j].setValue(0.0);
+ m_renderItemArray[i][j].setHeight(0.0f);
+ }
+ dataRowIndex++;
+ }
+
+ Abstract3DRenderer::updateDataModel(dataProxy);
+}
+
+void Bars3DRenderer::updateScene(Q3DScene *scene)
+{
+ // TODO: Move these to more suitable place e.g. controller should be controlling the viewports.
+ scene->setSecondarySubViewport(m_sliceViewPort);
+ scene->setPrimarySubViewport(m_mainViewPort);
+
+ // TODO: See QTRD-2374
+ if (m_hasNegativeValues)
+ scene->activeCamera()->setMinYRotation(-90.0);
+ else
+ scene->activeCamera()->setMinYRotation(0.0);
+
+ if (m_hasHeightAdjustmentChanged) {
+ // Set initial camera position. Also update if height adjustment has changed.
+ scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp),
+ QVector3D(0.0f, -m_yAdjustment, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ m_hasHeightAdjustmentChanged = false;
+ }
+
+ scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment);
+ // Set light position (rotate light with camera, a bit above it (as set in defaultLightPos))
+ scene->setLightPositionRelativeToCamera(defaultLightPos);
+
+ Abstract3DRenderer::updateScene(scene);
+
+ updateSlicingActive(scene->isSlicingActive());
+}
+
+void Bars3DRenderer::render(GLuint defaultFboHandle)
+{
+ bool slicingChanged = m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive();
+
+ // Handle GL state setup for FBO buffers and clearing of the render surface
+ Abstract3DRenderer::render(defaultFboHandle);
+
+ // If slice selection is on, draw the sliced scene
+ if (m_cachedIsSlicingActivated)
+ drawSlicedScene(m_axisCacheX.titleItem(), m_axisCacheY.titleItem(), m_axisCacheZ.titleItem());
+
+ // Draw bars scene
+ drawScene(defaultFboHandle);
+
+ // If slicing has been activated by this render pass, we need another render
+ // Also trigger another render always when slicing changes in general to ensure
+ // final draw is correct.
+ if (m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive() || slicingChanged)
+ emit needRender();
+}
+
+void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel,
+ const LabelItem &yLabel,
+ const LabelItem &zLabel)
+{
+ GLfloat barPosX = 0;
+ GLint startBar = 0;
+ GLint stopBar = m_sliceSelection->size();
+ GLint stepBar = 1;
+ QVector3D lightPos;
+ GLfloat negativesComp = 1.0f;
+
+ // Compensate bar scaling a bit to avoid drawing on axis titles when we have negative values
+ if (m_hasNegativeValues)
+ negativesComp = 0.67f;
+
+ // Specify viewport
+ glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(),
+ m_sliceViewPort.width(), m_sliceViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)m_sliceViewPort.width()
+ / (GLfloat)m_sliceViewPort.height(), 0.1f, 100.0f);
+
+ // Set view matrix
+ QMatrix4x4 viewMatrix;
+
+ // Adjust scaling (zoom rate based on aspect ratio)
+ GLfloat camZPosSliced = 5.0f / m_autoScaleAdjustment + zComp;
+
+ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, camZPosSliced),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // Set light position
+ lightPos = QVector3D(0.0f, -m_yAdjustment, zComp);
+
+ // Bind bar shader
+ m_barShader->bind();
+
+ // Draw bars
+ // Draw the selected row / column
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ BarRenderItem *item = m_sliceSelection->at(bar);
+ if (!item)
+ continue;
+
+ if (item->height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ GLfloat barPosY = negativesComp * item->translation().y() - m_yAdjustment / 2.0f + 0.2f; // we need some room for labels underneath; add +0.2f
+ if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode)
+ barPosX = item->translation().x();
+ else
+ barPosX = -(item->translation().z() - zComp); // flip z; frontmost bar to the left
+ modelMatrix.translate(barPosX, barPosY, zComp);
+ modelMatrix.scale(QVector3D(m_scaleX, negativesComp * item->height(), m_scaleZ));
+ itModelMatrix.scale(QVector3D(m_scaleX, negativesComp * item->height(), m_scaleZ));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+#if 0
+ QVector3D baseColor;
+ if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y())
+ baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor);
+ else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode)
+ baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor);
+ else
+ baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor);
+
+ QVector3D heightColor = Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item->height();
+ QVector3D barColor = baseColor + heightColor;
+#else
+ QVector3D barColor;
+ if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y())
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor);
+ else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode)
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor);
+ else
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor);
+#endif
+
+ if (item->height() != 0) {
+ // Set shader bindings
+ m_barShader->setUniformValue(m_barShader->lightP(), lightPos);
+ m_barShader->setUniformValue(m_barShader->view(), viewMatrix);
+ m_barShader->setUniformValue(m_barShader->model(), modelMatrix);
+ m_barShader->setUniformValue(m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix);
+ m_barShader->setUniformValue(m_barShader->color(), barColor);
+ m_barShader->setUniformValue(m_barShader->lightS(), 0.5f);
+ m_barShader->setUniformValue(m_barShader->ambientS(),
+ m_cachedTheme.m_ambientStrength * 2.0f);
+ // Draw the object
+#if defined (Q_OS_MAC)
+ // Mac slice issue hack fix. TODO: Fix correctly
+ m_drawer->drawObject(m_barShader, m_barObj, 0, -1);
+#else
+ m_drawer->drawObject(m_barShader, m_barObj);
+#endif
+ }
+ }
+
+ // Release bar shader
+ m_barShader->release();
+
+ // Draw labels
+ m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ glCullFace(GL_BACK);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // Draw labels for axes
+ BarRenderItem *dummyItem(0);
+ const LabelItem &sliceSelectionLabel = *m_sliceTitleItem;
+ if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) {
+ if (m_sliceTitleItem) {
+ m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelTop);
+ }
+ m_drawer->drawLabel(*dummyItem, zLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelBottom);
+ } else {
+ m_drawer->drawLabel(*dummyItem, xLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelBottom);
+ if (m_sliceTitleItem) {
+ m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelTop);
+ }
+ }
+ m_drawer->drawLabel(*dummyItem, yLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 90.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelLeft);
+
+ // Draw labels for bars
+ for (int col = 0; col < m_sliceSelection->size(); col++) {
+ BarRenderItem *item = m_sliceSelection->at(col);
+ // Draw values
+ if (negativesComp == 1.0f) {
+ m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 90.0f),
+ item->height(),
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false,
+ Drawer::LabelOver, Qt::AlignTop);
+ } else {
+ m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f),
+ negativesComp * negativesComp * item->height(),
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera());
+ }
+
+ // Draw labels
+ if (m_sliceCache->labelItems().size() > col) {
+ const LabelItem *labelItem(0);
+ labelItem = m_sliceCache->labelItems().at(col);
+ m_drawer->drawLabel(*item, *labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_autoScaleAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, -45.0f), item->height(),
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), false, false,
+ Drawer::LabelBelow);
+ }
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+
+ // Release label shader
+ m_labelShader->release();
+}
+
+void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
+{
+ GLint startBar = 0;
+ GLint stopBar = 0;
+ GLint stepBar = 0;
+
+ GLint startRow = 0;
+ GLint stopRow = 0;
+ GLint stepRow = 0;
+
+ GLfloat backgroundRotation = 0;
+
+ GLfloat colPos = 0;
+ GLfloat rowPos = 0;
+
+ // Specify viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f);
+
+ // Get the view matrix
+ QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix();
+
+ // Calculate drawing order
+ // Draw order is reversed to optimize amount of drawing (ie. draw front objects first, depth test handles not needing to draw objects behind them)
+ if (viewMatrix.row(0).x() > 0) {
+ startRow = 0;
+ stopRow = m_cachedRowCount;
+ stepRow = 1;
+ m_zFlipped = false;
+ } else {
+ startRow = m_cachedRowCount - 1;
+ stopRow = -1;
+ stepRow = -1;
+ m_zFlipped = true;
+ }
+ if (viewMatrix.row(0).z() <= 0) {
+ startBar = 0;
+ stopBar = m_cachedColumnCount;
+ stepBar = 1;
+ m_xFlipped = false;
+ } else {
+ startBar = m_cachedColumnCount - 1;
+ stopBar = -1;
+ stepBar = -1;
+ m_xFlipped = true;
+ }
+
+ // Check if we're viewing the scene from below
+ if (viewMatrix.row(2).y() < 0)
+ m_yFlipped = true;
+ else
+ m_yFlipped = false;
+
+ // calculate background rotation based on view matrix rotation
+ if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() <= 0)
+ backgroundRotation = 270.0f;
+ else if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() > 0)
+ backgroundRotation = 180.0f;
+ else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() > 0)
+ backgroundRotation = 90.0f;
+ else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() <= 0)
+ backgroundRotation = 0.0f;
+
+ // Get light position from the scene
+ QVector3D lightPos = m_cachedScene->activeLight()->position();
+
+ // Skip depth rendering if we're in slice mode
+ // Introduce regardless of shadow quality to simplify logic
+ QMatrix4x4 depthViewMatrix;
+ QMatrix4x4 depthProjectionMatrix;
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone && !m_cachedIsSlicingActivated) {
+ // Render scene into a depth texture for using with shadow mapping
+ // Enable drawing to depth framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Bind depth shader
+ m_depthShader->bind();
+
+ // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows.
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width() * m_shadowQualityMultiplier,
+ m_mainViewPort.height() * m_shadowQualityMultiplier);
+
+ // Get the depth view matrix
+ // It may be possible to hack lightPos here if we want to make some tweaks to shadow
+ QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera(
+ QVector3D(0.0f, 0.0f, zComp), 0.0f, 1.5f / m_autoScaleAdjustment);
+ depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, -m_yAdjustment, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above?
+ // That causes the scene to be not drawn from above -> must be fixed
+ // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3);
+
+ // Set the depth projection matrix
+ depthProjectionMatrix.perspective(10.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f);
+
+ // Draw bars to depth buffer
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ const BarRenderItem &item = m_renderItemArray.at(row).at(bar);
+ if (!item.value())
+ continue;
+
+ GLfloat shadowOffset = 0.0f;
+
+ // Set front face culling for negative valued bars and back face culling for
+ // positive valued bars to remove peter-panning issues
+ if (item.height() > 0) {
+ glCullFace(GL_BACK);
+ if (m_yFlipped)
+ shadowOffset = 0.015f;
+ } else {
+ glCullFace(GL_FRONT);
+ if (!m_yFlipped)
+ shadowOffset = -0.015f;
+ }
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ colPos = (bar + 0.5f) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
+
+ // Draw shadows for bars "on the other side" a bit off ground to avoid seeing
+ // shadows through the ground
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height() - m_yAdjustment + shadowOffset,
+ (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+ // Scale the bars down in X and Z to reduce self-shadowing issues
+ modelMatrix.scale(QVector3D(m_scaleX * 0.9f, item.height(), m_scaleZ * 0.9f));
+
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_barObj->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, m_barObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+ }
+ }
+
+ // Disable drawing to depth framebuffer (= enable drawing to screen)
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Release depth shader
+ m_depthShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it)
+ m_labelShader->bind();
+ glCullFace(GL_BACK);
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+ m_drawer->drawObject(m_labelShader, m_labelObj,
+ m_depthTexture);
+ glDisable(GL_TEXTURE_2D);
+ m_labelShader->release();
+#endif
+ // Reset culling to normal
+ glCullFace(GL_BACK);
+
+ // Revert to original viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+ }
+#endif
+
+ // Skip selection mode drawing if we're slicing or have no selection mode
+ if (!m_cachedIsSlicingActivated && m_cachedSelectionMode > QDataVis::SelectionModeNone) {
+ // Bind selection shader
+ m_selectionShader->bind();
+
+ // Draw bars to selection buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
+ glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
+ glClearColor(selectionSkipColor.x() / 255, selectionSkipColor.y() / 255,
+ selectionSkipColor.z() / 255, 1.0f); // Set clear color to white (= selectionSkipColor)
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
+ glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ const BarRenderItem &item = m_renderItemArray.at(row).at(bar);
+ if (!item.value())
+ continue;
+
+ if (item.height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ colPos = (bar + 0.5f) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
+
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height() - m_yAdjustment,
+ (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ // TODO: Save position to qdataitem, so that we don't need to calculate it each time?
+
+ //#if !defined(QT_OPENGL_ES_2)
+ // QVector3D barColor = QVector3D((GLdouble)row / 32767.0,
+ // (GLdouble)bar / 32767.0,
+ // 0.0);
+ //#else
+ QVector3D barColor = QVector3D((GLdouble)row / 255.0,
+ (GLdouble)bar / 255.0,
+ 0.0);
+ //#endif
+
+ m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
+ m_selectionShader->setUniformValue(m_selectionShader->color(), barColor);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_selectionShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_barObj->vertexBuf());
+ glVertexAttribPointer(m_selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, m_barObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_selectionShader->posAtt());
+ }
+ }
+ glEnable(GL_DITHER);
+
+ // Read color under cursor
+ if (QDataVis::InputStateOnScene == m_controller->inputState()) {
+ m_selection = Utils::getSelection(m_controller->inputPosition(),
+ m_cachedBoundingRect.height());
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Release selection shader
+ m_selectionShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ glCullFace(GL_BACK);
+ m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+ m_drawer->drawObject(m_labelShader, m_labelObj, m_selectionTexture);
+ glDisable(GL_TEXTURE_2D);
+ m_labelShader->release();
+#endif
+ }
+
+ // Enable texturing
+ glEnable(GL_TEXTURE_2D);
+
+ // Bind bar shader
+ m_barShader->bind();
+
+ bool selectionDirty = (m_selection != m_previousSelection
+ || (m_selection != selectionSkipColor
+ && QDataVis::InputStateOnScene == m_controller->inputState()
+ && !m_cachedIsSlicingActivated));
+ if (selectionDirty) {
+ m_previousSelection = m_selection;
+ if (m_sliceSelection) {
+ if (!m_cachedIsSlicingActivated) {
+ m_sliceCache = 0;
+ m_sliceTitleItem = 0;
+ }
+ if (m_sliceSelection->size()) {
+ // Slice doesn't own its items, no need to delete them - just clear
+ m_sliceSelection->clear();
+ }
+ }
+ }
+
+ // Draw bars
+ bool barSelectionFound = false;
+ BarRenderItem *selectedBar(0);
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ BarRenderItem &item = m_renderItemArray[row][bar];
+
+ if (item.height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+
+ colPos = (bar + 0.5f) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
+
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height() - m_yAdjustment,
+ (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ));
+ itModelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ));
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+#if 0
+ QVector3D baseColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor);
+ QVector3D heightColor = Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item.height();
+ QVector3D depthColor = Utils::vectorFromColor(m_cachedTheme.m_depthColor)
+ * (float(row) / GLfloat(m_cachedRowCount));
+
+ QVector3D barColor = baseColor + heightColor + depthColor;
+#else
+ QVector3D barColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor);
+#endif
+
+ GLfloat lightStrength = m_cachedTheme.m_lightStrength;
+
+ if (m_cachedSelectionMode > QDataVis::SelectionModeNone) {
+ Bars3DController::SelectionType selectionType = isSelected(row, bar);
+
+ switch (selectionType) {
+ case Bars3DController::SelectionItem: {
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor);
+ lightStrength = m_cachedTheme.m_highlightLightStrength;
+ // Insert position data into render item. We have no ownership, don't delete the previous one
+ if (!m_cachedIsSlicingActivated) {
+ selectedBar = &item;
+ selectedBar->setPosition(QPoint(row, bar));
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ barSelectionFound = true;
+ }
+ if (selectionDirty && m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow) {
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ item.setPosition(QPoint(row, bar));
+ m_sliceSelection->append(&item);
+ barSelectionFound = true;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ if (m_axisCacheX.labelItems().size() > row)
+ m_sliceTitleItem = m_axisCacheX.labelItems().at(row);
+ if (!m_sliceCache) {
+ // m_sliceCache is the axis for labels, while title comes from different axis.
+ m_sliceCache = &m_axisCacheZ;
+ }
+ } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) {
+ if (m_axisCacheZ.labelItems().size() > bar)
+ m_sliceTitleItem = m_axisCacheZ.labelItems().at(bar);
+ if (!m_sliceCache) {
+ // m_sliceCache is the axis for labels, while title comes from different axis.
+ m_sliceCache = &m_axisCacheX;
+ }
+ }
+ }
+ break;
+ }
+ case Bars3DController::SelectionRow: {
+ // Current bar is on the same row as the selected bar
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor);
+ lightStrength = m_cachedTheme.m_highlightLightStrength;
+ if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) {
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ item.setPosition(QPoint(row, bar));
+ if (selectionDirty)
+ m_sliceSelection->append(&item);
+ }
+ break;
+ }
+ case Bars3DController::SelectionColumn: {
+ // Current bar is on the same column as the selected bar
+ barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor);
+ lightStrength = m_cachedTheme.m_highlightLightStrength;
+ if (QDataVis::SelectionModeSliceColumn == m_cachedSelectionMode) {
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ item.setPosition(QPoint(row, bar));
+ if (selectionDirty)
+ m_sliceSelection->append(&item);
+ }
+ break;
+ }
+ case Bars3DController::SelectionNone: {
+ // Current bar is not selected, nor on a row or column
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ // Skip drawing of 0 -height bars
+ if (item.height() != 0) {
+ // Set shader bindings
+ m_barShader->setUniformValue(m_barShader->lightP(), lightPos);
+ m_barShader->setUniformValue(m_barShader->view(), viewMatrix);
+ m_barShader->setUniformValue(m_barShader->model(), modelMatrix);
+ m_barShader->setUniformValue(m_barShader->nModel(),
+ itModelMatrix.transposed().inverted());
+ m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix);
+ m_barShader->setUniformValue(m_barShader->color(), barColor);
+ m_barShader->setUniformValue(m_barShader->ambientS(), m_cachedTheme.m_ambientStrength);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone
+ && !m_cachedIsSlicingActivated) {
+ // Set shadow shader bindings
+ m_barShader->setUniformValue(m_barShader->shadowQ(), m_shadowQualityToShader);
+ m_barShader->setUniformValue(m_barShader->depth(), depthMVPMatrix);
+ m_barShader->setUniformValue(m_barShader->lightS(), lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(m_barShader, m_barObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_barShader->setUniformValue(m_barShader->lightS(), lightStrength);
+
+ // Draw the object
+#if defined (Q_OS_MAC)
+ // Mac slice issue hack fix. TODO: Fix correctly
+ m_drawer->drawObject(m_barShader, m_barObj, 0, -1);
+#else
+ m_drawer->drawObject(m_barShader, m_barObj);
+#endif
+ }
+ }
+ }
+ }
+
+ if (selectionDirty)
+ emit selectedBarPosChanged(QPoint(int(m_selection.x()), int(m_selection.y())));
+
+ // Release bar shader
+ m_barShader->release();
+
+ // Bind background shader
+ m_backgroundShader->bind();
+
+ if (m_hasNegativeValues)
+ glDisable(GL_CULL_FACE);
+ else
+ glCullFace(GL_BACK);
+
+ // Draw background
+ if (m_cachedIsBackgroundEnabled && m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, 1.0f - m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor,
+ 1.0f,
+ m_columnDepth / m_scaleFactor));
+ modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f);
+ itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor,
+ 1.0f,
+ m_columnDepth / m_scaleFactor));
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor);
+
+ // Set shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
+ m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor);
+ m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(),
+ m_cachedTheme.m_ambientStrength * 2.0f);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(),
+ m_shadowQualityToShader);
+ m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj);
+ }
+ }
+
+ // Release background shader
+ m_backgroundShader->release();
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // Reset culling
+ if (m_hasNegativeValues) {
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ }
+
+ // Draw grid lines
+ if (m_cachedIsGridEnabled && m_heightNormalizer) {
+ ShaderHelper *lineShader = m_backgroundShader;
+ // Bind bar shader
+ lineShader->bind();
+
+ // Set unchanging shader bindings
+ QVector3D barColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine);
+ lineShader->setUniformValue(lineShader->lightP(), lightPos);
+ lineShader->setUniformValue(lineShader->view(), viewMatrix);
+ lineShader->setUniformValue(lineShader->color(), barColor);
+ lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength);
+
+ // Floor lines: rows
+ for (GLfloat row = 0.0f; row <= m_cachedRowCount; row++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ rowPos = row * m_cachedBarSpacing.height();
+ modelMatrix.translate(0.0f, -m_yAdjustment,
+ (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+ itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ }
+
+ // Floor lines: columns
+ for (GLfloat bar = 0.0f; bar <= m_cachedColumnCount; bar++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ colPos = bar * m_cachedBarSpacing.width();
+ modelMatrix.translate((m_rowWidth - colPos) / m_scaleFactor,
+ -m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ m_columnDepth / m_scaleFactor));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ m_columnDepth / m_scaleFactor));
+
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ }
+
+ if (m_axisCacheY.segmentCount() > 0) {
+ // Wall lines: back wall
+ GLfloat heightStep = m_axisCacheY.subSegmentStep();
+ GLfloat startLine = 0.0f;
+
+ if (m_hasNegativeValues)
+ startLine = -m_heightNormalizer;
+
+ for (GLfloat lineHeight = startLine; lineHeight <= m_heightNormalizer;
+ lineHeight += heightStep) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_zFlipped) {
+ modelMatrix.translate(0.0f,
+ 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment,
+ m_columnDepth / m_scaleFactor + zComp);
+ } else {
+ modelMatrix.translate(0.0f,
+ 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment,
+ -m_columnDepth / m_scaleFactor + zComp);
+ }
+ modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+ itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ }
+
+ // Wall lines: side wall
+ for (GLfloat lineHeight = startLine; lineHeight <= m_heightNormalizer;
+ lineHeight += heightStep) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_xFlipped) {
+ modelMatrix.translate(m_rowWidth / m_scaleFactor,
+ 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment,
+ zComp);
+ } else {
+ modelMatrix.translate(-m_rowWidth / m_scaleFactor,
+ 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment,
+ zComp);
+ }
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ m_columnDepth / m_scaleFactor));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ m_columnDepth / m_scaleFactor));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ }
+ }
+ // Release bar shader
+ lineShader->release();
+ }
+
+ // TODO: Calculations done temporarily here. When optimizing, move to after data set addition? Keep drawing of the labels here.
+ // Bind label shader
+ m_labelShader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // Calculate the positions for row and column labels and store them
+ for (int row = 0; row != m_cachedRowCount; row++) {
+ if (m_axisCacheX.labelItems().size() > row) {
+ // Go through all rows and get position of max+1 or min-1 column, depending on x flip
+ // We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems
+ rowPos = (row + 0.5f) * m_cachedBarSpacing.height();
+ colPos = (m_rowWidth / m_scaleFactor) + labelMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 0.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ if (m_xFlipped) {
+ colPos = -(m_rowWidth / m_scaleFactor) - labelMargin;
+ alignment = Qt::AlignLeft;
+ }
+ if (m_yFlipped) {
+ if (m_zFlipped)
+ rotLabelY = 0.0f;
+ else
+ rotLabelY = 180.0f;
+ rotLabelZ = 180.0f;
+ }
+ QVector3D labelPos = QVector3D(colPos,
+ -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+
+ m_dummyBarRenderItem.setTranslation(labelPos);
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(row);
+ //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << m_axisCacheX.labels().at(row);
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ }
+ for (int column = 0; column != m_cachedColumnCount; column += 1) {
+ if (m_axisCacheZ.labelItems().size() > column) {
+ // Go through all columns and get position of max+1 or min-1 row, depending on z flip
+ // We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems
+ colPos = (column + 0.5f) * m_cachedBarSpacing.width();
+ rowPos = (m_columnDepth / m_scaleFactor) + labelMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (m_xFlipped)
+ rotLabelY = -90.0f;
+ if (m_zFlipped) {
+ rowPos = -(m_columnDepth / m_scaleFactor) - labelMargin;
+ alignment = Qt::AlignRight;
+ }
+ if (m_yFlipped) {
+ if (m_xFlipped)
+ rotLabelY = -90.0f;
+ else
+ rotLabelY = 90.0f;
+ rotLabelZ = 180.0f;
+ }
+ QVector3D labelPos = QVector3D((colPos - m_rowWidth) / m_scaleFactor,
+ -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ rowPos + zComp);
+
+ m_dummyBarRenderItem.setTranslation(labelPos);
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(column);
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ }
+
+ // Y Labels
+ int labelNbr = 0;
+ GLfloat heightStep = m_axisCacheY.segmentStep();
+ GLfloat startLine = 0.0f;
+ int labelCount = m_axisCacheY.labels().size();
+ if (m_hasNegativeValues)
+ startLine = -m_heightNormalizer;
+ GLfloat labelPos = startLine;
+
+ for (int i = 0; i < labelCount; i++) {
+ if (m_axisCacheY.labelItems().size() > labelNbr) {
+ GLfloat labelMarginXTrans = labelMargin;
+ GLfloat labelMarginZTrans = labelMargin;
+ GLfloat labelXTrans = m_rowWidth / m_scaleFactor;
+ GLfloat labelZTrans = m_columnDepth / m_scaleFactor;
+ GLfloat labelYTrans = 2.0f * labelPos / m_heightNormalizer - m_yAdjustment;
+ GLfloat rotLabelX = 0.0f;
+ GLfloat rotLabelY = -90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (!m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ labelMarginXTrans = -labelMargin;
+ rotLabelY = 90.0f;
+ }
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ labelMarginZTrans = -labelMargin;
+ alignment = Qt::AlignRight;
+ }
+
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+
+ // Back wall
+ QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans,
+ labelZTrans + labelMarginZTrans + zComp);
+
+ //qDebug() << "labelPos, value:" << labelTrans;
+
+ m_dummyBarRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+
+ // Side wall
+ if (m_xFlipped)
+ alignment = Qt::AlignLeft;
+ else
+ alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ else
+ rotLabelY = 0.0f;
+
+ labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelYTrans,
+ -labelZTrans + zComp);
+
+ m_dummyBarRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ labelNbr++;
+ labelPos += heightStep;
+ }
+
+ // Handle slice activation and selection label drawing
+ if (!barSelectionFound) {
+ // We have no ownership, don't delete. Just NULL the pointer.
+ m_selectedBar = NULL;
+ if (m_cachedIsSlicingActivated
+ && (m_selection == selectionSkipColor
+ || QDataVis::InputStateOnOverview == m_controller->inputState())) {
+ m_cachedScene->setSlicingActive(false);
+ }
+ } else if (m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow && selectionDirty) {
+ // Activate slice mode
+ m_cachedScene->setSlicingActive(true);
+
+ // Create label textures
+ for (int col = 0; col < m_sliceSelection->size(); col++) {
+ BarRenderItem *item = m_sliceSelection->at(col);
+ if (item->sliceLabel().isNull())
+ item->setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(), item->value()));
+ m_drawer->generateLabelItem(item->sliceLabelItem(), item->sliceLabel());
+ }
+ } else {
+ // Print value of selected bar
+ glDisable(GL_DEPTH_TEST);
+ // Draw the selection label
+ LabelItem &labelItem = selectedBar->selectionLabelItem();
+ if (m_selectedBar != selectedBar || m_updateLabels || !labelItem.textureId()) {
+ QString labelText = selectedBar->selectionLabel();
+ if (labelText.isNull()) {
+ static const QString rowIndexTag(QStringLiteral("@rowIdx"));
+ static const QString rowLabelTag(QStringLiteral("@rowLabel"));
+ static const QString rowTitleTag(QStringLiteral("@rowTitle"));
+ static const QString colIndexTag(QStringLiteral("@colIdx"));
+ static const QString colLabelTag(QStringLiteral("@colLabel"));
+ static const QString colTitleTag(QStringLiteral("@colTitle"));
+ static const QString valueTitleTag(QStringLiteral("@valueTitle"));
+ static const QString valueLabelTag(QStringLiteral("@valueLabel"));
+
+ // Custom format expects printf format specifier. There is no tag for it.
+ labelText = generateValueLabel(itemLabelFormat(), selectedBar->value());
+
+ int selBarPosX = selectedBar->position().x();
+ int selBarPosY = selectedBar->position().y();
+ labelText.replace(rowIndexTag, QString::number(selBarPosX));
+ if (m_axisCacheX.labels().size() > selBarPosX)
+ labelText.replace(rowLabelTag, m_axisCacheX.labels().at(selBarPosX));
+ else
+ labelText.replace(rowLabelTag, QString());
+ labelText.replace(rowTitleTag, m_axisCacheX.title());
+ labelText.replace(colIndexTag, QString::number(selBarPosY));
+ if (m_axisCacheZ.labels().size() > selBarPosY)
+ labelText.replace(colLabelTag, m_axisCacheZ.labels().at(selBarPosY));
+ else
+ labelText.replace(colLabelTag, QString());
+ labelText.replace(colTitleTag, m_axisCacheZ.title());
+ labelText.replace(valueTitleTag, m_axisCacheY.title());
+
+ if (labelText.contains(valueLabelTag)) {
+ QString labelFormat = m_axisCacheY.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat, selectedBar->value());
+ labelText.replace(valueLabelTag, valueLabelText);
+ }
+
+ selectedBar->setSelectionLabel(labelText);
+ }
+ m_drawer->generateLabelItem(labelItem, labelText);
+ m_selectedBar = selectedBar;
+ }
+
+ m_drawer->drawLabel(*selectedBar, labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), selectedBar->height(),
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), true, false);
+
+ // Reset label update flag; they should have been updated when we get here
+ m_updateLabels = false;
+
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ m_labelShader->release();
+}
+
+void Bars3DRenderer::handleResize()
+{
+ if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0)
+ return;
+
+ // Set view port
+ if (m_cachedIsSlicingActivated) {
+ m_mainViewPort = QRect(0,
+ m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / 5,
+ m_cachedBoundingRect.width() / 5,
+ m_cachedBoundingRect.height() / 5);
+ m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+ } else {
+ m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+ m_sliceViewPort = QRect(0, 0, 0, 0);
+ }
+
+ Abstract3DRenderer::handleResize();
+}
+
+void Bars3DRenderer::updateBarSpecs(GLfloat thicknessRatio, const QSizeF &spacing, bool relative)
+{
+ // Convert ratio to QSizeF, as we need it in that format for autoscaling calculations
+ m_cachedBarThickness.setWidth(1.0f);
+ m_cachedBarThickness.setHeight(1.0f / thicknessRatio);
+
+ if (relative) {
+ m_cachedBarSpacing.setWidth((m_cachedBarThickness.width() * 2) * (spacing.width() + 1.0f));
+ m_cachedBarSpacing.setHeight((m_cachedBarThickness.height() * 2) * (spacing.height() + 1.0f));
+ } else {
+ m_cachedBarSpacing = m_cachedBarThickness * 2 + spacing * 2;
+ }
+
+ // Calculate here and at setting sample space
+ calculateSceneScalingFactors();
+}
+
+void Bars3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max)
+{
+ Abstract3DRenderer::updateAxisRange(orientation, min, max);
+
+ if (orientation == Q3DAbstractAxis::AxisOrientationY) {
+ calculateHeightAdjustment();
+ // Check if we have negative values
+ if (min < 0 && !m_hasNegativeValues) {
+ m_hasNegativeValues = true;
+ // Reload background
+ loadBackgroundMesh();
+ emit needRender();
+ } else if (min >= 0 && m_hasNegativeValues) {
+ m_hasNegativeValues = false;
+ // Reload background
+ loadBackgroundMesh();
+ emit needRender();
+ }
+
+ // TODO Currently bargraph only supports zero centered or zero minimum ranges
+ if (min > 0.0 || (min != 0.0 && (qFabs(min) != qFabs(max)))) {
+ qWarning() << __FUNCTION__ << "Bar graph currently properly supports only "
+ "zero-centered and zero minimum ranges for Y-axis.";
+ }
+ }
+}
+
+void Bars3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode)
+{
+ Abstract3DRenderer::updateSelectionMode(mode);
+
+ // Create zoom selection if there isn't one
+ if (mode >= QDataVis::SelectionModeSliceRow && !m_sliceSelection) {
+ m_sliceSelection = new QList<BarRenderItem *>;
+ if (mode == QDataVis::SelectionModeSliceRow)
+ m_sliceSelection->reserve(m_cachedRowCount);
+ else
+ m_sliceSelection->reserve(m_cachedColumnCount);
+ }
+}
+
+void Bars3DRenderer::updateBackgroundEnabled(bool enable)
+{
+ if (enable != m_cachedIsBackgroundEnabled) {
+ Abstract3DRenderer::updateBackgroundEnabled(enable);
+ loadMeshFile(); // Load changed bar type
+ }
+}
+
+void Bars3DRenderer::updateSelectedBarPos(const QPoint &position)
+{
+ if (position == Bars3DController::noSelectionPoint())
+ m_selection = selectionSkipColor;
+ else
+ m_selection = QVector3D(position.x(), position.y(), 0);
+ emit needRender();
+}
+
+void Bars3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality)
+{
+ m_cachedShadowQuality = quality;
+ switch (quality) {
+ case QDataVis::ShadowQualityLow:
+ m_shadowQualityToShader = 33.3f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualityMedium:
+ m_shadowQualityToShader = 100.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualityHigh:
+ m_shadowQualityToShader = 200.0f;
+ m_shadowQualityMultiplier = 5;
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ m_shadowQualityToShader = 7.5f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ m_shadowQualityToShader = 10.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ m_shadowQualityToShader = 15.0f;
+ m_shadowQualityMultiplier = 4;
+ break;
+ default:
+ m_shadowQualityToShader = 0.0f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ }
+
+ handleShadowQualityChange();
+
+#if !defined(QT_OPENGL_ES_2)
+ // Re-init depth buffer
+ updateDepthBuffer();
+#endif
+}
+
+void Bars3DRenderer::loadMeshFile()
+{
+ QString objectFileName = m_cachedObjFile;
+ if (m_barObj)
+ delete m_barObj;
+ // If background is disabled, load full version of bar mesh
+ if (!m_cachedIsBackgroundEnabled)
+ objectFileName.append(QStringLiteral("Full"));
+ m_barObj = new ObjectHelper(objectFileName);
+ m_barObj->load();
+}
+
+void Bars3DRenderer::loadBackgroundMesh()
+{
+ if (m_backgroundObj)
+ delete m_backgroundObj;
+ if (m_hasNegativeValues)
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground"));
+ else
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
+ m_backgroundObj->load();
+}
+
+void Bars3DRenderer::loadGridLineMesh()
+{
+ if (m_gridLineObj)
+ delete m_gridLineObj;
+ m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar"));
+ m_gridLineObj->load();
+}
+
+void Bars3DRenderer::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void Bars3DRenderer::updateTextures()
+{
+ // Drawer has changed; this flag needs to be checked when checking if we need to update labels
+ m_updateLabels = true;
+}
+
+void Bars3DRenderer::calculateSceneScalingFactors()
+{
+ // Calculate scene scaling and translation factors
+ m_rowWidth = (m_cachedColumnCount * m_cachedBarSpacing.width()) / 2.0f;
+ m_columnDepth = (m_cachedRowCount * m_cachedBarSpacing.height()) / 2.0f;
+ m_maxDimension = qMax(m_rowWidth, m_columnDepth);
+ m_scaleFactor = qMin((m_cachedColumnCount * (m_maxDimension / m_maxSceneSize)),
+ (m_cachedRowCount * (m_maxDimension / m_maxSceneSize)));
+ m_scaleX = m_cachedBarThickness.width() / m_scaleFactor;
+ m_scaleZ = m_cachedBarThickness.height() / m_scaleFactor;
+ //qDebug() << "m_scaleX" << m_scaleX << "m_scaleFactor" << m_scaleFactor;
+ //qDebug() << "m_scaleZ" << m_scaleZ << "m_scaleFactor" << m_scaleFactor;
+ //qDebug() << "m_rowWidth:" << m_rowWidth << "m_columnDepth:" << m_columnDepth << "m_maxDimension:" << m_maxDimension;
+}
+
+void Bars3DRenderer::calculateHeightAdjustment()
+{
+ m_heightNormalizer = (GLfloat)qMax(qFabs(m_axisCacheY.min()), qFabs(m_axisCacheY.max()));
+
+ // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer
+ GLfloat newAdjustment = 2.0f - ((m_heightNormalizer - m_axisCacheY.min()) / m_heightNormalizer);
+ if (newAdjustment != m_yAdjustment) {
+ m_hasHeightAdjustmentChanged = true;
+ m_yAdjustment = newAdjustment;
+ }
+ //qDebug() << m_yAdjustment;
+}
+
+Bars3DController::SelectionType Bars3DRenderer::isSelected(GLint row, GLint bar)
+{
+ //static QVector3D prevSel = m_selection; // TODO: For debugging
+ Bars3DController::SelectionType isSelectedType = Bars3DController::SelectionNone;
+ if (m_selection == selectionSkipColor)
+ return isSelectedType; // skip window
+
+ //#if !defined(QT_OPENGL_ES_2)
+ // QVector3D current = QVector3D((GLuint)row, (GLuint)bar, 0);
+ //#else
+ QVector3D current = QVector3D((GLubyte)row, (GLubyte)bar, 0);
+ //#endif
+
+ // TODO: For debugging
+ //if (selection != prevSel) {
+ // qDebug() << "current" << current.x() << current .y() << current.z();
+ // qDebug() << "selection" << selection.x() << selection .y() << selection.z();
+ // prevSel = selection;
+ //}
+ if (current == m_selection) {
+ isSelectedType = Bars3DController::SelectionItem;
+ }
+ else if (current.y() == m_selection.y() && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndColumn
+ || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn
+ || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn)) {
+ isSelectedType = Bars3DController::SelectionColumn;
+ }
+ else if (current.x() == m_selection.x() && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndRow
+ || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn
+ || m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)) {
+ isSelectedType = Bars3DController::SelectionRow;
+ }
+ return isSelectedType;
+}
+
+void Bars3DRenderer::updateSlicingActive(bool isSlicing)
+{
+ if (isSlicing == m_cachedIsSlicingActivated)
+ return;
+
+ m_cachedIsSlicingActivated = isSlicing;
+ if (isSlicing) {
+ m_mainViewPort = QRect(0, m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / 5,
+ m_cachedBoundingRect.width() / 5, m_cachedBoundingRect.height() / 5);
+ m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+ if (m_depthTexture) {
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_depthTexture = 0;
+ }
+ } else {
+ m_mainViewPort = QRect(0, 0, this->m_cachedBoundingRect.width(),
+ this->m_cachedBoundingRect.height());
+ m_sliceViewPort = QRect(0, 0, 0, 0);
+ initSelectionBuffer(); // We need to re-init selection buffer in case there has been a resize
+#if !defined(QT_OPENGL_ES_2)
+ updateDepthBuffer(); // Re-init depth buffer as well
+#endif
+ }
+}
+
+QRect Bars3DRenderer::mainViewPort()
+{
+ return m_mainViewPort;
+}
+
+void Bars3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_barShader)
+ delete m_barShader;
+ m_barShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_barShader->initialize();
+}
+
+void Bars3DRenderer::initSelectionShader()
+{
+ if (m_selectionShader)
+ delete m_selectionShader;
+ m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSelection"),
+ QStringLiteral(":/shaders/fragmentSelection"));
+ m_selectionShader->initialize();
+}
+
+void Bars3DRenderer::initSelectionBuffer()
+{
+ if (m_cachedIsSlicingActivated)
+ return;
+
+ if (m_selectionTexture)
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+
+ m_selectionTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(),
+ m_selectionFrameBuffer,
+ m_selectionDepthBuffer);
+}
+
+#if !defined(QT_OPENGL_ES_2)
+void Bars3DRenderer::initDepthShader()
+{
+ if (m_depthShader)
+ delete m_depthShader;
+ m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"),
+ QStringLiteral(":/shaders/fragmentDepth"));
+ m_depthShader->initialize();
+}
+
+void Bars3DRenderer::updateDepthBuffer()
+{
+ if (m_cachedIsSlicingActivated)
+ return;
+
+ if (m_depthTexture) {
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_depthTexture = 0;
+ }
+
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(),
+ m_depthFrameBuffer,
+ m_shadowQualityMultiplier);
+ if (!m_depthTexture) {
+ switch (m_cachedShadowQuality) {
+ case QDataVis::ShadowQualityHigh:
+ qWarning("Creating high quality shadows failed. Changing to medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium);
+ updateShadowQuality(QDataVis::ShadowQualityMedium);
+ break;
+ case QDataVis::ShadowQualityMedium:
+ qWarning("Creating medium quality shadows failed. Changing to low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow);
+ updateShadowQuality(QDataVis::ShadowQualityLow);
+ break;
+ case QDataVis::ShadowQualityLow:
+ qWarning("Creating low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ qWarning("Creating soft high quality shadows failed. Changing to soft medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ updateShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ qWarning("Creating soft medium quality shadows failed. Changing to soft low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow);
+ updateShadowQuality(QDataVis::ShadowQualitySoftLow);
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ qWarning("Creating soft low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ default:
+ // You'll never get here
+ break;
+ }
+ }
+ }
+}
+#endif
+
+void Bars3DRenderer::initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_backgroundShader)
+ delete m_backgroundShader;
+ m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_backgroundShader->initialize();
+}
+
+void Bars3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_labelShader->initialize();
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h
new file mode 100644
index 00000000..9b612474
--- /dev/null
+++ b/src/datavisualization/engine/bars3drenderer_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DBARSRENDERER_p_H
+#define Q3DBARSRENDERER_p_H
+
+#include "datavisualizationglobal_p.h"
+#include "bars3dcontroller_p.h"
+#include "abstract3drenderer_p.h"
+#include "qbardataproxy.h"
+#include "barrenderitem_p.h"
+
+class QPoint;
+class QSizeF;
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper;
+class ObjectHelper;
+class LabelItem;
+class Q3DScene;
+
+class QT_DATAVISUALIZATION_EXPORT Bars3DRenderer : public Abstract3DRenderer
+{
+ Q_OBJECT
+
+private:
+ // TODO: Filter to the set of attributes to be moved to the model object.
+ Bars3DController *m_controller;
+
+ // Cached state based on emitted signals from the controller
+ QSizeF m_cachedBarThickness;
+ QSizeF m_cachedBarSpacing;
+ bool m_cachedIsSlicingActivated;
+ int m_cachedRowCount;
+ int m_cachedColumnCount;
+
+ // Internal state
+ BarRenderItem *m_selectedBar; // points to renderitem array
+ QList<BarRenderItem *> *m_sliceSelection;
+ AxisRenderCache *m_sliceCache; // not owned
+ const LabelItem *m_sliceTitleItem; // not owned
+ bool m_xFlipped;
+ bool m_zFlipped;
+ bool m_yFlipped;
+ QRect m_mainViewPort;
+ QRect m_sliceViewPort;
+ bool m_updateLabels;
+ ShaderHelper *m_barShader;
+ ShaderHelper *m_depthShader;
+ ShaderHelper *m_selectionShader;
+ ShaderHelper *m_backgroundShader;
+ ShaderHelper *m_labelShader;
+ ObjectHelper *m_barObj;
+ ObjectHelper *m_backgroundObj;
+ ObjectHelper *m_gridLineObj;
+ ObjectHelper *m_labelObj;
+ GLuint m_bgrTexture;
+ GLuint m_depthTexture;
+ GLuint m_selectionTexture;
+ GLuint m_depthFrameBuffer;
+ GLuint m_selectionFrameBuffer;
+ GLuint m_selectionDepthBuffer;
+ GLfloat m_shadowQualityToShader;
+ GLint m_shadowQualityMultiplier;
+ GLfloat m_heightNormalizer;
+ GLfloat m_yAdjustment;
+ GLfloat m_rowWidth;
+ GLfloat m_columnDepth;
+ GLfloat m_maxDimension;
+ GLfloat m_scaleX;
+ GLfloat m_scaleZ;
+ GLfloat m_scaleFactor;
+ GLfloat m_maxSceneSize;
+ QVector3D m_selection;
+ QVector3D m_previousSelection;
+
+ bool m_hasHeightAdjustmentChanged;
+ BarRenderItem m_dummyBarRenderItem;
+
+ BarRenderItemArray m_renderItemArray;
+
+public:
+ explicit Bars3DRenderer(Bars3DController *controller);
+ ~Bars3DRenderer();
+
+ void updateDataModel(QBarDataProxy *dataProxy);
+ void updateScene(Q3DScene *scene);
+ void render(GLuint defaultFboHandle = 0);
+
+ QRect mainViewPort();
+
+protected:
+ virtual void initializeOpenGL();
+ virtual void loadMeshFile();
+
+public slots:
+ void updateBarSpecs(GLfloat thicknessRatio = 1.0f,
+ const QSizeF &spacing = QSizeF(1.0, 1.0),
+ bool relative = true);
+ void updateSelectionMode(QDataVis::SelectionMode newMode);
+ void updateSlicingActive(bool isSlicing);
+ void updateBackgroundEnabled(bool enable);
+ void updateSelectedBarPos(const QPoint &position);
+
+ // Overloaded from abstract renderer
+ virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
+
+signals:
+ void selectedBarPosChanged(QPoint position);
+
+private:
+ virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
+ virtual void updateShadowQuality(QDataVis::ShadowQuality quality);
+ virtual void updateTextures();
+
+ void drawSlicedScene(const LabelItem &xLabel, const LabelItem &yLabel, const LabelItem &zLabel);
+ void drawScene(GLuint defaultFboHandle);
+ void handleResize();
+
+ void loadBackgroundMesh();
+ void loadGridLineMesh();
+ void loadLabelMesh();
+ void initSelectionShader();
+ void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initSelectionBuffer();
+#if !defined(QT_OPENGL_ES_2)
+ void initDepthShader();
+ void updateDepthBuffer();
+#endif
+ void calculateSceneScalingFactors();
+ void calculateHeightAdjustment();
+ Abstract3DController::SelectionType isSelected(GLint row, GLint bar);
+
+ Q_DISABLE_COPY(Bars3DRenderer)
+
+ friend class BarRenderItem;
+};
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/drawer.cpp b/src/datavisualization/engine/drawer.cpp
new file mode 100644
index 00000000..9d50186d
--- /dev/null
+++ b/src/datavisualization/engine/drawer.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qdatavisualizationenums.h"
+#include "drawer_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "abstractobjecthelper_p.h"
+#include "surfaceobject_p.h"
+#include "q3dcamera.h"
+#include "utils_p.h"
+#include "texturehelper_p.h"
+#include <QMatrix4x4>
+#include <qmath.h>
+
+// Resources need to be explicitly initialized when building as static library
+class StaticLibInitializer
+{
+public:
+ StaticLibInitializer()
+ {
+ Q_INIT_RESOURCE(engine);
+ }
+};
+StaticLibInitializer staticLibInitializer;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Drawer::Drawer(const Theme &theme, const QFont &font, QDataVis::LabelStyle style)
+ : m_theme(theme),
+ m_font(font),
+ m_style(style),
+ m_textureHelper(0)
+{
+}
+
+Drawer::~Drawer()
+{
+ delete m_textureHelper;
+}
+
+void Drawer::initializeOpenGL()
+{
+ if (!m_textureHelper) {
+ initializeOpenGLFunctions();
+ m_textureHelper = new TextureHelper();
+ }
+}
+
+void Drawer::setTheme(const Theme &theme)
+{
+ m_theme = theme;
+ emit drawerChanged();
+}
+
+Theme Drawer::theme() const
+{
+ return m_theme;
+}
+
+void Drawer::setFont(const QFont &font)
+{
+ m_font = font;
+ emit drawerChanged();
+}
+
+QFont Drawer::font() const
+{
+ return m_font;
+}
+
+void Drawer::setStyle(QDataVis::LabelStyle style)
+{
+ m_style = style;
+ emit drawerChanged();
+}
+
+void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId,
+ GLuint depthTextureId)
+{
+ // Store the GL state before changing
+ GLint oldActiveTex[1];
+ glGetIntegerv(GL_ACTIVE_TEXTURE, oldActiveTex);
+ GLint oldTexId[1];
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, oldTexId);
+
+ if (textureId) {
+ // Activate texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ shader->setUniformValue(shader->texture(), 0);
+ }
+
+ if (depthTextureId) {
+ // Activate depth texture
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, depthTextureId);
+ shader->setUniformValue(shader->shadow(), 1);
+ }
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf());
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ // 2nd attribute buffer : normals
+ glEnableVertexAttribArray(shader->normalAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->normalBuf());
+ glVertexAttribPointer(shader->normalAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ if (textureId || depthTextureId) {
+ // 3rd attribute buffer : UVs
+ glEnableVertexAttribArray(shader->uvAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->uvBuf());
+ glVertexAttribPointer(shader->uvAtt(), 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
+ }
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, object->indexCount(), object->indicesType(), (void*)0);
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ if (textureId || depthTextureId)
+ glDisableVertexAttribArray(shader->uvAtt());
+
+ glDisableVertexAttribArray(shader->normalAtt());
+ glDisableVertexAttribArray(shader->posAtt());
+
+ // Restore the GL state
+ glActiveTexture(*oldActiveTex);
+ glBindTexture(GL_TEXTURE_2D, *oldTexId);
+}
+
+void Drawer::drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object)
+{
+ // Store the GL state before changing
+ GLint oldActiveTex[1];
+ glGetIntegerv(GL_ACTIVE_TEXTURE, oldActiveTex);
+ GLint oldTexId[1];
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, oldTexId);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf());
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gridElementBuf());
+
+ // Draw the lines
+ glDrawElements(GL_LINES, object->gridIndexCount(), object->indicesType(), (void*)0);
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(shader->posAtt());
+
+ // Restore the GL state
+ glActiveTexture(*oldActiveTex);
+ glBindTexture(GL_TEXTURE_2D, *oldTexId);
+}
+
+void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem,
+ const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
+ const QVector3D &positionComp, const QVector3D &rotation,
+ GLfloat itemHeight, QDataVis::SelectionMode mode,
+ ShaderHelper *shader, ObjectHelper *object,
+ const Q3DCamera *camera,
+ bool useDepth, bool rotateAlong,
+ LabelPosition position, Qt::AlignmentFlag alignment)
+{
+ // Draw label
+ if (!labelItem.textureId())
+ return; // No texture, skip
+
+ QSize textureSize = labelItem.size();
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ GLfloat xPosition = 0.0f;
+ GLfloat yPosition = 0.0f;
+ GLfloat zPosition = positionComp.z();
+
+ switch (position) {
+ case LabelBelow: {
+ yPosition = -2.6f + positionComp.y(); // minus maximum negative height (+ some extra for axis title label)
+ break;
+ }
+ case LabelLow: {
+ yPosition = -positionComp.y();
+ break;
+ }
+ case LabelMid: {
+ // Use this for positioning with absolute item y position value
+ yPosition = item.translation().y();
+ break;
+ }
+ case LabelHigh: {
+ // TODO: Fix this. Can't seem to get it right (if ok with positive-only bars, doesn't look good on +- and vice versa)
+ yPosition = item.translation().y() + itemHeight / 2.0f;
+ break;
+ }
+ case LabelOver: {
+ float mod = 0.3f;
+ if (itemHeight < 0)
+ mod = 0.15f;
+ yPosition = item.translation().y() - (positionComp.y() / 2.0f) + itemHeight + mod;
+ break;
+ }
+ case LabelBottom: {
+ yPosition = -2.95f + positionComp.y();
+ xPosition = 0.0f;
+ break;
+ }
+ case LabelTop: {
+ yPosition = 2.95f - positionComp.y();
+ xPosition = 0.0f;
+ break;
+ }
+ case LabelLeft: {
+ yPosition = 0.0f;
+ xPosition = -2.95f;
+ break;
+ }
+ case LabelRight: {
+ yPosition = 0.0f;
+ xPosition = 2.95f;
+ break;
+ }
+ }
+
+ // Calculate scale factor to get uniform font size
+ GLfloat scaledFontSize = 0.05f + m_font.pointSizeF() / 500.0f;
+ GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
+
+ // Apply alignment
+ GLfloat xAlignment = 0.0f;
+ GLfloat yAlignment = 0.0f;
+ GLfloat zAlignment = 0.0f;
+ switch (alignment) {
+ case Qt::AlignLeft: {
+ xAlignment = (-(GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qCos(qDegreesToRadians(rotation.y())));
+ zAlignment = ((GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qSin(qDegreesToRadians(rotation.y())));
+ break;
+ }
+ case Qt::AlignRight: {
+ xAlignment = ((GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qCos(qDegreesToRadians(rotation.y())));
+ zAlignment = (-(GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qSin(qDegreesToRadians(rotation.y())));
+ break;
+ }
+ case Qt::AlignTop: {
+ yAlignment = ((GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qCos(qDegreesToRadians(rotation.y())));
+ if (itemHeight < 0)
+ yAlignment = -yAlignment;
+ break;
+ }
+ case Qt::AlignBottom: {
+ yAlignment = (-(GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(qCos(qDegreesToRadians(rotation.y())));
+ if (itemHeight < 0)
+ yAlignment = -yAlignment;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (position < LabelBottom) {
+ xPosition = item.translation().x();
+ if (useDepth)
+ zPosition = item.translation().z();
+ else if (QDataVis::SelectionModeSliceColumn == mode)
+ xPosition = -(item.translation().z()) + positionComp.z(); // flip first to left
+ }
+
+ // Position label
+ modelMatrix.translate(xPosition + xAlignment, yPosition + yAlignment, zPosition + zAlignment);
+
+ // Rotate
+ // TODO: We should convert rotations to use quaternions to avoid rotation order problems
+ //QQuaternion rotQuatX = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, rotation.x());
+ //QQuaternion rotQuatY = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, rotation.y());
+ //QQuaternion rotQuatZ = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, rotation.z());
+ //QQuaternion rotQuaternion = rotQuatX + rotQuatY + rotQuatZ;
+ //modelMatrix.rotate(rotQuaternion);
+ modelMatrix.rotate(rotation.y(), 0.0f, 1.0f, 0.0f);
+ modelMatrix.rotate(rotation.z(), 0.0f, 0.0f, 1.0f);
+ modelMatrix.rotate(rotation.x(), 1.0f, 0.0f, 0.0f);
+
+ if (useDepth && !rotateAlong) {
+ qreal yComp = qreal(qRadiansToDegrees(qTan(positionComp.y() / cameraDistance)));
+ // Apply negative camera rotations to keep labels facing camera
+ qreal camRotationX = camera->xRotation();
+ qreal camRotationY = camera->yRotation();
+ modelMatrix.rotate(-camRotationX, 0.0f, 1.0f, 0.0f);
+ modelMatrix.rotate(-camRotationY - yComp, 1.0f, 0.0f, 0.0f);
+ }
+
+ // Scale label based on text size
+ modelMatrix.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
+ scaledFontSize,
+ 0.0f));
+
+ MVPMatrix = projectionmatrix * viewmatrix * modelMatrix;
+
+ // Set shader bindings
+ shader->setUniformValue(shader->MVP(), MVPMatrix);
+
+ // Draw the object
+ drawObject(shader, object, labelItem.textureId());
+}
+
+void Drawer::generateSelectionLabelTexture(AbstractRenderItem *item)
+{
+ LabelItem &labelItem = item->selectionLabelItem();
+ generateLabelItem(labelItem, item->selectionLabel());
+}
+
+void Drawer::generateLabelItem(LabelItem &item, const QString &text, int widestLabel)
+{
+ initializeOpenGL();
+
+ item.clear();
+
+ if (!text.isEmpty()) {
+ // Create labels
+ // Print label into a QImage using QPainter
+ QImage label = Utils::printTextToImage(m_font,
+ text,
+ m_theme.m_textBackgroundColor,
+ m_theme.m_textColor,
+ m_style,
+ m_theme.m_labelBorders,
+ widestLabel);
+
+ // Set label size
+ item.setSize(label.size());
+ // Insert text texture into label (also deletes the old texture)
+ item.setTextureId(m_textureHelper->create2DTexture(label, true, true));
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/drawer_p.h b/src/datavisualization/engine/drawer_p.h
new file mode 100644
index 00000000..89a4ce8c
--- /dev/null
+++ b/src/datavisualization/engine/drawer_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 DRAWER_P_H
+#define DRAWER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+#include "theme_p.h"
+#include "labelitem_p.h"
+#include "abstractrenderitem_p.h"
+#include <QFont>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper;
+class ObjectHelper;
+class AbstractObjectHelper;
+class SurfaceObject;
+class TextureHelper;
+class Q3DCamera;
+
+class Drawer : public QObject, public QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ enum LabelPosition {
+ LabelBelow = 0,
+ LabelLow,
+ LabelMid,
+ LabelHigh,
+ LabelOver,
+ LabelBottom, // Absolute positions from here onward, used for axes (QDataItem is ignored)
+ LabelTop,
+ LabelLeft,
+ LabelRight
+ };
+
+public:
+ explicit Drawer(const Theme &theme, const QFont &font, QDataVis::LabelStyle style);
+ ~Drawer();
+
+ void initializeOpenGL();
+
+ void setTheme(const Theme &theme);
+ Theme theme() const;
+ void setFont(const QFont &font);
+ QFont font() const;
+ void setStyle(QDataVis::LabelStyle style);
+
+ void drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId = 0,
+ GLuint depthTextureId = 0);
+ void drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object);
+ void drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem,
+ const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
+ const QVector3D &positionComp, const QVector3D &rotation, GLfloat itemHeight,
+ QDataVis::SelectionMode mode, ShaderHelper *shader, ObjectHelper *object,
+ const Q3DCamera *camera,
+ bool useDepth = false, bool rotateAlong = false,
+ LabelPosition position = LabelOver,
+ Qt::AlignmentFlag alignment = Qt::AlignCenter);
+
+ void generateSelectionLabelTexture(AbstractRenderItem *item);
+ void generateLabelItem(LabelItem &item, const QString &text, int widestLabel = 0);
+
+Q_SIGNALS:
+ void drawerChanged();
+
+private:
+ Theme m_theme;
+ QFont m_font;
+ QDataVis::LabelStyle m_style;
+ TextureHelper *m_textureHelper;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/engine.pri b/src/datavisualization/engine/engine.pri
new file mode 100644
index 00000000..4c905fe9
--- /dev/null
+++ b/src/datavisualization/engine/engine.pri
@@ -0,0 +1,53 @@
+HEADERS += $$PWD/q3dwindow_p.h \
+ $$PWD/q3dwindow.h \
+ $$PWD/q3dbars.h \
+ $$PWD/q3dbars_p.h \
+ $$PWD/theme_p.h \
+ $$PWD/drawer_p.h \
+ $$PWD/bars3dcontroller_p.h \
+ $$PWD/bars3drenderer_p.h \
+ $$PWD/q3dsurface.h \
+ $$PWD/q3dsurface_p.h \
+ $$PWD/surface3dcontroller_p.h \
+ $$PWD/surface3drenderer_p.h \
+ $$PWD/abstract3dcontroller_p.h \
+ $$PWD/q3dscatter.h \
+ $$PWD/q3dscatter_p.h \
+ $$PWD/scatter3dcontroller_p.h \
+ $$PWD/scatter3drenderer_p.h \
+ $$PWD/axisrendercache_p.h \
+ $$PWD/abstract3drenderer_p.h \
+ $$PWD/selectionpointer_p.h \
+ $$PWD/q3dcamera.h \
+ $$PWD/q3dcamera_p.h \
+ $$PWD/q3dscene.h \
+ $$PWD/q3dlight.h \
+ $$PWD/q3dlight_p.h \
+ $$PWD/q3dbox.h \
+ $$PWD/q3dobject.h \
+ $$PWD/q3dobject_p.h \
+ $$PWD/q3dscene_p.h
+
+SOURCES += $$PWD/q3dwindow.cpp \
+ $$PWD/q3dbars.cpp \
+ $$PWD/theme.cpp \
+ $$PWD/drawer.cpp \
+ $$PWD/bars3dcontroller.cpp \
+ $$PWD/bars3drenderer.cpp \
+ $$PWD/q3dsurface.cpp \
+ $$PWD/surface3drenderer.cpp \
+ $$PWD/surface3dcontroller.cpp \
+ $$PWD/abstract3dcontroller.cpp \
+ $$PWD/q3dscatter.cpp \
+ $$PWD/scatter3dcontroller.cpp \
+ $$PWD/scatter3drenderer.cpp \
+ $$PWD/axisrendercache.cpp \
+ $$PWD/abstract3drenderer.cpp \
+ $$PWD/selectionpointer.cpp \
+ $$PWD/q3dcamera.cpp \
+ $$PWD/q3dlight.cpp \
+ $$PWD/q3dbox.cpp \
+ $$PWD/q3dobject.cpp \
+ $$PWD/q3dscene.cpp
+
+RESOURCES += engine/engine.qrc
diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc
new file mode 100644
index 00000000..7420ae51
--- /dev/null
+++ b/src/datavisualization/engine/engine.qrc
@@ -0,0 +1,62 @@
+<RCC>
+ <qresource prefix="/defaultMeshes">
+ <file alias="cone">meshes/coneFlat.obj</file>
+ <file alias="coneSmooth">meshes/coneSmooth.obj</file>
+ <file alias="pyramid">meshes/pyramidFlat.obj</file>
+ <file alias="pyramidSmooth">meshes/pyramidSmooth.obj</file>
+ <file alias="bar">meshes/cubeFlat.obj</file>
+ <file alias="barSmooth">meshes/cubeSmooth.obj</file>
+ <file alias="cylinder">meshes/cylinderFlat.obj</file>
+ <file alias="cylinderSmooth">meshes/cylinderSmooth.obj</file>
+ <file alias="background">meshes/backgroudFlat.obj</file>
+ <file alias="backgroundSmooth">meshes/backgroudSmooth.obj</file>
+ <file alias="label">meshes/plane.obj</file>
+ <file alias="sphere">meshes/sphere.obj</file>
+ <file alias="sphereSmooth">meshes/sphereSmooth.obj</file>
+ <file alias="bevelbar">meshes/barFlat.obj</file>
+ <file alias="bevelbarSmooth">meshes/barSmooth.obj</file>
+ <file alias="negativeBackground">meshes/backgroudNegatives.obj</file>
+ <file alias="coneFull">meshes/coneFilledFlat.obj</file>
+ <file alias="coneSmoothFull">meshes/coneFilledSmooth.obj</file>
+ <file alias="cylinderFull">meshes/cylinderFilledFlat.obj</file>
+ <file alias="cylinderSmoothFull">meshes/cylinderFilledSmooth.obj</file>
+ <file alias="pyramidFull">meshes/pyramidFilledFlat.obj</file>
+ <file alias="pyramidSmoothFull">meshes/pyramidFilledSmooth.obj</file>
+ <file alias="bevelbarFull">meshes/barFilledFlat.obj</file>
+ <file alias="bevelbarSmoothFull">meshes/barFilledSmooth.obj</file>
+ <file alias="barFull">meshes/cubeFilledFlat.obj</file>
+ <file alias="barSmoothFull">meshes/cubeFilledSmooth.obj</file>
+ <file alias="dotSmooth">meshes/scatterdot.obj</file>
+ <file alias="dot">meshes/scatterdotFlat.obj</file>
+ </qresource>
+ <qresource prefix="/shaders">
+ <file alias="fragment">shaders/default.frag</file>
+ <file alias="vertex">shaders/default.vert</file>
+ <file alias="fragmentAmbient">shaders/ambient.frag</file>
+ <file alias="fragmentColorOnY">shaders/colorOnY.frag</file>
+ <file alias="fragmentSelection">shaders/selection.frag</file>
+ <file alias="vertexSelection">shaders/selection.vert</file>
+ <file alias="fragmentTexture">shaders/texture.frag</file>
+ <file alias="vertexTexture">shaders/texture.vert</file>
+ <file alias="fragmentLabel">shaders/label.frag</file>
+ <file alias="vertexLabel">shaders/label.vert</file>
+ <file alias="fragmentDepth">shaders/depth.frag</file>
+ <file alias="vertexDepth">shaders/depth.vert</file>
+ <file alias="fragmentShadow">shaders/shadow.frag</file>
+ <file alias="vertexShadow">shaders/shadow.vert</file>
+ <file alias="fragmentShadowNoTex">shaders/shadowNoTex.frag</file>
+ <file alias="fragmentShadowNoTexColorOnY">shaders/shadowNoTexColorOnY.frag</file>
+ <file alias="fragmentColorOnYES2">shaders/colorOnY_ES2.frag</file>
+ <file alias="fragmentES2">shaders/default_ES2.frag</file>
+ <file alias="vertexES2">shaders/default_ES2.vert</file>
+ <file alias="fragmentTextureES2">shaders/texture_ES2.frag</file>
+ <file alias="fragmentSurface">shaders/surface.frag</file>
+ <file alias="vertexSurface">shaders/surface.vert</file>
+ <file alias="fragmentSurfaceGrid">shaders/surfaceGrid.frag</file>
+ <file alias="vertexSurfaceGrid">shaders/surfaceGrid.vert</file>
+ <file alias="vertexSurfaceFlat">shaders/surfaceFlat.vert</file>
+ <file alias="fragmentSurfaceFlat">shaders/surfaceFlat.frag</file>
+ <file alias="fragmentSurfaceES2">shaders/surface_ES2.frag</file>
+ </qresource>
+ <qresource prefix="/textures"/>
+</RCC>
diff --git a/src/datavisualization/engine/meshes/backgroudFlat.obj b/src/datavisualization/engine/meshes/backgroudFlat.obj
new file mode 100644
index 00000000..cf4d10a5
--- /dev/null
+++ b/src/datavisualization/engine/meshes/backgroudFlat.obj
@@ -0,0 +1,32 @@
+# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend'
+# www.blender.org
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vt 0.000000 0.501529
+vt 0.001529 1.000000
+vt 0.500000 0.998471
+vt 0.501529 0.500000
+vt 1.000000 0.498471
+vt 0.998471 0.000000
+vt 0.500000 0.498471
+vt 0.498471 0.000000
+vt 0.000000 0.001529
+vt 0.498471 0.500000
+vt 0.500000 0.001529
+vt 0.001529 0.500000
+vn -0.000000 1.000000 0.000000
+vn 0.000000 -0.000000 -1.000000
+vn 1.000000 0.000000 0.000000
+s off
+f 1/1/1 4/2/1 3/3/1
+f 2/4/2 3/5/2 6/6/2
+f 3/7/3 4/8/3 7/9/3
+f 2/10/1 1/1/1 3/3/1
+f 5/11/2 2/4/2 6/6/2
+f 6/12/3 3/7/3 7/9/3
diff --git a/src/datavisualization/engine/meshes/backgroudNegatives.obj b/src/datavisualization/engine/meshes/backgroudNegatives.obj
new file mode 100644
index 00000000..dd4d3f05
--- /dev/null
+++ b/src/datavisualization/engine/meshes/backgroudNegatives.obj
@@ -0,0 +1,37 @@
+# Blender v2.66 (sub 0) OBJ File: 'backgroudNegatives.blend'
+# www.blender.org
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 -3.000000 1.000000
+v -1.000000 -3.000000 1.000000
+v -1.000000 -3.000000 -1.000000
+vt 0.000100 0.666700
+vt 0.333300 0.666700
+vt 0.333300 0.999900
+vt 0.000100 0.000100
+vt 0.333300 0.000100
+vt 0.333300 0.666500
+vt 0.666500 0.000100
+vt 0.666500 0.666500
+vt 0.000100 0.999900
+vt 0.000100 0.666500
+vn 0.000000 0.999969 0.000000
+vn 0.000000 1.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 0.707083 0.000000 -0.707083
+vn 1.000000 0.000000 0.000000
+vn 0.999969 0.000000 0.000000
+vn 0.000000 0.000000 -0.999969
+s 1
+f 1/1/1 4/2/2 3/3/2
+f 8/4/3 9/5/4 6/6/4
+f 9/5/4 10/7/5 7/8/6
+f 2/9/2 1/1/1 3/3/2
+f 5/10/7 8/4/3 6/6/4
+f 6/6/4 9/5/4 7/8/6
diff --git a/src/datavisualization/engine/meshes/backgroudSmooth.obj b/src/datavisualization/engine/meshes/backgroudSmooth.obj
new file mode 100644
index 00000000..ad16d904
--- /dev/null
+++ b/src/datavisualization/engine/meshes/backgroudSmooth.obj
@@ -0,0 +1,36 @@
+# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend'
+# www.blender.org
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vt 0.000000 0.501529
+vt 0.001529 1.000000
+vt 0.500000 0.998471
+vt 0.501529 0.500000
+vt 1.000000 0.498471
+vt 0.998471 0.000000
+vt 0.500000 0.498471
+vt 0.498471 0.000000
+vt 0.000000 0.001529
+vt 0.498471 0.500000
+vt 0.500000 0.001529
+vt 0.001529 0.500000
+vn 0.000000 0.999969 0.000000
+vn 0.707083 0.707083 0.000000
+vn 0.577349 0.577349 -0.577349
+vn 0.000000 0.707083 -0.707083
+vn 0.707083 0.000000 -0.707083
+vn 0.999969 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+s 1
+f 1/1/1 4/2/2 3/3/3
+f 2/4/4 3/5/3 6/6/5
+f 3/7/3 4/8/2 7/9/6
+f 2/10/4 1/1/1 3/3/3
+f 5/11/7 2/4/4 6/6/5
+f 6/12/5 3/7/3 7/9/6
diff --git a/src/datavisualization/engine/meshes/barFilledFlat.obj b/src/datavisualization/engine/meshes/barFilledFlat.obj
new file mode 100644
index 00000000..5f627091
--- /dev/null
+++ b/src/datavisualization/engine/meshes/barFilledFlat.obj
@@ -0,0 +1,242 @@
+# Blender v2.66 (sub 0) OBJ File: 'smoothcube_filled.blend'
+# www.blender.org
+o Cube
+v -0.980000 -1.000000 1.000000
+v -1.000000 -1.000000 0.980000
+v -0.994142 -1.000000 0.994142
+v -1.000000 -1.000000 -0.980000
+v -0.980000 -1.000000 -1.000000
+v -0.994142 -1.000000 -0.994142
+v 0.980000 -1.000000 -1.000000
+v 1.000000 -1.000000 -0.980000
+v 0.994142 -1.000000 -0.994142
+v 1.000000 -1.000000 0.980000
+v 0.980000 -1.000000 1.000000
+v 0.994142 -1.000000 0.994142
+v -0.980000 0.980000 1.000000
+v -0.980000 1.000000 0.980000
+v -1.000000 0.980000 0.980000
+v -0.980000 0.994142 0.994142
+v -0.994142 0.994142 0.980000
+v -0.994142 0.980000 0.994142
+v -0.992998 0.992998 0.992998
+v -1.000000 0.980000 -0.980000
+v -0.980000 1.000000 -0.980000
+v -0.980000 0.980000 -1.000000
+v -0.994142 0.994142 -0.980000
+v -0.980000 0.994142 -0.994142
+v -0.994142 0.980000 -0.994142
+v -0.992998 0.992998 -0.992998
+v 0.980000 0.980000 -1.000000
+v 0.980000 1.000000 -0.980000
+v 1.000000 0.980000 -0.980000
+v 0.980000 0.994142 -0.994142
+v 0.994142 0.994142 -0.980000
+v 0.994142 0.980000 -0.994142
+v 0.992998 0.992998 -0.992998
+v 1.000000 0.980000 0.980000
+v 0.980000 1.000000 0.980000
+v 0.980000 0.980000 1.000000
+v 0.994142 0.994142 0.980000
+v 0.980000 0.994142 0.994142
+v 0.994142 0.980000 0.994142
+v 0.992998 0.992998 0.992998
+vt 0.339018 0.659342
+vt 0.338105 0.335826
+vt 0.664825 0.343846
+vt 0.669233 0.664931
+vt 0.668227 0.337019
+vt 0.995472 0.336015
+vt 0.337976 0.003372
+vt 0.665888 0.002366
+vt 0.666894 0.330278
+vt 0.672755 0.331283
+vt 0.671749 0.003372
+vt 1.000000 0.330280
+vt 0.335610 0.335927
+vt 0.337937 0.333650
+vt 0.338982 0.331284
+vt 0.338989 0.333650
+vt 0.336616 0.331291
+vt 0.326720 0.346123
+vt 0.326875 0.343630
+vt 0.329215 0.346022
+vt 0.327633 0.669639
+vt 0.330128 0.669538
+vt 0.327801 0.671815
+vt 0.669260 0.330271
+vt 0.666901 0.332644
+vt 0.672610 0.333650
+vt 0.670266 0.331291
+vt 0.669260 0.003379
+vt 0.669412 0.001204
+vt 0.665880 0.000000
+vt 0.668056 0.000185
+vt 0.669089 0.667298
+vt 0.666910 0.667113
+vt 0.665738 0.337027
+vt 0.665891 0.334852
+vt 0.335610 0.003379
+vt 0.335795 0.001204
+vt 0.338863 0.661835
+vt 0.336686 0.661624
+vt 0.001081 0.663795
+vt 0.664657 0.341670
+vt 0.000155 0.335610
+vt 0.000000 0.338102
+vt 0.996478 0.663927
+vt 0.996334 0.666294
+vt 0.671590 0.001006
+vt 0.998835 0.000002
+vt 0.998994 0.002368
+vt 0.337969 0.001006
+vt 0.666744 0.664939
+vt 0.665738 0.667363
+vt 0.665583 0.669855
+vt 0.668068 0.334654
+vt 0.995313 0.333650
+vt 0.336523 0.659443
+vt 0.001006 0.332274
+vt 0.000000 0.004362
+vt 0.001993 0.334637
+vt 0.335761 0.333817
+vt 0.336814 0.333465
+vt 0.329052 0.343841
+vt 0.329977 0.671648
+vt 0.669075 0.332446
+vt 0.670432 0.333465
+vt 0.668254 0.002359
+vt 0.999855 0.332646
+vt 0.000913 0.661618
+vt 0.000973 0.001993
+vt 0.003336 0.001006
+vt 0.331248 0.000000
+vt 0.333617 0.000973
+vt 0.334604 0.003336
+vt 0.335610 0.331248
+vt 0.334637 0.333617
+vt 0.332274 0.334604
+vt 0.004362 0.335610
+vn 0.000000 0.000000 1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 1.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn -0.357407 0.357407 0.862856
+vn -0.357409 0.862855 0.357407
+vn -0.862855 0.357409 0.357407
+vn -0.862855 0.357407 -0.357409
+vn -0.357407 0.862855 -0.357409
+vn -0.357408 0.357408 -0.862855
+vn 0.114222 0.380181 -0.917832
+vn 0.380181 0.917832 -0.114222
+vn 0.917832 0.114222 -0.380181
+vn 0.917832 0.380181 0.114222
+vn 0.114222 0.917832 0.380181
+vn 0.380181 0.114222 0.917832
+vn -0.382685 0.923879 0.000000
+vn -0.923879 0.382685 0.000000
+vn -0.382685 0.000000 -0.923879
+vn -0.923879 0.000000 -0.382685
+vn -0.382685 0.000000 0.923879
+vn -0.923879 0.000000 0.382685
+vn 0.000000 0.923879 -0.382685
+vn 0.000000 0.382685 -0.923879
+vn 0.923879 0.000000 -0.382685
+vn 0.382685 0.000000 -0.923879
+vn 0.382685 0.923879 0.000000
+vn 0.923879 0.382685 0.000000
+vn 0.382685 -0.000000 0.923879
+vn 0.923879 -0.000000 0.382685
+vn -0.000000 0.923879 0.382685
+vn -0.000000 0.382685 0.923879
+vn -1.000000 0.000000 0.000000
+vn -0.000000 -1.000000 -0.000000
+vn -0.095602 0.095602 0.990818
+vn -0.095602 0.990818 0.095602
+vn -0.990818 0.095602 0.095602
+vn -0.990818 0.095602 -0.095602
+vn -0.095602 0.990818 -0.095602
+vn -0.095602 0.095602 -0.990818
+vn 0.380181 0.114222 -0.917832
+vn 0.114222 0.917832 -0.380181
+vn 0.917832 0.380181 -0.114222
+vn 0.917832 0.114222 0.380181
+vn 0.380181 0.917832 0.114222
+vn 0.114222 0.380181 0.917832
+s off
+f 36/1/1 13/2/1 1/3/1
+f 29/4/2 34/5/2 10/6/2
+f 35/7/3 28/8/3 21/9/3
+f 22/10/4 27/11/4 5/12/4
+f 13/2/5 16/13/5 18/14/5
+f 14/15/6 17/16/6 16/17/6
+f 15/18/7 18/19/7 17/20/7
+f 20/21/8 23/22/8 25/23/8
+f 21/9/9 24/24/9 23/25/9
+f 22/10/10 25/26/10 24/27/10
+f 27/11/11 30/28/11 33/29/11
+f 28/8/12 31/30/12 33/31/12
+f 29/4/13 32/32/13 33/33/13
+f 34/5/14 37/34/14 40/35/14
+f 35/7/15 38/36/15 40/37/15
+f 36/1/16 39/38/16 40/39/16
+f 14/15/17 21/9/17 17/16/17
+f 17/20/18 23/22/18 15/18/18
+f 22/10/19 5/12/19 25/26/19
+f 25/23/20 6/40/20 20/21/20
+f 1/3/21 13/2/21 3/41/21
+f 3/42/22 18/19/22 2/43/22
+f 21/9/23 28/8/23 24/24/23
+f 24/27/24 30/28/24 22/10/24
+f 29/4/25 8/44/25 9/45/25
+f 32/46/26 9/47/26 7/48/26
+f 28/8/27 35/7/27 37/49/27
+f 31/50/28 37/34/28 34/5/28
+f 36/1/29 11/51/29 12/52/29
+f 39/53/30 12/54/30 10/6/30
+f 35/7/31 14/15/31 16/17/31
+f 38/55/32 16/13/32 13/2/32
+f 15/18/33 20/21/33 2/43/33
+f 5/56/34 7/57/34 6/58/34
+f 11/51/1 36/1/1 1/3/1
+f 8/44/2 29/4/2 10/6/2
+f 14/15/3 35/7/3 21/9/3
+f 27/11/4 7/48/4 5/12/4
+f 16/13/35 19/59/35 18/14/35
+f 17/16/36 19/60/36 16/17/36
+f 18/19/37 19/61/37 17/20/37
+f 23/22/38 26/62/38 25/23/38
+f 24/24/39 26/63/39 23/25/39
+f 25/26/40 26/64/40 24/27/40
+f 32/46/41 27/11/41 33/29/41
+f 30/65/42 28/8/42 33/31/42
+f 31/50/43 29/4/43 33/33/43
+f 39/53/44 34/5/44 40/35/44
+f 37/49/45 35/7/45 40/37/45
+f 38/55/46 36/1/46 40/39/46
+f 21/9/17 23/25/17 17/16/17
+f 23/22/18 20/21/18 15/18/18
+f 5/12/19 6/66/19 25/26/19
+f 6/40/20 4/67/20 20/21/20
+f 13/2/21 18/14/21 3/41/21
+f 18/19/22 15/18/22 2/43/22
+f 28/8/23 30/65/23 24/24/23
+f 30/28/24 27/11/24 22/10/24
+f 32/32/25 29/4/25 9/45/25
+f 27/11/26 32/46/26 7/48/26
+f 31/30/27 28/8/27 37/49/27
+f 29/4/28 31/50/28 34/5/28
+f 39/38/29 36/1/29 12/52/29
+f 34/5/30 39/53/30 10/6/30
+f 38/36/31 35/7/31 16/17/31
+f 36/1/32 38/55/32 13/2/32
+f 20/21/33 4/67/33 2/43/33
+f 7/57/34 9/68/34 6/58/34
+f 9/68/34 8/69/34 6/58/34
+f 8/69/34 10/70/34 6/58/34
+f 10/70/34 12/71/34 6/58/34
+f 12/71/34 11/72/34 6/58/34
+f 11/72/34 1/73/34 6/58/34
+f 1/73/34 3/74/34 6/58/34
+f 3/74/34 2/75/34 4/76/34
+f 6/58/34 3/74/34 4/76/34
diff --git a/src/datavisualization/engine/meshes/barFilledSmooth.obj b/src/datavisualization/engine/meshes/barFilledSmooth.obj
new file mode 100644
index 00000000..efc4317a
--- /dev/null
+++ b/src/datavisualization/engine/meshes/barFilledSmooth.obj
@@ -0,0 +1,236 @@
+# Blender v2.66 (sub 0) OBJ File: 'smoothcube_filled.blend'
+# www.blender.org
+o Cube
+v -0.980000 -1.000000 1.000000
+v -1.000000 -1.000000 0.980000
+v -0.994142 -1.000000 0.994142
+v -1.000000 -1.000000 -0.980000
+v -0.980000 -1.000000 -1.000000
+v -0.994142 -1.000000 -0.994142
+v 0.980000 -1.000000 -1.000000
+v 1.000000 -1.000000 -0.980000
+v 0.994142 -1.000000 -0.994142
+v 1.000000 -1.000000 0.980000
+v 0.980000 -1.000000 1.000000
+v 0.994142 -1.000000 0.994142
+v -0.980000 0.980000 1.000000
+v -0.980000 1.000000 0.980000
+v -1.000000 0.980000 0.980000
+v -0.980000 0.994142 0.994142
+v -0.994142 0.994142 0.980000
+v -0.994142 0.980000 0.994142
+v -0.992998 0.992998 0.992998
+v -1.000000 0.980000 -0.980000
+v -0.980000 1.000000 -0.980000
+v -0.980000 0.980000 -1.000000
+v -0.994142 0.994142 -0.980000
+v -0.980000 0.994142 -0.994142
+v -0.994142 0.980000 -0.994142
+v -0.992998 0.992998 -0.992998
+v 0.980000 0.980000 -1.000000
+v 0.980000 1.000000 -0.980000
+v 1.000000 0.980000 -0.980000
+v 0.980000 0.994142 -0.994142
+v 0.994142 0.994142 -0.980000
+v 0.994142 0.980000 -0.994142
+v 0.992998 0.992998 -0.992998
+v 1.000000 0.980000 0.980000
+v 0.980000 1.000000 0.980000
+v 0.980000 0.980000 1.000000
+v 0.994142 0.994142 0.980000
+v 0.980000 0.994142 0.994142
+v 0.994142 0.980000 0.994142
+v 0.992998 0.992998 0.992998
+vt 0.339018 0.659342
+vt 0.338105 0.335826
+vt 0.664825 0.343846
+vt 0.669233 0.664931
+vt 0.668227 0.337019
+vt 0.995472 0.336015
+vt 0.337976 0.003372
+vt 0.665888 0.002366
+vt 0.666894 0.330278
+vt 0.672755 0.331283
+vt 0.671749 0.003372
+vt 0.998994 0.002368
+vt 0.335610 0.335927
+vt 0.335761 0.333817
+vt 0.338982 0.331284
+vt 0.338989 0.333650
+vt 0.336814 0.333465
+vt 0.326720 0.346123
+vt 0.326875 0.343630
+vt 0.329052 0.343841
+vt 0.327633 0.669639
+vt 0.330128 0.669538
+vt 0.329977 0.671648
+vt 0.669260 0.330271
+vt 0.669075 0.332446
+vt 0.672610 0.333650
+vt 0.670432 0.333465
+vt 0.669260 0.003379
+vt 0.669412 0.001204
+vt 0.665880 0.000000
+vt 0.668056 0.000185
+vt 0.669089 0.667298
+vt 0.666910 0.667113
+vt 0.665738 0.337027
+vt 0.665891 0.334852
+vt 0.335610 0.003379
+vt 0.335795 0.001204
+vt 0.338863 0.661835
+vt 0.336686 0.661624
+vt 0.666901 0.332644
+vt 0.329215 0.346022
+vt 1.000000 0.330280
+vt 0.999855 0.332646
+vt 0.327801 0.671815
+vt 0.001081 0.663795
+vt 0.000913 0.661618
+vt 0.337937 0.333650
+vt 0.000155 0.335610
+vt 0.668254 0.002359
+vt 0.670266 0.331291
+vt 0.996478 0.663927
+vt 0.996334 0.666294
+vt 0.671590 0.001006
+vt 0.998835 0.000002
+vt 0.337969 0.001006
+vt 0.666744 0.664939
+vt 0.665738 0.667363
+vt 0.665583 0.669855
+vt 0.668068 0.334654
+vt 0.995313 0.333650
+vt 0.336616 0.331291
+vt 0.336523 0.659443
+vt 0.000000 0.004362
+vt 0.000973 0.001993
+vt 0.003336 0.001006
+vt 0.664657 0.341670
+vt 0.000000 0.338102
+vt 0.334604 0.003336
+vt 0.331248 0.000000
+vt 0.333617 0.000973
+vt 0.332274 0.334604
+vt 0.335610 0.331248
+vt 0.334637 0.333617
+vt 0.001993 0.334637
+vt 0.001006 0.332274
+vt 0.004362 0.335610
+vn 0.161046 0.161046 0.973693
+vn -0.161046 0.161046 0.973693
+vn -0.145573 -0.665700 0.731864
+vn 0.973693 0.161046 -0.161046
+vn 0.973693 0.161046 0.161046
+vn 0.731864 -0.665700 0.145573
+vn 0.161046 0.973693 0.161046
+vn 0.161046 0.973693 -0.161046
+vn -0.161046 0.973693 -0.161046
+vn -0.161046 0.161046 -0.973693
+vn 0.161046 0.161046 -0.973693
+vn 0.145573 -0.665700 -0.731864
+vn -0.060945 0.705771 0.705771
+vn -0.577349 0.577349 0.577349
+vn -0.161046 0.973693 0.161046
+vn -0.705771 0.705771 0.060945
+vn -0.973693 0.161046 0.161046
+vn -0.705771 0.060945 0.705771
+vn -0.973693 0.161046 -0.161046
+vn -0.705771 0.705771 -0.060945
+vn -0.577349 0.577349 -0.577349
+vn -0.060945 0.705771 -0.705771
+vn -0.705771 0.060945 -0.705771
+vn 0.060945 0.705771 -0.705771
+vn 0.577349 0.577349 -0.577349
+vn 0.705771 0.705771 -0.060945
+vn 0.705771 0.060945 -0.705771
+vn 0.705771 0.705771 0.060945
+vn 0.577349 0.577349 0.577349
+vn 0.060945 0.705771 0.705771
+vn 0.705771 0.060945 0.705771
+vn -0.145573 -0.665700 -0.731864
+vn -0.548967 -0.630238 -0.548967
+vn -0.731864 -0.665700 -0.145573
+vn -0.548967 -0.630238 0.548967
+vn 0.731864 -0.665700 -0.145573
+vn 0.548967 -0.630238 -0.548967
+vn 0.145573 -0.665700 0.731864
+vn 0.548967 -0.630238 0.548967
+vn -0.731864 -0.665700 0.145573
+s 1
+f 36/1/1 13/2/2 1/3/3
+f 29/4/4 34/5/5 10/6/6
+f 35/7/7 28/8/8 21/9/9
+f 22/10/10 27/11/11 7/12/12
+f 13/2/2 16/13/13 19/14/14
+f 14/15/15 17/16/16 19/17/14
+f 15/18/17 18/19/18 19/20/14
+f 20/21/19 23/22/20 26/23/21
+f 21/9/9 24/24/22 26/25/21
+f 22/10/10 25/26/23 26/27/21
+f 27/11/11 30/28/24 33/29/25
+f 28/8/8 31/30/26 33/31/25
+f 29/4/4 32/32/27 33/33/25
+f 34/5/5 37/34/28 40/35/29
+f 35/7/7 38/36/30 40/37/29
+f 36/1/1 39/38/31 40/39/29
+f 14/15/15 21/9/9 23/40/20
+f 17/41/16 23/22/20 20/21/19
+f 22/10/10 5/42/32 6/43/33
+f 25/44/23 6/45/33 4/46/34
+f 1/3/3 13/2/2 18/47/18
+f 3/48/35 18/19/18 15/18/17
+f 21/9/9 28/8/8 30/49/24
+f 24/50/22 30/28/24 27/11/11
+f 29/4/4 8/51/36 9/52/37
+f 32/53/27 9/54/37 7/12/12
+f 28/8/8 35/7/7 37/55/28
+f 31/56/26 37/34/28 34/5/5
+f 36/1/1 11/57/38 12/58/39
+f 39/59/31 12/60/39 10/6/6
+f 35/7/7 14/15/15 16/61/13
+f 38/62/30 16/13/13 13/2/2
+f 15/18/17 20/21/19 4/46/34
+f 7/63/12 9/64/37 8/65/36
+f 11/57/38 36/1/1 1/3/3
+f 8/51/36 29/4/4 10/6/6
+f 14/15/15 35/7/7 21/9/9
+f 5/42/32 22/10/10 7/12/12
+f 18/47/18 13/2/2 19/14/14
+f 16/61/13 14/15/15 19/17/14
+f 17/41/16 15/18/17 19/20/14
+f 25/44/23 20/21/19 26/23/21
+f 23/40/20 21/9/9 26/25/21
+f 24/50/22 22/10/10 26/27/21
+f 32/53/27 27/11/11 33/29/25
+f 30/49/24 28/8/8 33/31/25
+f 31/56/26 29/4/4 33/33/25
+f 39/59/31 34/5/5 40/35/29
+f 37/55/28 35/7/7 40/37/29
+f 38/62/30 36/1/1 40/39/29
+f 17/16/16 14/15/15 23/40/20
+f 15/18/17 17/41/16 20/21/19
+f 25/26/23 22/10/10 6/43/33
+f 20/21/19 25/44/23 4/46/34
+f 3/66/35 1/3/3 18/47/18
+f 2/67/40 3/48/35 15/18/17
+f 24/24/22 21/9/9 30/49/24
+f 22/10/10 24/50/22 27/11/11
+f 32/32/27 29/4/4 9/52/37
+f 27/11/11 32/53/27 7/12/12
+f 31/30/26 28/8/8 37/55/28
+f 29/4/4 31/56/26 34/5/5
+f 39/38/31 36/1/1 12/58/39
+f 34/5/5 39/59/31 10/6/6
+f 38/36/30 35/7/7 16/61/13
+f 36/1/1 38/62/30 13/2/2
+f 2/67/40 15/18/17 4/46/34
+f 11/68/38 10/69/6 12/70/39
+f 2/71/40 1/72/3 3/73/35
+f 6/74/33 5/75/32 4/76/34
+f 5/75/32 7/63/12 4/76/34
+f 2/71/40 4/76/34 8/65/36
+f 8/65/36 10/69/6 2/71/40
+f 10/69/6 11/68/38 1/72/3
+f 2/71/40 10/69/6 1/72/3
+f 4/76/34 7/63/12 8/65/36
diff --git a/src/datavisualization/engine/meshes/barFlat.obj b/src/datavisualization/engine/meshes/barFlat.obj
new file mode 100644
index 00000000..b802feab
--- /dev/null
+++ b/src/datavisualization/engine/meshes/barFlat.obj
@@ -0,0 +1,219 @@
+# Blender v2.66 (sub 0) OBJ File: 'smoothcube.blend'
+# www.blender.org
+o Cube
+v -0.980000 -1.000000 1.000000
+v -1.000000 -1.000000 0.980000
+v -0.994142 -1.000000 0.994142
+v -1.000000 -1.000000 -0.980000
+v -0.980000 -1.000000 -1.000000
+v -0.994142 -1.000000 -0.994142
+v 0.980000 -1.000000 -1.000000
+v 1.000000 -1.000000 -0.980000
+v 0.994142 -1.000000 -0.994142
+v 1.000000 -1.000000 0.980000
+v 0.980000 -1.000000 1.000000
+v 0.994142 -1.000000 0.994142
+v -0.980000 0.980000 1.000000
+v -0.980000 1.000000 0.980000
+v -1.000000 0.980000 0.980000
+v -0.980000 0.994142 0.994142
+v -0.994142 0.994142 0.980000
+v -0.994142 0.980000 0.994142
+v -0.992998 0.992998 0.992998
+v -1.000000 0.980000 -0.980000
+v -0.980000 1.000000 -0.980000
+v -0.980000 0.980000 -1.000000
+v -0.994142 0.994142 -0.980000
+v -0.980000 0.994142 -0.994142
+v -0.994142 0.980000 -0.994142
+v -0.992998 0.992998 -0.992998
+v 0.980000 0.980000 -1.000000
+v 0.980000 1.000000 -0.980000
+v 1.000000 0.980000 -0.980000
+v 0.980000 0.994142 -0.994142
+v 0.994142 0.994142 -0.980000
+v 0.994142 0.980000 -0.994142
+v 0.992998 0.992998 -0.992998
+v 1.000000 0.980000 0.980000
+v 0.980000 1.000000 0.980000
+v 0.980000 0.980000 1.000000
+v 0.994142 0.994142 0.980000
+v 0.980000 0.994142 0.994142
+v 0.994142 0.980000 0.994142
+v 0.992998 0.992998 0.992998
+vt 0.338795 0.668183
+vt 0.337784 0.338666
+vt 0.666630 0.337658
+vt 0.003512 0.668185
+vt 0.002502 0.338668
+vt 0.331348 0.337660
+vt 0.002378 0.003388
+vt 0.331894 0.002378
+vt 0.332905 0.331894
+vt 0.671154 0.332902
+vt 0.670143 0.003386
+vt 1.000000 0.331893
+vt 0.335282 0.338674
+vt 0.337624 0.336289
+vt 0.003388 0.332905
+vt 0.003396 0.335282
+vt 0.001011 0.332912
+vt 0.338795 0.332902
+vt 0.338649 0.335280
+vt 0.336293 0.332910
+vt 0.337784 0.003386
+vt 0.335282 0.003394
+vt 0.337624 0.001009
+vt 0.335282 0.331887
+vt 0.332912 0.334272
+vt 0.671008 0.335280
+vt 0.668652 0.332910
+vt 0.667641 0.003394
+vt 0.667795 0.001208
+vt 0.331887 0.000000
+vt 0.334073 0.000186
+vt 0.003367 0.670563
+vt 0.001178 0.670377
+vt 0.000000 0.338676
+vt 0.000153 0.336490
+vt 0.000000 0.003396
+vt 0.000186 0.001210
+vt 0.338649 0.670561
+vt 0.336460 0.670375
+vt 0.666470 0.000000
+vt 0.666470 0.335280
+vt 0.667496 0.334272
+vt 0.667641 0.331894
+vt 0.332359 0.667176
+vt 0.332213 0.669554
+vt 0.669983 0.001009
+vt 0.998829 0.000000
+vt 0.998989 0.002377
+vt 0.002370 0.001011
+vt 0.001011 0.668192
+vt 0.667641 0.667174
+vt 0.667496 0.669552
+vt 0.002341 0.336291
+vt 0.331188 0.335282
+vt 0.336293 0.668191
+vt 0.335436 0.336488
+vt 0.001210 0.335097
+vt 0.336460 0.335095
+vt 0.335436 0.001208
+vt 0.335097 0.334073
+vt 0.668819 0.335095
+vt 0.334272 0.002370
+vt 0.999855 0.334272
+vt 0.666630 0.002377
+vn 0.000000 0.000000 1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 1.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn -0.357407 0.357407 0.862856
+vn -0.357409 0.862855 0.357407
+vn -0.862855 0.357409 0.357407
+vn -0.862855 0.357407 -0.357409
+vn -0.357407 0.862855 -0.357409
+vn -0.357408 0.357408 -0.862855
+vn 0.114222 0.380181 -0.917832
+vn 0.380181 0.917832 -0.114222
+vn 0.917832 0.114222 -0.380181
+vn 0.917832 0.380181 0.114222
+vn 0.114222 0.917832 0.380181
+vn 0.380181 0.114222 0.917832
+vn -0.382685 0.923879 0.000000
+vn -0.923879 0.382685 0.000000
+vn -0.382685 0.000000 -0.923879
+vn -0.923879 0.000000 -0.382685
+vn -0.382685 0.000000 0.923879
+vn -0.923879 0.000000 0.382685
+vn 0.000000 0.923879 -0.382685
+vn 0.000000 0.382685 -0.923879
+vn 0.923879 0.000000 -0.382685
+vn 0.382685 0.000000 -0.923879
+vn 0.382685 0.923879 0.000000
+vn 0.923879 0.382685 0.000000
+vn 0.382685 -0.000000 0.923879
+vn 0.923879 -0.000000 0.382685
+vn -0.000000 0.923879 0.382685
+vn -0.000000 0.382685 0.923879
+vn -1.000000 0.000000 0.000000
+vn -0.095602 0.095602 0.990818
+vn -0.095602 0.990818 0.095602
+vn -0.990818 0.095602 0.095602
+vn -0.990818 0.095602 -0.095602
+vn -0.095602 0.990818 -0.095602
+vn -0.095602 0.095602 -0.990818
+vn 0.380181 0.114222 -0.917832
+vn 0.114222 0.917832 -0.380181
+vn 0.917832 0.380181 -0.114222
+vn 0.917832 0.114222 0.380181
+vn 0.380181 0.917832 0.114222
+vn 0.114222 0.380181 0.917832
+s off
+f 36/1/1 13/2/1 1/3/1
+f 29/4/2 34/5/2 10/6/2
+f 35/7/3 28/8/3 21/9/3
+f 22/10/4 27/11/4 5/12/4
+f 13/2/5 16/13/5 18/14/5
+f 14/15/6 17/16/6 16/17/6
+f 15/18/7 18/19/7 17/20/7
+f 20/21/8 23/22/8 25/23/8
+f 21/9/9 24/24/9 23/25/9
+f 22/10/10 25/26/10 24/27/10
+f 27/11/11 30/28/11 33/29/11
+f 28/8/12 31/30/12 33/31/12
+f 29/4/13 32/32/13 33/33/13
+f 34/5/14 37/34/14 40/35/14
+f 35/7/15 38/36/15 40/37/15
+f 36/1/16 39/38/16 40/39/16
+f 14/15/17 21/9/17 17/16/17
+f 17/20/18 23/22/18 15/18/18
+f 22/10/19 5/12/19 25/26/19
+f 25/23/20 6/40/20 20/21/20
+f 1/3/21 13/2/21 3/41/21
+f 3/42/22 18/19/22 2/43/22
+f 21/9/23 28/8/23 24/24/23
+f 24/27/24 30/28/24 22/10/24
+f 29/4/25 8/44/25 9/45/25
+f 32/46/26 9/47/26 7/48/26
+f 28/8/27 35/7/27 37/49/27
+f 31/50/28 37/34/28 34/5/28
+f 36/1/29 11/51/29 12/52/29
+f 39/53/30 12/54/30 10/6/30
+f 35/7/31 14/15/31 16/17/31
+f 38/55/32 16/13/32 13/2/32
+f 15/18/33 20/21/33 2/43/33
+f 11/51/1 36/1/1 1/3/1
+f 8/44/2 29/4/2 10/6/2
+f 14/15/3 35/7/3 21/9/3
+f 27/11/4 7/48/4 5/12/4
+f 16/13/34 19/56/34 18/14/34
+f 17/16/35 19/57/35 16/17/35
+f 18/19/36 19/58/36 17/20/36
+f 23/22/37 26/59/37 25/23/37
+f 24/24/38 26/60/38 23/25/38
+f 25/26/39 26/61/39 24/27/39
+f 32/46/40 27/11/40 33/29/40
+f 30/62/41 28/8/41 33/31/41
+f 31/50/42 29/4/42 33/33/42
+f 39/53/43 34/5/43 40/35/43
+f 37/49/44 35/7/44 40/37/44
+f 38/55/45 36/1/45 40/39/45
+f 21/9/17 23/25/17 17/16/17
+f 23/22/18 20/21/18 15/18/18
+f 5/12/19 6/63/19 25/26/19
+f 6/40/20 4/64/20 20/21/20
+f 13/2/21 18/14/21 3/41/21
+f 18/19/22 15/18/22 2/43/22
+f 28/8/23 30/62/23 24/24/23
+f 30/28/24 27/11/24 22/10/24
+f 32/32/25 29/4/25 9/45/25
+f 27/11/26 32/46/26 7/48/26
+f 31/30/27 28/8/27 37/49/27
+f 29/4/28 31/50/28 34/5/28
+f 39/38/29 36/1/29 12/52/29
+f 34/5/30 39/53/30 10/6/30
+f 38/36/31 35/7/31 16/17/31
+f 36/1/32 38/55/32 13/2/32
+f 20/21/33 4/64/33 2/43/33
diff --git a/src/datavisualization/engine/meshes/barSmooth.obj b/src/datavisualization/engine/meshes/barSmooth.obj
new file mode 100644
index 00000000..aa4fdd92
--- /dev/null
+++ b/src/datavisualization/engine/meshes/barSmooth.obj
@@ -0,0 +1,214 @@
+# Blender v2.66 (sub 0) OBJ File: 'smoothcube.blend'
+# www.blender.org
+o Cube
+v -0.980000 -1.000000 1.000000
+v -1.000000 -1.000000 0.980000
+v -0.994142 -1.000000 0.994142
+v -1.000000 -1.000000 -0.980000
+v -0.980000 -1.000000 -1.000000
+v -0.994142 -1.000000 -0.994142
+v 0.980000 -1.000000 -1.000000
+v 1.000000 -1.000000 -0.980000
+v 0.994142 -1.000000 -0.994142
+v 1.000000 -1.000000 0.980000
+v 0.980000 -1.000000 1.000000
+v 0.994142 -1.000000 0.994142
+v -0.980000 0.980000 1.000000
+v -0.980000 1.000000 0.980000
+v -1.000000 0.980000 0.980000
+v -0.980000 0.994142 0.994142
+v -0.994142 0.994142 0.980000
+v -0.994142 0.980000 0.994142
+v -0.992998 0.992998 0.992998
+v -1.000000 0.980000 -0.980000
+v -0.980000 1.000000 -0.980000
+v -0.980000 0.980000 -1.000000
+v -0.994142 0.994142 -0.980000
+v -0.980000 0.994142 -0.994142
+v -0.994142 0.980000 -0.994142
+v -0.992998 0.992998 -0.992998
+v 0.980000 0.980000 -1.000000
+v 0.980000 1.000000 -0.980000
+v 1.000000 0.980000 -0.980000
+v 0.980000 0.994142 -0.994142
+v 0.994142 0.994142 -0.980000
+v 0.994142 0.980000 -0.994142
+v 0.992998 0.992998 -0.992998
+v 1.000000 0.980000 0.980000
+v 0.980000 1.000000 0.980000
+v 0.980000 0.980000 1.000000
+v 0.994142 0.994142 0.980000
+v 0.980000 0.994142 0.994142
+v 0.994142 0.980000 0.994142
+v 0.992998 0.992998 0.992998
+vt 0.338795 0.668183
+vt 0.337784 0.338666
+vt 0.666630 0.337658
+vt 0.003512 0.668185
+vt 0.002502 0.338668
+vt 0.331348 0.337660
+vt 0.002378 0.003388
+vt 0.331894 0.002378
+vt 0.332905 0.331894
+vt 0.671154 0.332902
+vt 0.670143 0.003386
+vt 1.000000 0.331893
+vt 0.335282 0.338674
+vt 0.337624 0.336289
+vt 0.003388 0.332905
+vt 0.003396 0.335282
+vt 0.001011 0.332912
+vt 0.338795 0.332902
+vt 0.338649 0.335280
+vt 0.336293 0.332910
+vt 0.337784 0.003386
+vt 0.335282 0.003394
+vt 0.337624 0.001009
+vt 0.335282 0.331887
+vt 0.332912 0.334272
+vt 0.671008 0.335280
+vt 0.668652 0.332910
+vt 0.667641 0.003394
+vt 0.667795 0.001208
+vt 0.331887 0.000000
+vt 0.334073 0.000186
+vt 0.003367 0.670563
+vt 0.001178 0.670377
+vt 0.000000 0.338676
+vt 0.000153 0.336490
+vt 0.000000 0.003396
+vt 0.000186 0.001210
+vt 0.338649 0.670561
+vt 0.336460 0.670375
+vt 0.666470 0.000000
+vt 0.666470 0.335280
+vt 0.667496 0.334272
+vt 0.667641 0.331894
+vt 0.332359 0.667176
+vt 0.332213 0.669554
+vt 0.669983 0.001009
+vt 0.998829 0.000000
+vt 0.998989 0.002377
+vt 0.002370 0.001011
+vt 0.001011 0.668192
+vt 0.667641 0.667174
+vt 0.667496 0.669552
+vt 0.002341 0.336291
+vt 0.331188 0.335282
+vt 0.336293 0.668191
+vt 0.335436 0.336488
+vt 0.001210 0.335097
+vt 0.336460 0.335095
+vt 0.335436 0.001208
+vt 0.335097 0.334073
+vt 0.668819 0.335095
+vt 0.334272 0.002370
+vt 0.999855 0.334272
+vt 0.666630 0.002377
+vn 0.161046 0.161046 0.973693
+vn -0.187689 0.187689 0.964110
+vn -0.195074 0.000000 0.980773
+vn 0.973693 0.161046 -0.161046
+vn 0.973693 0.161046 0.161046
+vn 0.980773 0.000000 0.195074
+vn 0.161046 0.973693 0.161046
+vn 0.161046 0.973693 -0.161046
+vn -0.187689 0.964110 -0.187689
+vn -0.187689 0.187689 -0.964110
+vn 0.161046 0.161046 -0.973693
+vn -0.195074 0.000000 -0.980773
+vn -0.135655 0.700552 0.700552
+vn -0.700552 0.135655 0.700552
+vn -0.187689 0.964110 0.187689
+vn -0.700552 0.700552 0.135655
+vn -0.964110 0.187689 0.187689
+vn -0.964110 0.187689 -0.187689
+vn -0.700552 0.700552 -0.135655
+vn -0.700552 0.135655 -0.700552
+vn -0.135655 0.700552 -0.700552
+vn 0.060945 0.705771 -0.705771
+vn 0.577349 0.577349 -0.577349
+vn 0.705771 0.705771 -0.060945
+vn 0.705771 0.060945 -0.705771
+vn 0.705771 0.705771 0.060945
+vn 0.577349 0.577349 0.577349
+vn 0.060945 0.705771 0.705771
+vn 0.705771 0.060945 0.705771
+vn -0.707083 0.000000 -0.707083
+vn -0.707083 0.000000 0.707083
+vn -0.980773 0.000000 0.195074
+vn 0.980773 0.000000 -0.195074
+vn 0.707083 0.000000 -0.707083
+vn 0.195074 0.000000 -0.980773
+vn 0.195074 0.000000 0.980773
+vn 0.707083 0.000000 0.707083
+vn -0.577349 0.577349 0.577349
+vn -0.577349 0.577349 -0.577349
+vn -0.980773 0.000000 -0.195074
+s 1
+f 36/1/1 13/2/2 1/3/3
+f 29/4/4 34/5/5 10/6/6
+f 35/7/7 28/8/8 21/9/9
+f 22/10/10 27/11/11 5/12/12
+f 13/2/2 16/13/13 18/14/14
+f 14/15/15 17/16/16 16/17/13
+f 15/18/17 18/19/14 17/20/16
+f 20/21/18 23/22/19 25/23/20
+f 21/9/9 24/24/21 23/25/19
+f 22/10/10 25/26/20 24/27/21
+f 27/11/11 30/28/22 33/29/23
+f 28/8/8 31/30/24 33/31/23
+f 29/4/4 32/32/25 33/33/23
+f 34/5/5 37/34/26 40/35/27
+f 35/7/7 38/36/28 40/37/27
+f 36/1/1 39/38/29 40/39/27
+f 14/15/15 21/9/9 17/16/16
+f 17/20/16 23/22/19 15/18/17
+f 22/10/10 5/12/12 25/26/20
+f 25/23/20 6/40/30 20/21/18
+f 1/3/3 13/2/2 3/41/31
+f 3/42/31 18/19/14 2/43/32
+f 21/9/9 28/8/8 24/24/21
+f 24/27/21 30/28/22 22/10/10
+f 29/4/4 8/44/33 9/45/34
+f 32/46/25 9/47/34 7/48/35
+f 28/8/8 35/7/7 37/49/26
+f 31/50/24 37/34/26 34/5/5
+f 36/1/1 11/51/36 12/52/37
+f 39/53/29 12/54/37 10/6/6
+f 35/7/7 14/15/15 16/17/13
+f 38/55/28 16/13/13 13/2/2
+f 15/18/17 20/21/18 2/43/32
+f 11/51/36 36/1/1 1/3/3
+f 8/44/33 29/4/4 10/6/6
+f 14/15/15 35/7/7 21/9/9
+f 27/11/11 7/48/35 5/12/12
+f 16/13/13 19/56/38 18/14/14
+f 17/16/16 19/57/38 16/17/13
+f 18/19/14 19/58/38 17/20/16
+f 23/22/19 26/59/39 25/23/20
+f 24/24/21 26/60/39 23/25/19
+f 25/26/20 26/61/39 24/27/21
+f 32/46/25 27/11/11 33/29/23
+f 30/62/22 28/8/8 33/31/23
+f 31/50/24 29/4/4 33/33/23
+f 39/53/29 34/5/5 40/35/27
+f 37/49/26 35/7/7 40/37/27
+f 38/55/28 36/1/1 40/39/27
+f 21/9/9 23/25/19 17/16/16
+f 23/22/19 20/21/18 15/18/17
+f 5/12/12 6/63/30 25/26/20
+f 6/40/30 4/64/40 20/21/18
+f 13/2/2 18/14/14 3/41/31
+f 18/19/14 15/18/17 2/43/32
+f 28/8/8 30/62/22 24/24/21
+f 30/28/22 27/11/11 22/10/10
+f 32/32/25 29/4/4 9/45/34
+f 27/11/11 32/46/25 7/48/35
+f 31/30/24 28/8/8 37/49/26
+f 29/4/4 31/50/24 34/5/5
+f 39/38/29 36/1/1 12/52/37
+f 34/5/5 39/53/29 10/6/6
+f 38/36/28 35/7/7 16/17/13
+f 36/1/1 38/55/28 13/2/2
+f 20/21/18 4/64/40 2/43/32
diff --git a/src/datavisualization/engine/meshes/coneFilledFlat.obj b/src/datavisualization/engine/meshes/coneFilledFlat.obj
new file mode 100644
index 00000000..cbbffaff
--- /dev/null
+++ b/src/datavisualization/engine/meshes/coneFilledFlat.obj
@@ -0,0 +1,128 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone_filled.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.636534 0.537407
+vt 0.609784 0.926283
+vt 0.571680 0.562142
+vt 0.911640 0.504376
+vt 0.571680 0.368442
+vt 0.953118 0.448721
+vt 0.853526 0.537297
+vt 0.973901 0.375780
+vt 0.712378 0.537297
+vt 0.791787 0.561822
+vt 0.866987 0.608581
+vt 0.930618 0.672998
+vt 0.976451 0.748767
+vt 1.000000 0.828470
+vt 0.998959 0.904307
+vt 0.973430 0.968853
+vt 0.629860 0.006965
+vt 0.571746 0.039886
+vt 0.698921 0.000000
+vt 0.772169 0.019673
+vt 0.842434 0.064059
+vt 0.902837 0.128812
+vt 0.947467 0.207594
+vt 0.971954 0.292693
+vt 0.154453 0.543699
+vt 0.081201 0.490478
+vt 0.240567 0.571679
+vt 0.027980 0.417226
+vt 0.000000 0.331112
+vt 0.000000 0.240567
+vt 0.027980 0.154454
+vt 0.081201 0.081201
+vt 0.154454 0.027980
+vt 0.240567 0.000000
+vt 0.331112 0.000000
+vt 0.417226 0.027980
+vt 0.490479 0.081201
+vt 0.543700 0.154454
+vt 0.571680 0.240567
+vt 0.571680 0.331113
+vt 0.543699 0.417226
+vt 0.490478 0.490479
+vt 0.417226 0.543700
+vt 0.331112 0.571680
+vn -0.407058 0.442793 -0.798898
+vn 0.140263 0.442793 -0.885585
+vn -0.140262 0.442793 -0.885585
+vn 0.407059 0.442793 -0.798898
+vn -0.634008 0.442793 -0.634010
+vn -0.798897 0.442793 -0.407060
+vn -0.885585 0.442793 -0.140264
+vn -0.885585 0.442793 0.140262
+vn -0.798898 0.442793 0.407058
+vn -0.634009 0.442793 0.634009
+vn -0.407059 0.442793 0.798898
+vn -0.140263 0.442793 0.885585
+vn 0.140263 0.442793 0.885585
+vn 0.407059 0.442793 0.798898
+vn 0.634009 0.442793 0.634009
+vn 0.798898 0.442793 0.407059
+vn 0.885585 0.442793 0.140263
+vn 0.885585 0.442793 -0.140263
+vn 0.798898 0.442793 -0.407059
+vn 0.634009 0.442793 -0.634009
+vn -0.000000 -1.000000 -0.000000
+s off
+f 20/1/1 9/2/1 21/3/1
+f 1/4/2 9/5/2 2/6/2
+f 21/7/3 9/5/3 1/4/3
+f 2/6/4 9/5/4 3/8/4
+f 19/9/5 9/2/5 20/1/5
+f 18/10/6 9/2/6 19/9/6
+f 17/11/7 9/2/7 18/10/7
+f 16/12/8 9/2/8 17/11/8
+f 15/13/9 9/2/9 16/12/9
+f 14/14/10 9/2/10 15/13/10
+f 13/15/11 9/2/11 14/14/11
+f 12/16/12 9/2/12 13/15/12
+f 11/17/13 9/5/13 12/18/13
+f 10/19/14 9/5/14 11/17/14
+f 8/20/15 9/5/15 10/19/15
+f 7/21/16 9/5/16 8/20/16
+f 6/22/17 9/5/17 7/21/17
+f 5/23/18 9/5/18 6/22/18
+f 4/24/19 9/5/19 5/23/19
+f 3/8/20 9/5/20 4/24/20
+f 21/25/21 1/26/21 20/27/21
+f 1/26/21 2/28/21 20/27/21
+f 2/28/21 3/29/21 20/27/21
+f 3/29/21 4/30/21 20/27/21
+f 4/30/21 5/31/21 20/27/21
+f 5/31/21 6/32/21 20/27/21
+f 6/32/21 7/33/21 20/27/21
+f 7/33/21 8/34/21 20/27/21
+f 8/34/21 10/35/21 20/27/21
+f 10/35/21 11/36/21 20/27/21
+f 11/36/21 12/37/21 20/27/21
+f 12/37/21 13/38/21 20/27/21
+f 13/38/21 14/39/21 20/27/21
+f 14/39/21 15/40/21 20/27/21
+f 15/40/21 16/41/21 20/27/21
+f 16/41/21 17/42/21 20/27/21
+f 17/42/21 18/43/21 19/44/21
+f 20/27/21 17/42/21 19/44/21
diff --git a/src/datavisualization/engine/meshes/coneFilledSmooth.obj b/src/datavisualization/engine/meshes/coneFilledSmooth.obj
new file mode 100644
index 00000000..ea3a8702
--- /dev/null
+++ b/src/datavisualization/engine/meshes/coneFilledSmooth.obj
@@ -0,0 +1,128 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone_filled.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.636534 0.537407
+vt 0.609784 0.926283
+vt 0.571680 0.562142
+vt 0.911640 0.504376
+vt 0.571680 0.368442
+vt 0.953118 0.448721
+vt 0.853526 0.537297
+vt 0.973901 0.375780
+vt 0.712378 0.537297
+vt 0.791787 0.561822
+vt 0.866987 0.608581
+vt 0.930618 0.672998
+vt 0.976451 0.748767
+vt 1.000000 0.828470
+vt 0.998959 0.904307
+vt 0.973430 0.968853
+vt 0.629860 0.006965
+vt 0.571746 0.039886
+vt 0.698921 0.000000
+vt 0.772169 0.019673
+vt 0.842434 0.064059
+vt 0.902837 0.128812
+vt 0.947467 0.207594
+vt 0.971954 0.292693
+vt 0.154453 0.543699
+vt 0.081201 0.490478
+vt 0.240567 0.571679
+vt 0.027980 0.417226
+vt 0.000000 0.331112
+vt 0.000000 0.240567
+vt 0.027980 0.154454
+vt 0.081201 0.081201
+vt 0.154454 0.027980
+vt 0.240567 0.000000
+vt 0.331112 0.000000
+vt 0.417226 0.027980
+vt 0.490479 0.081201
+vt 0.543700 0.154454
+vt 0.571680 0.240567
+vt 0.571680 0.331113
+vt 0.543699 0.417226
+vt 0.490478 0.490479
+vt 0.417226 0.543700
+vt 0.331112 0.571680
+vn -0.512009 -0.491043 -0.704733
+vn 0.000000 1.000000 0.000000
+vn -0.269173 -0.491043 -0.828486
+vn 0.000000 -0.491043 -0.871120
+vn 0.269173 -0.491043 -0.828486
+vn 0.512009 -0.491043 -0.704733
+vn -0.704733 -0.491043 -0.512040
+vn -0.828486 -0.491043 -0.269173
+vn -0.871120 -0.491043 0.000000
+vn -0.828486 -0.491043 0.269173
+vn -0.704733 -0.491043 0.512009
+vn -0.512009 -0.491043 0.704733
+vn -0.269173 -0.491043 0.828486
+vn 0.000000 -0.491043 0.871120
+vn 0.269173 -0.491043 0.828486
+vn 0.512009 -0.491043 0.704733
+vn 0.704733 -0.491043 0.512009
+vn 0.828486 -0.491043 0.269173
+vn 0.871120 -0.491043 0.000000
+vn 0.828486 -0.491043 -0.269173
+vn 0.704733 -0.491043 -0.512009
+s 1
+f 20/1/1 9/2/2 21/3/3
+f 1/4/4 9/5/2 2/6/5
+f 21/7/3 9/5/2 1/4/4
+f 2/6/5 9/5/2 3/8/6
+f 19/9/7 9/2/2 20/1/1
+f 18/10/8 9/2/2 19/9/7
+f 17/11/9 9/2/2 18/10/8
+f 16/12/10 9/2/2 17/11/9
+f 15/13/11 9/2/2 16/12/10
+f 14/14/12 9/2/2 15/13/11
+f 13/15/13 9/2/2 14/14/12
+f 12/16/14 9/2/2 13/15/13
+f 11/17/15 9/5/2 12/18/14
+f 10/19/16 9/5/2 11/17/15
+f 8/20/17 9/5/2 10/19/16
+f 7/21/18 9/5/2 8/20/17
+f 6/22/19 9/5/2 7/21/18
+f 5/23/20 9/5/2 6/22/19
+f 4/24/21 9/5/2 5/23/20
+f 3/8/6 9/5/2 4/24/21
+f 21/25/3 1/26/4 20/27/1
+f 1/26/4 2/28/5 20/27/1
+f 2/28/5 3/29/6 20/27/1
+f 3/29/6 4/30/21 20/27/1
+f 4/30/21 5/31/20 20/27/1
+f 5/31/20 6/32/19 20/27/1
+f 6/32/19 7/33/18 20/27/1
+f 7/33/18 8/34/17 20/27/1
+f 8/34/17 10/35/16 20/27/1
+f 10/35/16 11/36/15 20/27/1
+f 11/36/15 12/37/14 20/27/1
+f 12/37/14 13/38/13 20/27/1
+f 13/38/13 14/39/12 20/27/1
+f 14/39/12 15/40/11 20/27/1
+f 15/40/11 16/41/10 20/27/1
+f 16/41/10 17/42/9 20/27/1
+f 17/42/9 18/43/8 19/44/7
+f 20/27/1 17/42/9 19/44/7
diff --git a/src/datavisualization/engine/meshes/coneFlat.obj b/src/datavisualization/engine/meshes/coneFlat.obj
new file mode 100644
index 00000000..51c3821e
--- /dev/null
+++ b/src/datavisualization/engine/meshes/coneFlat.obj
@@ -0,0 +1,89 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.018984 0.308330
+vt 0.500000 0.482045
+vt 0.000000 0.410924
+vt 0.011213 0.505476
+vt 0.051524 0.582730
+vt 0.116989 0.635124
+vt 0.066306 0.207736
+vt 0.137334 0.118990
+vt 0.225115 0.050777
+vt 0.321057 0.009776
+vt 0.415768 0.000000
+vt 0.499978 0.022406
+vt 0.551525 0.582730
+vt 1.000000 0.482045
+vt 0.616989 0.635125
+vt 0.511213 0.505476
+vt 0.500000 0.410924
+vt 0.518984 0.308330
+vt 0.566306 0.207736
+vt 0.637334 0.118990
+vt 0.725115 0.050777
+vt 0.821057 0.009776
+vt 0.915768 0.000000
+vt 0.999978 0.022406
+vn -0.407058 0.442793 -0.798898
+vn 0.140263 0.442793 -0.885585
+vn -0.140262 0.442793 -0.885585
+vn 0.407059 0.442793 -0.798898
+vn -0.634008 0.442793 -0.634010
+vn -0.798897 0.442793 -0.407060
+vn -0.885585 0.442793 -0.140264
+vn -0.885585 0.442793 0.140262
+vn -0.798898 0.442793 0.407058
+vn -0.634009 0.442793 0.634009
+vn -0.407059 0.442793 0.798898
+vn -0.140263 0.442793 0.885585
+vn 0.140263 0.442793 0.885585
+vn 0.407059 0.442793 0.798898
+vn 0.634009 0.442793 0.634009
+vn 0.798898 0.442793 0.407059
+vn 0.885585 0.442793 0.140263
+vn 0.885585 0.442793 -0.140263
+vn 0.798898 0.442793 -0.407059
+vn 0.634009 0.442793 -0.634009
+s off
+f 20/1/1 9/2/1 21/3/1
+f 1/4/2 9/2/2 2/5/2
+f 21/3/3 9/2/3 1/4/3
+f 2/5/4 9/2/4 3/6/4
+f 19/7/5 9/2/5 20/1/5
+f 18/8/6 9/2/6 19/7/6
+f 17/9/7 9/2/7 18/8/7
+f 16/10/8 9/2/8 17/9/8
+f 15/11/9 9/2/9 16/10/9
+f 14/12/10 9/2/10 15/11/10
+f 13/13/11 9/14/11 14/15/11
+f 12/16/12 9/14/12 13/13/12
+f 11/17/13 9/14/13 12/16/13
+f 10/18/14 9/14/14 11/17/14
+f 8/19/15 9/14/15 10/18/15
+f 7/20/16 9/14/16 8/19/16
+f 6/21/17 9/14/17 7/20/17
+f 5/22/18 9/14/18 6/21/18
+f 4/23/19 9/14/19 5/22/19
+f 3/24/20 9/14/20 4/23/20
diff --git a/src/datavisualization/engine/meshes/coneSmooth.obj b/src/datavisualization/engine/meshes/coneSmooth.obj
new file mode 100644
index 00000000..48c48ba8
--- /dev/null
+++ b/src/datavisualization/engine/meshes/coneSmooth.obj
@@ -0,0 +1,90 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.018984 0.308330
+vt 0.500000 0.482045
+vt 0.000000 0.410924
+vt 0.011213 0.505476
+vt 0.051524 0.582730
+vt 0.116989 0.635124
+vt 0.066306 0.207736
+vt 0.137334 0.118990
+vt 0.225115 0.050777
+vt 0.321057 0.009776
+vt 0.415768 0.000000
+vt 0.499978 0.022406
+vt 0.551525 0.582730
+vt 1.000000 0.482045
+vt 0.616989 0.635125
+vt 0.511213 0.505476
+vt 0.500000 0.410924
+vt 0.518984 0.308330
+vt 0.566306 0.207736
+vt 0.637334 0.118990
+vt 0.725115 0.050777
+vt 0.821057 0.009776
+vt 0.915768 0.000000
+vt 0.999978 0.022406
+vn -0.525712 0.447188 -0.723594
+vn 0.000000 1.000000 0.000000
+vn -0.276376 0.447188 -0.850642
+vn 0.000000 0.447188 -0.894406
+vn 0.276376 0.447188 -0.850642
+vn 0.525712 0.447188 -0.723594
+vn -0.723594 0.447188 -0.525712
+vn -0.850642 0.447188 -0.276376
+vn -0.894406 0.447188 0.000000
+vn -0.850642 0.447188 0.276376
+vn -0.723594 0.447188 0.525712
+vn -0.525712 0.447188 0.723594
+vn -0.276376 0.447188 0.850642
+vn 0.000000 0.447188 0.894406
+vn 0.276376 0.447188 0.850642
+vn 0.525712 0.447188 0.723594
+vn 0.723594 0.447188 0.525712
+vn 0.850642 0.447188 0.276376
+vn 0.894406 0.447188 0.000000
+vn 0.850642 0.447188 -0.276376
+vn 0.723594 0.447188 -0.525712
+s 1
+f 20/1/1 9/2/2 21/3/3
+f 1/4/4 9/2/2 2/5/5
+f 21/3/3 9/2/2 1/4/4
+f 2/5/5 9/2/2 3/6/6
+f 19/7/7 9/2/2 20/1/1
+f 18/8/8 9/2/2 19/7/7
+f 17/9/9 9/2/2 18/8/8
+f 16/10/10 9/2/2 17/9/9
+f 15/11/11 9/2/2 16/10/10
+f 14/12/12 9/2/2 15/11/11
+f 13/13/13 9/14/2 14/15/12
+f 12/16/14 9/14/2 13/13/13
+f 11/17/15 9/14/2 12/16/14
+f 10/18/16 9/14/2 11/17/15
+f 8/19/17 9/14/2 10/18/16
+f 7/20/18 9/14/2 8/19/17
+f 6/21/19 9/14/2 7/20/18
+f 5/22/20 9/14/2 6/21/19
+f 4/23/21 9/14/2 5/22/20
+f 3/24/6 9/14/2 4/23/21
diff --git a/src/datavisualization/engine/meshes/cubeFilledFlat.obj b/src/datavisualization/engine/meshes/cubeFilledFlat.obj
new file mode 100644
index 00000000..108cf7ac
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cubeFilledFlat.obj
@@ -0,0 +1,54 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube_filled.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.666667 0.332314
+vt 0.334353 0.333333
+vt 0.665647 0.000000
+vt 0.001020 0.333333
+vt 0.000000 0.001020
+vt 0.333333 0.332314
+vt 0.333333 0.665647
+vt 0.001019 0.666667
+vt 0.000000 0.334353
+vt 0.334353 0.666667
+vt 0.333333 0.334353
+vt 0.665647 0.333333
+vt 0.333333 0.667686
+vt 0.665647 0.666667
+vt 0.666667 0.998980
+vt 0.667686 0.333333
+vt 0.666667 0.001019
+vt 0.998980 0.000000
+vt 0.333333 0.001019
+vt 0.332314 0.000000
+vt 0.332314 0.333333
+vt 0.666667 0.665647
+vt 0.334353 1.000000
+vt 1.000000 0.332314
+vn -1.000000 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 0.000000 1.000000
+vn 0.000000 1.000000 0.000000
+vn -0.000000 -1.000000 -0.000000
+s off
+f 5/1/1 6/2/1 1/3/1
+f 6/4/2 7/5/2 2/6/2
+f 7/7/3 8/8/3 4/9/3
+f 8/10/4 5/11/4 1/12/4
+f 8/13/5 7/14/5 6/15/5
+f 2/16/6 3/17/6 4/18/6
+f 6/2/1 2/19/1 1/3/1
+f 7/5/2 3/20/2 2/6/2
+f 3/21/3 7/7/3 4/9/3
+f 4/22/4 8/10/4 1/12/4
+f 5/23/5 8/13/5 6/15/5
+f 1/24/6 2/16/6 4/18/6
diff --git a/src/datavisualization/engine/meshes/cubeFilledSmooth.obj b/src/datavisualization/engine/meshes/cubeFilledSmooth.obj
new file mode 100644
index 00000000..07350f03
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cubeFilledSmooth.obj
@@ -0,0 +1,56 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube_filled.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.666667 0.332314
+vt 0.334353 0.333333
+vt 0.665647 0.000000
+vt 0.001020 0.333333
+vt 0.000000 0.001020
+vt 0.333333 0.332314
+vt 0.333333 0.665647
+vt 0.001019 0.666667
+vt 0.000000 0.334353
+vt 0.334353 0.666667
+vt 0.333333 0.334353
+vt 0.665647 0.333333
+vt 0.333333 0.667686
+vt 0.665647 0.666667
+vt 0.666667 0.998980
+vt 0.667686 0.333333
+vt 0.666667 0.001019
+vt 0.998980 0.000000
+vt 0.333333 0.001019
+vt 0.332314 0.000000
+vt 0.332314 0.333333
+vt 0.666667 0.665647
+vt 0.334353 1.000000
+vt 1.000000 0.332314
+vn -0.577349 0.577349 0.577349
+vn -0.577349 0.577349 -0.577349
+vn -0.577349 -0.577349 0.577349
+vn 0.577349 0.577349 -0.577349
+vn -0.577349 -0.577349 -0.577349
+vn 0.577349 0.577349 0.577349
+vn 0.577349 -0.577349 0.577349
+vn 0.577349 -0.577349 -0.577349
+s 1
+f 5/1/1 6/2/2 1/3/3
+f 6/4/2 7/5/4 2/6/5
+f 7/7/4 8/8/6 4/9/7
+f 8/10/6 5/11/1 1/12/3
+f 8/13/6 7/14/4 6/15/2
+f 2/16/5 3/17/8 4/18/7
+f 6/2/2 2/19/5 1/3/3
+f 7/5/4 3/20/8 2/6/5
+f 3/21/8 7/7/4 4/9/7
+f 4/22/7 8/10/6 1/12/3
+f 5/23/1 8/13/6 6/15/2
+f 1/24/3 2/16/5 4/18/7
diff --git a/src/datavisualization/engine/meshes/cubeFlat.obj b/src/datavisualization/engine/meshes/cubeFlat.obj
new file mode 100644
index 00000000..3c8d6d0a
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cubeFlat.obj
@@ -0,0 +1,47 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.998999 0.334334
+vt 0.667668 0.334334
+vt 0.998999 0.665666
+vt 0.332332 0.001001
+vt 0.001001 0.001001
+vt 0.332332 0.332332
+vt 0.332332 0.334334
+vt 0.001001 0.334334
+vt 0.001001 0.665666
+vt 0.665666 0.001001
+vt 0.334334 0.001001
+vt 0.334334 0.332332
+vt 0.665666 0.334334
+vt 0.334334 0.334334
+vt 0.334334 0.665666
+vt 0.667668 0.665666
+vt 0.001001 0.332332
+vt 0.332332 0.665666
+vt 0.665666 0.332332
+vt 0.665666 0.665666
+vn -1.000000 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 0.000000 1.000000
+vn 0.000000 1.000000 0.000000
+s off
+f 5/1/1 6/2/1 1/3/1
+f 6/4/2 7/5/2 2/6/2
+f 7/7/3 8/8/3 4/9/3
+f 8/10/4 5/11/4 1/12/4
+f 8/13/5 7/14/5 6/15/5
+f 6/2/1 2/16/1 1/3/1
+f 7/5/2 3/17/2 2/6/2
+f 3/18/3 7/7/3 4/9/3
+f 4/19/4 8/10/4 1/12/4
+f 5/20/5 8/13/5 6/15/5
diff --git a/src/datavisualization/engine/meshes/cubeSmooth.obj b/src/datavisualization/engine/meshes/cubeSmooth.obj
new file mode 100644
index 00000000..9d147bfd
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cubeSmooth.obj
@@ -0,0 +1,50 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.998999 0.334334
+vt 0.667668 0.334334
+vt 0.998999 0.665666
+vt 0.332332 0.001001
+vt 0.001001 0.001001
+vt 0.332332 0.332332
+vt 0.332332 0.334334
+vt 0.001001 0.334334
+vt 0.001001 0.665666
+vt 0.665666 0.001001
+vt 0.334334 0.001001
+vt 0.334334 0.332332
+vt 0.665666 0.334334
+vt 0.334334 0.334334
+vt 0.334334 0.665666
+vt 0.667668 0.665666
+vt 0.001001 0.332332
+vt 0.332332 0.665666
+vt 0.665666 0.332332
+vt 0.665666 0.665666
+vn -0.577349 0.577349 0.577349
+vn -0.577349 0.577349 -0.577349
+vn -0.707083 0.000000 0.707083
+vn 0.577349 0.577349 -0.577349
+vn -0.707083 0.000000 -0.707083
+vn 0.577349 0.577349 0.577349
+vn 0.707083 0.000000 0.707083
+vn 0.707083 0.000000 -0.707083
+s 1
+f 5/1/1 6/2/2 1/3/3
+f 6/4/2 7/5/4 2/6/5
+f 7/7/4 8/8/6 4/9/7
+f 8/10/6 5/11/1 1/12/3
+f 8/13/6 7/14/4 6/15/2
+f 6/2/2 2/16/5 1/3/3
+f 7/5/4 3/17/8 2/6/5
+f 3/18/8 7/7/4 4/9/7
+f 4/19/7 8/10/6 1/12/3
+f 5/20/1 8/13/6 6/15/2
diff --git a/src/datavisualization/engine/meshes/cylinderFilledFlat.obj b/src/datavisualization/engine/meshes/cylinderFilledFlat.obj
new file mode 100644
index 00000000..16c2ef36
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cylinderFilledFlat.obj
@@ -0,0 +1,361 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder_filled.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.059001 0.355439
+vt 0.057906 0.712417
+vt 0.027048 0.712322
+vt 0.028143 0.355344
+vt 0.000000 0.712239
+vt 0.998905 0.355261
+vt 1.000000 0.712239
+vt 0.972952 0.712322
+vt 0.971857 0.355344
+vt 0.942094 0.712417
+vt 0.940999 0.355439
+vt 0.908611 0.712520
+vt 0.907515 0.355541
+vt 0.873789 0.712627
+vt 0.872694 0.355648
+vt 0.838968 0.712733
+vt 0.837872 0.355755
+vt 0.805484 0.712836
+vt 0.777341 0.713350
+vt 0.776246 1.070328
+vt 0.742763 1.070225
+vt 0.743858 0.713247
+vt 0.707941 1.070119
+vt 0.709036 0.713140
+vt 0.673120 1.070012
+vt 0.674215 0.713033
+vt 0.639636 1.069909
+vt 0.640732 0.712931
+vt 0.608778 1.069814
+vt 0.609873 0.712836
+vt 0.608778 0.355858
+vt 0.642261 0.355755
+vt 0.643357 0.712733
+vt 0.677083 0.355648
+vt 0.678178 0.712627
+vt 0.711904 0.355541
+vt 0.713000 0.712520
+vt 0.746483 0.712417
+vt 0.745388 0.355439
+vt 0.777341 0.712322
+vt 0.776246 0.355344
+vt 0.804389 0.712239
+vt 0.607683 0.355261
+vt 0.608778 0.712239
+vt 0.580635 0.355344
+vt 0.581730 0.712322
+vt 0.549777 0.355439
+vt 0.550872 0.712417
+vt 0.516293 0.355541
+vt 0.517389 0.712520
+vt 0.481472 0.355648
+vt 0.482567 0.712627
+vt 0.446650 0.355755
+vt 0.447746 0.712733
+vt 0.413167 0.355858
+vt 0.414262 0.712836
+vt 0.382309 0.355952
+vt 0.383404 0.712931
+vt 0.355261 0.356035
+vt 0.226469 0.355952
+vt 0.225374 0.712931
+vt 0.195611 0.355858
+vt 0.194516 0.712836
+vt 0.162127 0.355755
+vt 0.161032 0.712733
+vt 0.127306 0.355648
+vt 0.000000 0.160135
+vt 0.006826 0.125818
+vt 0.000000 0.195126
+vt 0.092484 0.355541
+vt 0.091389 0.712520
+vt 0.126211 0.712627
+vt 0.394917 0.290863
+vt 0.375477 0.261770
+vt 0.419658 0.315605
+vt 0.001095 0.355261
+vt 0.804389 0.355858
+vt 0.803294 0.355261
+vt 0.356356 0.713014
+vt 0.020216 0.093491
+vt 0.039656 0.064398
+vt 0.064397 0.039656
+vt 0.093491 0.020217
+vt 0.125817 0.006826
+vt 0.160135 0.000000
+vt 0.195125 0.000000
+vt 0.229443 0.006826
+vt 0.261770 0.020216
+vt 0.290863 0.039656
+vt 0.315605 0.064398
+vt 0.335045 0.093491
+vt 0.348435 0.125818
+vt 0.355261 0.160135
+vt 0.355261 0.195126
+vt 0.348435 0.229443
+vt 0.335045 0.261770
+vt 0.315605 0.290863
+vt 0.290863 0.315605
+vt 0.261770 0.335045
+vt 0.229443 0.348435
+vt 0.195126 0.355261
+vt 0.160135 0.355261
+vt 0.125818 0.348435
+vt 0.093491 0.335045
+vt 0.064398 0.315605
+vt 0.039656 0.290863
+vt 0.020216 0.261770
+vt 0.006826 0.229443
+vt 0.362087 0.229443
+vt 0.362087 0.125818
+vt 0.375477 0.093491
+vt 0.394917 0.064398
+vt 0.419659 0.039656
+vt 0.448752 0.020216
+vt 0.481079 0.006826
+vt 0.515396 0.000000
+vt 0.550387 0.000000
+vt 0.584704 0.006826
+vt 0.617031 0.020216
+vt 0.646124 0.039656
+vt 0.670866 0.064398
+vt 0.690306 0.093491
+vt 0.703696 0.125818
+vt 0.710522 0.160136
+vt 0.710522 0.195126
+vt 0.703696 0.229444
+vt 0.690306 0.261770
+vt 0.670866 0.290864
+vt 0.646124 0.315605
+vt 0.617031 0.335045
+vt 0.584704 0.348435
+vt 0.550386 0.355261
+vt 0.515396 0.355261
+vt 0.481078 0.348435
+vt 0.448752 0.335045
+vn 0.098017 0.000000 -0.995185
+vn 0.290285 0.000000 -0.956940
+vn 0.471397 0.000000 -0.881921
+vn 0.634393 0.000000 -0.773010
+vn 0.773010 0.000000 -0.634393
+vn 0.881921 0.000000 -0.471397
+vn 0.956940 0.000000 -0.290285
+vn 0.995185 0.000000 -0.098017
+vn 0.995185 0.000000 0.098017
+vn 0.956940 0.000000 0.290285
+vn 0.881921 0.000000 0.471396
+vn 0.773010 0.000000 0.634393
+vn 0.634393 0.000000 0.773010
+vn 0.471397 0.000000 0.881921
+vn 0.290284 0.000000 0.956940
+vn 0.098017 0.000000 0.995185
+vn -0.098018 0.000000 0.995185
+vn -0.290285 0.000000 0.956940
+vn -0.471397 0.000000 0.881921
+vn -0.634394 0.000000 0.773010
+vn -0.773011 0.000000 0.634393
+vn -0.881922 0.000000 0.471396
+vn -0.956941 0.000000 0.290284
+vn -0.995185 0.000000 0.098016
+vn -0.995185 -0.000000 -0.098018
+vn -0.956940 -0.000000 -0.290286
+vn -0.881921 -0.000000 -0.471398
+vn -0.773010 -0.000000 -0.634394
+vn -0.634392 -0.000000 -0.773011
+vn -0.471395 -0.000000 -0.881922
+vn -0.000000 1.000000 0.000000
+vn -0.098017 -0.000000 -0.995185
+vn -0.290283 -0.000000 -0.956941
+vn -0.000000 -1.000000 -0.000000
+s off
+f 1/1/1 2/2/1 4/3/1
+f 3/4/2 4/3/2 6/5/2
+f 5/6/3 6/7/3 8/8/3
+f 7/9/4 8/8/4 10/10/4
+f 9/11/5 10/10/5 12/12/5
+f 11/13/6 12/12/6 14/14/6
+f 13/15/7 14/14/7 16/16/7
+f 15/17/8 16/16/8 18/18/8
+f 17/19/9 18/20/9 20/21/9
+f 19/22/10 20/21/10 22/23/10
+f 21/24/11 22/23/11 24/25/11
+f 23/26/12 24/25/12 26/27/12
+f 25/28/13 26/27/13 28/29/13
+f 27/30/14 28/31/14 30/32/14
+f 29/33/15 30/32/15 32/34/15
+f 31/35/16 32/34/16 34/36/16
+f 33/37/17 34/36/17 35/38/17
+f 35/38/18 36/39/18 37/40/18
+f 37/40/19 38/41/19 39/42/19
+f 39/43/20 40/44/20 41/45/20
+f 41/45/21 42/46/21 43/47/21
+f 43/47/22 44/48/22 45/49/22
+f 45/49/23 46/50/23 47/51/23
+f 47/51/24 48/52/24 49/53/24
+f 49/53/25 50/54/25 51/55/25
+f 51/55/26 52/56/26 53/57/26
+f 53/57/27 54/58/27 55/59/27
+f 55/60/28 56/61/28 57/62/28
+f 57/62/29 58/63/29 59/64/29
+f 59/64/30 60/65/30 61/66/30
+f 4/67/31 2/68/31 6/69/31
+f 63/70/32 64/71/32 1/1/32
+f 61/66/33 62/72/33 63/70/33
+f 63/73/34 1/74/34 61/75/34
+f 3/4/1 1/1/1 4/3/1
+f 5/76/2 3/4/2 6/5/2
+f 7/9/3 5/6/3 8/8/3
+f 9/11/4 7/9/4 10/10/4
+f 11/13/5 9/11/5 12/12/5
+f 13/15/6 11/13/6 14/14/6
+f 15/17/7 13/15/7 16/16/7
+f 17/77/8 15/17/8 18/18/8
+f 19/22/9 17/19/9 20/21/9
+f 21/24/10 19/22/10 22/23/10
+f 23/26/11 21/24/11 24/25/11
+f 25/28/12 23/26/12 26/27/12
+f 27/30/13 25/28/13 28/29/13
+f 29/33/14 27/30/14 30/32/14
+f 31/35/15 29/33/15 32/34/15
+f 33/37/16 31/35/16 34/36/16
+f 34/36/17 36/39/17 35/38/17
+f 36/39/18 38/41/18 37/40/18
+f 38/41/19 40/78/19 39/42/19
+f 40/44/20 42/46/20 41/45/20
+f 42/46/21 44/48/21 43/47/21
+f 44/48/22 46/50/22 45/49/22
+f 46/50/23 48/52/23 47/51/23
+f 48/52/24 50/54/24 49/53/24
+f 50/54/25 52/56/25 51/55/25
+f 52/56/26 54/58/26 53/57/26
+f 54/58/27 56/79/27 55/59/27
+f 56/61/28 58/63/28 57/62/28
+f 58/63/29 60/65/29 59/64/29
+f 60/65/30 62/72/30 61/66/30
+f 2/68/31 64/80/31 6/69/31
+f 64/80/31 62/81/31 6/69/31
+f 62/81/31 60/82/31 6/69/31
+f 60/82/31 58/83/31 6/69/31
+f 58/83/31 56/84/31 6/69/31
+f 56/84/31 54/85/31 6/69/31
+f 54/85/31 52/86/31 6/69/31
+f 52/86/31 50/87/31 6/69/31
+f 50/87/31 48/88/31 6/69/31
+f 48/88/31 46/89/31 6/69/31
+f 46/89/31 44/90/31 6/69/31
+f 44/90/31 42/91/31 6/69/31
+f 42/91/31 40/92/31 6/69/31
+f 40/92/31 38/93/31 6/69/31
+f 38/93/31 36/94/31 6/69/31
+f 36/94/31 34/95/31 6/69/31
+f 34/95/31 32/96/31 6/69/31
+f 32/96/31 30/97/31 6/69/31
+f 30/97/31 28/98/31 6/69/31
+f 28/98/31 26/99/31 6/69/31
+f 26/99/31 24/100/31 6/69/31
+f 24/100/31 22/101/31 6/69/31
+f 22/101/31 20/102/31 6/69/31
+f 20/102/31 18/103/31 6/69/31
+f 18/103/31 16/104/31 6/69/31
+f 16/104/31 14/105/31 6/69/31
+f 14/105/31 12/106/31 6/69/31
+f 12/106/31 10/107/31 8/108/31
+f 6/69/31 12/106/31 8/108/31
+f 64/71/32 2/2/32 1/1/32
+f 62/72/33 64/71/33 63/70/33
+f 1/74/34 3/109/34 61/75/34
+f 3/109/34 5/94/34 61/75/34
+f 5/94/34 7/93/34 61/75/34
+f 7/93/34 9/110/34 61/75/34
+f 9/110/34 11/111/34 61/75/34
+f 11/111/34 13/112/34 61/75/34
+f 13/112/34 15/113/34 61/75/34
+f 15/113/34 17/114/34 61/75/34
+f 17/114/34 19/115/34 61/75/34
+f 19/115/34 21/116/34 61/75/34
+f 21/116/34 23/117/34 61/75/34
+f 23/117/34 25/118/34 61/75/34
+f 25/118/34 27/119/34 61/75/34
+f 27/119/34 29/120/34 61/75/34
+f 29/120/34 31/121/34 61/75/34
+f 31/121/34 33/122/34 61/75/34
+f 33/122/34 35/123/34 61/75/34
+f 35/123/34 37/124/34 61/75/34
+f 37/124/34 39/125/34 61/75/34
+f 39/125/34 41/126/34 61/75/34
+f 41/126/34 43/127/34 61/75/34
+f 43/127/34 45/128/34 61/75/34
+f 45/128/34 47/129/34 61/75/34
+f 47/129/34 49/130/34 61/75/34
+f 49/130/34 51/131/34 61/75/34
+f 51/131/34 53/132/34 61/75/34
+f 53/132/34 55/133/34 61/75/34
+f 55/133/34 57/134/34 59/135/34
+f 61/75/34 55/133/34 59/135/34
diff --git a/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj b/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj
new file mode 100644
index 00000000..90db7d63
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj
@@ -0,0 +1,391 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder_filled.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.059001 0.355439
+vt 0.057906 0.712417
+vt 0.027048 0.712322
+vt 0.028143 0.355344
+vt 0.000000 0.712239
+vt 0.998905 0.355261
+vt 1.000000 0.712239
+vt 0.972952 0.712322
+vt 0.971857 0.355344
+vt 0.942094 0.712417
+vt 0.940999 0.355439
+vt 0.908611 0.712520
+vt 0.907515 0.355541
+vt 0.873789 0.712627
+vt 0.872694 0.355648
+vt 0.838968 0.712733
+vt 0.837872 0.355755
+vt 0.805484 0.712836
+vt 0.777341 0.713350
+vt 0.776246 1.070328
+vt 0.742763 1.070225
+vt 0.743858 0.713247
+vt 0.707941 1.070119
+vt 0.709036 0.713140
+vt 0.673120 1.070012
+vt 0.674215 0.713033
+vt 0.639636 1.069909
+vt 0.640732 0.712931
+vt 0.608778 1.069814
+vt 0.609873 0.712836
+vt 0.608778 0.355858
+vt 0.642261 0.355755
+vt 0.643357 0.712733
+vt 0.677083 0.355648
+vt 0.678178 0.712627
+vt 0.711904 0.355541
+vt 0.713000 0.712520
+vt 0.746483 0.712417
+vt 0.745388 0.355439
+vt 0.777341 0.712322
+vt 0.776246 0.355344
+vt 0.804389 0.712239
+vt 0.607683 0.355261
+vt 0.608778 0.712239
+vt 0.580635 0.355344
+vt 0.581730 0.712322
+vt 0.549777 0.355439
+vt 0.550872 0.712417
+vt 0.516293 0.355541
+vt 0.517389 0.712520
+vt 0.481472 0.355648
+vt 0.482567 0.712627
+vt 0.446650 0.355755
+vt 0.447746 0.712733
+vt 0.413167 0.355858
+vt 0.414262 0.712836
+vt 0.382309 0.355952
+vt 0.383404 0.712931
+vt 0.355261 0.356035
+vt 0.226469 0.355952
+vt 0.225374 0.712931
+vt 0.195611 0.355858
+vt 0.194516 0.712836
+vt 0.162127 0.355755
+vt 0.161032 0.712733
+vt 0.127306 0.355648
+vt 0.000000 0.160135
+vt 0.006826 0.125818
+vt 0.000000 0.195126
+vt 0.092484 0.355541
+vt 0.091389 0.712520
+vt 0.126211 0.712627
+vt 0.394917 0.290863
+vt 0.375477 0.261770
+vt 0.419658 0.315605
+vt 0.001095 0.355261
+vt 0.804389 0.355858
+vt 0.803294 0.355261
+vt 0.356356 0.713014
+vt 0.020216 0.093491
+vt 0.039656 0.064398
+vt 0.064397 0.039656
+vt 0.093491 0.020217
+vt 0.125817 0.006826
+vt 0.160135 0.000000
+vt 0.195125 0.000000
+vt 0.229443 0.006826
+vt 0.261770 0.020216
+vt 0.290863 0.039656
+vt 0.315605 0.064398
+vt 0.335045 0.093491
+vt 0.348435 0.125818
+vt 0.355261 0.160135
+vt 0.355261 0.195126
+vt 0.348435 0.229443
+vt 0.335045 0.261770
+vt 0.315605 0.290863
+vt 0.290863 0.315605
+vt 0.261770 0.335045
+vt 0.229443 0.348435
+vt 0.195126 0.355261
+vt 0.160135 0.355261
+vt 0.125818 0.348435
+vt 0.093491 0.335045
+vt 0.064398 0.315605
+vt 0.039656 0.290863
+vt 0.020216 0.261770
+vt 0.006826 0.229443
+vt 0.362087 0.229443
+vt 0.362087 0.125818
+vt 0.375477 0.093491
+vt 0.394917 0.064398
+vt 0.419659 0.039656
+vt 0.448752 0.020216
+vt 0.481079 0.006826
+vt 0.515396 0.000000
+vt 0.550387 0.000000
+vt 0.584704 0.006826
+vt 0.617031 0.020216
+vt 0.646124 0.039656
+vt 0.670866 0.064398
+vt 0.690306 0.093491
+vt 0.703696 0.125818
+vt 0.710522 0.160136
+vt 0.710522 0.195126
+vt 0.703696 0.229444
+vt 0.690306 0.261770
+vt 0.670866 0.290864
+vt 0.646124 0.315605
+vt 0.617031 0.335045
+vt 0.584704 0.348435
+vt 0.550386 0.355261
+vt 0.515396 0.355261
+vt 0.481078 0.348435
+vt 0.448752 0.335045
+vn 0.000000 -0.685690 -0.727866
+vn 0.000000 0.685690 -0.727866
+vn 0.142003 0.685690 -0.713889
+vn 0.142003 -0.685690 -0.713889
+vn 0.278542 0.685690 -0.672475
+vn 0.278542 -0.685690 -0.672475
+vn 0.404370 0.685690 -0.605213
+vn 0.404370 -0.685690 -0.605213
+vn 0.514664 0.685690 -0.514664
+vn 0.514664 -0.685690 -0.514664
+vn 0.605213 0.685690 -0.404370
+vn 0.605213 -0.685690 -0.404370
+vn 0.672475 0.685690 -0.278542
+vn 0.672475 -0.685690 -0.278542
+vn 0.713889 0.685690 -0.142003
+vn 0.713889 -0.685690 -0.142003
+vn 0.727866 0.685690 0.000000
+vn 0.727866 -0.685690 0.000000
+vn 0.713889 0.685690 0.142003
+vn 0.713889 -0.685690 0.142003
+vn 0.672475 0.685690 0.278542
+vn 0.672475 -0.685690 0.278542
+vn 0.605213 0.685690 0.404370
+vn 0.605213 -0.685690 0.404370
+vn 0.514664 0.685690 0.514664
+vn 0.514664 -0.685690 0.514664
+vn 0.404370 0.685690 0.605213
+vn 0.404370 -0.685690 0.605213
+vn 0.278542 0.685690 0.672475
+vn 0.278542 -0.685690 0.672475
+vn 0.142003 0.685690 0.713889
+vn 0.142003 -0.685690 0.713889
+vn 0.000000 0.685690 0.727866
+vn 0.000000 -0.685690 0.727866
+vn -0.142003 -0.685690 0.713889
+vn -0.142003 0.685690 0.713889
+vn -0.278542 -0.685690 0.672475
+vn -0.278542 0.685690 0.672475
+vn -0.404370 -0.685690 0.605213
+vn -0.404370 0.685690 0.605213
+vn -0.514695 -0.685690 0.514664
+vn -0.514664 0.685690 0.514664
+vn -0.605213 -0.685690 0.404370
+vn -0.605213 0.685690 0.404370
+vn -0.672475 -0.685690 0.278542
+vn -0.672475 0.685690 0.278542
+vn -0.713889 -0.685690 0.142003
+vn -0.713889 0.685690 0.142003
+vn -0.727866 -0.685690 0.000000
+vn -0.727866 0.685690 0.000000
+vn -0.713889 -0.685690 -0.142003
+vn -0.713889 0.685690 -0.142003
+vn -0.672475 -0.685690 -0.278542
+vn -0.672475 0.685690 -0.278542
+vn -0.605213 -0.685690 -0.404370
+vn -0.605213 0.685690 -0.404370
+vn -0.514664 -0.685690 -0.514695
+vn -0.514664 0.685690 -0.514695
+vn -0.404370 -0.685690 -0.605213
+vn -0.404370 0.685690 -0.605213
+vn -0.278542 -0.685690 -0.672475
+vn -0.142003 -0.685690 -0.713889
+vn -0.142003 0.685690 -0.713889
+vn -0.278542 0.685690 -0.672475
+s 1
+f 1/1/1 2/2/2 4/3/3
+f 3/4/4 4/3/3 6/5/5
+f 5/6/6 6/7/5 8/8/7
+f 7/9/8 8/8/7 10/10/9
+f 9/11/10 10/10/9 12/12/11
+f 11/13/12 12/12/11 14/14/13
+f 13/15/14 14/14/13 16/16/15
+f 15/17/16 16/16/15 18/18/17
+f 17/19/18 18/20/17 20/21/19
+f 19/22/20 20/21/19 22/23/21
+f 21/24/22 22/23/21 24/25/23
+f 23/26/24 24/25/23 26/27/25
+f 25/28/26 26/27/25 28/29/27
+f 27/30/28 28/31/27 30/32/29
+f 29/33/30 30/32/29 32/34/31
+f 31/35/32 32/34/31 34/36/33
+f 33/37/34 34/36/33 35/38/35
+f 35/38/35 36/39/36 37/40/37
+f 37/40/37 38/41/38 39/42/39
+f 39/43/39 40/44/40 41/45/41
+f 41/45/41 42/46/42 43/47/43
+f 43/47/43 44/48/44 45/49/45
+f 45/49/45 46/50/46 47/51/47
+f 47/51/47 48/52/48 49/53/49
+f 49/53/49 50/54/50 51/55/51
+f 51/55/51 52/56/52 53/57/53
+f 53/57/53 54/58/54 55/59/55
+f 55/60/55 56/61/56 57/62/57
+f 57/62/57 58/63/58 59/64/59
+f 59/64/59 60/65/60 61/66/61
+f 4/67/3 2/68/2 6/69/5
+f 63/70/62 64/71/63 1/1/1
+f 61/66/61 62/72/64 63/70/62
+f 63/73/62 1/74/1 61/75/61
+f 3/4/4 1/1/1 4/3/3
+f 5/76/6 3/4/4 6/5/5
+f 7/9/8 5/6/6 8/8/7
+f 9/11/10 7/9/8 10/10/9
+f 11/13/12 9/11/10 12/12/11
+f 13/15/14 11/13/12 14/14/13
+f 15/17/16 13/15/14 16/16/15
+f 17/77/18 15/17/16 18/18/17
+f 19/22/20 17/19/18 20/21/19
+f 21/24/22 19/22/20 22/23/21
+f 23/26/24 21/24/22 24/25/23
+f 25/28/26 23/26/24 26/27/25
+f 27/30/28 25/28/26 28/29/27
+f 29/33/30 27/30/28 30/32/29
+f 31/35/32 29/33/30 32/34/31
+f 33/37/34 31/35/32 34/36/33
+f 34/36/33 36/39/36 35/38/35
+f 36/39/36 38/41/38 37/40/37
+f 38/41/38 40/78/40 39/42/39
+f 40/44/40 42/46/42 41/45/41
+f 42/46/42 44/48/44 43/47/43
+f 44/48/44 46/50/46 45/49/45
+f 46/50/46 48/52/48 47/51/47
+f 48/52/48 50/54/50 49/53/49
+f 50/54/50 52/56/52 51/55/51
+f 52/56/52 54/58/54 53/57/53
+f 54/58/54 56/79/56 55/59/55
+f 56/61/56 58/63/58 57/62/57
+f 58/63/58 60/65/60 59/64/59
+f 60/65/60 62/72/64 61/66/61
+f 2/68/2 64/80/63 6/69/5
+f 64/80/63 62/81/64 6/69/5
+f 62/81/64 60/82/60 6/69/5
+f 60/82/60 58/83/58 6/69/5
+f 58/83/58 56/84/56 6/69/5
+f 56/84/56 54/85/54 6/69/5
+f 54/85/54 52/86/52 6/69/5
+f 52/86/52 50/87/50 6/69/5
+f 50/87/50 48/88/48 6/69/5
+f 48/88/48 46/89/46 6/69/5
+f 46/89/46 44/90/44 6/69/5
+f 44/90/44 42/91/42 6/69/5
+f 42/91/42 40/92/40 6/69/5
+f 40/92/40 38/93/38 6/69/5
+f 38/93/38 36/94/36 6/69/5
+f 36/94/36 34/95/33 6/69/5
+f 34/95/33 32/96/31 6/69/5
+f 32/96/31 30/97/29 6/69/5
+f 30/97/29 28/98/27 6/69/5
+f 28/98/27 26/99/25 6/69/5
+f 26/99/25 24/100/23 6/69/5
+f 24/100/23 22/101/21 6/69/5
+f 22/101/21 20/102/19 6/69/5
+f 20/102/19 18/103/17 6/69/5
+f 18/103/17 16/104/15 6/69/5
+f 16/104/15 14/105/13 6/69/5
+f 14/105/13 12/106/11 6/69/5
+f 12/106/11 10/107/9 8/108/7
+f 6/69/5 12/106/11 8/108/7
+f 64/71/63 2/2/2 1/1/1
+f 62/72/64 64/71/63 63/70/62
+f 1/74/1 3/109/4 61/75/61
+f 3/109/4 5/94/6 61/75/61
+f 5/94/6 7/93/8 61/75/61
+f 7/93/8 9/110/10 61/75/61
+f 9/110/10 11/111/12 61/75/61
+f 11/111/12 13/112/14 61/75/61
+f 13/112/14 15/113/16 61/75/61
+f 15/113/16 17/114/18 61/75/61
+f 17/114/18 19/115/20 61/75/61
+f 19/115/20 21/116/22 61/75/61
+f 21/116/22 23/117/24 61/75/61
+f 23/117/24 25/118/26 61/75/61
+f 25/118/26 27/119/28 61/75/61
+f 27/119/28 29/120/30 61/75/61
+f 29/120/30 31/121/32 61/75/61
+f 31/121/32 33/122/34 61/75/61
+f 33/122/34 35/123/35 61/75/61
+f 35/123/35 37/124/37 61/75/61
+f 37/124/37 39/125/39 61/75/61
+f 39/125/39 41/126/41 61/75/61
+f 41/126/41 43/127/43 61/75/61
+f 43/127/43 45/128/45 61/75/61
+f 45/128/45 47/129/47 61/75/61
+f 47/129/47 49/130/49 61/75/61
+f 49/130/49 51/131/51 61/75/61
+f 51/131/51 53/132/53 61/75/61
+f 53/132/53 55/133/55 61/75/61
+f 55/133/55 57/134/57 59/135/59
+f 61/75/61 55/133/55 59/135/59
diff --git a/src/datavisualization/engine/meshes/cylinderFlat.obj b/src/datavisualization/engine/meshes/cylinderFlat.obj
new file mode 100644
index 00000000..2b7e3e5e
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cylinderFlat.obj
@@ -0,0 +1,299 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.289718 0.879351
+vt 0.288367 0.438844
+vt 0.330714 0.438714
+vt 0.332066 0.879221
+vt 0.370605 0.438592
+vt 0.371956 0.879099
+vt 0.406505 0.438482
+vt 0.407857 0.878988
+vt 0.437036 0.438388
+vt 0.778904 0.000000
+vt 0.780256 0.440507
+vt 0.749725 0.440601
+vt 0.748373 0.000094
+vt 0.713824 0.440711
+vt 0.712473 0.000204
+vt 0.673934 0.440833
+vt 0.672582 0.000326
+vt 0.631586 0.440963
+vt 0.630235 0.000456
+vt 0.588409 0.441095
+vt 0.587057 0.000588
+vt 0.546061 0.441225
+vt 0.544710 0.000718
+vt 0.506171 0.441348
+vt 0.504819 0.000841
+vt 0.470270 0.441458
+vt 0.468919 0.000951
+vt 0.439739 0.441552
+vt 0.720545 0.882916
+vt 0.719194 0.442409
+vt 0.755094 0.442299
+vt 0.756446 0.882806
+vt 0.794985 0.442176
+vt 0.796336 0.882683
+vt 0.837333 0.442046
+vt 0.838684 0.882553
+vt 0.881861 0.882421
+vt 0.880510 0.441914
+vt 0.924209 0.882291
+vt 0.922857 0.441784
+vt 0.964099 0.882168
+vt 0.962748 0.441662
+vt 1.000000 0.882058
+vt 0.717842 0.441552
+vt 0.719194 0.882058
+vt 0.681942 0.441662
+vt 0.683293 0.882169
+vt 0.642051 0.441784
+vt 0.643403 0.882291
+vt 0.599704 0.441914
+vt 0.601055 0.882421
+vt 0.556526 0.442046
+vt 0.557878 0.882553
+vt 0.514179 0.442176
+vt 0.515530 0.882683
+vt 0.474288 0.442299
+vt 0.475640 0.882806
+vt 0.438388 0.442409
+vt 0.097872 0.879939
+vt 0.096520 0.439433
+vt 0.128403 0.879846
+vt 0.127051 0.439339
+vt 0.164303 0.879735
+vt 0.162952 0.439229
+vt 0.204194 0.879613
+vt 0.000000 0.197605
+vt 0.008423 0.155257
+vt 0.000000 0.240783
+vt 0.246541 0.879483
+vt 0.245190 0.438976
+vt 0.202842 0.439106
+vt 0.438388 0.878895
+vt 0.438388 0.001045
+vt 0.998649 0.441552
+vt 0.439739 0.882916
+vt 0.024947 0.115367
+vt 0.048935 0.079466
+vt 0.079466 0.048935
+vt 0.115366 0.024947
+vt 0.155257 0.008424
+vt 0.197605 0.000000
+vt 0.240782 0.000000
+vt 0.283130 0.008423
+vt 0.323021 0.024947
+vt 0.358922 0.048935
+vt 0.389453 0.079466
+vt 0.413441 0.115367
+vt 0.429964 0.155257
+vt 0.438388 0.197605
+vt 0.438388 0.240783
+vt 0.429964 0.283130
+vt 0.413441 0.323021
+vt 0.389453 0.358922
+vt 0.358922 0.389453
+vt 0.323021 0.413441
+vt 0.283130 0.429964
+vt 0.240783 0.438388
+vt 0.197605 0.438388
+vt 0.155257 0.429964
+vt 0.115367 0.413441
+vt 0.079466 0.389453
+vt 0.048935 0.358922
+vt 0.024947 0.323021
+vt 0.008423 0.283130
+vn 0.098017 0.000000 -0.995185
+vn 0.290285 0.000000 -0.956940
+vn 0.471397 0.000000 -0.881921
+vn 0.634393 0.000000 -0.773010
+vn 0.773010 0.000000 -0.634393
+vn 0.881921 0.000000 -0.471397
+vn 0.956940 0.000000 -0.290285
+vn 0.995185 0.000000 -0.098017
+vn 0.995185 0.000000 0.098017
+vn 0.956940 0.000000 0.290285
+vn 0.881921 0.000000 0.471396
+vn 0.773010 0.000000 0.634393
+vn 0.634393 0.000000 0.773010
+vn 0.471397 0.000000 0.881921
+vn 0.290284 0.000000 0.956940
+vn 0.098017 0.000000 0.995185
+vn -0.098018 0.000000 0.995185
+vn -0.290285 0.000000 0.956940
+vn -0.471397 0.000000 0.881921
+vn -0.634394 0.000000 0.773010
+vn -0.773011 0.000000 0.634393
+vn -0.881922 0.000000 0.471396
+vn -0.956941 0.000000 0.290284
+vn -0.995185 0.000000 0.098016
+vn -0.995185 -0.000000 -0.098018
+vn -0.956940 -0.000000 -0.290286
+vn -0.881921 -0.000000 -0.471398
+vn -0.773010 -0.000000 -0.634394
+vn -0.634392 -0.000000 -0.773011
+vn -0.471395 -0.000000 -0.881922
+vn -0.000000 1.000000 0.000000
+vn -0.098017 -0.000000 -0.995185
+vn -0.290283 -0.000000 -0.956941
+s off
+f 1/1/1 2/2/1 4/3/1
+f 3/4/2 4/3/2 6/5/2
+f 5/6/3 6/5/3 8/7/3
+f 7/8/4 8/7/4 10/9/4
+f 9/10/5 10/11/5 12/12/5
+f 11/13/6 12/12/6 14/14/6
+f 13/15/7 14/14/7 16/16/7
+f 15/17/8 16/16/8 18/18/8
+f 17/19/9 18/18/9 20/20/9
+f 19/21/10 20/20/10 22/22/10
+f 21/23/11 22/22/11 24/24/11
+f 23/25/12 24/24/12 26/26/12
+f 25/27/13 26/26/13 28/28/13
+f 27/29/14 28/30/14 30/31/14
+f 29/32/15 30/31/15 32/33/15
+f 31/34/16 32/33/16 34/35/16
+f 33/36/17 34/35/17 35/37/17
+f 35/37/18 36/38/18 37/39/18
+f 37/39/19 38/40/19 39/41/19
+f 39/41/20 40/42/20 41/43/20
+f 41/44/21 42/45/21 43/46/21
+f 43/46/22 44/47/22 45/48/22
+f 45/48/23 46/49/23 47/50/23
+f 47/50/24 48/51/24 49/52/24
+f 49/52/25 50/53/25 51/54/25
+f 51/54/26 52/55/26 53/56/26
+f 53/56/27 54/57/27 55/58/27
+f 55/59/28 56/60/28 57/61/28
+f 57/61/29 58/62/29 59/63/29
+f 59/63/30 60/64/30 61/65/30
+f 4/66/31 2/67/31 6/68/31
+f 63/69/32 64/70/32 1/1/32
+f 61/65/33 62/71/33 63/69/33
+f 3/4/1 1/1/1 4/3/1
+f 5/6/2 3/4/2 6/5/2
+f 7/8/3 5/6/3 8/7/3
+f 9/72/4 7/8/4 10/9/4
+f 11/13/5 9/10/5 12/12/5
+f 13/15/6 11/13/6 14/14/6
+f 15/17/7 13/15/7 16/16/7
+f 17/19/8 15/17/8 18/18/8
+f 19/21/9 17/19/9 20/20/9
+f 21/23/10 19/21/10 22/22/10
+f 23/25/11 21/23/11 24/24/11
+f 25/27/12 23/25/12 26/26/12
+f 27/73/13 25/27/13 28/28/13
+f 29/32/14 27/29/14 30/31/14
+f 31/34/15 29/32/15 32/33/15
+f 33/36/16 31/34/16 34/35/16
+f 34/35/17 36/38/17 35/37/17
+f 36/38/18 38/40/18 37/39/18
+f 38/40/19 40/42/19 39/41/19
+f 40/42/20 42/74/20 41/43/20
+f 42/45/21 44/47/21 43/46/21
+f 44/47/22 46/49/22 45/48/22
+f 46/49/23 48/51/23 47/50/23
+f 48/51/24 50/53/24 49/52/24
+f 50/53/25 52/55/25 51/54/25
+f 52/55/26 54/57/26 53/56/26
+f 54/57/27 56/75/27 55/58/27
+f 56/60/28 58/62/28 57/61/28
+f 58/62/29 60/64/29 59/63/29
+f 60/64/30 62/71/30 61/65/30
+f 2/67/31 64/76/31 6/68/31
+f 64/76/31 62/77/31 6/68/31
+f 62/77/31 60/78/31 6/68/31
+f 60/78/31 58/79/31 6/68/31
+f 58/79/31 56/80/31 6/68/31
+f 56/80/31 54/81/31 6/68/31
+f 54/81/31 52/82/31 6/68/31
+f 52/82/31 50/83/31 6/68/31
+f 50/83/31 48/84/31 6/68/31
+f 48/84/31 46/85/31 6/68/31
+f 46/85/31 44/86/31 6/68/31
+f 44/86/31 42/87/31 6/68/31
+f 42/87/31 40/88/31 6/68/31
+f 40/88/31 38/89/31 6/68/31
+f 38/89/31 36/90/31 6/68/31
+f 36/90/31 34/91/31 6/68/31
+f 34/91/31 32/92/31 6/68/31
+f 32/92/31 30/93/31 6/68/31
+f 30/93/31 28/94/31 6/68/31
+f 28/94/31 26/95/31 6/68/31
+f 26/95/31 24/96/31 6/68/31
+f 24/96/31 22/97/31 6/68/31
+f 22/97/31 20/98/31 6/68/31
+f 20/98/31 18/99/31 6/68/31
+f 18/99/31 16/100/31 6/68/31
+f 16/100/31 14/101/31 6/68/31
+f 14/101/31 12/102/31 6/68/31
+f 12/102/31 10/103/31 8/104/31
+f 6/68/31 12/102/31 8/104/31
+f 64/70/32 2/2/32 1/1/32
+f 62/71/33 64/70/33 63/69/33
diff --git a/src/datavisualization/engine/meshes/cylinderSmooth.obj b/src/datavisualization/engine/meshes/cylinderSmooth.obj
new file mode 100644
index 00000000..6ccbb286
--- /dev/null
+++ b/src/datavisualization/engine/meshes/cylinderSmooth.obj
@@ -0,0 +1,330 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.289718 0.879351
+vt 0.288367 0.438844
+vt 0.330714 0.438714
+vt 0.332066 0.879221
+vt 0.370605 0.438592
+vt 0.371956 0.879099
+vt 0.406505 0.438482
+vt 0.407857 0.878988
+vt 0.437036 0.438388
+vt 0.778904 0.000000
+vt 0.780256 0.440507
+vt 0.749725 0.440601
+vt 0.748373 0.000094
+vt 0.713824 0.440711
+vt 0.712473 0.000204
+vt 0.673934 0.440833
+vt 0.672582 0.000326
+vt 0.631586 0.440963
+vt 0.630235 0.000456
+vt 0.588409 0.441095
+vt 0.587057 0.000588
+vt 0.546061 0.441225
+vt 0.544710 0.000718
+vt 0.506171 0.441348
+vt 0.504819 0.000841
+vt 0.470270 0.441458
+vt 0.468919 0.000951
+vt 0.439739 0.441552
+vt 0.720545 0.882916
+vt 0.719194 0.442409
+vt 0.755094 0.442299
+vt 0.756446 0.882806
+vt 0.794985 0.442176
+vt 0.796336 0.882683
+vt 0.837333 0.442046
+vt 0.838684 0.882553
+vt 0.881861 0.882421
+vt 0.880510 0.441914
+vt 0.924209 0.882291
+vt 0.922857 0.441784
+vt 0.964099 0.882168
+vt 0.962748 0.441662
+vt 1.000000 0.882058
+vt 0.717842 0.441552
+vt 0.719194 0.882058
+vt 0.681942 0.441662
+vt 0.683293 0.882169
+vt 0.642051 0.441784
+vt 0.643403 0.882291
+vt 0.599704 0.441914
+vt 0.601055 0.882421
+vt 0.556526 0.442046
+vt 0.557878 0.882553
+vt 0.514179 0.442176
+vt 0.515530 0.882683
+vt 0.474288 0.442299
+vt 0.475640 0.882806
+vt 0.438388 0.442409
+vt 0.097872 0.879939
+vt 0.096520 0.439433
+vt 0.128403 0.879846
+vt 0.127051 0.439339
+vt 0.164303 0.879735
+vt 0.162952 0.439229
+vt 0.204194 0.879613
+vt 0.000000 0.197605
+vt 0.008423 0.155257
+vt 0.000000 0.240783
+vt 0.246541 0.879483
+vt 0.245190 0.438976
+vt 0.202842 0.439106
+vt 0.438388 0.878895
+vt 0.438388 0.001045
+vt 0.998649 0.441552
+vt 0.439739 0.882916
+vt 0.024947 0.115367
+vt 0.048935 0.079466
+vt 0.079466 0.048935
+vt 0.115366 0.024947
+vt 0.155257 0.008424
+vt 0.197605 0.000000
+vt 0.240782 0.000000
+vt 0.283130 0.008423
+vt 0.323021 0.024947
+vt 0.358922 0.048935
+vt 0.389453 0.079466
+vt 0.413441 0.115367
+vt 0.429964 0.155257
+vt 0.438388 0.197605
+vt 0.438388 0.240783
+vt 0.429964 0.283130
+vt 0.413441 0.323021
+vt 0.389453 0.358922
+vt 0.358922 0.389453
+vt 0.323021 0.413441
+vt 0.283130 0.429964
+vt 0.240783 0.438388
+vt 0.197605 0.438388
+vt 0.155257 0.429964
+vt 0.115367 0.413441
+vt 0.079466 0.389453
+vt 0.048935 0.358922
+vt 0.024947 0.323021
+vt 0.008423 0.283130
+vn 0.000000 0.000000 -1.000000
+vn 0.000000 0.685690 -0.727866
+vn 0.142003 0.685690 -0.713889
+vn 0.195074 0.000000 -0.980773
+vn 0.278542 0.685690 -0.672475
+vn 0.382672 0.000000 -0.923856
+vn 0.404370 0.685690 -0.605213
+vn 0.555559 0.000000 -0.831446
+vn 0.514664 0.685690 -0.514664
+vn 0.707083 0.000000 -0.707083
+vn 0.605213 0.685690 -0.404370
+vn 0.831446 0.000000 -0.555559
+vn 0.672475 0.685690 -0.278542
+vn 0.923856 0.000000 -0.382672
+vn 0.713889 0.685690 -0.142003
+vn 0.980773 0.000000 -0.195074
+vn 0.727866 0.685690 0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.713889 0.685690 0.142003
+vn 0.980773 0.000000 0.195074
+vn 0.672475 0.685690 0.278542
+vn 0.923856 0.000000 0.382672
+vn 0.605213 0.685690 0.404370
+vn 0.831446 0.000000 0.555559
+vn 0.514664 0.685690 0.514664
+vn 0.707083 0.000000 0.707083
+vn 0.404370 0.685690 0.605213
+vn 0.555559 0.000000 0.831446
+vn 0.278542 0.685690 0.672475
+vn 0.382672 0.000000 0.923856
+vn 0.142003 0.685690 0.713889
+vn 0.195074 0.000000 0.980773
+vn 0.000000 0.685690 0.727866
+vn 0.000000 0.000000 0.999969
+vn -0.195074 0.000000 0.980773
+vn -0.142003 0.685690 0.713889
+vn -0.382672 0.000000 0.923856
+vn -0.278542 0.685690 0.672475
+vn -0.555559 0.000000 0.831446
+vn -0.404370 0.685690 0.605213
+vn -0.707083 0.000000 0.707083
+vn -0.514664 0.685690 0.514664
+vn -0.831446 0.000000 0.555559
+vn -0.605213 0.685690 0.404370
+vn -0.923856 0.000000 0.382672
+vn -0.672475 0.685690 0.278542
+vn -0.980773 0.000000 0.195074
+vn -0.713889 0.685690 0.142003
+vn -1.000000 0.000000 0.000000
+vn -0.727866 0.685690 0.000000
+vn -0.980773 0.000000 -0.195074
+vn -0.713889 0.685690 -0.142003
+vn -0.923856 0.000000 -0.382672
+vn -0.672475 0.685690 -0.278542
+vn -0.831446 0.000000 -0.555559
+vn -0.605213 0.685690 -0.404370
+vn -0.707083 0.000000 -0.707083
+vn -0.514664 0.685690 -0.514695
+vn -0.555559 0.000000 -0.831446
+vn -0.404370 0.685690 -0.605213
+vn -0.382672 0.000000 -0.923856
+vn -0.195074 0.000000 -0.980773
+vn -0.142003 0.685690 -0.713889
+vn -0.278542 0.685690 -0.672475
+s 1
+f 1/1/1 2/2/2 4/3/3
+f 3/4/4 4/3/3 6/5/5
+f 5/6/6 6/5/5 8/7/7
+f 7/8/8 8/7/7 10/9/9
+f 9/10/10 10/11/9 12/12/11
+f 11/13/12 12/12/11 14/14/13
+f 13/15/14 14/14/13 16/16/15
+f 15/17/16 16/16/15 18/18/17
+f 17/19/18 18/18/17 20/20/19
+f 19/21/20 20/20/19 22/22/21
+f 21/23/22 22/22/21 24/24/23
+f 23/25/24 24/24/23 26/26/25
+f 25/27/26 26/26/25 28/28/27
+f 27/29/28 28/30/27 30/31/29
+f 29/32/30 30/31/29 32/33/31
+f 31/34/32 32/33/31 34/35/33
+f 33/36/34 34/35/33 35/37/35
+f 35/37/35 36/38/36 37/39/37
+f 37/39/37 38/40/38 39/41/39
+f 39/41/39 40/42/40 41/43/41
+f 41/44/41 42/45/42 43/46/43
+f 43/46/43 44/47/44 45/48/45
+f 45/48/45 46/49/46 47/50/47
+f 47/50/47 48/51/48 49/52/49
+f 49/52/49 50/53/50 51/54/51
+f 51/54/51 52/55/52 53/56/53
+f 53/56/53 54/57/54 55/58/55
+f 55/59/55 56/60/56 57/61/57
+f 57/61/57 58/62/58 59/63/59
+f 59/63/59 60/64/60 61/65/61
+f 4/66/3 2/67/2 6/68/5
+f 63/69/62 64/70/63 1/1/1
+f 61/65/61 62/71/64 63/69/62
+f 3/4/4 1/1/1 4/3/3
+f 5/6/6 3/4/4 6/5/5
+f 7/8/8 5/6/6 8/7/7
+f 9/72/10 7/8/8 10/9/9
+f 11/13/12 9/10/10 12/12/11
+f 13/15/14 11/13/12 14/14/13
+f 15/17/16 13/15/14 16/16/15
+f 17/19/18 15/17/16 18/18/17
+f 19/21/20 17/19/18 20/20/19
+f 21/23/22 19/21/20 22/22/21
+f 23/25/24 21/23/22 24/24/23
+f 25/27/26 23/25/24 26/26/25
+f 27/73/28 25/27/26 28/28/27
+f 29/32/30 27/29/28 30/31/29
+f 31/34/32 29/32/30 32/33/31
+f 33/36/34 31/34/32 34/35/33
+f 34/35/33 36/38/36 35/37/35
+f 36/38/36 38/40/38 37/39/37
+f 38/40/38 40/42/40 39/41/39
+f 40/42/40 42/74/42 41/43/41
+f 42/45/42 44/47/44 43/46/43
+f 44/47/44 46/49/46 45/48/45
+f 46/49/46 48/51/48 47/50/47
+f 48/51/48 50/53/50 49/52/49
+f 50/53/50 52/55/52 51/54/51
+f 52/55/52 54/57/54 53/56/53
+f 54/57/54 56/75/56 55/58/55
+f 56/60/56 58/62/58 57/61/57
+f 58/62/58 60/64/60 59/63/59
+f 60/64/60 62/71/64 61/65/61
+f 2/67/2 64/76/63 6/68/5
+f 64/76/63 62/77/64 6/68/5
+f 62/77/64 60/78/60 6/68/5
+f 60/78/60 58/79/58 6/68/5
+f 58/79/58 56/80/56 6/68/5
+f 56/80/56 54/81/54 6/68/5
+f 54/81/54 52/82/52 6/68/5
+f 52/82/52 50/83/50 6/68/5
+f 50/83/50 48/84/48 6/68/5
+f 48/84/48 46/85/46 6/68/5
+f 46/85/46 44/86/44 6/68/5
+f 44/86/44 42/87/42 6/68/5
+f 42/87/42 40/88/40 6/68/5
+f 40/88/40 38/89/38 6/68/5
+f 38/89/38 36/90/36 6/68/5
+f 36/90/36 34/91/33 6/68/5
+f 34/91/33 32/92/31 6/68/5
+f 32/92/31 30/93/29 6/68/5
+f 30/93/29 28/94/27 6/68/5
+f 28/94/27 26/95/25 6/68/5
+f 26/95/25 24/96/23 6/68/5
+f 24/96/23 22/97/21 6/68/5
+f 22/97/21 20/98/19 6/68/5
+f 20/98/19 18/99/17 6/68/5
+f 18/99/17 16/100/15 6/68/5
+f 16/100/15 14/101/13 6/68/5
+f 14/101/13 12/102/11 6/68/5
+f 12/102/11 10/103/9 8/104/7
+f 6/68/5 12/102/11 8/104/7
+f 64/70/63 2/2/2 1/1/1
+f 62/71/64 64/70/63 63/69/62
diff --git a/src/datavisualization/engine/meshes/plane.obj b/src/datavisualization/engine/meshes/plane.obj
new file mode 100644
index 00000000..96ac0dd7
--- /dev/null
+++ b/src/datavisualization/engine/meshes/plane.obj
@@ -0,0 +1,15 @@
+# Blender v2.66 (sub 0) OBJ File: 'plane.blend'
+# www.blender.org
+o Plane
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000000
+v 1.000000 -1.000000 0.000000
+v 1.000000 1.000000 0.000001
+vt 0.003058 1.000000
+vt 0.000000 0.003058
+vt 1.000000 0.996942
+vt 0.996942 0.000000
+vn -0.000001 -0.000001 1.000000
+s off
+f 2/1/1 1/2/1 4/3/1
+f 1/2/1 3/4/1 4/3/1
diff --git a/src/datavisualization/engine/meshes/pyramidFilledFlat.obj b/src/datavisualization/engine/meshes/pyramidFilledFlat.obj
new file mode 100644
index 00000000..0cf73bbe
--- /dev/null
+++ b/src/datavisualization/engine/meshes/pyramidFilledFlat.obj
@@ -0,0 +1,36 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid_filled.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.323067 0.577790
+vt 0.000097 0.866793
+vt 0.000000 0.433396
+vt 0.646133 0.144393
+vt 0.323164 0.433396
+vt 0.323067 0.000000
+vt 0.646133 0.577790
+vt 0.323163 0.866793
+vt 0.323067 0.433396
+vt 0.323067 0.144393
+vt 0.000097 0.433396
+vt 0.000000 0.000000
+vt 0.646133 0.787263
+vt 0.646133 0.433396
+vt 1.000000 0.433396
+vt 1.000000 0.787263
+vn -0.894427 0.447214 -0.000000
+vn 0.894427 0.447213 0.000000
+vn 0.000000 0.447214 -0.894427
+vn -0.000000 0.447214 0.894427
+vn 0.000000 -1.000000 -0.000000
+s off
+f 3/1/1 4/2/1 5/3/1
+f 1/4/2 4/5/2 2/6/2
+f 5/7/3 4/8/3 1/9/3
+f 2/10/4 4/11/4 3/12/4
+f 5/13/5 1/14/5 2/15/5
+f 3/16/5 5/13/5 2/15/5
diff --git a/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj b/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj
new file mode 100644
index 00000000..306bda58
--- /dev/null
+++ b/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj
@@ -0,0 +1,36 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid_filled.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.323067 0.577790
+vt 0.000097 0.866793
+vt 0.000000 0.433396
+vt 0.646133 0.144393
+vt 0.323164 0.433396
+vt 0.323067 0.000000
+vt 0.646133 0.577790
+vt 0.323163 0.866793
+vt 0.323067 0.433396
+vt 0.323067 0.144393
+vt 0.000097 0.433396
+vt 0.000000 0.000000
+vt 0.646133 0.787263
+vt 0.646133 0.433396
+vt 1.000000 0.433396
+vt 1.000000 0.787263
+vn -0.662618 -0.349040 0.662618
+vn 0.000000 1.000000 0.000000
+vn -0.662618 -0.349040 -0.662618
+vn 0.662618 -0.349040 -0.662618
+vn 0.662618 -0.349040 0.662618
+s 1
+f 3/1/1 4/2/2 5/3/3
+f 1/4/4 4/5/2 2/6/5
+f 5/7/3 4/8/2 1/9/4
+f 2/10/5 4/11/2 3/12/1
+f 5/13/3 1/14/4 2/15/5
+f 3/16/1 5/13/3 2/15/5
diff --git a/src/datavisualization/engine/meshes/pyramidFlat.obj b/src/datavisualization/engine/meshes/pyramidFlat.obj
new file mode 100644
index 00000000..35edb477
--- /dev/null
+++ b/src/datavisualization/engine/meshes/pyramidFlat.obj
@@ -0,0 +1,22 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.999900 0.000100
+vt 0.500000 0.500000
+vt 0.000100 0.000100
+vt 0.000100 0.999900
+vt 0.999900 0.999900
+vn -0.894427 0.447214 -0.000000
+vn 0.894427 0.447213 0.000000
+vn 0.000000 0.447214 -0.894427
+vn -0.000000 0.447214 0.894427
+s off
+f 3/1/1 4/2/1 5/3/1
+f 1/4/2 4/2/2 2/5/2
+f 5/3/3 4/2/3 1/4/3
+f 2/5/4 4/2/4 3/1/4
diff --git a/src/datavisualization/engine/meshes/pyramidSmooth.obj b/src/datavisualization/engine/meshes/pyramidSmooth.obj
new file mode 100644
index 00000000..b11c8750
--- /dev/null
+++ b/src/datavisualization/engine/meshes/pyramidSmooth.obj
@@ -0,0 +1,23 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.999900 0.000100
+vt 0.500000 0.500000
+vt 0.000100 0.000100
+vt 0.000100 0.999900
+vt 0.999900 0.999900
+vn -0.577349 0.577349 0.577349
+vn 0.000000 1.000000 0.000000
+vn -0.577349 0.577349 -0.577349
+vn 0.577349 0.577349 -0.577349
+vn 0.577349 0.577349 0.577349
+s 1
+f 3/1/1 4/2/2 5/3/3
+f 1/4/4 4/2/2 2/5/5
+f 5/3/3 4/2/2 1/4/4
+f 2/5/5 4/2/2 3/1/1
diff --git a/src/datavisualization/engine/meshes/scatterdot.obj b/src/datavisualization/engine/meshes/scatterdot.obj
new file mode 100644
index 00000000..d994a80f
--- /dev/null
+++ b/src/datavisualization/engine/meshes/scatterdot.obj
@@ -0,0 +1,28 @@
+# Blender v2.66 (sub 0) OBJ File: 'scatterdot.blend'
+# www.blender.org
+o Cone
+v 0.000000 -0.500000 -1.000000
+v 0.866025 -0.500000 0.500000
+v 0.000000 0.500000 0.000000
+v -0.866025 -0.500000 0.500000
+vt 0.999727 0.000000
+vt 1.000000 0.492691
+vt 0.522886 0.369782
+vt 0.477114 0.973202
+vt 0.000000 1.096111
+vt 0.000273 0.603420
+vt 0.523159 0.985382
+vt 0.522886 0.492691
+vt 1.000000 0.615600
+vt 0.000000 0.603420
+vt 0.000617 0.000000
+vt 0.522886 0.302245
+vn -0.833033 -0.273293 0.480941
+vn 0.000000 0.999969 0.000000
+vn 0.000000 -0.273293 -0.961913
+vn 0.833033 -0.273293 0.480941
+s 1
+f 4/1/1 3/2/2 1/3/3
+f 1/4/3 3/5/2 2/6/4
+f 2/7/4 3/8/2 4/9/1
+f 1/10/3 2/11/4 4/12/1
diff --git a/src/datavisualization/engine/meshes/scatterdotFlat.obj b/src/datavisualization/engine/meshes/scatterdotFlat.obj
new file mode 100644
index 00000000..4052738d
--- /dev/null
+++ b/src/datavisualization/engine/meshes/scatterdotFlat.obj
@@ -0,0 +1,28 @@
+# Blender v2.66 (sub 0) OBJ File: 'scatterdot.blend'
+# www.blender.org
+o Cone
+v 0.000000 -0.500000 -1.000000
+v 0.866025 -0.500000 0.500000
+v 0.000000 0.500000 0.000000
+v -0.866025 -0.500000 0.500000
+vt 0.999727 0.000000
+vt 1.000000 0.492691
+vt 0.522886 0.369782
+vt 0.477114 0.973202
+vt 0.000000 1.096111
+vt 0.000273 0.603420
+vt 0.523159 0.985382
+vt 0.522886 0.492691
+vt 1.000000 0.615600
+vt 0.000000 0.603420
+vt 0.000617 0.000000
+vt 0.522886 0.302245
+vn -0.774597 0.447214 -0.447214
+vn 0.774597 0.447214 -0.447214
+vn -0.000000 0.447214 0.894427
+vn 0.000000 -1.000000 -0.000000
+s off
+f 4/1/1 3/2/1 1/3/1
+f 1/4/2 3/5/2 2/6/2
+f 2/7/3 3/8/3 4/9/3
+f 1/10/4 2/11/4 4/12/4
diff --git a/src/datavisualization/engine/meshes/sphere.obj b/src/datavisualization/engine/meshes/sphere.obj
new file mode 100644
index 00000000..671a7bcc
--- /dev/null
+++ b/src/datavisualization/engine/meshes/sphere.obj
@@ -0,0 +1,1301 @@
+# Blender v2.66 (sub 0) OBJ File: 'sphere.blend'
+# www.blender.org
+o Sphere
+v -0.195090 0.980785 0.000000
+v -0.382683 0.923880 0.000000
+v -0.555570 0.831470 0.000000
+v -0.707107 0.707107 0.000000
+v -0.831470 0.555570 0.000000
+v -0.923880 0.382683 0.000000
+v -0.980785 0.195090 0.000000
+v -1.000000 0.000000 0.000000
+v -0.980785 -0.195090 0.000000
+v -0.923880 -0.382683 0.000000
+v -0.831470 -0.555570 0.000000
+v -0.707107 -0.707107 0.000000
+v -0.555570 -0.831470 0.000000
+v -0.382683 -0.923880 0.000000
+v -0.195090 -0.980785 0.000000
+v -0.180240 0.980785 -0.074658
+v -0.353553 0.923880 -0.146447
+v -0.513280 0.831470 -0.212608
+v -0.653281 0.707107 -0.270598
+v -0.768178 0.555570 -0.318190
+v -0.853553 0.382683 -0.353553
+v -0.906127 0.195090 -0.375330
+v -0.923880 0.000000 -0.382684
+v -0.906127 -0.195090 -0.375330
+v -0.853553 -0.382683 -0.353554
+v -0.768178 -0.555570 -0.318190
+v -0.653281 -0.707107 -0.270598
+v -0.513280 -0.831470 -0.212608
+v -0.353553 -0.923880 -0.146447
+v -0.180240 -0.980785 -0.074658
+v 0.000000 -1.000000 0.000000
+v -0.137950 0.980785 -0.137950
+v -0.270598 0.923880 -0.270598
+v -0.392847 0.831470 -0.392848
+v -0.500000 0.707107 -0.500000
+v -0.587938 0.555570 -0.587938
+v -0.653281 0.382683 -0.653282
+v -0.693520 0.195090 -0.693520
+v -0.707107 0.000000 -0.707107
+v -0.693520 -0.195090 -0.693520
+v -0.653281 -0.382683 -0.653282
+v -0.587938 -0.555570 -0.587938
+v -0.500000 -0.707107 -0.500000
+v -0.392847 -0.831470 -0.392848
+v -0.270598 -0.923880 -0.270598
+v -0.137949 -0.980785 -0.137950
+v -0.074658 0.980785 -0.180240
+v -0.146446 0.923880 -0.353554
+v -0.212607 0.831470 -0.513280
+v -0.270598 0.707107 -0.653282
+v -0.318189 0.555570 -0.768178
+v -0.353553 0.382683 -0.853554
+v -0.375330 0.195090 -0.906128
+v -0.382683 0.000000 -0.923880
+v -0.375330 -0.195090 -0.906128
+v -0.353553 -0.382683 -0.853554
+v -0.318189 -0.555570 -0.768178
+v -0.270598 -0.707107 -0.653282
+v -0.212607 -0.831470 -0.513280
+v -0.146446 -0.923880 -0.353554
+v -0.074658 -0.980785 -0.180240
+v 0.000000 0.980785 -0.195091
+v 0.000000 0.923880 -0.382684
+v 0.000000 0.831470 -0.555570
+v 0.000000 0.707107 -0.707107
+v 0.000000 0.555570 -0.831470
+v 0.000000 0.382683 -0.923880
+v 0.000000 0.195090 -0.980785
+v 0.000000 0.000000 -1.000000
+v 0.000000 -0.195090 -0.980785
+v 0.000000 -0.382683 -0.923880
+v 0.000000 -0.555570 -0.831470
+v 0.000000 -0.707107 -0.707107
+v 0.000000 -0.831470 -0.555570
+v 0.000000 -0.923880 -0.382684
+v 0.000000 -0.980785 -0.195090
+v 0.074658 0.980785 -0.180240
+v 0.146447 0.923880 -0.353554
+v 0.212608 0.831470 -0.513280
+v 0.270598 0.707107 -0.653282
+v 0.318190 0.555570 -0.768178
+v 0.353554 0.382683 -0.853553
+v 0.375331 0.195090 -0.906128
+v 0.382684 0.000000 -0.923880
+v 0.375331 -0.195090 -0.906128
+v 0.353554 -0.382683 -0.853553
+v 0.318190 -0.555570 -0.768178
+v 0.270598 -0.707107 -0.653282
+v 0.212608 -0.831470 -0.513280
+v 0.146447 -0.923880 -0.353554
+v 0.074658 -0.980785 -0.180240
+v 0.137950 0.980785 -0.137950
+v 0.270599 0.923880 -0.270598
+v 0.392848 0.831470 -0.392848
+v 0.500000 0.707107 -0.500000
+v 0.587938 0.555570 -0.587938
+v 0.653282 0.382683 -0.653282
+v 0.693520 0.195090 -0.693520
+v 0.707107 0.000000 -0.707107
+v 0.693520 -0.195090 -0.693520
+v 0.653282 -0.382683 -0.653281
+v 0.587938 -0.555570 -0.587938
+v 0.500000 -0.707107 -0.500000
+v 0.392848 -0.831470 -0.392848
+v 0.270599 -0.923880 -0.270598
+v 0.137950 -0.980785 -0.137950
+v 0.180241 0.980785 -0.074658
+v 0.353554 0.923880 -0.146447
+v 0.513280 0.831470 -0.212608
+v 0.653282 0.707107 -0.270598
+v 0.768178 0.555570 -0.318190
+v 0.853554 0.382683 -0.353553
+v 0.906128 0.195090 -0.375330
+v 0.923880 0.000000 -0.382683
+v 0.906128 -0.195090 -0.375330
+v 0.853554 -0.382683 -0.353553
+v 0.768178 -0.555570 -0.318190
+v 0.653282 -0.707107 -0.270598
+v 0.513280 -0.831470 -0.212608
+v 0.353554 -0.923880 -0.146447
+v 0.180240 -0.980785 -0.074658
+v 0.195091 0.980785 0.000000
+v 0.382684 0.923880 0.000000
+v 0.555571 0.831470 0.000000
+v 0.707107 0.707107 0.000000
+v 0.831470 0.555570 0.000000
+v 0.923880 0.382683 0.000000
+v 0.980786 0.195090 0.000000
+v 1.000000 0.000000 0.000000
+v 0.980786 -0.195090 0.000000
+v 0.923880 -0.382683 0.000000
+v 0.831470 -0.555570 0.000000
+v 0.707107 -0.707107 0.000000
+v 0.555571 -0.831470 0.000000
+v 0.382684 -0.923880 0.000000
+v 0.195091 -0.980785 0.000000
+v 0.180241 0.980785 0.074658
+v 0.353554 0.923880 0.146447
+v 0.513280 0.831470 0.212608
+v 0.653282 0.707107 0.270598
+v 0.768178 0.555570 0.318190
+v 0.853554 0.382683 0.353553
+v 0.906128 0.195090 0.375330
+v 0.923880 0.000000 0.382684
+v 0.906128 -0.195090 0.375330
+v 0.853554 -0.382683 0.353553
+v 0.768178 -0.555570 0.318190
+v 0.653282 -0.707107 0.270598
+v 0.513280 -0.831470 0.212608
+v 0.353554 -0.923880 0.146447
+v 0.180240 -0.980785 0.074658
+v 0.137950 0.980785 0.137950
+v 0.270599 0.923880 0.270598
+v 0.392848 0.831470 0.392848
+v 0.500000 0.707107 0.500000
+v 0.587938 0.555570 0.587938
+v 0.653282 0.382683 0.653282
+v 0.693520 0.195090 0.693520
+v 0.707107 0.000000 0.707107
+v 0.693520 -0.195090 0.693520
+v 0.653282 -0.382683 0.653282
+v 0.587938 -0.555570 0.587938
+v 0.500000 -0.707107 0.500000
+v 0.392848 -0.831470 0.392848
+v 0.270599 -0.923880 0.270598
+v 0.137950 -0.980785 0.137950
+v 0.074658 0.980785 0.180240
+v 0.146447 0.923880 0.353554
+v 0.212608 0.831470 0.513280
+v 0.270598 0.707107 0.653282
+v 0.318190 0.555570 0.768178
+v 0.353554 0.382683 0.853553
+v 0.375331 0.195090 0.906128
+v 0.382684 0.000000 0.923880
+v 0.375331 -0.195090 0.906128
+v 0.353554 -0.382683 0.853553
+v 0.318190 -0.555570 0.768178
+v 0.270598 -0.707107 0.653282
+v 0.212608 -0.831470 0.513280
+v 0.146447 -0.923880 0.353554
+v 0.074658 -0.980785 0.180240
+v 0.000000 0.980785 0.195091
+v 0.000000 0.923880 0.382684
+v 0.000000 0.831470 0.555570
+v 0.000000 0.707107 0.707107
+v 0.000000 0.555570 0.831470
+v 0.000000 0.382683 0.923880
+v 0.000000 0.195090 0.980785
+v 0.000000 0.000000 1.000000
+v 0.000000 -0.195090 0.980785
+v 0.000000 -0.382683 0.923879
+v 0.000000 -0.555570 0.831470
+v 0.000000 -0.707107 0.707107
+v 0.000000 -0.831470 0.555570
+v 0.000000 -0.923880 0.382684
+v 0.000000 -0.980785 0.195090
+v -0.074658 0.980785 0.180240
+v -0.146446 0.923880 0.353554
+v -0.212607 0.831470 0.513280
+v -0.270598 0.707107 0.653282
+v -0.318189 0.555570 0.768178
+v -0.353553 0.382683 0.853553
+v -0.375330 0.195090 0.906128
+v -0.382683 0.000000 0.923880
+v -0.375330 -0.195090 0.906128
+v -0.353553 -0.382683 0.853553
+v -0.318189 -0.555570 0.768178
+v -0.270598 -0.707107 0.653282
+v -0.212607 -0.831470 0.513280
+v -0.146446 -0.923880 0.353554
+v -0.074658 -0.980785 0.180240
+v 0.000000 1.000000 0.000000
+v -0.137950 0.980785 0.137950
+v -0.270598 0.923880 0.270598
+v -0.392847 0.831470 0.392848
+v -0.500000 0.707107 0.500000
+v -0.587938 0.555570 0.587938
+v -0.653281 0.382683 0.653281
+v -0.693520 0.195090 0.693520
+v -0.707107 0.000000 0.707107
+v -0.693520 -0.195090 0.693520
+v -0.653281 -0.382683 0.653281
+v -0.587938 -0.555570 0.587938
+v -0.500000 -0.707107 0.500000
+v -0.392847 -0.831470 0.392848
+v -0.270598 -0.923880 0.270598
+v -0.137949 -0.980785 0.137950
+v -0.180240 0.980785 0.074658
+v -0.353553 0.923880 0.146447
+v -0.513280 0.831470 0.212608
+v -0.653281 0.707107 0.270598
+v -0.768177 0.555570 0.318190
+v -0.853553 0.382683 0.353553
+v -0.906127 0.195090 0.375330
+v -0.923879 0.000000 0.382683
+v -0.906127 -0.195090 0.375330
+v -0.853553 -0.382683 0.353553
+v -0.768177 -0.555570 0.318190
+v -0.653281 -0.707107 0.270598
+v -0.513280 -0.831470 0.212608
+v -0.353553 -0.923880 0.146447
+v -0.180240 -0.980785 0.074658
+vt 0.040867 0.325557
+vt 0.048386 0.386583
+vt 0.001015 0.334499
+vt 0.081872 0.692529
+vt 0.092315 0.752973
+vt 0.006404 0.709363
+vt 1.031336 0.264931
+vt 1.040867 0.325557
+vt 0.999822 0.272029
+vt 0.073887 0.631595
+vt 0.005301 0.646891
+vt 0.333915 0.937286
+vt 0.448527 0.905466
+vt 0.447682 0.976645
+vt 1.017784 0.205113
+vt 0.998129 0.209571
+vt 0.067156 0.570413
+vt 0.004397 0.584414
+vt 0.196016 0.918498
+vt 0.034176 0.958662
+vt 0.060989 0.509119
+vt 0.003585 0.521934
+vt 0.135028 0.869370
+vt 0.015221 0.896641
+vt 0.054891 0.447811
+vt 0.002796 0.459454
+vt 0.107782 0.812401
+vt 0.010297 0.834265
+vt 0.001965 0.396975
+vt 0.007907 0.771825
+vt 0.978319 0.207096
+vt 1.004397 0.584414
+vt 1.005301 0.646891
+vt 0.941200 0.576589
+vt 1.034176 0.958662
+vt 0.823807 0.933258
+vt 1.003585 0.521934
+vt 0.945911 0.514786
+vt 1.015221 0.896641
+vt 0.885287 0.880701
+vt 1.002796 0.459454
+vt 0.950535 0.452971
+vt 1.010297 0.834265
+vt 0.908873 0.821779
+vt 1.001965 0.396975
+vt 0.955439 0.391196
+vt 1.007907 0.771825
+vt 0.921503 0.761167
+vt 1.001015 0.334499
+vt 0.961079 0.329532
+vt 1.006404 0.709363
+vt 0.929787 0.699898
+vt 0.968202 0.268089
+vt 0.936013 0.638321
+vt 0.488610 0.915189
+vt 0.647808 0.950687
+vt 0.921611 0.311033
+vt 0.859136 0.666985
+vt 0.937209 0.253354
+vt 0.870446 0.607941
+vt 0.532175 0.909643
+vt 0.657607 0.903302
+vt 0.959449 0.197860
+vt 0.880347 0.548455
+vt 0.745300 0.879338
+vt 0.889690 0.488794
+vt 0.796385 0.834663
+vt 0.899158 0.429173
+vt 0.825891 0.781668
+vt 0.909472 0.369816
+vt 0.845097 0.725165
+vt 0.848920 0.390841
+vt 0.761226 0.728711
+vt 0.864196 0.334814
+vt 0.780693 0.674598
+vt 0.882867 0.280332
+vt 0.796418 0.618773
+vt 0.907539 0.228698
+vt 0.810089 0.562031
+vt 0.558962 0.891763
+vt 0.641452 0.857179
+vt 0.942759 0.182515
+vt 0.822818 0.504873
+vt 0.697492 0.824480
+vt 0.835477 0.447684
+vt 0.735147 0.779653
+vt 0.879896 0.195479
+vt 0.753309 0.508011
+vt 0.618082 0.815427
+vt 0.767315 0.452094
+vt 0.657173 0.773912
+vt 0.782092 0.396562
+vt 0.685241 0.725518
+vt 0.798714 0.341964
+vt 0.706593 0.673391
+vt 0.818709 0.289116
+vt 0.723996 0.619193
+vt 0.844487 0.239416
+vt 0.739178 0.563865
+vt 0.567268 0.868303
+vt 0.563300 0.844314
+vt 0.770454 0.236269
+vt 0.670392 0.566231
+vt 0.805029 0.190637
+vt 0.683774 0.509644
+vt 0.551952 0.822879
+vt 0.929896 0.162212
+vt 0.855308 0.155368
+vt 0.697011 0.452991
+vt 0.591182 0.780044
+vt 0.710973 0.396675
+vt 0.618699 0.730484
+vt 0.726705 0.341193
+vt 0.639317 0.677374
+vt 0.745717 0.287291
+vt 0.655961 0.622327
+vt 0.665037 0.288362
+vt 0.594131 0.638967
+vt 0.684737 0.232805
+vt 0.605914 0.580518
+vt 0.713639 0.180821
+vt 0.616615 0.521685
+vt 0.760428 0.136665
+vt 0.627046 0.462757
+vt 0.536166 0.805967
+vt 0.923407 0.138703
+vt 0.836350 0.110271
+vt 0.637946 0.403995
+vt 0.562017 0.752770
+vt 0.650183 0.345708
+vt 0.580132 0.696622
+vt 0.517784 0.794886
+vt 0.927547 0.114679
+vt 0.833915 0.062714
+vt 0.573887 0.368405
+vt 0.531336 0.735069
+vt 0.581872 0.307471
+vt 0.540867 0.674443
+vt 0.592315 0.247027
+vt 0.548386 0.613417
+vt 0.607782 0.187599
+vt 0.554891 0.552189
+vt 0.635028 0.130630
+vt 0.560989 0.490881
+vt 0.696016 0.081502
+vt 0.567156 0.429587
+vt 0.502796 0.540546
+vt 0.515221 0.103359
+vt 0.503585 0.478066
+vt 0.534176 0.041338
+vt 0.504397 0.415586
+vt 0.498129 0.790428
+vt 0.948527 0.094534
+vt 0.947682 0.023355
+vt 0.505301 0.353109
+vt 0.499822 0.727971
+vt 0.506404 0.290637
+vt 0.501015 0.665501
+vt 0.507907 0.228175
+vt 0.501965 0.603025
+vt 0.510297 0.165735
+vt 0.429787 0.300102
+vt 0.461079 0.670468
+vt 0.421503 0.238833
+vt 0.455439 0.608804
+vt 0.408873 0.178221
+vt 0.445911 0.485214
+vt 0.385287 0.119299
+vt 1.323807 0.066742
+vt 0.441200 0.423411
+vt 0.478319 0.792904
+vt 0.988610 0.084811
+vt 1.147808 0.049313
+vt 0.436013 0.361679
+vt 0.468202 0.731911
+vt 0.147808 0.049313
+vt 0.323807 0.066742
+vt 0.245300 0.120661
+vt 0.380347 0.451545
+vt 0.459449 0.802140
+vt 0.032175 0.090357
+vt 0.157607 0.096698
+vt 0.370446 0.392059
+vt 0.437209 0.746646
+vt 0.359136 0.333015
+vt 0.421611 0.688967
+vt 0.345097 0.274835
+vt 0.450536 0.547029
+vt 0.409472 0.630184
+vt 0.325892 0.218332
+vt 0.399158 0.570827
+vt 0.296385 0.165337
+vt 0.389690 0.511206
+vt 0.261226 0.271289
+vt 0.348920 0.609159
+vt 0.235147 0.220347
+vt 0.335478 0.552316
+vt 0.197492 0.175520
+vt 0.322818 0.495127
+vt 0.442759 0.817485
+vt 0.058962 0.108237
+vt 0.141452 0.142821
+vt 0.310089 0.437969
+vt 0.407539 0.771302
+vt 0.296418 0.381227
+vt 0.382867 0.719668
+vt 0.280693 0.325402
+vt 0.364196 0.665186
+vt 0.223996 0.380807
+vt 0.318709 0.710884
+vt 0.206593 0.326609
+vt 0.298714 0.658036
+vt 0.185241 0.274482
+vt 0.282092 0.603438
+vt 0.157173 0.226088
+vt 0.267315 0.547906
+vt 0.118082 0.184573
+vt 0.253309 0.491989
+vt 0.379896 0.804521
+vt 0.067268 0.131697
+vt 0.063300 0.155685
+vt 0.239178 0.436135
+vt 0.344487 0.760584
+vt 0.091182 0.219955
+vt 0.197011 0.547009
+vt 0.429896 0.837788
+vt 0.355308 0.844632
+vt 0.051952 0.177121
+vt 0.183774 0.490356
+vt 0.305029 0.809363
+vt 0.170392 0.433769
+vt 0.270454 0.763731
+vt 0.155961 0.377673
+vt 0.245717 0.712709
+vt 0.226706 0.658807
+vt 0.118699 0.269516
+vt 0.210973 0.603325
+vt 0.139317 0.322626
+vt 0.094131 0.361033
+vt 0.165037 0.711638
+vt 0.080132 0.303378
+vt 0.150183 0.654292
+vt 0.062017 0.247229
+vt 0.137946 0.596005
+vt 0.423407 0.861296
+vt 0.336350 0.889729
+vt 0.036166 0.194032
+vt 0.127046 0.537243
+vt 0.260428 0.863335
+vt 0.116615 0.478315
+vt 0.213639 0.819179
+vt 0.105914 0.419482
+vt 0.184737 0.767195
+vt 0.495265 0.852856
+vt 0.995265 0.147143
+vt 1.032175 0.090357
+vt 1.058962 0.108237
+vt 1.067268 0.131697
+vt 1.063300 0.155685
+vt 1.051952 0.177121
+vt 0.427547 0.885321
+vt 1.036166 0.194032
+vt 0.031336 0.264931
+vt 0.017784 0.205113
+vn -0.629402 -0.766928 -0.125196
+vn -0.940062 0.285165 -0.186990
+vn -0.469338 -0.878070 -0.093357
+vn -0.976241 0.096152 -0.194186
+vn -0.289802 0.955349 -0.057645
+vn -0.289802 -0.955349 -0.057645
+vn -0.976241 -0.096151 -0.194186
+vn -0.469338 0.878070 -0.093357
+vn -0.940062 -0.285165 -0.186990
+vn -0.629402 0.766928 -0.125196
+vn -0.868657 -0.464306 -0.172787
+vn -0.764031 0.627024 -0.151975
+vn -0.764031 -0.627024 -0.151975
+vn -0.868657 0.464306 -0.172787
+vn -0.245682 -0.955349 -0.164159
+vn -0.827617 -0.096152 -0.552996
+vn -0.397886 0.878069 -0.265859
+vn -0.796946 -0.285165 -0.532502
+vn -0.533581 0.766929 -0.356527
+vn -0.736412 -0.464306 -0.492055
+vn -0.647715 0.627024 -0.432789
+vn -0.647714 -0.627024 -0.432789
+vn -0.736412 0.464306 -0.492055
+vn -0.533581 -0.766928 -0.356528
+vn -0.796946 0.285165 -0.532502
+vn -0.397886 -0.878070 -0.265859
+vn -0.827617 0.096152 -0.552996
+vn -0.245682 0.955349 -0.164160
+vn -0.356527 -0.766928 -0.533581
+vn -0.532502 0.285165 -0.796946
+vn -0.265859 -0.878070 -0.397886
+vn -0.552996 0.096152 -0.827617
+vn -0.164160 0.955349 -0.245682
+vn -0.164159 -0.955349 -0.245682
+vn -0.552996 -0.096152 -0.827617
+vn -0.265859 0.878069 -0.397886
+vn -0.532502 -0.285165 -0.796946
+vn -0.356527 0.766929 -0.533581
+vn -0.492054 -0.464306 -0.736412
+vn -0.432789 0.627024 -0.647715
+vn -0.432789 -0.627024 -0.647715
+vn -0.492054 0.464306 -0.736412
+vn -0.172786 -0.464306 -0.868657
+vn -0.151975 0.627024 -0.764032
+vn -0.151975 -0.627024 -0.764032
+vn -0.172786 0.464306 -0.868657
+vn -0.125196 -0.766928 -0.629402
+vn -0.186990 0.285165 -0.940062
+vn -0.093357 -0.878070 -0.469338
+vn -0.194186 0.096152 -0.976241
+vn -0.057645 0.955349 -0.289802
+vn -0.057645 -0.955349 -0.289801
+vn -0.194186 -0.096152 -0.976241
+vn -0.093357 0.878069 -0.469338
+vn -0.186990 -0.285165 -0.940062
+vn -0.125196 0.766929 -0.629402
+vn 0.057645 -0.955349 -0.289801
+vn 0.194186 -0.096152 -0.976241
+vn 0.093357 0.878069 -0.469338
+vn 0.186990 -0.285165 -0.940062
+vn 0.125196 0.766929 -0.629402
+vn 0.172787 -0.464306 -0.868657
+vn 0.151975 0.627024 -0.764031
+vn 0.151975 -0.627024 -0.764031
+vn 0.172787 0.464306 -0.868657
+vn 0.125196 -0.766928 -0.629402
+vn 0.186990 0.285165 -0.940062
+vn 0.093357 -0.878070 -0.469338
+vn 0.194186 0.096152 -0.976241
+vn 0.057645 0.955349 -0.289802
+vn 0.356528 -0.766928 -0.533581
+vn 0.532502 0.285165 -0.796946
+vn 0.265859 -0.878070 -0.397886
+vn 0.552996 0.096152 -0.827617
+vn 0.164160 0.955349 -0.245682
+vn 0.164159 -0.955349 -0.245682
+vn 0.552996 -0.096152 -0.827617
+vn 0.265859 0.878069 -0.397886
+vn 0.532502 -0.285165 -0.796946
+vn 0.356527 0.766929 -0.533581
+vn 0.492055 -0.464306 -0.736412
+vn 0.432789 0.627024 -0.647715
+vn 0.432789 -0.627024 -0.647714
+vn 0.492055 0.464306 -0.736412
+vn 0.736412 -0.464306 -0.492055
+vn 0.647715 0.627024 -0.432789
+vn 0.647715 -0.627024 -0.432789
+vn 0.736412 0.464306 -0.492054
+vn 0.533581 -0.766928 -0.356528
+vn 0.796946 0.285165 -0.532502
+vn 0.397886 -0.878070 -0.265859
+vn 0.827617 0.096152 -0.552996
+vn 0.245682 0.955349 -0.164160
+vn 0.245682 -0.955349 -0.164159
+vn 0.827617 -0.096152 -0.552996
+vn 0.397886 0.878069 -0.265859
+vn 0.796946 -0.285165 -0.532502
+vn 0.533581 0.766929 -0.356527
+vn 0.289802 0.955349 -0.057645
+vn 0.289801 -0.955349 -0.057645
+vn 0.976241 -0.096152 -0.194186
+vn 0.469338 0.878069 -0.093357
+vn 0.940062 -0.285165 -0.186990
+vn 0.629402 0.766929 -0.125196
+vn 0.868657 -0.464306 -0.172786
+vn 0.764032 0.627024 -0.151975
+vn 0.764032 -0.627024 -0.151975
+vn 0.868657 0.464307 -0.172786
+vn 0.629402 -0.766928 -0.125196
+vn 0.940062 0.285165 -0.186990
+vn 0.469338 -0.878069 -0.093357
+vn 0.976241 0.096152 -0.194186
+vn 0.868657 0.464306 0.172787
+vn 0.629402 -0.766928 0.125196
+vn 0.940062 0.285165 0.186990
+vn 0.469338 -0.878069 0.093357
+vn 0.976241 0.096152 0.194186
+vn 0.289802 0.955349 0.057645
+vn 0.289801 -0.955349 0.057645
+vn 0.976241 -0.096152 0.194187
+vn 0.469338 0.878069 0.093357
+vn 0.940061 -0.285165 0.186990
+vn 0.629402 0.766929 0.125196
+vn 0.868657 -0.464306 0.172787
+vn 0.764032 0.627024 0.151975
+vn 0.764032 -0.627024 0.151976
+vn 0.796946 -0.285165 0.532502
+vn 0.533581 0.766929 0.356527
+vn 0.736412 -0.464306 0.492055
+vn 0.647715 0.627024 0.432789
+vn 0.647715 -0.627024 0.432789
+vn 0.736411 0.464307 0.492054
+vn 0.533581 -0.766928 0.356528
+vn 0.796946 0.285165 0.532502
+vn 0.397886 -0.878070 0.265859
+vn 0.827617 0.096151 0.552996
+vn 0.245682 0.955349 0.164160
+vn 0.245682 -0.955349 0.164159
+vn 0.827617 -0.096151 0.552996
+vn 0.397886 0.878070 0.265859
+vn 0.265859 -0.878070 0.397886
+vn 0.552996 0.096151 0.827617
+vn 0.164160 0.955349 0.245682
+vn 0.164159 -0.955349 0.245682
+vn 0.552996 -0.096151 0.827617
+vn 0.265859 0.878070 0.397886
+vn 0.532502 -0.285165 0.796946
+vn 0.356527 0.766929 0.533581
+vn 0.492054 -0.464306 0.736412
+vn 0.432789 0.627024 0.647715
+vn 0.432789 -0.627024 0.647715
+vn 0.492054 0.464307 0.736412
+vn 0.356528 -0.766928 0.533581
+vn 0.532502 0.285165 0.796946
+vn 0.151975 -0.627024 0.764032
+vn 0.172786 0.464307 0.868656
+vn 0.125196 -0.766928 0.629402
+vn 0.186990 0.285165 0.940062
+vn 0.093357 -0.878070 0.469338
+vn 0.194186 0.096151 0.976241
+vn 0.057645 0.955349 0.289802
+vn 0.057645 -0.955349 0.289801
+vn 0.194186 -0.096151 0.976241
+vn 0.093357 0.878070 0.469338
+vn 0.186990 -0.285166 0.940061
+vn 0.125196 0.766929 0.629402
+vn 0.172786 -0.464306 0.868657
+vn 0.151975 0.627023 0.764032
+vn -0.186990 -0.285166 0.940061
+vn -0.125196 0.766929 0.629402
+vn -0.172787 -0.464306 0.868657
+vn -0.151976 0.627023 0.764032
+vn -0.151975 -0.627024 0.764032
+vn -0.172787 0.464307 0.868656
+vn -0.125196 -0.766928 0.629402
+vn -0.186990 0.285165 0.940062
+vn -0.093357 -0.878069 0.469338
+vn -0.194186 0.096151 0.976241
+vn -0.057645 0.955349 0.289802
+vn -0.057645 -0.955349 0.289801
+vn -0.194186 -0.096151 0.976241
+vn -0.093357 0.878069 0.469338
+vn -0.265859 -0.878070 0.397886
+vn -0.552996 0.096151 0.827617
+vn -0.164160 0.955349 0.245682
+vn -0.164159 -0.955349 0.245682
+vn -0.552996 -0.096151 0.827617
+vn -0.265859 0.878070 0.397886
+vn -0.532502 -0.285166 0.796945
+vn -0.356527 0.766929 0.533581
+vn -0.492054 -0.464306 0.736412
+vn -0.432790 0.627023 0.647715
+vn -0.432789 -0.627024 0.647715
+vn -0.492054 0.464307 0.736411
+vn -0.356528 -0.766928 0.533581
+vn -0.532502 0.285165 0.796946
+vn -0.647715 -0.627024 0.432789
+vn -0.736411 0.464307 0.492054
+vn -0.533581 -0.766928 0.356528
+vn -0.796946 0.285165 0.532502
+vn -0.397886 -0.878070 0.265859
+vn -0.827617 0.096151 0.552996
+vn -0.245682 0.955349 0.164160
+vn -0.245682 -0.955349 0.164159
+vn -0.827617 -0.096151 0.552996
+vn -0.397886 0.878070 0.265859
+vn -0.796946 -0.285166 0.532502
+vn -0.533581 0.766929 0.356527
+vn -0.736412 -0.464306 0.492054
+vn -0.647715 0.627023 0.432789
+vn -0.097999 0.994996 -0.019493
+vn -0.097998 -0.994996 -0.019493
+vn -0.083079 -0.994996 -0.055512
+vn -0.083079 0.994996 -0.055512
+vn -0.055512 0.994996 -0.083079
+vn -0.055512 -0.994996 -0.083079
+vn -0.019493 0.994996 -0.097998
+vn -0.019493 -0.994996 -0.097998
+vn 0.019493 -0.994996 -0.097998
+vn 0.019493 0.994996 -0.097998
+vn 0.055512 0.994996 -0.083079
+vn 0.055512 -0.994996 -0.083079
+vn 0.083079 0.994996 -0.055512
+vn 0.083079 -0.994996 -0.055512
+vn 0.097998 -0.994996 -0.019493
+vn 0.097998 0.994996 -0.019493
+vn 0.097998 0.994996 0.019493
+vn 0.097998 -0.994996 0.019493
+vn 0.083079 0.994996 0.055512
+vn 0.083079 -0.994996 0.055512
+vn 0.055512 -0.994996 0.083079
+vn 0.055512 0.994996 0.083079
+vn 0.019493 0.994996 0.097999
+vn 0.019493 -0.994996 0.097998
+vn -0.019493 -0.994996 0.097998
+vn -0.019493 0.994996 0.097999
+vn -0.055512 -0.994996 0.083079
+vn -0.055512 0.994996 0.083079
+vn -0.083079 0.994996 0.055512
+vn -0.083079 -0.994996 0.055512
+vn -0.097998 -0.994996 0.019493
+vn -0.940061 -0.285166 0.186991
+vn -0.629402 0.766929 0.125196
+vn -0.868656 -0.464306 0.172788
+vn -0.764032 0.627023 0.151977
+vn -0.764032 -0.627024 0.151976
+vn -0.868656 0.464307 0.172787
+vn -0.629402 -0.766928 0.125196
+vn -0.940061 0.285165 0.186990
+vn -0.097999 0.994996 0.019493
+vn -0.469338 -0.878070 0.093357
+vn -0.976241 0.096151 0.194187
+vn -0.289802 0.955349 0.057646
+vn -0.289801 -0.955349 0.057645
+vn -0.976241 -0.096151 0.194187
+vn -0.469338 0.878070 0.093358
+vn -0.976241 -0.096152 -0.194186
+vn -0.469338 0.878069 -0.093357
+vn -0.629401 0.766929 -0.125196
+vn -0.764032 0.627024 -0.151975
+vn -0.736411 -0.464306 -0.492055
+vn -0.736411 0.464306 -0.492055
+vn -0.356528 -0.766928 -0.533581
+vn -0.151975 -0.627024 -0.764031
+vn -0.194186 -0.096151 -0.976241
+vn 0.186990 -0.285165 -0.940061
+vn 0.151975 0.627024 -0.764032
+vn 0.432789 -0.627024 -0.647715
+vn 0.492055 0.464306 -0.736411
+vn 0.736412 -0.464306 -0.492054
+vn 0.736411 0.464307 -0.492054
+vn 0.976241 -0.096151 -0.194186
+vn 0.940062 -0.285166 -0.186990
+vn 0.868657 -0.464306 -0.172787
+vn 0.868657 0.464306 -0.172786
+vn 0.940061 0.285165 -0.186990
+vn 0.868656 0.464307 0.172787
+vn 0.976241 0.096151 0.194187
+vn 0.976241 -0.096151 0.194186
+vn 0.469338 0.878070 0.093357
+vn 0.940061 -0.285166 0.186990
+vn 0.764032 0.627024 0.151976
+vn 0.764032 -0.627024 0.151975
+vn 0.796945 -0.285166 0.532502
+vn 0.647715 0.627023 0.432790
+vn 0.736411 0.464307 0.492055
+vn 0.532502 -0.285166 0.796946
+vn 0.432789 0.627023 0.647715
+vn 0.492054 0.464307 0.736411
+vn 0.151975 -0.627023 0.764032
+vn 0.186990 0.285165 0.940061
+vn 0.093357 0.878069 0.469338
+vn -0.151975 0.627023 0.764032
+vn -0.151976 -0.627023 0.764032
+vn -0.186990 0.285165 0.940061
+vn -0.093357 -0.878070 0.469338
+vn -0.093357 0.878070 0.469338
+vn -0.532502 -0.285166 0.796946
+vn -0.492055 -0.464306 0.736412
+vn -0.432789 -0.627023 0.647715
+vn -0.647715 -0.627023 0.432789
+vn -0.796945 -0.285166 0.532502
+vn -0.647715 0.627023 0.432790
+vn -0.940062 -0.285165 0.186990
+vn -0.629402 0.766928 0.125196
+vn -0.764031 0.627024 0.151975
+vn -0.764031 -0.627024 0.151976
+vn -0.868657 0.464306 0.172788
+vn -0.940062 0.285165 0.186991
+vn -0.976241 0.096152 0.194187
+vn -0.289802 -0.955349 0.057645
+s off
+f 13/1/1 12/2/1 28/3/1
+f 7/4/2 6/5/2 22/6/2
+f 14/7/3 13/8/3 29/9/3
+f 8/10/4 7/4/4 23/11/4
+f 2/12/5 1/13/5 17/14/5
+f 15/15/6 14/7/6 30/16/6
+f 9/17/7 8/10/7 24/18/7
+f 3/19/8 2/12/8 18/20/8
+f 10/21/9 9/17/9 25/22/9
+f 4/23/10 3/19/10 19/24/10
+f 11/25/11 10/21/11 26/26/11
+f 5/27/12 4/23/12 20/28/12
+f 12/2/13 11/25/13 27/29/13
+f 6/5/14 5/27/14 21/30/14
+f 30/16/15 29/9/15 46/31/15
+f 24/32/16 23/33/16 40/34/16
+f 18/35/17 17/14/17 34/36/17
+f 25/37/18 24/32/18 41/38/18
+f 19/39/19 18/35/19 35/40/19
+f 26/41/20 25/37/20 42/42/20
+f 20/43/21 19/39/21 36/44/21
+f 27/45/22 26/41/22 43/46/22
+f 21/47/23 20/43/23 37/48/23
+f 28/49/24 27/45/24 44/50/24
+f 22/51/25 21/47/25 38/52/25
+f 29/9/26 28/49/26 45/53/26
+f 23/33/27 22/51/27 39/54/27
+f 17/14/28 16/55/28 33/56/28
+f 44/50/29 43/46/29 59/57/29
+f 38/52/30 37/48/30 53/58/30
+f 45/53/31 44/50/31 60/59/31
+f 39/54/32 38/52/32 54/60/32
+f 33/56/33 32/61/33 48/62/33
+f 46/31/34 45/53/34 61/63/34
+f 40/34/35 39/54/35 55/64/35
+f 34/36/36 33/56/36 49/65/36
+f 41/38/37 40/34/37 56/66/37
+f 35/40/38 34/36/38 50/67/38
+f 42/42/39 41/38/39 57/68/39
+f 36/44/40 35/40/40 51/69/40
+f 43/46/41 42/42/41 58/70/41
+f 37/48/42 36/44/42 52/71/42
+f 57/68/43 56/66/43 72/72/43
+f 51/69/44 50/67/44 66/73/44
+f 58/70/45 57/68/45 73/74/45
+f 52/71/46 51/69/46 67/75/46
+f 59/57/47 58/70/47 74/76/47
+f 53/58/48 52/71/48 68/77/48
+f 60/59/49 59/57/49 75/78/49
+f 54/60/50 53/58/50 69/79/50
+f 48/62/51 47/80/51 63/81/51
+f 61/63/52 60/59/52 76/82/52
+f 55/64/53 54/60/53 70/83/53
+f 49/65/54 48/62/54 64/84/54
+f 56/66/55 55/64/55 71/85/55
+f 50/67/56 49/65/56 65/86/56
+f 76/82/57 75/78/57 90/87/57
+f 70/83/58 69/79/58 84/88/58
+f 64/84/59 63/81/59 78/89/59
+f 71/85/60 70/83/60 85/90/60
+f 65/86/61 64/84/61 79/91/61
+f 72/72/62 71/85/62 86/92/62
+f 66/73/63 65/86/63 80/93/63
+f 73/74/64 72/72/64 87/94/64
+f 67/75/65 66/73/65 81/95/65
+f 74/76/66 73/74/66 88/96/66
+f 68/77/67 67/75/67 82/97/67
+f 75/78/68 74/76/68 89/98/68
+f 69/79/69 68/77/69 83/99/69
+f 63/81/70 62/100/70 77/101/70
+f 89/98/71 88/96/71 103/102/71
+f 83/99/72 82/97/72 97/103/72
+f 90/87/73 89/98/73 104/104/73
+f 84/88/74 83/99/74 98/105/74
+f 78/89/75 77/101/75 92/106/75
+f 91/107/76 90/87/76 105/108/76
+f 85/90/77 84/88/77 99/109/77
+f 79/91/78 78/89/78 93/110/78
+f 86/92/79 85/90/79 100/111/79
+f 80/93/80 79/91/80 94/112/80
+f 87/94/81 86/92/81 101/113/81
+f 81/95/82 80/93/82 95/114/82
+f 88/96/83 87/94/83 102/115/83
+f 82/97/84 81/95/84 96/116/84
+f 102/115/85 101/113/85 116/117/85
+f 96/116/86 95/114/86 110/118/86
+f 103/102/87 102/115/87 117/119/87
+f 97/103/88 96/116/88 111/120/88
+f 104/104/89 103/102/89 118/121/89
+f 98/105/90 97/103/90 112/122/90
+f 105/108/91 104/104/91 119/123/91
+f 99/109/92 98/105/92 113/124/92
+f 93/110/93 92/106/93 107/125/93
+f 106/126/94 105/108/94 120/127/94
+f 100/111/95 99/109/95 114/128/95
+f 94/112/96 93/110/96 108/129/96
+f 101/113/97 100/111/97 115/130/97
+f 95/114/98 94/112/98 109/131/98
+f 108/129/99 107/125/99 122/132/99
+f 121/133/100 120/127/100 135/134/100
+f 115/130/101 114/128/101 129/135/101
+f 109/131/102 108/129/102 123/136/102
+f 116/117/103 115/130/103 130/137/103
+f 110/118/104 109/131/104 124/138/104
+f 117/119/105 116/117/105 131/139/105
+f 111/120/106 110/118/106 125/140/106
+f 118/121/107 117/119/107 132/141/107
+f 112/122/108 111/120/108 126/142/108
+f 119/123/109 118/121/109 133/143/109
+f 113/124/110 112/122/110 127/144/110
+f 120/127/111 119/123/111 134/145/111
+f 114/128/112 113/124/112 128/146/112
+f 127/144/113 126/142/113 141/147/113
+f 134/145/114 133/143/114 148/148/114
+f 128/146/115 127/144/115 142/149/115
+f 135/134/116 134/145/116 149/150/116
+f 129/135/117 128/146/117 143/151/117
+f 123/136/118 122/132/118 137/152/118
+f 136/153/119 135/134/119 150/154/119
+f 130/137/120 129/135/120 144/155/120
+f 124/138/121 123/136/121 138/156/121
+f 131/139/122 130/137/122 145/157/122
+f 125/140/123 124/138/123 139/158/123
+f 132/141/124 131/139/124 146/159/124
+f 126/142/125 125/140/125 140/160/125
+f 133/143/126 132/141/126 147/161/126
+f 146/159/127 145/157/127 160/162/127
+f 140/160/128 139/158/128 154/163/128
+f 147/161/129 146/159/129 161/164/129
+f 141/147/130 140/160/130 155/165/130
+f 148/148/131 147/161/131 162/166/131
+f 142/149/132 141/147/132 157/167/132
+f 149/150/133 148/148/133 163/168/133
+f 143/151/134 142/149/134 157/167/134
+f 150/154/135 149/150/135 164/169/135
+f 144/155/136 143/151/136 158/170/136
+f 138/156/137 137/152/137 152/171/137
+f 151/172/138 150/154/138 165/173/138
+f 145/157/139 144/155/139 159/174/139
+f 139/158/140 138/156/140 153/175/140
+f 165/176/141 164/177/141 179/178/141
+f 159/174/142 158/170/142 173/179/142
+f 153/175/143 152/171/143 167/180/143
+f 166/181/144 165/176/144 180/182/144
+f 160/162/145 159/174/145 174/183/145
+f 154/163/146 153/175/146 168/184/146
+f 161/164/147 160/162/147 175/185/147
+f 155/165/148 154/163/148 169/186/148
+f 162/166/149 161/164/149 176/187/149
+f 156/188/150 155/165/150 170/189/150
+f 163/168/151 162/166/151 177/190/151
+f 157/167/152 156/188/152 171/191/152
+f 164/177/153 163/168/153 178/192/153
+f 158/170/154 157/167/154 172/193/154
+f 178/192/155 177/190/155 192/194/155
+f 172/193/156 171/191/156 186/195/156
+f 179/178/157 178/192/157 193/196/157
+f 173/179/158 172/193/158 187/197/158
+f 180/182/159 179/178/159 194/198/159
+f 174/183/160 173/179/160 188/199/160
+f 168/184/161 167/180/161 182/200/161
+f 181/201/162 180/182/162 195/202/162
+f 175/185/163 174/183/163 189/203/163
+f 169/186/164 168/184/164 183/204/164
+f 176/187/165 175/185/165 190/205/165
+f 170/189/166 169/186/166 184/206/166
+f 177/190/167 176/187/167 191/207/167
+f 171/191/168 170/189/168 185/208/168
+f 191/207/169 190/205/169 206/209/169
+f 185/208/170 184/206/170 200/210/170
+f 192/194/171 191/207/171 207/211/171
+f 186/195/172 185/208/172 201/212/172
+f 193/196/173 192/194/173 208/213/173
+f 187/197/174 186/195/174 202/214/174
+f 194/198/175 193/196/175 209/215/175
+f 188/199/176 187/197/176 203/216/176
+f 195/202/177 194/198/177 210/217/177
+f 189/203/178 188/199/178 204/218/178
+f 183/204/179 182/200/179 198/219/179
+f 196/220/180 195/202/180 211/221/180
+f 190/205/181 189/203/181 205/222/181
+f 184/206/182 183/204/182 199/223/182
+f 210/217/183 209/215/183 226/224/183
+f 204/218/184 203/216/184 220/225/184
+f 198/219/185 197/226/185 214/227/185
+f 211/221/186 210/217/186 227/228/186
+f 205/222/187 204/218/187 221/229/187
+f 199/223/188 198/219/188 215/230/188
+f 206/209/189 205/222/189 222/231/189
+f 200/210/190 199/223/190 216/232/190
+f 207/211/191 206/209/191 223/233/191
+f 201/212/192 200/210/192 217/234/192
+f 208/213/193 207/211/193 223/233/193
+f 202/214/194 201/212/194 218/235/194
+f 209/215/195 208/213/195 225/236/195
+f 203/216/196 202/214/196 219/237/196
+f 224/238/197 223/233/197 239/239/197
+f 218/235/198 217/234/198 233/240/198
+f 225/236/199 224/238/199 240/241/199
+f 219/237/200 218/235/200 234/242/200
+f 226/224/201 225/236/201 241/243/201
+f 220/225/202 219/237/202 235/244/202
+f 214/227/203 213/245/203 229/246/203
+f 227/228/204 226/224/204 242/247/204
+f 221/229/205 220/225/205 236/248/205
+f 215/230/206 214/227/206 230/249/206
+f 222/231/207 221/229/207 237/250/207
+f 216/232/208 215/230/208 231/251/208
+f 223/233/209 222/231/209 238/252/209
+f 217/234/210 216/232/210 232/253/210
+f 1/13/211 212/254/211 16/55/211
+f 31/255/212 15/15/212 30/16/212
+f 31/255/213 30/16/213 46/31/213
+f 16/55/214 212/254/214 32/61/214
+f 32/61/215 212/254/215 47/80/215
+f 31/255/216 46/31/216 61/63/216
+f 47/80/217 212/254/217 62/100/217
+f 31/255/218 61/63/218 76/82/218
+f 31/255/219 76/82/219 91/107/219
+f 62/100/220 212/254/220 77/101/220
+f 77/101/221 212/254/221 92/106/221
+f 31/255/222 91/107/222 106/126/222
+f 92/106/223 212/254/223 107/125/223
+f 31/255/224 106/126/224 121/133/224
+f 31/255/225 121/133/225 136/153/225
+f 107/125/226 212/254/226 122/132/226
+f 122/132/227 212/254/227 137/152/227
+f 31/255/228 136/153/228 151/172/228
+f 137/152/229 212/254/229 152/171/229
+f 31/255/230 151/172/230 166/256/230
+f 31/255/231 166/256/231 181/257/231
+f 152/171/232 212/254/232 167/180/232
+f 167/180/233 212/254/233 182/200/233
+f 31/255/234 181/257/234 196/258/234
+f 31/255/235 196/258/235 211/259/235
+f 182/200/236 212/254/236 197/226/236
+f 31/255/237 211/259/237 227/260/237
+f 197/226/238 212/254/238 213/245/238
+f 213/245/239 212/254/239 228/261/239
+f 31/255/240 227/260/240 242/262/240
+f 31/255/241 242/262/241 15/15/241
+f 237/250/242 236/248/242 10/21/242
+f 231/251/243 230/249/243 4/23/243
+f 238/252/244 237/250/244 10/21/244
+f 232/253/245 231/251/245 5/27/245
+f 239/239/246 238/252/246 11/25/246
+f 233/240/247 232/253/247 6/5/247
+f 240/241/248 239/239/248 13/1/248
+f 234/242/249 233/240/249 7/4/249
+f 228/261/250 212/254/250 1/13/250
+f 241/243/251 240/241/251 14/263/251
+f 235/244/252 234/242/252 8/10/252
+f 229/246/253 228/261/253 2/12/253
+f 242/247/254 241/243/254 15/264/254
+f 236/248/255 235/244/255 9/17/255
+f 230/249/256 229/246/256 3/19/256
+f 12/2/1 27/29/1 28/3/1
+f 6/5/2 21/30/2 22/6/2
+f 13/8/3 28/49/3 29/9/3
+f 7/4/4 22/6/4 23/11/4
+f 1/13/5 16/55/5 17/14/5
+f 14/7/6 29/9/6 30/16/6
+f 8/10/257 23/11/257 24/18/257
+f 2/12/258 17/14/258 18/20/258
+f 9/17/9 24/18/9 25/22/9
+f 3/19/259 18/20/259 19/24/259
+f 10/21/11 25/22/11 26/26/11
+f 4/23/260 19/24/260 20/28/260
+f 11/25/13 26/26/13 27/29/13
+f 5/27/14 20/28/14 21/30/14
+f 29/9/15 45/53/15 46/31/15
+f 23/33/16 39/54/16 40/34/16
+f 17/14/17 33/56/17 34/36/17
+f 24/32/18 40/34/18 41/38/18
+f 18/35/19 34/36/19 35/40/19
+f 25/37/261 41/38/261 42/42/261
+f 19/39/21 35/40/21 36/44/21
+f 26/41/22 42/42/22 43/46/22
+f 20/43/262 36/44/262 37/48/262
+f 27/45/24 43/46/24 44/50/24
+f 21/47/25 37/48/25 38/52/25
+f 28/49/26 44/50/26 45/53/26
+f 22/51/27 38/52/27 39/54/27
+f 16/55/28 32/61/28 33/56/28
+f 43/46/263 58/70/263 59/57/263
+f 37/48/30 52/71/30 53/58/30
+f 44/50/31 59/57/31 60/59/31
+f 38/52/32 53/58/32 54/60/32
+f 32/61/33 47/80/33 48/62/33
+f 45/53/34 60/59/34 61/63/34
+f 39/54/35 54/60/35 55/64/35
+f 33/56/36 48/62/36 49/65/36
+f 40/34/37 55/64/37 56/66/37
+f 34/36/38 49/65/38 50/67/38
+f 41/38/39 56/66/39 57/68/39
+f 35/40/40 50/67/40 51/69/40
+f 42/42/41 57/68/41 58/70/41
+f 36/44/42 51/69/42 52/71/42
+f 56/66/43 71/85/43 72/72/43
+f 50/67/44 65/86/44 66/73/44
+f 57/68/264 72/72/264 73/74/264
+f 51/69/46 66/73/46 67/75/46
+f 58/70/47 73/74/47 74/76/47
+f 52/71/48 67/75/48 68/77/48
+f 59/57/49 74/76/49 75/78/49
+f 53/58/50 68/77/50 69/79/50
+f 47/80/51 62/100/51 63/81/51
+f 60/59/52 75/78/52 76/82/52
+f 54/60/265 69/79/265 70/83/265
+f 48/62/54 63/81/54 64/84/54
+f 55/64/55 70/83/55 71/85/55
+f 49/65/56 64/84/56 65/86/56
+f 91/107/57 76/82/57 90/87/57
+f 85/90/58 70/83/58 84/88/58
+f 79/91/59 64/84/59 78/89/59
+f 86/92/266 71/85/266 85/90/266
+f 80/93/61 65/86/61 79/91/61
+f 87/94/62 72/72/62 86/92/62
+f 81/95/267 66/73/267 80/93/267
+f 88/96/64 73/74/64 87/94/64
+f 82/97/65 67/75/65 81/95/65
+f 89/98/66 74/76/66 88/96/66
+f 83/99/67 68/77/67 82/97/67
+f 90/87/68 75/78/68 89/98/68
+f 84/88/69 69/79/69 83/99/69
+f 78/89/70 63/81/70 77/101/70
+f 104/104/71 89/98/71 103/102/71
+f 98/105/72 83/99/72 97/103/72
+f 105/108/73 90/87/73 104/104/73
+f 99/109/74 84/88/74 98/105/74
+f 93/110/75 78/89/75 92/106/75
+f 106/126/76 91/107/76 105/108/76
+f 100/111/77 85/90/77 99/109/77
+f 94/112/78 79/91/78 93/110/78
+f 101/113/79 86/92/79 100/111/79
+f 95/114/80 80/93/80 94/112/80
+f 102/115/81 87/94/81 101/113/81
+f 96/116/82 81/95/82 95/114/82
+f 103/102/268 88/96/268 102/115/268
+f 97/103/269 82/97/269 96/116/269
+f 117/119/270 102/115/270 116/117/270
+f 111/120/86 96/116/86 110/118/86
+f 118/121/87 103/102/87 117/119/87
+f 112/122/271 97/103/271 111/120/271
+f 119/123/89 104/104/89 118/121/89
+f 113/124/90 98/105/90 112/122/90
+f 120/127/91 105/108/91 119/123/91
+f 114/128/92 99/109/92 113/124/92
+f 108/129/93 93/110/93 107/125/93
+f 121/133/94 106/126/94 120/127/94
+f 115/130/95 100/111/95 114/128/95
+f 109/131/96 94/112/96 108/129/96
+f 116/117/97 101/113/97 115/130/97
+f 110/118/98 95/114/98 109/131/98
+f 123/136/99 108/129/99 122/132/99
+f 136/153/100 121/133/100 135/134/100
+f 130/137/272 115/130/272 129/135/272
+f 124/138/102 109/131/102 123/136/102
+f 131/139/273 116/117/273 130/137/273
+f 125/140/104 110/118/104 124/138/104
+f 132/141/274 117/119/274 131/139/274
+f 126/142/106 111/120/106 125/140/106
+f 133/143/107 118/121/107 132/141/107
+f 127/144/275 112/122/275 126/142/275
+f 134/145/109 119/123/109 133/143/109
+f 128/146/276 113/124/276 127/144/276
+f 135/134/111 120/127/111 134/145/111
+f 129/135/112 114/128/112 128/146/112
+f 142/149/277 127/144/277 141/147/277
+f 149/150/114 134/145/114 148/148/114
+f 143/151/115 128/146/115 142/149/115
+f 150/154/116 135/134/116 149/150/116
+f 144/155/278 129/135/278 143/151/278
+f 138/156/118 123/136/118 137/152/118
+f 151/172/119 136/153/119 150/154/119
+f 145/157/279 130/137/279 144/155/279
+f 139/158/280 124/138/280 138/156/280
+f 146/159/281 131/139/281 145/157/281
+f 140/160/123 125/140/123 139/158/123
+f 147/161/124 132/141/124 146/159/124
+f 141/147/282 126/142/282 140/160/282
+f 148/148/283 133/143/283 147/161/283
+f 161/164/284 146/159/284 160/162/284
+f 155/165/128 140/160/128 154/163/128
+f 162/166/129 147/161/129 161/164/129
+f 156/188/285 141/147/285 155/165/285
+f 163/168/131 148/148/131 162/166/131
+f 141/147/286 156/188/286 157/167/286
+f 164/177/133 149/150/133 163/168/133
+f 158/170/134 143/151/134 157/167/134
+f 165/173/135 150/154/135 164/169/135
+f 159/174/136 144/155/136 158/170/136
+f 153/175/137 138/156/137 152/171/137
+f 166/256/138 151/172/138 165/173/138
+f 160/162/139 145/157/139 159/174/139
+f 154/163/140 139/158/140 153/175/140
+f 180/182/141 165/176/141 179/178/141
+f 174/183/142 159/174/142 173/179/142
+f 168/184/143 153/175/143 167/180/143
+f 181/201/144 166/181/144 180/182/144
+f 175/185/145 160/162/145 174/183/145
+f 169/186/146 154/163/146 168/184/146
+f 176/187/287 161/164/287 175/185/287
+f 170/189/148 155/165/148 169/186/148
+f 177/190/149 162/166/149 176/187/149
+f 171/191/288 156/188/288 170/189/288
+f 178/192/151 163/168/151 177/190/151
+f 172/193/289 157/167/289 171/191/289
+f 179/178/153 164/177/153 178/192/153
+f 173/179/154 158/170/154 172/193/154
+f 193/196/290 178/192/290 192/194/290
+f 187/197/156 172/193/156 186/195/156
+f 194/198/157 179/178/157 193/196/157
+f 188/199/291 173/179/291 187/197/291
+f 195/202/159 180/182/159 194/198/159
+f 189/203/160 174/183/160 188/199/160
+f 183/204/161 168/184/161 182/200/161
+f 196/220/162 181/201/162 195/202/162
+f 190/205/163 175/185/163 189/203/163
+f 184/206/292 169/186/292 183/204/292
+f 191/207/165 176/187/165 190/205/165
+f 185/208/166 170/189/166 184/206/166
+f 192/194/167 177/190/167 191/207/167
+f 186/195/168 171/191/168 185/208/168
+f 190/205/169 205/222/169 206/209/169
+f 184/206/170 199/223/170 200/210/170
+f 191/207/171 206/209/171 207/211/171
+f 185/208/293 200/210/293 201/212/293
+f 192/194/294 207/211/294 208/213/294
+f 186/195/174 201/212/174 202/214/174
+f 193/196/175 208/213/175 209/215/175
+f 187/197/295 202/214/295 203/216/295
+f 194/198/296 209/215/296 210/217/296
+f 188/199/178 203/216/178 204/218/178
+f 182/200/179 197/226/179 198/219/179
+f 195/202/180 210/217/180 211/221/180
+f 189/203/181 204/218/181 205/222/181
+f 183/204/297 198/219/297 199/223/297
+f 209/215/183 225/236/183 226/224/183
+f 203/216/184 219/237/184 220/225/184
+f 197/226/185 213/245/185 214/227/185
+f 210/217/186 226/224/186 227/228/186
+f 204/218/187 220/225/187 221/229/187
+f 198/219/188 214/227/188 215/230/188
+f 205/222/298 221/229/298 222/231/298
+f 199/223/190 215/230/190 216/232/190
+f 206/209/299 222/231/299 223/233/299
+f 200/210/192 216/232/192 217/234/192
+f 224/238/300 208/213/300 223/233/300
+f 201/212/194 217/234/194 218/235/194
+f 208/213/195 224/238/195 225/236/195
+f 202/214/196 218/235/196 219/237/196
+f 223/233/301 238/252/301 239/239/301
+f 217/234/198 232/253/198 233/240/198
+f 224/238/199 239/239/199 240/241/199
+f 218/235/200 233/240/200 234/242/200
+f 225/236/201 240/241/201 241/243/201
+f 219/237/202 234/242/202 235/244/202
+f 213/245/203 228/261/203 229/246/203
+f 226/224/204 241/243/204 242/247/204
+f 220/225/205 235/244/205 236/248/205
+f 214/227/206 229/246/206 230/249/206
+f 221/229/302 236/248/302 237/250/302
+f 215/230/208 230/249/208 231/251/208
+f 222/231/209 237/250/209 238/252/209
+f 216/232/303 231/251/303 232/253/303
+f 236/248/304 9/17/304 10/21/304
+f 230/249/305 3/19/305 4/23/305
+f 11/25/244 238/252/244 10/21/244
+f 231/251/306 4/23/306 5/27/306
+f 12/2/307 239/239/307 11/25/307
+f 232/253/308 5/27/308 6/5/308
+f 239/239/248 12/2/248 13/1/248
+f 233/240/309 6/5/309 7/4/309
+f 240/241/251 13/1/251 14/263/251
+f 234/242/310 7/4/310 8/10/310
+f 228/261/253 1/13/253 2/12/253
+f 241/243/311 14/263/311 15/264/311
+f 235/244/255 8/10/255 9/17/255
+f 229/246/256 2/12/256 3/19/256
diff --git a/src/datavisualization/engine/meshes/sphereSmooth.obj b/src/datavisualization/engine/meshes/sphereSmooth.obj
new file mode 100644
index 00000000..3c5b1299
--- /dev/null
+++ b/src/datavisualization/engine/meshes/sphereSmooth.obj
@@ -0,0 +1,1232 @@
+# Blender v2.66 (sub 0) OBJ File: 'sphere.blend'
+# www.blender.org
+o Sphere
+v -0.195090 0.980785 0.000000
+v -0.382683 0.923880 0.000000
+v -0.555570 0.831470 0.000000
+v -0.707107 0.707107 0.000000
+v -0.831470 0.555570 0.000000
+v -0.923880 0.382683 0.000000
+v -0.980785 0.195090 0.000000
+v -1.000000 0.000000 0.000000
+v -0.980785 -0.195090 0.000000
+v -0.923880 -0.382683 0.000000
+v -0.831470 -0.555570 0.000000
+v -0.707107 -0.707107 0.000000
+v -0.555570 -0.831470 0.000000
+v -0.382683 -0.923880 0.000000
+v -0.195090 -0.980785 0.000000
+v -0.180240 0.980785 -0.074658
+v -0.353553 0.923880 -0.146447
+v -0.513280 0.831470 -0.212608
+v -0.653281 0.707107 -0.270598
+v -0.768178 0.555570 -0.318190
+v -0.853553 0.382683 -0.353553
+v -0.906127 0.195090 -0.375330
+v -0.923880 0.000000 -0.382684
+v -0.906127 -0.195090 -0.375330
+v -0.853553 -0.382683 -0.353554
+v -0.768178 -0.555570 -0.318190
+v -0.653281 -0.707107 -0.270598
+v -0.513280 -0.831470 -0.212608
+v -0.353553 -0.923880 -0.146447
+v -0.180240 -0.980785 -0.074658
+v 0.000000 -1.000000 0.000000
+v -0.137950 0.980785 -0.137950
+v -0.270598 0.923880 -0.270598
+v -0.392847 0.831470 -0.392848
+v -0.500000 0.707107 -0.500000
+v -0.587938 0.555570 -0.587938
+v -0.653281 0.382683 -0.653282
+v -0.693520 0.195090 -0.693520
+v -0.707107 0.000000 -0.707107
+v -0.693520 -0.195090 -0.693520
+v -0.653281 -0.382683 -0.653282
+v -0.587938 -0.555570 -0.587938
+v -0.500000 -0.707107 -0.500000
+v -0.392847 -0.831470 -0.392848
+v -0.270598 -0.923880 -0.270598
+v -0.137949 -0.980785 -0.137950
+v -0.074658 0.980785 -0.180240
+v -0.146446 0.923880 -0.353554
+v -0.212607 0.831470 -0.513280
+v -0.270598 0.707107 -0.653282
+v -0.318189 0.555570 -0.768178
+v -0.353553 0.382683 -0.853554
+v -0.375330 0.195090 -0.906128
+v -0.382683 0.000000 -0.923880
+v -0.375330 -0.195090 -0.906128
+v -0.353553 -0.382683 -0.853554
+v -0.318189 -0.555570 -0.768178
+v -0.270598 -0.707107 -0.653282
+v -0.212607 -0.831470 -0.513280
+v -0.146446 -0.923880 -0.353554
+v -0.074658 -0.980785 -0.180240
+v 0.000000 0.980785 -0.195091
+v 0.000000 0.923880 -0.382684
+v 0.000000 0.831470 -0.555570
+v 0.000000 0.707107 -0.707107
+v 0.000000 0.555570 -0.831470
+v 0.000000 0.382683 -0.923880
+v 0.000000 0.195090 -0.980785
+v 0.000000 0.000000 -1.000000
+v 0.000000 -0.195090 -0.980785
+v 0.000000 -0.382683 -0.923880
+v 0.000000 -0.555570 -0.831470
+v 0.000000 -0.707107 -0.707107
+v 0.000000 -0.831470 -0.555570
+v 0.000000 -0.923880 -0.382684
+v 0.000000 -0.980785 -0.195090
+v 0.074658 0.980785 -0.180240
+v 0.146447 0.923880 -0.353554
+v 0.212608 0.831470 -0.513280
+v 0.270598 0.707107 -0.653282
+v 0.318190 0.555570 -0.768178
+v 0.353554 0.382683 -0.853553
+v 0.375331 0.195090 -0.906128
+v 0.382684 0.000000 -0.923880
+v 0.375331 -0.195090 -0.906128
+v 0.353554 -0.382683 -0.853553
+v 0.318190 -0.555570 -0.768178
+v 0.270598 -0.707107 -0.653282
+v 0.212608 -0.831470 -0.513280
+v 0.146447 -0.923880 -0.353554
+v 0.074658 -0.980785 -0.180240
+v 0.137950 0.980785 -0.137950
+v 0.270599 0.923880 -0.270598
+v 0.392848 0.831470 -0.392848
+v 0.500000 0.707107 -0.500000
+v 0.587938 0.555570 -0.587938
+v 0.653282 0.382683 -0.653282
+v 0.693520 0.195090 -0.693520
+v 0.707107 0.000000 -0.707107
+v 0.693520 -0.195090 -0.693520
+v 0.653282 -0.382683 -0.653281
+v 0.587938 -0.555570 -0.587938
+v 0.500000 -0.707107 -0.500000
+v 0.392848 -0.831470 -0.392848
+v 0.270599 -0.923880 -0.270598
+v 0.137950 -0.980785 -0.137950
+v 0.180241 0.980785 -0.074658
+v 0.353554 0.923880 -0.146447
+v 0.513280 0.831470 -0.212608
+v 0.653282 0.707107 -0.270598
+v 0.768178 0.555570 -0.318190
+v 0.853554 0.382683 -0.353553
+v 0.906128 0.195090 -0.375330
+v 0.923880 0.000000 -0.382683
+v 0.906128 -0.195090 -0.375330
+v 0.853554 -0.382683 -0.353553
+v 0.768178 -0.555570 -0.318190
+v 0.653282 -0.707107 -0.270598
+v 0.513280 -0.831470 -0.212608
+v 0.353554 -0.923880 -0.146447
+v 0.180240 -0.980785 -0.074658
+v 0.195091 0.980785 0.000000
+v 0.382684 0.923880 0.000000
+v 0.555571 0.831470 0.000000
+v 0.707107 0.707107 0.000000
+v 0.831470 0.555570 0.000000
+v 0.923880 0.382683 0.000000
+v 0.980786 0.195090 0.000000
+v 1.000000 0.000000 0.000000
+v 0.980786 -0.195090 0.000000
+v 0.923880 -0.382683 0.000000
+v 0.831470 -0.555570 0.000000
+v 0.707107 -0.707107 0.000000
+v 0.555571 -0.831470 0.000000
+v 0.382684 -0.923880 0.000000
+v 0.195091 -0.980785 0.000000
+v 0.180241 0.980785 0.074658
+v 0.353554 0.923880 0.146447
+v 0.513280 0.831470 0.212608
+v 0.653282 0.707107 0.270598
+v 0.768178 0.555570 0.318190
+v 0.853554 0.382683 0.353553
+v 0.906128 0.195090 0.375330
+v 0.923880 0.000000 0.382684
+v 0.906128 -0.195090 0.375330
+v 0.853554 -0.382683 0.353553
+v 0.768178 -0.555570 0.318190
+v 0.653282 -0.707107 0.270598
+v 0.513280 -0.831470 0.212608
+v 0.353554 -0.923880 0.146447
+v 0.180240 -0.980785 0.074658
+v 0.137950 0.980785 0.137950
+v 0.270599 0.923880 0.270598
+v 0.392848 0.831470 0.392848
+v 0.500000 0.707107 0.500000
+v 0.587938 0.555570 0.587938
+v 0.653282 0.382683 0.653282
+v 0.693520 0.195090 0.693520
+v 0.707107 0.000000 0.707107
+v 0.693520 -0.195090 0.693520
+v 0.653282 -0.382683 0.653282
+v 0.587938 -0.555570 0.587938
+v 0.500000 -0.707107 0.500000
+v 0.392848 -0.831470 0.392848
+v 0.270599 -0.923880 0.270598
+v 0.137950 -0.980785 0.137950
+v 0.074658 0.980785 0.180240
+v 0.146447 0.923880 0.353554
+v 0.212608 0.831470 0.513280
+v 0.270598 0.707107 0.653282
+v 0.318190 0.555570 0.768178
+v 0.353554 0.382683 0.853553
+v 0.375331 0.195090 0.906128
+v 0.382684 0.000000 0.923880
+v 0.375331 -0.195090 0.906128
+v 0.353554 -0.382683 0.853553
+v 0.318190 -0.555570 0.768178
+v 0.270598 -0.707107 0.653282
+v 0.212608 -0.831470 0.513280
+v 0.146447 -0.923880 0.353554
+v 0.074658 -0.980785 0.180240
+v 0.000000 0.980785 0.195091
+v 0.000000 0.923880 0.382684
+v 0.000000 0.831470 0.555570
+v 0.000000 0.707107 0.707107
+v 0.000000 0.555570 0.831470
+v 0.000000 0.382683 0.923880
+v 0.000000 0.195090 0.980785
+v 0.000000 0.000000 1.000000
+v 0.000000 -0.195090 0.980785
+v 0.000000 -0.382683 0.923879
+v 0.000000 -0.555570 0.831470
+v 0.000000 -0.707107 0.707107
+v 0.000000 -0.831470 0.555570
+v 0.000000 -0.923880 0.382684
+v 0.000000 -0.980785 0.195090
+v -0.074658 0.980785 0.180240
+v -0.146446 0.923880 0.353554
+v -0.212607 0.831470 0.513280
+v -0.270598 0.707107 0.653282
+v -0.318189 0.555570 0.768178
+v -0.353553 0.382683 0.853553
+v -0.375330 0.195090 0.906128
+v -0.382683 0.000000 0.923880
+v -0.375330 -0.195090 0.906128
+v -0.353553 -0.382683 0.853553
+v -0.318189 -0.555570 0.768178
+v -0.270598 -0.707107 0.653282
+v -0.212607 -0.831470 0.513280
+v -0.146446 -0.923880 0.353554
+v -0.074658 -0.980785 0.180240
+v 0.000000 1.000000 0.000000
+v -0.137950 0.980785 0.137950
+v -0.270598 0.923880 0.270598
+v -0.392847 0.831470 0.392848
+v -0.500000 0.707107 0.500000
+v -0.587938 0.555570 0.587938
+v -0.653281 0.382683 0.653281
+v -0.693520 0.195090 0.693520
+v -0.707107 0.000000 0.707107
+v -0.693520 -0.195090 0.693520
+v -0.653281 -0.382683 0.653281
+v -0.587938 -0.555570 0.587938
+v -0.500000 -0.707107 0.500000
+v -0.392847 -0.831470 0.392848
+v -0.270598 -0.923880 0.270598
+v -0.137949 -0.980785 0.137950
+v -0.180240 0.980785 0.074658
+v -0.353553 0.923880 0.146447
+v -0.513280 0.831470 0.212608
+v -0.653281 0.707107 0.270598
+v -0.768177 0.555570 0.318190
+v -0.853553 0.382683 0.353553
+v -0.906127 0.195090 0.375330
+v -0.923879 0.000000 0.382683
+v -0.906127 -0.195090 0.375330
+v -0.853553 -0.382683 0.353553
+v -0.768177 -0.555570 0.318190
+v -0.653281 -0.707107 0.270598
+v -0.513280 -0.831470 0.212608
+v -0.353553 -0.923880 0.146447
+v -0.180240 -0.980785 0.074658
+vt 0.040867 0.325557
+vt 0.048386 0.386583
+vt 0.001015 0.334499
+vt 0.081872 0.692529
+vt 0.092315 0.752973
+vt 0.006404 0.709363
+vt 1.031336 0.264931
+vt 1.040867 0.325557
+vt 0.999822 0.272029
+vt 0.073887 0.631595
+vt 0.005301 0.646891
+vt 0.333915 0.937286
+vt 0.448527 0.905466
+vt 0.447682 0.976645
+vt 1.017784 0.205113
+vt 0.998129 0.209571
+vt 0.067156 0.570413
+vt 0.004397 0.584414
+vt 0.196016 0.918498
+vt 0.034176 0.958662
+vt 0.060989 0.509119
+vt 0.003585 0.521934
+vt 0.135028 0.869370
+vt 0.015221 0.896641
+vt 0.054891 0.447811
+vt 0.002796 0.459454
+vt 0.107782 0.812401
+vt 0.010297 0.834265
+vt 0.001965 0.396975
+vt 0.007907 0.771825
+vt 0.978319 0.207096
+vt 1.004397 0.584414
+vt 1.005301 0.646891
+vt 0.941200 0.576589
+vt 1.034176 0.958662
+vt 0.823807 0.933258
+vt 1.003585 0.521934
+vt 0.945911 0.514786
+vt 1.015221 0.896641
+vt 0.885287 0.880701
+vt 1.002796 0.459454
+vt 0.950535 0.452971
+vt 1.010297 0.834265
+vt 0.908873 0.821779
+vt 1.001965 0.396975
+vt 0.955439 0.391196
+vt 1.007907 0.771825
+vt 0.921503 0.761167
+vt 1.001015 0.334499
+vt 0.961079 0.329532
+vt 1.006404 0.709363
+vt 0.929787 0.699898
+vt 0.968202 0.268089
+vt 0.936013 0.638321
+vt 0.488610 0.915189
+vt 0.647808 0.950687
+vt 0.921611 0.311033
+vt 0.859136 0.666985
+vt 0.937209 0.253354
+vt 0.870446 0.607941
+vt 0.532175 0.909643
+vt 0.657607 0.903302
+vt 0.959449 0.197860
+vt 0.880347 0.548455
+vt 0.745300 0.879338
+vt 0.889690 0.488794
+vt 0.796385 0.834663
+vt 0.899158 0.429173
+vt 0.825891 0.781668
+vt 0.909472 0.369816
+vt 0.845097 0.725165
+vt 0.848920 0.390841
+vt 0.761226 0.728711
+vt 0.864196 0.334814
+vt 0.780693 0.674598
+vt 0.882867 0.280332
+vt 0.796418 0.618773
+vt 0.907539 0.228698
+vt 0.810089 0.562031
+vt 0.558962 0.891763
+vt 0.641452 0.857179
+vt 0.942759 0.182515
+vt 0.822818 0.504873
+vt 0.697492 0.824480
+vt 0.835477 0.447684
+vt 0.735147 0.779653
+vt 0.879896 0.195479
+vt 0.753309 0.508011
+vt 0.618082 0.815427
+vt 0.767315 0.452094
+vt 0.657173 0.773912
+vt 0.782092 0.396562
+vt 0.685241 0.725518
+vt 0.798714 0.341964
+vt 0.706593 0.673391
+vt 0.818709 0.289116
+vt 0.723996 0.619193
+vt 0.844487 0.239416
+vt 0.739178 0.563865
+vt 0.567268 0.868303
+vt 0.563300 0.844314
+vt 0.770454 0.236269
+vt 0.670392 0.566231
+vt 0.805029 0.190637
+vt 0.683774 0.509644
+vt 0.551952 0.822879
+vt 0.929896 0.162212
+vt 0.855308 0.155368
+vt 0.697011 0.452991
+vt 0.591182 0.780044
+vt 0.710973 0.396675
+vt 0.618699 0.730484
+vt 0.726705 0.341193
+vt 0.639317 0.677374
+vt 0.745717 0.287291
+vt 0.655961 0.622327
+vt 0.665037 0.288362
+vt 0.594131 0.638967
+vt 0.684737 0.232805
+vt 0.605914 0.580518
+vt 0.713639 0.180821
+vt 0.616615 0.521685
+vt 0.760428 0.136665
+vt 0.627046 0.462757
+vt 0.536166 0.805967
+vt 0.923407 0.138703
+vt 0.836350 0.110271
+vt 0.637946 0.403995
+vt 0.562017 0.752770
+vt 0.650183 0.345708
+vt 0.580132 0.696622
+vt 0.517784 0.794886
+vt 0.927547 0.114679
+vt 0.833915 0.062714
+vt 0.573887 0.368405
+vt 0.531336 0.735069
+vt 0.581872 0.307471
+vt 0.540867 0.674443
+vt 0.592315 0.247027
+vt 0.548386 0.613417
+vt 0.607782 0.187599
+vt 0.554891 0.552189
+vt 0.635028 0.130630
+vt 0.560989 0.490881
+vt 0.696016 0.081502
+vt 0.567156 0.429587
+vt 0.502796 0.540546
+vt 0.515221 0.103359
+vt 0.503585 0.478066
+vt 0.534176 0.041338
+vt 0.504397 0.415586
+vt 0.498129 0.790428
+vt 0.948527 0.094534
+vt 0.947682 0.023355
+vt 0.505301 0.353109
+vt 0.499822 0.727971
+vt 0.506404 0.290637
+vt 0.501015 0.665501
+vt 0.507907 0.228175
+vt 0.501965 0.603025
+vt 0.510297 0.165735
+vt 0.429787 0.300102
+vt 0.461079 0.670468
+vt 0.421503 0.238833
+vt 0.455439 0.608804
+vt 0.408873 0.178221
+vt 0.445911 0.485214
+vt 0.385287 0.119299
+vt 1.323807 0.066742
+vt 0.441200 0.423411
+vt 0.478319 0.792904
+vt 0.988610 0.084811
+vt 1.147808 0.049313
+vt 0.436013 0.361679
+vt 0.468202 0.731911
+vt 0.147808 0.049313
+vt 0.323807 0.066742
+vt 0.245300 0.120661
+vt 0.380347 0.451545
+vt 0.459449 0.802140
+vt 0.032175 0.090357
+vt 0.157607 0.096698
+vt 0.370446 0.392059
+vt 0.437209 0.746646
+vt 0.359136 0.333015
+vt 0.421611 0.688967
+vt 0.345097 0.274835
+vt 0.450536 0.547029
+vt 0.409472 0.630184
+vt 0.325892 0.218332
+vt 0.399158 0.570827
+vt 0.296385 0.165337
+vt 0.389690 0.511206
+vt 0.261226 0.271289
+vt 0.348920 0.609159
+vt 0.235147 0.220347
+vt 0.335478 0.552316
+vt 0.197492 0.175520
+vt 0.322818 0.495127
+vt 0.442759 0.817485
+vt 0.058962 0.108237
+vt 0.141452 0.142821
+vt 0.310089 0.437969
+vt 0.407539 0.771302
+vt 0.296418 0.381227
+vt 0.382867 0.719668
+vt 0.280693 0.325402
+vt 0.364196 0.665186
+vt 0.223996 0.380807
+vt 0.318709 0.710884
+vt 0.206593 0.326609
+vt 0.298714 0.658036
+vt 0.185241 0.274482
+vt 0.282092 0.603438
+vt 0.157173 0.226088
+vt 0.267315 0.547906
+vt 0.118082 0.184573
+vt 0.253309 0.491989
+vt 0.379896 0.804521
+vt 0.067268 0.131697
+vt 0.063300 0.155685
+vt 0.239178 0.436135
+vt 0.344487 0.760584
+vt 0.091182 0.219955
+vt 0.197011 0.547009
+vt 0.429896 0.837788
+vt 0.355308 0.844632
+vt 0.051952 0.177121
+vt 0.183774 0.490356
+vt 0.305029 0.809363
+vt 0.170392 0.433769
+vt 0.270454 0.763731
+vt 0.155961 0.377673
+vt 0.245717 0.712709
+vt 0.226706 0.658807
+vt 0.118699 0.269516
+vt 0.210973 0.603325
+vt 0.139317 0.322626
+vt 0.094131 0.361033
+vt 0.165037 0.711638
+vt 0.080132 0.303378
+vt 0.150183 0.654292
+vt 0.062017 0.247229
+vt 0.137946 0.596005
+vt 0.423407 0.861296
+vt 0.336350 0.889729
+vt 0.036166 0.194032
+vt 0.127046 0.537243
+vt 0.260428 0.863335
+vt 0.116615 0.478315
+vt 0.213639 0.819179
+vt 0.105914 0.419482
+vt 0.184737 0.767195
+vt 0.495265 0.852856
+vt 0.995265 0.147143
+vt 1.032175 0.090357
+vt 1.058962 0.108237
+vt 1.067268 0.131697
+vt 1.063300 0.155685
+vt 1.051952 0.177121
+vt 0.427547 0.885321
+vt 1.036166 0.194032
+vt 0.031336 0.264931
+vt 0.017784 0.205113
+vn -0.563891 -0.825831 0.000000
+vn -0.713095 -0.701041 0.000000
+vn -0.520981 -0.825831 -0.215796
+vn -0.981231 0.192785 0.000000
+vn -0.925596 0.378430 0.000000
+vn -0.906522 0.192785 -0.375500
+vn -0.393017 -0.919523 0.000000
+vn -0.363109 -0.919523 -0.150395
+vn -1.000000 0.000000 0.000000
+vn -0.923856 0.000000 -0.382672
+vn -0.393017 0.919523 0.000000
+vn -0.206793 0.978362 0.000000
+vn -0.363109 0.919523 -0.150395
+vn -0.206793 -0.978362 0.000000
+vn -0.191046 -0.978362 -0.079134
+vn -0.981231 -0.192785 0.000000
+vn -0.906522 -0.192785 -0.375500
+vn -0.563891 0.825831 0.000000
+vn -0.520981 0.825831 -0.215796
+vn -0.925596 -0.378430 0.000000
+vn -0.855159 -0.378430 -0.354198
+vn -0.713095 0.701041 0.000000
+vn -0.658803 0.701041 -0.272866
+vn -0.835139 -0.550005 0.000000
+vn -0.771569 -0.550005 -0.319590
+vn -0.835139 0.550005 0.000000
+vn -0.771569 0.550005 -0.319590
+vn -0.658803 -0.701041 -0.272866
+vn -0.855159 0.378430 -0.354198
+vn -0.146214 -0.978362 -0.146214
+vn -0.693838 -0.192785 -0.693838
+vn -0.398724 0.825831 -0.398724
+vn -0.654500 -0.378430 -0.654500
+vn -0.504227 0.701041 -0.504227
+vn -0.590533 -0.550005 -0.590533
+vn -0.590533 0.550005 -0.590533
+vn -0.504227 -0.701041 -0.504227
+vn -0.654500 0.378430 -0.654500
+vn -0.398724 -0.825831 -0.398724
+vn -0.693838 0.192785 -0.693838
+vn -0.277902 -0.919523 -0.277902
+vn -0.707083 0.000000 -0.707083
+vn -0.191046 0.978362 -0.079134
+vn -0.277902 0.919523 -0.277902
+vn -0.215796 -0.825831 -0.520981
+vn -0.375500 0.192785 -0.906522
+vn -0.150395 -0.919523 -0.363109
+vn -0.382672 0.000000 -0.923856
+vn -0.146214 0.978362 -0.146214
+vn -0.150395 0.919523 -0.363109
+vn -0.079134 -0.978362 -0.191046
+vn -0.375500 -0.192785 -0.906522
+vn -0.215796 0.825831 -0.520981
+vn -0.354198 -0.378430 -0.855159
+vn -0.272866 0.701041 -0.658803
+vn -0.319590 -0.550005 -0.771569
+vn -0.319590 0.550005 -0.771569
+vn -0.272866 -0.701041 -0.658803
+vn -0.354198 0.378430 -0.855159
+vn 0.000000 -0.550005 -0.835139
+vn 0.000000 0.550005 -0.835139
+vn 0.000000 -0.701041 -0.713095
+vn 0.000000 0.378430 -0.925596
+vn 0.000000 -0.825831 -0.563891
+vn 0.000000 0.192785 -0.981231
+vn 0.000000 -0.919523 -0.393017
+vn 0.000000 0.000000 -1.000000
+vn -0.079134 0.978362 -0.191046
+vn 0.000000 0.919523 -0.393017
+vn 0.000000 -0.978362 -0.206793
+vn 0.000000 -0.192785 -0.981231
+vn 0.000000 0.825831 -0.563891
+vn 0.000000 -0.378430 -0.925596
+vn 0.000000 0.701041 -0.713095
+vn 0.150395 -0.919523 -0.363109
+vn 0.382672 0.000000 -0.923856
+vn 0.150395 0.919523 -0.363109
+vn 0.375500 -0.192785 -0.906522
+vn 0.215796 0.825831 -0.520981
+vn 0.354198 -0.378430 -0.855159
+vn 0.272866 0.701041 -0.658803
+vn 0.319590 -0.550005 -0.771569
+vn 0.319590 0.550005 -0.771569
+vn 0.272866 -0.701041 -0.658803
+vn 0.354198 0.378430 -0.855159
+vn 0.215796 -0.825831 -0.520981
+vn 0.375500 0.192785 -0.906522
+vn 0.000000 0.978362 -0.206793
+vn 0.079134 0.978362 -0.191046
+vn 0.504227 -0.701041 -0.504227
+vn 0.654500 0.378430 -0.654500
+vn 0.398724 -0.825831 -0.398724
+vn 0.693838 0.192785 -0.693838
+vn 0.146214 0.978362 -0.146214
+vn 0.079134 -0.978362 -0.191046
+vn 0.277902 -0.919523 -0.277902
+vn 0.707083 0.000000 -0.707083
+vn 0.277902 0.919523 -0.277902
+vn 0.693838 -0.192785 -0.693838
+vn 0.398724 0.825831 -0.398724
+vn 0.654500 -0.378430 -0.654500
+vn 0.504227 0.701041 -0.504227
+vn 0.590533 -0.550005 -0.590533
+vn 0.590533 0.550005 -0.590533
+vn 0.855159 -0.378430 -0.354198
+vn 0.658803 0.701041 -0.272866
+vn 0.771569 -0.550005 -0.319590
+vn 0.771569 0.550005 -0.319590
+vn 0.658803 -0.701041 -0.272866
+vn 0.855159 0.378430 -0.354198
+vn 0.520981 -0.825831 -0.215796
+vn 0.906522 0.192785 -0.375500
+vn 0.191046 0.978362 -0.079134
+vn 0.146214 -0.978362 -0.146214
+vn 0.363109 -0.919523 -0.150395
+vn 0.923856 0.000000 -0.382672
+vn 0.363109 0.919523 -0.150395
+vn 0.906522 -0.192785 -0.375500
+vn 0.520981 0.825831 -0.215796
+vn 0.206793 0.978362 0.000000
+vn 0.191046 -0.978362 -0.079134
+vn 0.393017 -0.919523 0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.393017 0.919523 0.000000
+vn 0.981231 -0.192785 0.000000
+vn 0.563891 0.825831 0.000000
+vn 0.925596 -0.378430 0.000000
+vn 0.713095 0.701041 0.000000
+vn 0.835139 -0.550005 0.000000
+vn 0.835139 0.550005 0.000000
+vn 0.713095 -0.701041 0.000000
+vn 0.925596 0.378430 0.000000
+vn 0.563891 -0.825831 0.000000
+vn 0.981231 0.192785 0.000000
+vn 0.771569 0.550005 0.319590
+vn 0.658803 -0.701041 0.272866
+vn 0.855159 0.378430 0.354198
+vn 0.520981 -0.825831 0.215796
+vn 0.906522 0.192785 0.375500
+vn 0.191046 0.978362 0.079134
+vn 0.206793 -0.978362 0.000000
+vn 0.363109 -0.919523 0.150395
+vn 0.923856 0.000000 0.382672
+vn 0.363109 0.919523 0.150395
+vn 0.906522 -0.192785 0.375500
+vn 0.520981 0.825831 0.215796
+vn 0.855159 -0.378430 0.354198
+vn 0.658803 0.701041 0.272866
+vn 0.771569 -0.550005 0.319590
+vn 0.693838 -0.192785 0.693838
+vn 0.398724 0.825831 0.398724
+vn 0.654500 -0.378430 0.654500
+vn 0.504227 0.701041 0.504227
+vn 0.590533 -0.550005 0.590533
+vn 0.654500 0.378430 0.654500
+vn 0.504227 -0.701041 0.504227
+vn 0.398724 -0.825831 0.398724
+vn 0.693838 0.192785 0.693838
+vn 0.146214 0.978362 0.146214
+vn 0.191046 -0.978362 0.079134
+vn 0.277902 -0.919523 0.277902
+vn 0.707083 0.000000 0.707083
+vn 0.277902 0.919523 0.277902
+vn 0.215796 -0.825831 0.520981
+vn 0.375500 0.192785 0.906522
+vn 0.079134 0.978362 0.191046
+vn 0.146214 -0.978362 0.146214
+vn 0.150395 -0.919523 0.363109
+vn 0.382672 0.000000 0.923856
+vn 0.150395 0.919523 0.363109
+vn 0.375500 -0.192785 0.906522
+vn 0.215796 0.825831 0.520981
+vn 0.354198 -0.378430 0.855159
+vn 0.590533 0.550005 0.590533
+vn 0.272866 0.701041 0.658803
+vn 0.319590 -0.550005 0.771569
+vn 0.319590 0.550005 0.771569
+vn 0.272866 -0.701041 0.658803
+vn 0.354198 0.378430 0.855159
+vn 0.000000 -0.550005 0.835139
+vn 0.000000 0.550005 0.835139
+vn 0.000000 -0.701041 0.713095
+vn 0.000000 0.378430 0.925596
+vn 0.000000 -0.825831 0.563891
+vn 0.000000 0.192785 0.981231
+vn 0.000000 0.978362 0.206793
+vn 0.079134 -0.978362 0.191046
+vn 0.000000 -0.919523 0.393017
+vn 0.000000 0.000000 1.000000
+vn 0.000000 0.919523 0.393017
+vn 0.000000 -0.192785 0.981231
+vn 0.000000 0.825831 0.563891
+vn 0.000000 -0.378430 0.925596
+vn 0.000000 0.701041 0.713095
+vn -0.354198 -0.378430 0.855159
+vn -0.272866 0.701041 0.658803
+vn -0.319590 -0.550005 0.771569
+vn -0.319590 0.550005 0.771569
+vn -0.272866 -0.701041 0.658803
+vn -0.354198 0.378430 0.855159
+vn -0.215796 -0.825831 0.520981
+vn -0.375500 0.192785 0.906522
+vn -0.150395 -0.919523 0.363109
+vn -0.382672 0.000000 0.923856
+vn -0.150395 0.919523 0.363109
+vn 0.000000 -0.978362 0.206793
+vn -0.079134 -0.978362 0.191046
+vn -0.375500 -0.192785 0.906522
+vn -0.215796 0.825831 0.520981
+vn -0.277902 -0.919523 0.277902
+vn -0.707083 0.000000 0.707083
+vn -0.079134 0.978362 0.191046
+vn -0.277902 0.919523 0.277902
+vn -0.146214 -0.978362 0.146214
+vn -0.693838 -0.192785 0.693838
+vn -0.398724 0.825831 0.398724
+vn -0.654500 -0.378430 0.654500
+vn -0.504227 0.701041 0.504227
+vn -0.590533 -0.550005 0.590533
+vn -0.590533 0.550005 0.590533
+vn -0.654500 0.378430 0.654500
+vn -0.398724 -0.825831 0.398724
+vn -0.693838 0.192785 0.693838
+vn -0.504227 -0.701041 0.504227
+vn -0.658803 -0.701041 0.272866
+vn -0.855159 0.378430 0.354198
+vn -0.520981 -0.825831 0.215796
+vn -0.906522 0.192785 0.375500
+vn -0.363109 -0.919523 0.150395
+vn -0.923856 0.000000 0.382672
+vn -0.146214 0.978362 0.146214
+vn -0.363109 0.919523 0.150395
+vn -0.191046 -0.978362 0.079134
+vn -0.906522 -0.192785 0.375500
+vn -0.520981 0.825831 0.215796
+vn -0.855159 -0.378430 0.354198
+vn -0.658803 0.701041 0.272866
+vn -0.771569 -0.550005 0.319590
+vn -0.771569 0.550005 0.319590
+vn 0.000000 0.999969 0.000000
+vn 0.000000 -1.000000 0.000000
+vn -0.191046 0.978362 0.079134
+s 1
+f 13/1/1 12/2/2 28/3/3
+f 7/4/4 6/5/5 22/6/6
+f 14/7/7 13/8/1 29/9/8
+f 8/10/9 7/4/4 23/11/10
+f 2/12/11 1/13/12 17/14/13
+f 15/15/14 14/7/7 30/16/15
+f 9/17/16 8/10/9 24/18/17
+f 3/19/18 2/12/11 18/20/19
+f 10/21/20 9/17/16 25/22/21
+f 4/23/22 3/19/18 19/24/23
+f 11/25/24 10/21/20 26/26/25
+f 5/27/26 4/23/22 20/28/27
+f 12/2/2 11/25/24 27/29/28
+f 6/5/5 5/27/26 21/30/29
+f 30/16/15 29/9/8 46/31/30
+f 24/32/17 23/33/10 40/34/31
+f 18/35/19 17/14/13 34/36/32
+f 25/37/21 24/32/17 41/38/33
+f 19/39/23 18/35/19 35/40/34
+f 26/41/25 25/37/21 42/42/35
+f 20/43/27 19/39/23 36/44/36
+f 27/45/28 26/41/25 43/46/37
+f 21/47/29 20/43/27 37/48/38
+f 28/49/3 27/45/28 44/50/39
+f 22/51/6 21/47/29 38/52/40
+f 29/9/8 28/49/3 45/53/41
+f 23/33/10 22/51/6 39/54/42
+f 17/14/13 16/55/43 33/56/44
+f 44/50/39 43/46/37 59/57/45
+f 38/52/40 37/48/38 53/58/46
+f 45/53/41 44/50/39 60/59/47
+f 39/54/42 38/52/40 54/60/48
+f 33/56/44 32/61/49 48/62/50
+f 46/31/30 45/53/41 61/63/51
+f 40/34/31 39/54/42 55/64/52
+f 34/36/32 33/56/44 49/65/53
+f 41/38/33 40/34/31 56/66/54
+f 35/40/34 34/36/32 50/67/55
+f 42/42/35 41/38/33 57/68/56
+f 36/44/36 35/40/34 51/69/57
+f 43/46/37 42/42/35 58/70/58
+f 37/48/38 36/44/36 52/71/59
+f 57/68/56 56/66/54 72/72/60
+f 51/69/57 50/67/55 66/73/61
+f 58/70/58 57/68/56 73/74/62
+f 52/71/59 51/69/57 67/75/63
+f 59/57/45 58/70/58 74/76/64
+f 53/58/46 52/71/59 68/77/65
+f 60/59/47 59/57/45 75/78/66
+f 54/60/48 53/58/46 69/79/67
+f 48/62/50 47/80/68 63/81/69
+f 61/63/51 60/59/47 76/82/70
+f 55/64/52 54/60/48 70/83/71
+f 49/65/53 48/62/50 64/84/72
+f 56/66/54 55/64/52 71/85/73
+f 50/67/55 49/65/53 65/86/74
+f 76/82/70 75/78/66 90/87/75
+f 70/83/71 69/79/67 84/88/76
+f 64/84/72 63/81/69 78/89/77
+f 71/85/73 70/83/71 85/90/78
+f 65/86/74 64/84/72 79/91/79
+f 72/72/60 71/85/73 86/92/80
+f 66/73/61 65/86/74 80/93/81
+f 73/74/62 72/72/60 87/94/82
+f 67/75/63 66/73/61 81/95/83
+f 74/76/64 73/74/62 88/96/84
+f 68/77/65 67/75/63 82/97/85
+f 75/78/66 74/76/64 89/98/86
+f 69/79/67 68/77/65 83/99/87
+f 63/81/69 62/100/88 77/101/89
+f 89/98/86 88/96/84 103/102/90
+f 83/99/87 82/97/85 97/103/91
+f 90/87/75 89/98/86 104/104/92
+f 84/88/76 83/99/87 98/105/93
+f 78/89/77 77/101/89 92/106/94
+f 91/107/95 90/87/75 105/108/96
+f 85/90/78 84/88/76 99/109/97
+f 79/91/79 78/89/77 93/110/98
+f 86/92/80 85/90/78 100/111/99
+f 80/93/81 79/91/79 94/112/100
+f 87/94/82 86/92/80 101/113/101
+f 81/95/83 80/93/81 95/114/102
+f 88/96/84 87/94/82 102/115/103
+f 82/97/85 81/95/83 96/116/104
+f 102/115/103 101/113/101 116/117/105
+f 96/116/104 95/114/102 110/118/106
+f 103/102/90 102/115/103 117/119/107
+f 97/103/91 96/116/104 111/120/108
+f 104/104/92 103/102/90 118/121/109
+f 98/105/93 97/103/91 112/122/110
+f 105/108/96 104/104/92 119/123/111
+f 99/109/97 98/105/93 113/124/112
+f 93/110/98 92/106/94 107/125/113
+f 106/126/114 105/108/96 120/127/115
+f 100/111/99 99/109/97 114/128/116
+f 94/112/100 93/110/98 108/129/117
+f 101/113/101 100/111/99 115/130/118
+f 95/114/102 94/112/100 109/131/119
+f 108/129/117 107/125/113 122/132/120
+f 121/133/121 120/127/115 135/134/122
+f 115/130/118 114/128/116 129/135/123
+f 109/131/119 108/129/117 123/136/124
+f 116/117/105 115/130/118 130/137/125
+f 110/118/106 109/131/119 124/138/126
+f 117/119/107 116/117/105 131/139/127
+f 111/120/108 110/118/106 125/140/128
+f 118/121/109 117/119/107 132/141/129
+f 112/122/110 111/120/108 126/142/130
+f 119/123/111 118/121/109 133/143/131
+f 113/124/112 112/122/110 127/144/132
+f 120/127/115 119/123/111 134/145/133
+f 114/128/116 113/124/112 128/146/134
+f 127/144/132 126/142/130 141/147/135
+f 134/145/133 133/143/131 148/148/136
+f 128/146/134 127/144/132 142/149/137
+f 135/134/122 134/145/133 149/150/138
+f 129/135/123 128/146/134 143/151/139
+f 123/136/124 122/132/120 137/152/140
+f 136/153/141 135/134/122 150/154/142
+f 130/137/125 129/135/123 144/155/143
+f 124/138/126 123/136/124 138/156/144
+f 131/139/127 130/137/125 145/157/145
+f 125/140/128 124/138/126 139/158/146
+f 132/141/129 131/139/127 146/159/147
+f 126/142/130 125/140/128 140/160/148
+f 133/143/131 132/141/129 147/161/149
+f 146/159/147 145/157/145 160/162/150
+f 140/160/148 139/158/146 154/163/151
+f 147/161/149 146/159/147 161/164/152
+f 141/147/135 140/160/148 155/165/153
+f 148/148/136 147/161/149 162/166/154
+f 142/149/137 141/147/135 157/167/155
+f 149/150/138 148/148/136 163/168/156
+f 143/151/139 142/149/137 157/167/155
+f 150/154/142 149/150/138 164/169/157
+f 144/155/143 143/151/139 158/170/158
+f 138/156/144 137/152/140 152/171/159
+f 151/172/160 150/154/142 165/173/161
+f 145/157/145 144/155/143 159/174/162
+f 139/158/146 138/156/144 153/175/163
+f 165/176/161 164/177/157 179/178/164
+f 159/174/162 158/170/158 173/179/165
+f 153/175/163 152/171/159 167/180/166
+f 166/181/167 165/176/161 180/182/168
+f 160/162/150 159/174/162 174/183/169
+f 154/163/151 153/175/163 168/184/170
+f 161/164/152 160/162/150 175/185/171
+f 155/165/153 154/163/151 169/186/172
+f 162/166/154 161/164/152 176/187/173
+f 156/188/174 155/165/153 170/189/175
+f 163/168/156 162/166/154 177/190/176
+f 157/167/155 156/188/174 171/191/177
+f 164/177/157 163/168/156 178/192/178
+f 158/170/158 157/167/155 172/193/179
+f 178/192/178 177/190/176 192/194/180
+f 172/193/179 171/191/177 186/195/181
+f 179/178/164 178/192/178 193/196/182
+f 173/179/165 172/193/179 187/197/183
+f 180/182/168 179/178/164 194/198/184
+f 174/183/169 173/179/165 188/199/185
+f 168/184/170 167/180/166 182/200/186
+f 181/201/187 180/182/168 195/202/188
+f 175/185/171 174/183/169 189/203/189
+f 169/186/172 168/184/170 183/204/190
+f 176/187/173 175/185/171 190/205/191
+f 170/189/175 169/186/172 184/206/192
+f 177/190/176 176/187/173 191/207/193
+f 171/191/177 170/189/175 185/208/194
+f 191/207/193 190/205/191 206/209/195
+f 185/208/194 184/206/192 200/210/196
+f 192/194/180 191/207/193 207/211/197
+f 186/195/181 185/208/194 201/212/198
+f 193/196/182 192/194/180 208/213/199
+f 187/197/183 186/195/181 202/214/200
+f 194/198/184 193/196/182 209/215/201
+f 188/199/185 187/197/183 203/216/202
+f 195/202/188 194/198/184 210/217/203
+f 189/203/189 188/199/185 204/218/204
+f 183/204/190 182/200/186 198/219/205
+f 196/220/206 195/202/188 211/221/207
+f 190/205/191 189/203/189 205/222/208
+f 184/206/192 183/204/190 199/223/209
+f 210/217/203 209/215/201 226/224/210
+f 204/218/204 203/216/202 220/225/211
+f 198/219/205 197/226/212 214/227/213
+f 211/221/207 210/217/203 227/228/214
+f 205/222/208 204/218/204 221/229/215
+f 199/223/209 198/219/205 215/230/216
+f 206/209/195 205/222/208 222/231/217
+f 200/210/196 199/223/209 216/232/218
+f 207/211/197 206/209/195 223/233/219
+f 201/212/198 200/210/196 217/234/220
+f 208/213/199 207/211/197 223/233/219
+f 202/214/200 201/212/198 218/235/221
+f 209/215/201 208/213/199 225/236/222
+f 203/216/202 202/214/200 219/237/223
+f 224/238/224 223/233/219 239/239/225
+f 218/235/221 217/234/220 233/240/226
+f 225/236/222 224/238/224 240/241/227
+f 219/237/223 218/235/221 234/242/228
+f 226/224/210 225/236/222 241/243/229
+f 220/225/211 219/237/223 235/244/230
+f 214/227/213 213/245/231 229/246/232
+f 227/228/214 226/224/210 242/247/233
+f 221/229/215 220/225/211 236/248/234
+f 215/230/216 214/227/213 230/249/235
+f 222/231/217 221/229/215 237/250/236
+f 216/232/218 215/230/216 231/251/237
+f 223/233/219 222/231/217 238/252/238
+f 217/234/220 216/232/218 232/253/239
+f 1/13/12 212/254/240 16/55/43
+f 31/255/241 15/15/14 30/16/15
+f 31/255/241 30/16/15 46/31/30
+f 16/55/43 212/254/240 32/61/49
+f 32/61/49 212/254/240 47/80/68
+f 31/255/241 46/31/30 61/63/51
+f 47/80/68 212/254/240 62/100/88
+f 31/255/241 61/63/51 76/82/70
+f 31/255/241 76/82/70 91/107/95
+f 62/100/88 212/254/240 77/101/89
+f 77/101/89 212/254/240 92/106/94
+f 31/255/241 91/107/95 106/126/114
+f 92/106/94 212/254/240 107/125/113
+f 31/255/241 106/126/114 121/133/121
+f 31/255/241 121/133/121 136/153/141
+f 107/125/113 212/254/240 122/132/120
+f 122/132/120 212/254/240 137/152/140
+f 31/255/241 136/153/141 151/172/160
+f 137/152/140 212/254/240 152/171/159
+f 31/255/241 151/172/160 166/256/167
+f 31/255/241 166/256/167 181/257/187
+f 152/171/159 212/254/240 167/180/166
+f 167/180/166 212/254/240 182/200/186
+f 31/255/241 181/257/187 196/258/206
+f 31/255/241 196/258/206 211/259/207
+f 182/200/186 212/254/240 197/226/212
+f 31/255/241 211/259/207 227/260/214
+f 197/226/212 212/254/240 213/245/231
+f 213/245/231 212/254/240 228/261/242
+f 31/255/241 227/260/214 242/262/233
+f 31/255/241 242/262/233 15/15/14
+f 237/250/236 236/248/234 10/21/20
+f 231/251/237 230/249/235 4/23/22
+f 238/252/238 237/250/236 10/21/20
+f 232/253/239 231/251/237 5/27/26
+f 239/239/225 238/252/238 11/25/24
+f 233/240/226 232/253/239 6/5/5
+f 240/241/227 239/239/225 13/1/1
+f 234/242/228 233/240/226 7/4/4
+f 228/261/242 212/254/240 1/13/12
+f 241/243/229 240/241/227 14/263/7
+f 235/244/230 234/242/228 8/10/9
+f 229/246/232 228/261/242 2/12/11
+f 242/247/233 241/243/229 15/264/14
+f 236/248/234 235/244/230 9/17/16
+f 230/249/235 229/246/232 3/19/18
+f 12/2/2 27/29/28 28/3/3
+f 6/5/5 21/30/29 22/6/6
+f 13/8/1 28/49/3 29/9/8
+f 7/4/4 22/6/6 23/11/10
+f 1/13/12 16/55/43 17/14/13
+f 14/7/7 29/9/8 30/16/15
+f 8/10/9 23/11/10 24/18/17
+f 2/12/11 17/14/13 18/20/19
+f 9/17/16 24/18/17 25/22/21
+f 3/19/18 18/20/19 19/24/23
+f 10/21/20 25/22/21 26/26/25
+f 4/23/22 19/24/23 20/28/27
+f 11/25/24 26/26/25 27/29/28
+f 5/27/26 20/28/27 21/30/29
+f 29/9/8 45/53/41 46/31/30
+f 23/33/10 39/54/42 40/34/31
+f 17/14/13 33/56/44 34/36/32
+f 24/32/17 40/34/31 41/38/33
+f 18/35/19 34/36/32 35/40/34
+f 25/37/21 41/38/33 42/42/35
+f 19/39/23 35/40/34 36/44/36
+f 26/41/25 42/42/35 43/46/37
+f 20/43/27 36/44/36 37/48/38
+f 27/45/28 43/46/37 44/50/39
+f 21/47/29 37/48/38 38/52/40
+f 28/49/3 44/50/39 45/53/41
+f 22/51/6 38/52/40 39/54/42
+f 16/55/43 32/61/49 33/56/44
+f 43/46/37 58/70/58 59/57/45
+f 37/48/38 52/71/59 53/58/46
+f 44/50/39 59/57/45 60/59/47
+f 38/52/40 53/58/46 54/60/48
+f 32/61/49 47/80/68 48/62/50
+f 45/53/41 60/59/47 61/63/51
+f 39/54/42 54/60/48 55/64/52
+f 33/56/44 48/62/50 49/65/53
+f 40/34/31 55/64/52 56/66/54
+f 34/36/32 49/65/53 50/67/55
+f 41/38/33 56/66/54 57/68/56
+f 35/40/34 50/67/55 51/69/57
+f 42/42/35 57/68/56 58/70/58
+f 36/44/36 51/69/57 52/71/59
+f 56/66/54 71/85/73 72/72/60
+f 50/67/55 65/86/74 66/73/61
+f 57/68/56 72/72/60 73/74/62
+f 51/69/57 66/73/61 67/75/63
+f 58/70/58 73/74/62 74/76/64
+f 52/71/59 67/75/63 68/77/65
+f 59/57/45 74/76/64 75/78/66
+f 53/58/46 68/77/65 69/79/67
+f 47/80/68 62/100/88 63/81/69
+f 60/59/47 75/78/66 76/82/70
+f 54/60/48 69/79/67 70/83/71
+f 48/62/50 63/81/69 64/84/72
+f 55/64/52 70/83/71 71/85/73
+f 49/65/53 64/84/72 65/86/74
+f 91/107/95 76/82/70 90/87/75
+f 85/90/78 70/83/71 84/88/76
+f 79/91/79 64/84/72 78/89/77
+f 86/92/80 71/85/73 85/90/78
+f 80/93/81 65/86/74 79/91/79
+f 87/94/82 72/72/60 86/92/80
+f 81/95/83 66/73/61 80/93/81
+f 88/96/84 73/74/62 87/94/82
+f 82/97/85 67/75/63 81/95/83
+f 89/98/86 74/76/64 88/96/84
+f 83/99/87 68/77/65 82/97/85
+f 90/87/75 75/78/66 89/98/86
+f 84/88/76 69/79/67 83/99/87
+f 78/89/77 63/81/69 77/101/89
+f 104/104/92 89/98/86 103/102/90
+f 98/105/93 83/99/87 97/103/91
+f 105/108/96 90/87/75 104/104/92
+f 99/109/97 84/88/76 98/105/93
+f 93/110/98 78/89/77 92/106/94
+f 106/126/114 91/107/95 105/108/96
+f 100/111/99 85/90/78 99/109/97
+f 94/112/100 79/91/79 93/110/98
+f 101/113/101 86/92/80 100/111/99
+f 95/114/102 80/93/81 94/112/100
+f 102/115/103 87/94/82 101/113/101
+f 96/116/104 81/95/83 95/114/102
+f 103/102/90 88/96/84 102/115/103
+f 97/103/91 82/97/85 96/116/104
+f 117/119/107 102/115/103 116/117/105
+f 111/120/108 96/116/104 110/118/106
+f 118/121/109 103/102/90 117/119/107
+f 112/122/110 97/103/91 111/120/108
+f 119/123/111 104/104/92 118/121/109
+f 113/124/112 98/105/93 112/122/110
+f 120/127/115 105/108/96 119/123/111
+f 114/128/116 99/109/97 113/124/112
+f 108/129/117 93/110/98 107/125/113
+f 121/133/121 106/126/114 120/127/115
+f 115/130/118 100/111/99 114/128/116
+f 109/131/119 94/112/100 108/129/117
+f 116/117/105 101/113/101 115/130/118
+f 110/118/106 95/114/102 109/131/119
+f 123/136/124 108/129/117 122/132/120
+f 136/153/141 121/133/121 135/134/122
+f 130/137/125 115/130/118 129/135/123
+f 124/138/126 109/131/119 123/136/124
+f 131/139/127 116/117/105 130/137/125
+f 125/140/128 110/118/106 124/138/126
+f 132/141/129 117/119/107 131/139/127
+f 126/142/130 111/120/108 125/140/128
+f 133/143/131 118/121/109 132/141/129
+f 127/144/132 112/122/110 126/142/130
+f 134/145/133 119/123/111 133/143/131
+f 128/146/134 113/124/112 127/144/132
+f 135/134/122 120/127/115 134/145/133
+f 129/135/123 114/128/116 128/146/134
+f 142/149/137 127/144/132 141/147/135
+f 149/150/138 134/145/133 148/148/136
+f 143/151/139 128/146/134 142/149/137
+f 150/154/142 135/134/122 149/150/138
+f 144/155/143 129/135/123 143/151/139
+f 138/156/144 123/136/124 137/152/140
+f 151/172/160 136/153/141 150/154/142
+f 145/157/145 130/137/125 144/155/143
+f 139/158/146 124/138/126 138/156/144
+f 146/159/147 131/139/127 145/157/145
+f 140/160/148 125/140/128 139/158/146
+f 147/161/149 132/141/129 146/159/147
+f 141/147/135 126/142/130 140/160/148
+f 148/148/136 133/143/131 147/161/149
+f 161/164/152 146/159/147 160/162/150
+f 155/165/153 140/160/148 154/163/151
+f 162/166/154 147/161/149 161/164/152
+f 156/188/174 141/147/135 155/165/153
+f 163/168/156 148/148/136 162/166/154
+f 141/147/135 156/188/174 157/167/155
+f 164/177/157 149/150/138 163/168/156
+f 158/170/158 143/151/139 157/167/155
+f 165/173/161 150/154/142 164/169/157
+f 159/174/162 144/155/143 158/170/158
+f 153/175/163 138/156/144 152/171/159
+f 166/256/167 151/172/160 165/173/161
+f 160/162/150 145/157/145 159/174/162
+f 154/163/151 139/158/146 153/175/163
+f 180/182/168 165/176/161 179/178/164
+f 174/183/169 159/174/162 173/179/165
+f 168/184/170 153/175/163 167/180/166
+f 181/201/187 166/181/167 180/182/168
+f 175/185/171 160/162/150 174/183/169
+f 169/186/172 154/163/151 168/184/170
+f 176/187/173 161/164/152 175/185/171
+f 170/189/175 155/165/153 169/186/172
+f 177/190/176 162/166/154 176/187/173
+f 171/191/177 156/188/174 170/189/175
+f 178/192/178 163/168/156 177/190/176
+f 172/193/179 157/167/155 171/191/177
+f 179/178/164 164/177/157 178/192/178
+f 173/179/165 158/170/158 172/193/179
+f 193/196/182 178/192/178 192/194/180
+f 187/197/183 172/193/179 186/195/181
+f 194/198/184 179/178/164 193/196/182
+f 188/199/185 173/179/165 187/197/183
+f 195/202/188 180/182/168 194/198/184
+f 189/203/189 174/183/169 188/199/185
+f 183/204/190 168/184/170 182/200/186
+f 196/220/206 181/201/187 195/202/188
+f 190/205/191 175/185/171 189/203/189
+f 184/206/192 169/186/172 183/204/190
+f 191/207/193 176/187/173 190/205/191
+f 185/208/194 170/189/175 184/206/192
+f 192/194/180 177/190/176 191/207/193
+f 186/195/181 171/191/177 185/208/194
+f 190/205/191 205/222/208 206/209/195
+f 184/206/192 199/223/209 200/210/196
+f 191/207/193 206/209/195 207/211/197
+f 185/208/194 200/210/196 201/212/198
+f 192/194/180 207/211/197 208/213/199
+f 186/195/181 201/212/198 202/214/200
+f 193/196/182 208/213/199 209/215/201
+f 187/197/183 202/214/200 203/216/202
+f 194/198/184 209/215/201 210/217/203
+f 188/199/185 203/216/202 204/218/204
+f 182/200/186 197/226/212 198/219/205
+f 195/202/188 210/217/203 211/221/207
+f 189/203/189 204/218/204 205/222/208
+f 183/204/190 198/219/205 199/223/209
+f 209/215/201 225/236/222 226/224/210
+f 203/216/202 219/237/223 220/225/211
+f 197/226/212 213/245/231 214/227/213
+f 210/217/203 226/224/210 227/228/214
+f 204/218/204 220/225/211 221/229/215
+f 198/219/205 214/227/213 215/230/216
+f 205/222/208 221/229/215 222/231/217
+f 199/223/209 215/230/216 216/232/218
+f 206/209/195 222/231/217 223/233/219
+f 200/210/196 216/232/218 217/234/220
+f 224/238/224 208/213/199 223/233/219
+f 201/212/198 217/234/220 218/235/221
+f 208/213/199 224/238/224 225/236/222
+f 202/214/200 218/235/221 219/237/223
+f 223/233/219 238/252/238 239/239/225
+f 217/234/220 232/253/239 233/240/226
+f 224/238/224 239/239/225 240/241/227
+f 218/235/221 233/240/226 234/242/228
+f 225/236/222 240/241/227 241/243/229
+f 219/237/223 234/242/228 235/244/230
+f 213/245/231 228/261/242 229/246/232
+f 226/224/210 241/243/229 242/247/233
+f 220/225/211 235/244/230 236/248/234
+f 214/227/213 229/246/232 230/249/235
+f 221/229/215 236/248/234 237/250/236
+f 215/230/216 230/249/235 231/251/237
+f 222/231/217 237/250/236 238/252/238
+f 216/232/218 231/251/237 232/253/239
+f 236/248/234 9/17/16 10/21/20
+f 230/249/235 3/19/18 4/23/22
+f 11/25/24 238/252/238 10/21/20
+f 231/251/237 4/23/22 5/27/26
+f 12/2/2 239/239/225 11/25/24
+f 232/253/239 5/27/26 6/5/5
+f 239/239/225 12/2/2 13/1/1
+f 233/240/226 6/5/5 7/4/4
+f 240/241/227 13/1/1 14/263/7
+f 234/242/228 7/4/4 8/10/9
+f 228/261/242 1/13/12 2/12/11
+f 241/243/229 14/263/7 15/264/14
+f 235/244/230 8/10/9 9/17/16
+f 229/246/232 2/12/11 3/19/18
diff --git a/src/datavisualization/engine/q3dbars.cpp b/src/datavisualization/engine/q3dbars.cpp
new file mode 100644
index 00000000..0a543d54
--- /dev/null
+++ b/src/datavisualization/engine/q3dbars.cpp
@@ -0,0 +1,620 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dbars.h"
+#include "q3dbars_p.h"
+#include "bars3dcontroller_p.h"
+#include "q3dvalueaxis.h"
+#include "q3dcategoryaxis.h"
+#include "qbardataproxy.h"
+#include "q3dcamera.h"
+
+#include <QMouseEvent>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DBars
+ * \inmodule QtDataVisualization
+ * \brief The Q3DBars class provides methods for rendering 3D bar graphs.
+ * \since 1.0.0
+ *
+ * This class enables developers to render bar graphs in 3D and to view them by rotating the scene
+ * freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming
+ * is done by mouse wheel. Selection, if enabled, is done by left mouse button. The scene can be
+ * reset to default camera view by clicking mouse wheel. In touch devices rotation is done
+ * by tap-and-move, selection by tap-and-hold and zoom by pinch.
+ *
+ * If no axes are explicitly set to Q3DBars, temporary default axes with no labels are created.
+ * These default axes can be modified via axis accessors, but as soon any axis is explicitly
+ * set for the orientation, the default axis for that orientation is destroyed.
+ *
+ * Data proxies work similarly: If no data proxy is explicitly set, Q3DBars creates a default
+ * proxy. If any other proxy is set as active data proxy later, the default proxy and all data
+ * added to it is destroyed.
+ *
+ * Methods are provided for changing bar types, themes, bar selection modes and so on. See the
+ * methods for more detailed descriptions.
+ *
+ * \section1 How to construct a minimal Q3DBars graph
+ *
+ * First, construct an instance of Q3DBars:
+ *
+ * \snippet doc_src_q3dbars_construction.cpp 4
+ *
+ * After constructing Q3DBars, you can set the data window by changing the range on the row and
+ * column axes. It is not mandatory, as data window will default to showing all of the data in
+ * the data proxy. If the amount of data is large, it is usually preferable to show just a
+ * portion of it. For the example, let's set the data window to show first five rows and columns:
+ *
+ * \snippet doc_src_q3dbars_construction.cpp 0
+ *
+ * Now Q3DBars is ready to receive data to be rendered. Add one row of 5 qreals into the data
+ * set:
+ *
+ * \snippet doc_src_q3dbars_construction.cpp 1
+ *
+ * \note We set the data window to 5 x 5, but we are inserting only one row of data. This is ok,
+ * the rest of the rows will just be blank.
+ *
+ * Finally you will need to set it visible:
+ *
+ * \snippet doc_src_q3dbars_construction.cpp 2
+ *
+ * The complete code needed to create and display this graph is:
+ *
+ * \snippet doc_src_q3dbars_construction.cpp 3
+ *
+ * And this is what those few lines of code produce:
+ *
+ * \image q3dbars-minimal.png
+ *
+ * The scene can be rotated, zoomed into, and a bar can be selected to view it's value,
+ * but no other interaction is included in this minimal code example. You can learn more by
+ * familiarizing yourself with the examples provided, like the \l{Bars Example} or
+ * the \l{Custom Proxy Example}.
+ *
+ * \sa Q3DScatter, Q3DSurface, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs a new 3D bar window.
+ */
+Q3DBars::Q3DBars()
+ : d_ptr(new Q3DBarsPrivate(this, geometry()))
+{
+ setVisualController(d_ptr->m_shared);
+ d_ptr->m_shared->initializeOpenGL();
+ QObject::connect(d_ptr->m_shared, &Bars3DController::selectedBarPosChanged, this,
+ &Q3DBars::selectedBarPosChanged);
+ QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this,
+ &Q3DWindow::renderLater);
+}
+
+/*!
+ * Destroys the 3D bar window.
+ */
+Q3DBars::~Q3DBars()
+{
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseDoubleClickEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::touchEvent(QTouchEvent *event)
+{
+ d_ptr->m_shared->touchEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::mousePressEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mousePressEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::mouseReleaseEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseReleaseEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::mouseMoveEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseMoveEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::wheelEvent(QWheelEvent *event)
+{
+ d_ptr->m_shared->wheelEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DBars::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+ d_ptr->m_shared->setSize(width(), height());
+}
+
+/*!
+ * Sets window \a width.
+ */
+void Q3DBars::setWidth(const int width)
+{
+ d_ptr->m_shared->setWidth(width);
+ QWindow::setWidth(width);
+}
+
+/*!
+ * Sets window \a height.
+ */
+void Q3DBars::setHeight(const int height)
+{
+ d_ptr->m_shared->setHeight(height);
+ QWindow::setHeight(height);
+}
+
+/*!
+ * \property Q3DBars::barThickness
+ *
+ * Bar thickness ratio between X and Z dimensions. 1.0 means bars are as wide as they are deep, 0.5
+ * makes them twice as deep as they are wide. It is preset to \c 1.0 by default.
+ */
+void Q3DBars::setBarThickness(qreal thicknessRatio)
+{
+ d_ptr->m_shared->setBarSpecs(GLfloat(thicknessRatio), barSpacing(), isBarSpacingRelative());
+}
+
+qreal Q3DBars::barThickness()
+{
+ return d_ptr->m_shared->barThickness();
+}
+
+/*!
+ * \property Q3DBars::barSpacing
+ *
+ * Bar spacing, ie. the empty space between bars, in X and Z dimensions. It is preset to
+ * \c {(1.0, 1.0)} by default. Spacing is affected by barSpacingRelative -property.
+ *
+ * \sa barSpacingRelative
+ */
+void Q3DBars::setBarSpacing(QSizeF spacing)
+{
+ d_ptr->m_shared->setBarSpecs(GLfloat(barThickness()), spacing, isBarSpacingRelative());
+}
+
+QSizeF Q3DBars::barSpacing()
+{
+ return d_ptr->m_shared->barSpacing();
+}
+
+/*!
+ * \property Q3DBars::barSpacingRelative
+ *
+ * This is used to indicate if spacing is meant to be absolute or relative to bar thickness.
+ * If it is true, value of 0.0 means the bars are side-to-side and for example 1.0 means
+ * there is one thickness in between the bars. It is preset to \c true.
+ */
+void Q3DBars::setBarSpacingRelative(bool relative)
+{
+ d_ptr->m_shared->setBarSpecs(GLfloat(barThickness()), barSpacing(), relative);
+}
+
+bool Q3DBars::isBarSpacingRelative()
+{
+ return d_ptr->m_shared->isBarSpecRelative();
+}
+
+/*!
+ * Sets the bar \a style to one of the values in \c QDataVis::MeshStyle. It is preset to
+ * \c QDataVis::MeshStyleBars by default. A \a smooth flag can be used to set shading to smooth.
+ * It is \c false by default.
+ *
+ * \sa setMeshFileName()
+ */
+void Q3DBars::setBarType(QDataVis::MeshStyle style, bool smooth)
+{
+ d_ptr->m_shared->setBarType(style, smooth);
+}
+
+/*!
+ * Sets a predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by
+ * default. Theme affects bar colors, label colors, text color, background color, window color and
+ * grid color. Lighting is also adjusted by themes.
+ *
+ * \sa setBarColor()
+ *
+ * \warning This method is subject to change.
+ */
+void Q3DBars::setTheme(QDataVis::Theme theme)
+{
+ d_ptr->m_shared->setTheme(theme);
+}
+
+/*!
+ * Set bar color using your own color. \a baseColor sets the base color of a bar. The \a uniform
+ * -flag is used to define if color needs to be uniform throughout bar's length, or will the colors
+ * be applied by height, starting with dark at the bottom. It is \c true by default.
+ *
+ * Calling this method overrides colors from theme.
+ *
+ * \sa setTheme()
+ *
+ * \warning This method is subject to change.
+ */
+void Q3DBars::setBarColor(const QColor &baseColor, bool uniform)
+{
+ d_ptr->m_shared->setObjectColor(baseColor, uniform);
+}
+
+/*!
+ * \return bar color in use.
+ */
+QColor Q3DBars::barColor() const
+{
+ return d_ptr->m_shared->objectColor();
+}
+
+/*!
+ * \property Q3DBars::selectionMode
+ *
+ * Sets bar selection \a mode to one of \c QDataVis::SelectionMode. It is preset to
+ * \c QDataVis::SelectionModeItem by default.
+ */
+void Q3DBars::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ d_ptr->m_shared->setSelectionMode(mode);
+}
+
+QDataVis::SelectionMode Q3DBars::selectionMode() const
+{
+ return d_ptr->m_shared->selectionMode();
+}
+
+/*!
+ * \property Q3DBars::meshFileName
+ *
+ * Override bar type with a mesh object located in \a objFileName.
+ * \note Object needs to be in Wavefront obj format and include vertices, normals and UVs.
+ * It also needs to be in triangles.
+ *
+ * \sa setBarType()
+ */
+void Q3DBars::setMeshFileName(const QString &objFileName)
+{
+ d_ptr->m_shared->setMeshFileName(objFileName);
+}
+
+QString Q3DBars::meshFileName() const
+{
+ return d_ptr->m_shared->meshFileName();
+}
+
+/*!
+ * \property Q3DBars::font
+ *
+ * Sets the \a font for labels. It is preset to \c Arial by default.
+ */
+void Q3DBars::setFont(const QFont &font)
+{
+ d_ptr->m_shared->setFont(font);
+}
+
+QFont Q3DBars::font() const
+{
+ return d_ptr->m_shared->font();
+}
+
+/*!
+ * \property Q3DBars::scene
+ *
+ * This property contains the read only Q3DScene that can be used to access e.g. camera object.
+ */
+Q3DScene *Q3DBars::scene() const
+{
+ return d_ptr->m_shared->scene();
+}
+
+/*!
+ * \property Q3DBars::labelStyle
+ *
+ * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to
+ * \c QDataVis::LabelStyleFromTheme by default.
+ */
+void Q3DBars::setLabelStyle(QDataVis::LabelStyle style)
+{
+ d_ptr->m_shared->setLabelStyle(style);
+}
+
+QDataVis::LabelStyle Q3DBars::labelStyle() const
+{
+ return d_ptr->m_shared->labelStyle();
+}
+
+/*!
+ * \property Q3DBars::gridVisible
+ *
+ * Sets grid visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DBars::setGridVisible(bool visible)
+{
+ d_ptr->m_shared->setGridEnabled(visible);
+}
+
+bool Q3DBars::isGridVisible() const
+{
+ return d_ptr->m_shared->gridEnabled();
+}
+
+/*!
+ * \property Q3DBars::backgroundVisible
+ *
+ * Sets background visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DBars::setBackgroundVisible(bool visible)
+{
+ d_ptr->m_shared->setBackgroundEnabled(visible);
+}
+
+bool Q3DBars::isBackgroundVisible() const
+{
+ return d_ptr->m_shared->backgroundEnabled();
+}
+
+/*!
+ * \property Q3DBars::selectedBarPos
+ *
+ * Selects a bar in a \a position. The position is the position in data window.
+ * Only one bar can be selected at a time.
+ * To clear selection, specify an illegal \a position, e.g. (-1, -1).
+ */
+void Q3DBars::setSelectedBarPos(const QPoint &position)
+{
+ d_ptr->m_shared->setSelectedBarPos(position);
+}
+
+QPoint Q3DBars::selectedBarPos() const
+{
+ return d_ptr->m_shared->selectedBarPos();
+}
+
+/*!
+ * \property Q3DBars::shadowQuality
+ *
+ * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to
+ * \c QDataVis::ShadowQualityMedium by default.
+ *
+ * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered
+ * until it is successful and shadowQualityChanged signal is emitted for each time the change is
+ * done.
+ */
+void Q3DBars::setShadowQuality(QDataVis::ShadowQuality quality)
+{
+ d_ptr->m_shared->setShadowQuality(quality);
+}
+
+QDataVis::ShadowQuality Q3DBars::shadowQuality() const
+{
+ return d_ptr->m_shared->shadowQuality();
+}
+
+/*!
+ * Sets a user-defined row \a axis. Implicitly calls addAxis() to transfer ownership of
+ * the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DBars::setRowAxis(Q3DCategoryAxis *axis)
+{
+ d_ptr->m_shared->setAxisX(axis);
+}
+
+/*!
+ * \return category axis for rows.
+ */
+Q3DCategoryAxis *Q3DBars::rowAxis() const
+{
+ return static_cast<Q3DCategoryAxis *>(d_ptr->m_shared->axisX());
+}
+
+/*!
+ * Sets a user-defined column \a axis. Implicitly calls addAxis() to transfer ownership of
+ * the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DBars::setColumnAxis(Q3DCategoryAxis *axis)
+{
+ d_ptr->m_shared->setAxisZ(axis);
+}
+
+/*!
+ * \return category axis for columns.
+ */
+Q3DCategoryAxis *Q3DBars::columnAxis() const
+{
+ return static_cast<Q3DCategoryAxis *>(d_ptr->m_shared->axisZ());
+}
+
+/*!
+ * Sets a user-defined value \a axis (the Y-axis). Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DBars::setValueAxis(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisY(axis);
+}
+
+/*!
+ * \return used value axis (Y-axis).
+ */
+Q3DValueAxis *Q3DBars::valueAxis() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY());
+}
+
+/*!
+ * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use,
+ * addAxis is simply used to give the ownership of the \a axis to the graph.
+ * The \a axis must not be null or added to another graph.
+ *
+ * \sa releaseAxis(), setValueAxis(), setRowAxis(), setColumnAxis()
+ */
+void Q3DBars::addAxis(Q3DAbstractAxis *axis)
+{
+ d_ptr->m_shared->addAxis(axis);
+}
+
+/*!
+ * Releases the ownership of the \a axis back to the caller, if it is added to this graph.
+ * If the released \a axis is in use, a new default axis will be created and set active.
+ *
+ * If the default axis is released and added back later, it behaves as any other axis would.
+ *
+ * \sa addAxis(), setValueAxis(), setRowAxis(), setColumnAxis()
+ */
+void Q3DBars::releaseAxis(Q3DAbstractAxis *axis)
+{
+ d_ptr->m_shared->releaseAxis(axis);
+}
+
+/*!
+ * \return list of all added axes.
+ *
+ * \sa addAxis()
+ */
+QList<Q3DAbstractAxis *> Q3DBars::axes() const
+{
+ return d_ptr->m_shared->axes();
+}
+
+/*!
+ * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of
+ * the \a proxy to this graph.
+ *
+ * If the \a proxy is null, a temporary default proxy is created and activated.
+ * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method.
+ *
+ * \sa addDataProxy(), releaseDataProxy()
+ */
+void Q3DBars::setActiveDataProxy(QBarDataProxy *proxy)
+{
+ d_ptr->m_shared->setActiveDataProxy(proxy);
+}
+
+/*!
+ * \return active data proxy.
+ */
+QBarDataProxy *Q3DBars::activeDataProxy() const
+{
+ return static_cast<QBarDataProxy *>(d_ptr->m_shared->activeDataProxy());
+}
+
+/*!
+ * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use,
+ * addDataProxy is simply used to give the ownership of the data \a proxy to the graph.
+ * The \a proxy must not be null or added to another graph.
+ *
+ * \sa releaseDataProxy(), setActiveDataProxy()
+ */
+void Q3DBars::addDataProxy(QBarDataProxy *proxy)
+{
+ d_ptr->m_shared->addDataProxy(proxy);
+}
+
+/*!
+ * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph.
+ * If the released \a proxy is in use, a new empty default proxy is created and taken to use.
+ *
+ * If the default \a proxy is released and added back later, it behaves as any other proxy would.
+ *
+ * \sa addDataProxy(), setActiveDataProxy()
+ */
+void Q3DBars::releaseDataProxy(QBarDataProxy *proxy)
+{
+ d_ptr->m_shared->releaseDataProxy(proxy);
+}
+
+/*!
+ * \return list of all added data proxies.
+ *
+ * \sa addDataProxy()
+ */
+QList<QBarDataProxy *> Q3DBars::dataProxies() const
+{
+ QList<QBarDataProxy *> retList;
+ QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies();
+ foreach (QAbstractDataProxy *proxy, abstractList)
+ retList.append(static_cast<QBarDataProxy *>(proxy));
+
+ return retList;
+}
+
+Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q, QRect rect)
+ : q_ptr(q),
+ m_shared(new Bars3DController(rect))
+{
+ QObject::connect(m_shared, &Abstract3DController::shadowQualityChanged, this,
+ &Q3DBarsPrivate::handleShadowQualityUpdate);
+}
+
+Q3DBarsPrivate::~Q3DBarsPrivate()
+{
+ qDebug() << "Destroying Q3DBarsPrivate";
+ delete m_shared;
+}
+
+void Q3DBarsPrivate::handleShadowQualityUpdate(QDataVis::ShadowQuality quality)
+{
+ emit q_ptr->shadowQualityChanged(quality);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dbars.h b/src/datavisualization/engine/q3dbars.h
new file mode 100644
index 00000000..d0ddf3fb
--- /dev/null
+++ b/src/datavisualization/engine/q3dbars.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DBARS_H
+#define Q3DBARS_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/q3dwindow.h>
+#include <QFont>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DBarsPrivate;
+class Q3DAbstractAxis;
+class Q3DCategoryAxis;
+class Q3DValueAxis;
+class QBarDataProxy;
+class Q3DScene;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DBars : public Q3DWindow
+{
+ Q_OBJECT
+ Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
+ Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle)
+ Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged)
+ Q_PROPERTY(qreal barThickness READ barThickness WRITE setBarThickness)
+ Q_PROPERTY(QSizeF barSpacing READ barSpacing WRITE setBarSpacing)
+ Q_PROPERTY(bool barSpacingRelative READ isBarSpacingRelative WRITE setBarSpacingRelative)
+ Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName)
+ Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible)
+ Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible)
+ Q_PROPERTY(QPoint selectedBarPos READ selectedBarPos WRITE setSelectedBarPos NOTIFY selectedBarPosChanged)
+ Q_PROPERTY(Q3DScene* scene READ scene)
+
+ Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode)
+ Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality)
+ Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle)
+ Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset)
+
+public:
+ explicit Q3DBars();
+ ~Q3DBars();
+
+ void setBarType(QDataVis::MeshStyle style, bool smooth = false);
+
+ void setTheme(QDataVis::Theme theme);
+
+ void setBarThickness(qreal thicknessRatio);
+ qreal barThickness();
+
+ void setBarSpacing(QSizeF spacing);
+ QSizeF barSpacing();
+
+ void setBarSpacingRelative(bool relative);
+ bool isBarSpacingRelative();
+
+ void setBarColor(const QColor &baseColor, bool uniform = true);
+ QColor barColor() const;
+
+ void setMeshFileName(const QString &objFileName);
+ QString meshFileName() const;
+
+ void setSelectionMode(QDataVis::SelectionMode mode);
+ QDataVis::SelectionMode selectionMode() const;
+
+ void setFont(const QFont &font);
+ QFont font() const;
+
+ Q3DScene *scene() const;
+
+ void setLabelStyle(QDataVis::LabelStyle style);
+ QDataVis::LabelStyle labelStyle() const;
+
+ void setGridVisible(bool visible);
+ bool isGridVisible() const;
+
+ void setWidth(const int width);
+ void setHeight(const int height);
+
+ void setBackgroundVisible(bool visible);
+ bool isBackgroundVisible() const;
+
+ void setSelectedBarPos(const QPoint &position);
+ QPoint selectedBarPos() const;
+
+ void setShadowQuality(QDataVis::ShadowQuality quality);
+ QDataVis::ShadowQuality shadowQuality() const;
+
+ void setRowAxis(Q3DCategoryAxis *axis);
+ Q3DCategoryAxis *rowAxis() const;
+ void setColumnAxis(Q3DCategoryAxis *axis);
+ Q3DCategoryAxis *columnAxis() const;
+ void setValueAxis(Q3DValueAxis *axis);
+ Q3DValueAxis *valueAxis() const;
+ void addAxis(Q3DAbstractAxis *axis);
+ void releaseAxis(Q3DAbstractAxis *axis);
+ QList<Q3DAbstractAxis *> axes() const;
+
+ void setActiveDataProxy(QBarDataProxy *proxy);
+ QBarDataProxy *activeDataProxy() const;
+ void addDataProxy(QBarDataProxy *proxy);
+ void releaseDataProxy(QBarDataProxy *proxy);
+ QList<QBarDataProxy *> dataProxies() const;
+
+signals:
+ void shadowQualityChanged(QDataVis::ShadowQuality quality);
+ void selectedBarPosChanged(QPoint position);
+
+protected:
+
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void touchEvent(QTouchEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ QScopedPointer<Q3DBarsPrivate> d_ptr;
+ Q_DISABLE_COPY(Q3DBars)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dbars_p.h b/src/datavisualization/engine/q3dbars_p.h
new file mode 100644
index 00000000..653db606
--- /dev/null
+++ b/src/datavisualization/engine/q3dbars_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DBARS_p_H
+#define Q3DBARS_p_H
+
+#include "bars3dcontroller_p.h"
+#include "qdatavisualizationenums.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DBars;
+
+class Q3DBarsPrivate : public QObject
+{
+public:
+ Q3DBarsPrivate(Q3DBars *q, QRect rect);
+ ~Q3DBarsPrivate();
+
+ // Used to detect when shadow quality changes autonomously due to e.g. resizing.
+ void handleShadowQualityUpdate(QDataVis::ShadowQuality quality);
+
+ Q3DBars *q_ptr;
+ Bars3DController *m_shared;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dbox.cpp b/src/datavisualization/engine/q3dbox.cpp
new file mode 100644
index 00000000..43f3e90e
--- /dev/null
+++ b/src/datavisualization/engine/q3dbox.cpp
@@ -0,0 +1,481 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "datavisualizationglobal_p.h"
+#include "q3dbox.h"
+#include <QtCore/QList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DBox
+ \inmodule QtDataVisualization
+ \brief The Q3DBox class represents an axis-aligned box in 3D space.
+ \since 1.0.0
+
+ Q3DBox can be used to represent the bounding box of objects in a 3D
+ scene so that they can be easily culled if they are out of view.
+
+ The sides of the box are always aligned with the x, y, and z axes of
+ the world co-ordinate system. Transforming a box with transformed()
+ will result in the smallest axis-aligned bounding box that contains
+ the transformed box.
+
+ Boxes may be null, finite, or infinite. A null box does not occupy
+ any space and does not intersect with any other box. A finite
+ box consists of a minimum() and maximum() extent in 3D space.
+ An infinite box encompasses all points in 3D space.
+
+ The extents of a finite box are also included within the box.
+ A box with minimum() and maximum() set to the same value
+ contains a single point.
+*/
+
+/*!
+ \fn Q3DBox::Q3DBox()
+
+ Constructs a null box in 3D space.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn Q3DBox::Q3DBox(const QVector3D& corner1, const QVector3D& corner2)
+
+ Constructs a finite box in 3D space from \a corner1 to \a corner2.
+ The minimum() and maximum() co-ordinates of the new box are set
+ to the minimum and maximum x, y, and z values from \a corner1 and
+ \a corner2. The \a corner1 and \a corner2 values can be any two
+ opposite corners that define the box.
+
+ \sa isFinite(), minimum(), maximum()
+*/
+
+/*!
+ \fn bool Q3DBox::isNull() const
+
+ Returns true if this box is null; false otherwise.
+
+ \sa isFinite(), isInfinite(), setToNull()
+*/
+
+/*!
+ \fn bool Q3DBox::isFinite() const
+
+ Returns true if this box is finite in size; false otherwise.
+
+ \sa isNull(), isInfinite(), setExtents()
+*/
+
+/*!
+ \fn bool Q3DBox::isInfinite() const
+
+ Returns true if this box is infinite in size; false otherwise.
+
+ \sa isNull(), isFinite(), setToInfinite()
+*/
+
+/*!
+ \fn QVector3D Q3DBox::minimum() const
+
+ Returns the minimum corner of this box.
+
+ \sa maximum(), setExtents()
+*/
+
+/*!
+ \fn QVector3D Q3DBox::maximum() const
+
+ Returns the maximum corner of this box.
+
+ \sa minimum(), setExtents()
+*/
+
+/*!
+ \fn void Q3DBox::setExtents(const QVector3D& corner1, const QVector3D& corner2)
+
+ Sets the extents of this box to a finite region from \a corner1 to
+ \a corner2. The minimum() and maximum() co-ordinates of the box are
+ set to the minimum and maximum x, y, and z values from \a corner1 and
+ \a corner2. The \a corner1 and \a corner2 values can be any two
+ opposite corners that define the box.
+
+ \sa minimum(), maximum()
+*/
+
+/*!
+ \fn void Q3DBox::setToNull()
+
+ Sets this box to null.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn void Q3DBox::setToInfinite()
+
+ Sets this box to be infinite in size.
+
+ \sa isInfinite()
+*/
+
+/*!
+ \fn QVector3D Q3DBox::size() const
+
+ Returns the finite size of this box. If this box is null or
+ infinite, the returned value will be zero.
+
+ \sa center(), isNull(), isInfinite()
+*/
+
+/*!
+ \fn QVector3D Q3DBox::center() const
+
+ Returns the finite center of this box. If this box is null
+ or infinite, the returned value will be zero.
+
+ \sa size(), isNull(), isInfinite()
+*/
+
+/*!
+ \fn bool Q3DBox::contains(const QVector3D& point) const
+
+ Returns true if this box contains \a point; false otherwise.
+ Null boxes do not contain any points and infinite boxes contain
+ all points.
+
+ Containment is not a strict test: the point is contained if it
+ lies on one of the faces of the box.
+
+ \sa intersects()
+*/
+
+/*!
+ \fn bool Q3DBox::contains(const Q3DBox& box) const
+
+ Returns true if this box completely contains \a box. If this box
+ is null, then it will not contain \a box. If this box is infinite,
+ and \a box is not null, then \a box will be contained within this box.
+ If \a box is infinite, then this box must also be infinite to contain it.
+
+ \sa intersects()
+*/
+
+/*!
+ Returns true if \a box intersects this box; false otherwise.
+
+ \sa intersect(), intersected(), contains()
+*/
+bool Q3DBox::intersects(const Q3DBox& box) const
+{
+ if (boxtype == Null)
+ return false;
+ else if (boxtype == Infinite)
+ return box.boxtype != Null;
+ else if (box.boxtype == Null)
+ return false;
+ else if (box.boxtype == Infinite)
+ return true;
+
+ if (maxcorner.x() < box.mincorner.x())
+ return false;
+ if (mincorner.x() > box.maxcorner.x())
+ return false;
+
+ if (maxcorner.y() < box.mincorner.y())
+ return false;
+ if (mincorner.y() > box.maxcorner.y())
+ return false;
+
+ if (maxcorner.z() < box.mincorner.z())
+ return false;
+ if (mincorner.z() > box.maxcorner.z())
+ return false;
+
+ return true;
+}
+
+/*!
+ Intersects this box with \a box.
+
+ \sa intersected(), intersects(), unite()
+*/
+void Q3DBox::intersect(const Q3DBox& box)
+{
+ // Handle the simple cases first.
+ if (boxtype == Null) {
+ // Null intersected with anything is null.
+ return;
+ } else if (boxtype == Infinite) {
+ // Infinity intersected with a box is that box.
+ *this = box;
+ return;
+ } else if (box.boxtype == Null) {
+ // Anything intersected with null is null.
+ setToNull();
+ return;
+ } else if (box.boxtype == Infinite) {
+ // Box intersected with infinity is the box.
+ return;
+ }
+
+ // Intersect two finite boxes.
+ QVector3D min1 = mincorner;
+ QVector3D max1 = maxcorner;
+ QVector3D min2 = box.mincorner;
+ QVector3D max2 = box.maxcorner;
+ if (min2.x() > min1.x())
+ min1.setX(min2.x());
+ if (min2.y() > min1.y())
+ min1.setY(min2.y());
+ if (min2.z() > min1.z())
+ min1.setZ(min2.z());
+ if (max2.x() < max1.x())
+ max1.setX(max2.x());
+ if (max2.y() < max1.y())
+ max1.setY(max2.y());
+ if (max2.z() < max1.z())
+ max1.setZ(max2.z());
+ if (min1.x() > max1.x() || min1.y() > max1.y() || min1.z() > max1.z()) {
+ setToNull();
+ } else {
+ mincorner = min1;
+ maxcorner = max1;
+ }
+}
+
+/*!
+ Returns a new box which is the intersection of this box with \a box.
+
+ \sa intersect(), intersects(), united()
+*/
+Q3DBox Q3DBox::intersected(const Q3DBox& box) const
+{
+ Q3DBox result(*this);
+ result.intersect(box);
+ return result;
+}
+
+/*!
+ Unites this box with \a point by expanding it to encompass \a point.
+ If \a point is already contained within this box, then this box
+ will be unchanged.
+
+ \sa united(), intersect()
+*/
+void Q3DBox::unite(const QVector3D& point)
+{
+ if (boxtype == Finite) {
+ if (point.x() < mincorner.x())
+ mincorner.setX(point.x());
+ else if (point.x() > maxcorner.x())
+ maxcorner.setX(point.x());
+ if (point.y() < mincorner.y())
+ mincorner.setY(point.y());
+ else if (point.y() > maxcorner.y())
+ maxcorner.setY(point.y());
+ if (point.z() < mincorner.z())
+ mincorner.setZ(point.z());
+ else if (point.z() > maxcorner.z())
+ maxcorner.setZ(point.z());
+ } else if (boxtype == Null) {
+ boxtype = Finite;
+ mincorner = point;
+ maxcorner = point;
+ }
+}
+
+/*!
+ Unites this box with \a box by expanding this box to encompass the
+ region defined by \a box. If \a box is already contained within
+ this box, then this box will be unchanged.
+
+ \sa united(), intersect()
+*/
+void Q3DBox::unite(const Q3DBox& box)
+{
+ if (box.boxtype == Finite) {
+ unite(box.minimum());
+ unite(box.maximum());
+ } else if (box.boxtype == Infinite) {
+ setToInfinite();
+ }
+}
+
+/*!
+ Returns a new box which unites this box with \a point. The returned
+ value will be the smallest box that contains both this box and \a point.
+
+ \sa unite(), intersected()
+*/
+Q3DBox Q3DBox::united(const QVector3D& point) const
+{
+ if (boxtype == Finite) {
+ Q3DBox result(*this);
+ result.unite(point);
+ return result;
+ } else if (boxtype == Null) {
+ return Q3DBox(point, point);
+ } else {
+ return *this;
+ }
+}
+
+/*!
+ Returns a new box which unites this box with \a box. The returned value
+ will be the smallest box that contains both this box and \a box.
+
+ \sa unite(), intersected()
+*/
+Q3DBox Q3DBox::united(const Q3DBox& box) const
+{
+ if (boxtype == Finite) {
+ Q3DBox result(*this);
+ result.unite(box);
+ return result;
+ } else if (boxtype == Null) {
+ return box;
+ } else {
+ return *this;
+ }
+}
+
+/*!
+ Transforms this box according to \a matrix. Each of the 8 box
+ corners are transformed and then a new box that encompasses all
+ of the transformed corner values is created.
+
+ \sa transformed()
+*/
+void Q3DBox::transform(const QMatrix4x4& matrix)
+{
+ *this = transformed(matrix);
+}
+
+/*!
+ Returns this box transformed by \a matrix. Each of the 8 box
+ corners are transformed and then a new box that encompasses all
+ of the transformed corner values is returned.
+
+ \sa transform()
+*/
+Q3DBox Q3DBox::transformed(const QMatrix4x4& matrix) const
+{
+ if (boxtype != Finite)
+ return *this;
+ Q3DBox result;
+ result.unite(matrix * mincorner);
+ result.unite(matrix * QVector3D(mincorner.x(), mincorner.y(), maxcorner.z()));
+ result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), maxcorner.z()));
+ result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), maxcorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), maxcorner.z()));
+ result.unite(matrix * maxcorner);
+ return result;
+}
+
+/*!
+ \fn bool Q3DBox::operator==(const Q3DBox& box) const
+
+ Returns true if this box is identical to \a box.
+*/
+
+/*!
+ \fn bool Q3DBox::operator!=(const Q3DBox& box) const
+
+ Returns true if this box is not identical to \a box.
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2)
+ \relates Q3DBox
+
+ Returns true if \a box1 and \a box2 are almost equal; false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const Q3DBox &box)
+{
+ if (box.isFinite()) {
+ dbg.nospace() << "Q3DBox(("
+ << box.minimum().x() << ", " << box.minimum().y() << ", "
+ << box.minimum().z() << ") - ("
+ << box.maximum().x() << ", " << box.maximum().y() << ", "
+ << box.maximum().z() << "))";
+ return dbg.space();
+ } else if (box.isNull()) {
+ dbg << "Q3DBox(null)";
+ return dbg;
+ } else {
+ dbg << "Q3DBox(infinite)";
+ return dbg;
+ }
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \relates Q3DBox
+
+ Writes the given \a box to the given \a stream and returns a
+ reference to the stream.
+*/
+QDataStream &operator<<(QDataStream &stream, const Q3DBox &box)
+{
+ if (box.isNull()) {
+ stream << int(0);
+ } else if (box.isInfinite()) {
+ stream << int(2);
+ } else {
+ stream << int(1);
+ stream << box.minimum();
+ stream << box.maximum();
+ }
+ return stream;
+}
+
+/*!
+ \relates Q3DBox
+
+ Reads a 3D box from the given \a stream into the given \a box
+ and returns a reference to the stream.
+*/
+QDataStream &operator>>(QDataStream &stream, Q3DBox &box)
+{
+ int type;
+ stream >> type;
+ if (type == 1) {
+ QVector3D minimum, maximum;
+ stream >> minimum;
+ stream >> maximum;
+ box = Q3DBox(minimum, maximum);
+ } else if (type == 2) {
+ box.setToInfinite();
+ } else {
+ box.setToNull();
+ }
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dbox.h b/src/datavisualization/engine/q3dbox.h
new file mode 100644
index 00000000..aa63ec39
--- /dev/null
+++ b/src/datavisualization/engine/q3dbox.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DBOX_H
+#define Q3DBOX_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtGui/QMatrix4x4>
+#include <QtGui/QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DBox; // Needed to circumvent an issue with qdoc. If this line is removed, make docs will not work for this.
+
+class QT_DATAVISUALIZATION_EXPORT Q3DBox
+{
+public:
+ Q3DBox();
+ Q3DBox(const QVector3D& corner1, const QVector3D& corner2);
+
+ bool isNull() const;
+ bool isFinite() const;
+ bool isInfinite() const;
+
+ QVector3D minimum() const;
+ QVector3D maximum() const;
+ void setExtents(const QVector3D& corner1, const QVector3D& corner2);
+
+ void setToNull();
+ void setToInfinite();
+
+ QVector3D size() const;
+ QVector3D center() const;
+
+ bool contains(const QVector3D& point) const;
+ bool contains(const Q3DBox& box) const;
+
+ bool intersects(const Q3DBox& box) const;
+ void intersect(const Q3DBox& box);
+ Q3DBox intersected(const Q3DBox& box) const;
+
+ void unite(const QVector3D& point);
+ void unite(const Q3DBox& box);
+
+ Q3DBox united(const QVector3D& point) const;
+ Q3DBox united(const Q3DBox& box) const;
+
+ void transform(const QMatrix4x4& matrix);
+ Q3DBox transformed(const QMatrix4x4& matrix) const;
+
+ bool operator==(const Q3DBox& box) const;
+ bool operator!=(const Q3DBox& box) const;
+
+ friend bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2);
+
+private:
+ enum Type
+ {
+ Null,
+ Finite,
+ Infinite
+ };
+
+ Q3DBox::Type boxtype;
+ QVector3D mincorner, maxcorner;
+};
+
+inline Q3DBox::Q3DBox() : boxtype(Null), mincorner(0, 0, 0), maxcorner(0, 0, 0) {}
+
+inline Q3DBox::Q3DBox(const QVector3D& corner1, const QVector3D& corner2)
+ : boxtype(Finite),
+ mincorner(qMin(corner1.x(), corner2.x()),
+ qMin(corner1.y(), corner2.y()),
+ qMin(corner1.z(), corner2.z())),
+ maxcorner(qMax(corner1.x(), corner2.x()),
+ qMax(corner1.y(), corner2.y()),
+ qMax(corner1.z(), corner2.z())) {}
+
+inline bool Q3DBox::isNull() const { return (boxtype == Null); }
+inline bool Q3DBox::isFinite() const { return (boxtype == Finite); }
+inline bool Q3DBox::isInfinite() const { return (boxtype == Infinite); }
+
+inline QVector3D Q3DBox::minimum() const { return mincorner; }
+inline QVector3D Q3DBox::maximum() const { return maxcorner; }
+
+inline void Q3DBox::setExtents(const QVector3D& corner1, const QVector3D& corner2)
+{
+ boxtype = Finite;
+ mincorner = QVector3D(qMin(corner1.x(), corner2.x()),
+ qMin(corner1.y(), corner2.y()),
+ qMin(corner1.z(), corner2.z()));
+ maxcorner = QVector3D(qMax(corner1.x(), corner2.x()),
+ qMax(corner1.y(), corner2.y()),
+ qMax(corner1.z(), corner2.z()));
+}
+
+inline void Q3DBox::setToNull()
+{
+ boxtype = Null;
+ mincorner = QVector3D(0, 0, 0);
+ maxcorner = QVector3D(0, 0, 0);
+}
+
+inline void Q3DBox::setToInfinite()
+{
+ boxtype = Infinite;
+ mincorner = QVector3D(0, 0, 0);
+ maxcorner = QVector3D(0, 0, 0);
+}
+
+inline QVector3D Q3DBox::size() const { return maxcorner - mincorner; }
+inline QVector3D Q3DBox::center() const { return (mincorner + maxcorner) * 0.5f; }
+
+inline bool Q3DBox::contains(const QVector3D& point) const
+{
+ if (boxtype == Finite) {
+ return (point.x() >= mincorner.x() && point.x() <= maxcorner.x() &&
+ point.y() >= mincorner.y() && point.y() <= maxcorner.y() &&
+ point.z() >= mincorner.z() && point.z() <= maxcorner.z());
+ } else if (boxtype == Infinite) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+inline bool Q3DBox::contains(const Q3DBox& box) const
+{
+ if (box.boxtype == Finite)
+ return contains(box.mincorner) && contains(box.maxcorner);
+ else if (box.boxtype == Infinite)
+ return (boxtype == Infinite);
+ else
+ return false;
+}
+
+inline bool Q3DBox::operator==(const Q3DBox& box) const
+{
+ return (boxtype == box.boxtype &&
+ mincorner == box.mincorner &&
+ maxcorner == box.maxcorner);
+}
+
+inline bool Q3DBox::operator!=(const Q3DBox& box) const
+{
+ return (boxtype != box.boxtype ||
+ mincorner != box.mincorner ||
+ maxcorner != box.maxcorner);
+}
+
+inline bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2)
+{
+ return box1.boxtype == box2.boxtype &&
+ qFuzzyCompare(box1.mincorner, box2.mincorner) &&
+ qFuzzyCompare(box1.maxcorner, box2.maxcorner);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QT_DATAVISUALIZATION_EXPORT QDebug operator<<(QDebug dbg, const Q3DBox &box);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+QT_DATAVISUALIZATION_EXPORT QDataStream &operator<<(QDataStream &stream, const Q3DBox &box);
+QT_DATAVISUALIZATION_EXPORT QDataStream &operator>>(QDataStream &stream, Q3DBox &box);
+#endif
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dcamera.cpp b/src/datavisualization/engine/q3dcamera.cpp
new file mode 100644
index 00000000..571af1d7
--- /dev/null
+++ b/src/datavisualization/engine/q3dcamera.cpp
@@ -0,0 +1,698 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dcamera.h"
+#include "q3dcamera_p.h"
+#include "q3dscene.h"
+#include "q3dbox.h"
+#include "q3dobject.h"
+#include "utils_p.h"
+
+#include <qmath.h>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DCamera
+ \inmodule QtDataVisualization
+ \brief Representation of a camera in 3D space.
+ \since 1.0.0
+
+ Q3DCamera represents a basic orbit around centerpoint 3D camera that is used when rendering the data visualization.
+ The class offers simple methods for setting the orbit point in rotations, but allows also setting the 4x4 viewmatrix
+ directly in case a more customized camera behavior is needed.
+*/
+
+/*!
+ * Constructs a new 3D camera with position set to origo, up direction facing towards the Y-axis and looking at origo by default. An
+ * optional \a parent parameter can be given and is then passed to QObject constructor.
+ */
+Q3DCamera::Q3DCamera(QObject *parent) :
+ Q3DObject(parent),
+ d_ptr(new Q3DCameraPrivate(this))
+{
+}
+
+/*!
+ * Destroys the camera object.
+ */
+Q3DCamera::~Q3DCamera()
+{
+}
+
+/*!
+ * Copies the 3D camera's properties from the given source camera.
+ * Values are copied from the \a source to this object.
+ */
+void Q3DCamera::copyValuesFrom(const Q3DCamera &source)
+{
+ Q3DObject::copyValuesFrom(source);
+
+ d_ptr->m_target.setX(source.d_ptr->m_target.x());
+ d_ptr->m_target.setY(source.d_ptr->m_target.y());
+ d_ptr->m_target.setZ(source.d_ptr->m_target.z());
+
+ d_ptr->m_up.setX(source.d_ptr->m_up.x());
+ d_ptr->m_up.setY(source.d_ptr->m_up.y());
+ d_ptr->m_up.setZ(source.d_ptr->m_up.z());
+
+ float *values = new float[16];
+ source.d_ptr->m_viewMatrix.copyDataTo(values);
+ d_ptr->m_viewMatrix = QMatrix4x4(values);
+ delete[] values;
+
+ d_ptr->m_xRotation = source.d_ptr->m_xRotation;
+ d_ptr->m_yRotation = source.d_ptr->m_yRotation;
+
+ d_ptr->m_minXRotation = source.d_ptr->m_minXRotation;
+ d_ptr->m_minYRotation = source.d_ptr->m_minYRotation;
+ d_ptr->m_maxXRotation = source.d_ptr->m_maxXRotation;
+ d_ptr->m_maxYRotation = source.d_ptr->m_maxYRotation;
+
+ d_ptr->m_wrapXRotation = source.d_ptr->m_wrapXRotation;
+ d_ptr->m_wrapYRotation = source.d_ptr->m_wrapYRotation;
+
+ d_ptr->m_zoomLevel = source.d_ptr->m_zoomLevel;
+ d_ptr->m_activePreset = source.d_ptr->m_activePreset;
+}
+
+/*!
+ * \property Q3DCamera::xRotation
+ *
+ * This property contains the X-rotation angle of the camera around the target point in degrees starting from
+ * the current base position set by the setBaseOrientation() methods.
+ */
+qreal Q3DCamera::xRotation() const {
+ return d_ptr->m_xRotation;
+}
+
+void Q3DCamera::setXRotation(qreal rotation)
+{
+ if (d_ptr->m_wrapXRotation)
+ rotation = Utils::wrapValue(rotation, d_ptr->m_minXRotation, d_ptr->m_maxXRotation);
+ else
+ rotation = qBound(qreal(d_ptr->m_minXRotation), qreal(rotation), qreal(d_ptr->m_maxXRotation));
+
+ if (d_ptr->m_xRotation != rotation) {
+ d_ptr->setXRotation(rotation);
+ if (d_ptr->m_activePreset != QDataVis::CameraPresetNone) {
+ d_ptr->m_activePreset = QDataVis::CameraPresetNone;
+ setDirty(true);
+ }
+
+ emit xRotationChanged(d_ptr->m_xRotation);
+ }
+}
+
+/*!
+ * \property Q3DCamera::yRotation
+ *
+ * This property contains the Y-rotation angle of the camera around the target point in degrees starting from
+ * the current base position set by the setBaseOrientation() methods.
+ */
+qreal Q3DCamera::yRotation() const {
+ return d_ptr->m_yRotation;
+}
+
+void Q3DCamera::setYRotation(qreal rotation)
+{
+ if (d_ptr->m_wrapYRotation)
+ rotation = Utils::wrapValue(rotation, d_ptr->m_minYRotation, d_ptr->m_maxYRotation);
+ else
+ rotation = qBound(qreal(d_ptr->m_minYRotation), qreal(rotation), qreal(d_ptr->m_maxYRotation));
+
+ if (d_ptr->m_yRotation != rotation) {
+ d_ptr->setYRotation(rotation);
+ if (d_ptr->m_activePreset != QDataVis::CameraPresetNone) {
+ d_ptr->m_activePreset = QDataVis::CameraPresetNone;
+ setDirty(true);
+ }
+
+ emit yRotationChanged(d_ptr->m_yRotation);
+ }
+}
+
+/*!
+ * \property Q3DCamera::minXRotation
+ *
+ * This property contains the current minimum X-rotation for the camera.
+ * The full circle range is [-180,180] and the minimum value is limited to -180.
+ * Also the value can't be higher than maximum, and is adjusted if necessary.
+ *
+ * \sa wrapXRotation, maxXRotation
+ */
+qreal Q3DCamera::minXRotation() const
+{
+ return d_ptr->m_minXRotation;
+}
+
+/*!
+ * \internal
+ */
+void Q3DCamera::setMinXRotation(qreal minRotation)
+{
+ minRotation = qBound(-180.0, minRotation, 180.0);
+ if (minRotation > d_ptr->m_maxXRotation)
+ minRotation = d_ptr->m_maxXRotation;
+
+ if (d_ptr->m_minXRotation != minRotation) {
+ d_ptr->m_minXRotation = minRotation;
+ emit minXRotationChanged(minRotation);
+
+ if (d_ptr->m_xRotation < d_ptr->m_minXRotation)
+ setXRotation(d_ptr->m_xRotation);
+ }
+}
+
+/*!
+ * \property Q3DCamera::minYRotation
+ *
+ * This property contains the current minimum Y-rotation for the camera.
+ * The full Y angle range is [-90,90] and the minimum value is limited to -90.
+ * Also the value can't be higher than maximum, and is adjusted if necessary.
+ *
+ * \sa wrapYRotation, maxYRotation
+ */
+qreal Q3DCamera::minYRotation() const
+{
+ return d_ptr->m_minYRotation;
+}
+
+/*!
+ * \internal
+ */
+void Q3DCamera::setMinYRotation(qreal minRotation)
+{
+ minRotation = qBound(-90.0, minRotation, 90.0);
+ if (minRotation > d_ptr->m_maxYRotation)
+ minRotation = d_ptr->m_maxYRotation;
+
+ if (d_ptr->m_minYRotation != minRotation) {
+ d_ptr->m_minYRotation = minRotation;
+ emit minYRotationChanged(minRotation);
+
+ if (d_ptr->m_yRotation < d_ptr->m_minYRotation)
+ setYRotation(d_ptr->m_yRotation);
+ }
+}
+
+/*!
+ * \property Q3DCamera::maxXRotation
+ *
+ * This property contains the current maximum X-rotation for the camera.
+ * The full circle range is [-180,180] and the maximum value is limited to 180.
+ * Also the value can't be lower than minimum, and is adjusted if necessary.
+ *
+ * \sa wrapXRotation, minXRotation
+ */
+qreal Q3DCamera::maxXRotation() const
+{
+ return d_ptr->m_maxXRotation;
+}
+
+/*!
+ * \internal
+ */
+void Q3DCamera::setMaxXRotation(qreal maxRotation)
+{
+ maxRotation = qBound(-180.0, maxRotation, 180.0);
+
+ if (maxRotation < d_ptr->m_minXRotation)
+ maxRotation = d_ptr->m_minXRotation;
+
+ if (d_ptr->m_maxXRotation != maxRotation) {
+ d_ptr->m_maxXRotation = maxRotation;
+ emit maxXRotationChanged(maxRotation);
+
+ if (d_ptr->m_xRotation > d_ptr->m_maxXRotation)
+ setXRotation(d_ptr->m_xRotation);
+ }
+}
+
+/*!
+ * \property Q3DCamera::maxYRotation
+ *
+ * This property contains the current maximum Y-rotation for the camera.
+ * The full Y angle range is [-90,90] and the maximum value is limited to 90.
+ * Also the value can't be lower than minimum, and is adjusted if necessary.
+ *
+ * \sa wrapYRotation, minYRotation
+ */
+qreal Q3DCamera::maxYRotation() const
+{
+ return d_ptr->m_maxYRotation;
+}
+
+/*!
+ * \internal
+ */
+void Q3DCamera::setMaxYRotation(qreal maxRotation)
+{
+ maxRotation = qBound(-90.0, maxRotation, 90.0);
+
+ if (maxRotation < d_ptr->m_minYRotation)
+ maxRotation = d_ptr->m_minYRotation;
+
+ if (d_ptr->m_maxYRotation != maxRotation) {
+ d_ptr->m_maxYRotation = maxRotation;
+ emit maxYRotationChanged(maxRotation);
+
+ if (d_ptr->m_yRotation > d_ptr->m_maxYRotation)
+ setYRotation(d_ptr->m_yRotation);
+ }
+}
+
+/*!
+ * Sets the base values for the camera that are used when calculating the camera position using the rotation values.
+ * The base position of the camera is defined by \a basePosition, expectation is that the x and y values are 0.
+ * Look at target point is defined by \a target and the camera rotates around it. Up direction for the camera is
+ * defined by \a baseUp, normally this is a vector with only y values set to 1.
+ */
+void Q3DCamera::setBaseOrientation(const QVector3D &basePosition,
+ const QVector3D &target,
+ const QVector3D &baseUp)
+{
+ if (position() != basePosition
+ || d_ptr->m_target != target
+ || d_ptr->m_up != baseUp) {
+ setPosition(basePosition);
+ d_ptr->m_target = target;
+ d_ptr->m_up = baseUp;
+ setDirty(true);
+ }
+}
+
+/*!
+ * \property Q3DCamera::viewMatrix
+ *
+ * This property contains the view matrix used in the 3D calculations. When the default orbiting camera behavior is sufficient
+ * there is no need to touch this property. But if the default behavior is insufficient the view matrix can be set directly.
+ * When setting the view matrix directly remember to set Q3DCamera::viewMatrixAutoUpdateEnabled to false.
+ */
+QMatrix4x4 Q3DCamera::viewMatrix() const
+{
+ return d_ptr->m_viewMatrix;
+}
+
+void Q3DCamera::setViewMatrix(const QMatrix4x4 &viewMatrix)
+{
+ if (d_ptr->m_viewMatrix != viewMatrix) {
+ d_ptr->m_viewMatrix = viewMatrix;
+ setDirty(true);
+ emit viewMatrixChanged(d_ptr->m_viewMatrix);
+ }
+}
+
+/*!
+ * \property Q3DCamera::viewMatrixAutoUpdateEnabled
+ *
+ * This property determines if view matrix is automatically updated each render cycle using the current base orientation and
+ * rotations. If set to false, no automatic recalculation is done and the view matrix can be set using the
+ * Q3DMatrix::viewMatrix property.
+ */
+bool Q3DCamera::isViewMatrixAutoUpdateEnabled()
+{
+ return d_ptr->m_isViewMatrixUpdateActive;
+}
+
+void Q3DCamera::setViewMatrixAutoUpdateEnabled(bool isEnabled)
+{
+ d_ptr->m_isViewMatrixUpdateActive = isEnabled;
+ emit viewMatrixAutoUpdateChanged(isEnabled);
+}
+
+/*!
+ * \property Q3DCamera::cameraPreset
+ *
+ * This property contains the currently active camera preset,
+ * if no preset is active the value is QDataVis::CameraPresetNone.
+ * \note The base camera orientation set by setBaseOrientation() will affect
+ * the presets as all calculations are based on those values.
+ */
+QDataVis::CameraPreset Q3DCamera::cameraPreset()
+{
+ return d_ptr->m_activePreset;
+}
+
+void Q3DCamera::setCameraPreset(QDataVis::CameraPreset preset)
+{
+ switch (preset) {
+ case QDataVis::CameraPresetFrontLow: {
+ setXRotation(0.0);
+ setYRotation(0.0);
+ break;
+ }
+ case QDataVis::CameraPresetFront: {
+ setXRotation(0.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetFrontHigh: {
+ setXRotation(0.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetLeftLow: {
+ setXRotation(90.0);
+ setYRotation(0.0);
+ break;
+ }
+ case QDataVis::CameraPresetLeft: {
+ setXRotation(90.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetLeftHigh: {
+ setXRotation(90.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetRightLow: {
+ setXRotation(-90.0);
+ setYRotation(0.0);
+ break;
+ }
+ case QDataVis::CameraPresetRight: {
+ setXRotation(-90.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetRightHigh: {
+ setXRotation(-90.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetBehindLow: {
+ setXRotation(180.0);
+ setYRotation(0.0);
+ break;
+ }
+ case QDataVis::CameraPresetBehind: {
+ setXRotation(180.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetBehindHigh: {
+ setXRotation(180.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetIsometricLeft: {
+ setXRotation(45.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetIsometricLeftHigh: {
+ setXRotation(45.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetIsometricRight: {
+ setXRotation(-45.0);
+ setYRotation(22.5);
+ break;
+ }
+ case QDataVis::CameraPresetIsometricRightHigh: {
+ setXRotation(-45.0);
+ setYRotation(45.0);
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAbove: {
+ setXRotation(0.0);
+ setYRotation(90.0);
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAboveCW45: {
+ setXRotation(-45.0);
+ setYRotation(90.0);
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAboveCCW45: {
+ setXRotation(45.0);
+ setYRotation(90.0);
+ break;
+ }
+ case QDataVis::CameraPresetFrontBelow: {
+ setXRotation(0.0);
+ setYRotation(-45.0);
+ break;
+ }
+ case QDataVis::CameraPresetLeftBelow: {
+ setXRotation(90.0);
+ setYRotation(-45.0);
+ break;
+ }
+ case QDataVis::CameraPresetRightBelow: {
+ setXRotation(-90.0);
+ setYRotation(-45.0);
+ break;
+ }
+ case QDataVis::CameraPresetBehindBelow: {
+ setXRotation(180.0);
+ setYRotation(-45.0);
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyBelow: {
+ setXRotation(0.0);
+ setYRotation(-90.0);
+ break;
+ }
+ default:
+ preset = QDataVis::CameraPresetNone;
+ break;
+ }
+
+ if (d_ptr->m_activePreset != preset) {
+ d_ptr->m_activePreset = preset;
+ setDirty(true);
+ emit cameraPresetChanged(preset);
+ }
+}
+
+/*!
+ * \property Q3DCamera::zoomLevel
+ *
+ * This property contains the the camera zoom level in percentages.
+ * 100% means there is no zoom in or out set in the camera.
+ */
+int Q3DCamera::zoomLevel()
+{
+ return d_ptr->m_zoomLevel;
+}
+
+void Q3DCamera::setZoomLevel(int zoomLevel)
+{
+ if (d_ptr->m_zoomLevel != zoomLevel) {
+ d_ptr->m_zoomLevel = zoomLevel;
+ setDirty(true);
+ emit zoomLevelChanged(zoomLevel);
+ }
+}
+
+/*!
+ * Calculates and returns a position relative to the camera using the given parameters
+ * and the current camera viewMatrix property.
+ * \a relativePosition defines the relative 3D offset to the current camera position.
+ * \a fixedRotation is optional, if given fixes rotation of the calculated point around the data visualization area to the given value in degrees.
+ * \a distanceModifier is also optional, if given modifies the distance of the calculated point from the data visualization.
+ * \return Calculated position relative to this camera's position.
+ */
+QVector3D Q3DCamera::calculatePositionRelativeToCamera(const QVector3D &relativePosition,
+ qreal fixedRotation,
+ qreal distanceModifier) const
+{
+ // Move the position with camera
+ GLfloat radiusFactor = relativePosition.z() * (1.5f + distanceModifier);
+ GLfloat xAngle;
+ GLfloat yAngle;
+ if (!fixedRotation) {
+ xAngle = qDegreesToRadians(d_ptr->m_xRotation);
+ yAngle = qDegreesToRadians(d_ptr->m_yRotation);
+ } else {
+ xAngle = qDegreesToRadians(fixedRotation);
+ yAngle = 0;
+ }
+ GLfloat radius = (radiusFactor + relativePosition.y()); // set radius to match the highest height of the position
+ GLfloat zPos = radius * qCos(xAngle) * qCos(yAngle);
+ GLfloat xPos = radius * qSin(xAngle) * qCos(yAngle);
+ GLfloat yPos = (radiusFactor + relativePosition.y()) * qSin(yAngle);
+ // Keep in the set position in relation to camera
+ return QVector3D(-xPos + relativePosition.x(),
+ yPos + relativePosition.y(),
+ zPos + relativePosition.z());
+}
+
+/*!
+ * \property Q3DCamera::wrapXRotation
+ *
+ * This property determines the behavior of the minimum and maximum limits in the X-rotation.
+ * By default the X-rotation wraps from minimum value to maximum and from maximum to minimum.
+ *
+ * If set to true the X-rotation of the camera is wrapped from minimum to maximum and from maximum to minimum.
+ * If set to false the X-rotation of the camera is limited to the sector determined by minimum and maximum values.
+ */
+bool Q3DCamera::wrapXRotation() const
+{
+ return d_ptr->m_wrapXRotation;
+}
+
+void Q3DCamera::setWrapXRotation(bool isEnabled)
+{
+ d_ptr->m_wrapXRotation = isEnabled;
+}
+
+/*!
+ * \property Q3DCamera::wrapYRotation
+ *
+ * This property determines the behavior of the minimum and maximum limits in the Y-rotation.
+ * By default the Y-rotation is limited between the minimum and maximum values without any wrapping.
+ *
+ * If true the Y-rotation of the camera is wrapped from minimum to maximum and from maximum to minimum.
+ * If false the Y-rotation of the camera is limited to the sector determined by minimum and maximum values.
+ */
+bool Q3DCamera::wrapYRotation() const
+{
+ return d_ptr->m_wrapYRotation;
+}
+
+void Q3DCamera::setWrapYRotation(bool isEnabled)
+{
+ d_ptr->m_wrapYRotation = isEnabled;
+}
+
+/*!
+ * Utility function that sets the camera rotations and distance.\a horizontal and \a vertical define the camera rotations to be used.
+ * Optional \a zoom parameter can be given to set the zoom of the camera in range of 10-500%.
+ */
+void Q3DCamera::setCameraPosition(qreal horizontal, qreal vertical, qreal zoom)
+{
+ setZoomLevel(qBound(10.0, zoom, 500.0));
+ setXRotation(horizontal);
+ setYRotation(vertical);
+}
+
+Q3DCameraPrivate::Q3DCameraPrivate(Q3DCamera *q) :
+ q_ptr(q),
+ m_isViewMatrixUpdateActive(true),
+ m_xRotation(0.0),
+ m_yRotation(0.0),
+ m_minXRotation(-180.0),
+ m_minYRotation(0.0),
+ m_maxXRotation(180.0),
+ m_maxYRotation(90.0),
+ m_wrapXRotation(true),
+ m_wrapYRotation(false),
+ m_zoomLevel(100),
+ m_activePreset(QDataVis::CameraPresetNone)
+{
+}
+
+Q3DCameraPrivate::~Q3DCameraPrivate()
+{
+}
+
+// Copies changed values from this camera to the other camera. If the other camera had same changes,
+// those changes are discarded.
+void Q3DCameraPrivate::sync(Q3DCamera &other)
+{
+ if (q_ptr->isDirty()) {
+ other.copyValuesFrom(*q_ptr);
+ q_ptr->setDirty(false);
+ other.setDirty(false);
+ }
+}
+
+void Q3DCameraPrivate::setXRotation(const qreal rotation)
+{
+ if (m_xRotation != rotation) {
+ m_xRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+void Q3DCameraPrivate::setYRotation(const qreal rotation)
+{
+ if (m_yRotation != rotation) {
+ m_yRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+void Q3DCameraPrivate::setMinXRotation(const qreal rotation)
+{
+ if (m_minXRotation != rotation) {
+ m_minXRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+void Q3DCameraPrivate::setMinYRotation(const qreal rotation)
+{
+ if (m_minYRotation != rotation) {
+ m_minYRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+void Q3DCameraPrivate::setMaxXRotation(const qreal rotation)
+{
+ if (m_maxXRotation != rotation) {
+ m_maxXRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+void Q3DCameraPrivate::setMaxYRotation(const qreal rotation)
+{
+ if (m_maxYRotation != rotation) {
+ m_maxYRotation = rotation;
+ q_ptr->setDirty(true);
+ }
+}
+
+// Recalculates the view matrix based on the currently set base orientation, rotation and zoom level values.
+// zoomAdjustment is adjustment to ensure that the 3D visualization stays inside the view area in the 100% zoom.
+void Q3DCameraPrivate::updateViewMatrix(qreal zoomAdjustment)
+{
+ if (!m_isViewMatrixUpdateActive)
+ return;
+
+ int zoom = m_zoomLevel * zoomAdjustment;
+ QMatrix4x4 viewMatrix;
+
+ // Apply to view matrix
+ viewMatrix.lookAt(q_ptr->position(), m_target, m_up);
+ // Compensate for translation (if d_ptr->m_target is off origin)
+ viewMatrix.translate(m_target.x(), m_target.y(), m_target.z());
+ // Apply rotations
+ // Handle x and z rotation when y -angle is other than 0
+ viewMatrix.rotate(m_xRotation, 0, qCos(qDegreesToRadians(m_yRotation)),
+ qSin(qDegreesToRadians(m_yRotation)));
+ // y rotation is always "clean"
+ viewMatrix.rotate(m_yRotation, 1.0f, 0.0f, 0.0f);
+ // handle zoom by scaling
+ viewMatrix.scale((GLfloat)zoom / 100.0f);
+ // Compensate for translation (if d_ptr->m_target is off origin)
+ viewMatrix.translate(-m_target.x(), -m_target.y(), -m_target.z());
+
+ q_ptr->setViewMatrix(viewMatrix);
+}
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dcamera.h b/src/datavisualization/engine/q3dcamera.h
new file mode 100644
index 00000000..ee750cec
--- /dev/null
+++ b/src/datavisualization/engine/q3dcamera.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DCAMERA_H
+#define Q3DCAMERA_H
+
+#include <QtDataVisualization/q3dobject.h>
+#include <QMatrix4x4>
+
+class QVector3D;
+class QPoint;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCameraPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DCamera : public Q3DObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation NOTIFY xRotationChanged)
+ Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation NOTIFY yRotationChanged)
+ Q_PROPERTY(qreal minXRotation READ minXRotation NOTIFY minXRotationChanged)
+ Q_PROPERTY(qreal minYRotation READ minYRotation NOTIFY minYRotationChanged)
+ Q_PROPERTY(qreal maxXRotation READ maxXRotation NOTIFY maxXRotationChanged)
+ Q_PROPERTY(qreal maxYRotation READ maxYRotation NOTIFY maxYRotationChanged)
+ Q_PROPERTY(int zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+ Q_PROPERTY(QMatrix4x4 viewMatrix READ viewMatrix WRITE setViewMatrix NOTIFY viewMatrixChanged)
+ Q_PROPERTY(QtDataVisualization::QDataVis::CameraPreset cameraPreset READ cameraPreset WRITE setCameraPreset NOTIFY cameraPresetChanged)
+ Q_PROPERTY(bool viewMatrixAutoUpdateEnabled READ isViewMatrixAutoUpdateEnabled WRITE setViewMatrixAutoUpdateEnabled NOTIFY viewMatrixAutoUpdateChanged)
+ Q_PROPERTY(bool wrapXRotation READ wrapXRotation WRITE setWrapXRotation NOTIFY wrapXRotationChanged )
+ Q_PROPERTY(bool wrapYRotation READ wrapYRotation WRITE setWrapYRotation NOTIFY wrapYRotationChanged )
+ Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset)
+
+public:
+ Q3DCamera(QObject *parent = 0);
+ virtual ~Q3DCamera();
+
+ qreal xRotation() const;
+ void setXRotation(qreal rotation);
+ qreal yRotation() const;
+ void setYRotation(qreal rotation);
+
+ qreal minXRotation() const;
+ qreal maxXRotation() const;
+
+ qreal minYRotation() const;
+ qreal maxYRotation() const;
+
+ bool wrapXRotation() const;
+ void setWrapXRotation(bool isEnabled);
+
+ bool wrapYRotation() const;
+ void setWrapYRotation(bool isEnabled);
+
+ void copyValuesFrom(const Q3DCamera &source);
+
+ QMatrix4x4 viewMatrix() const;
+ void setViewMatrix(const QMatrix4x4 &viewMatrix);
+
+ bool isViewMatrixAutoUpdateEnabled();
+ void setViewMatrixAutoUpdateEnabled(bool isEnabled);
+
+ QDataVis::CameraPreset cameraPreset();
+ void setCameraPreset(QDataVis::CameraPreset preset);
+
+ int zoomLevel();
+ void setZoomLevel(int zoomLevel);
+
+ void setBaseOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp);
+
+ QVector3D calculatePositionRelativeToCamera(const QVector3D &relativePosition,
+ qreal fixedRotation,
+ qreal distanceModifier) const;
+ void setCameraPosition(qreal horizontal, qreal vertical, qreal distance = 100.0);
+
+signals:
+ void xRotationChanged(qreal rotation);
+ void yRotationChanged(qreal rotation);
+ void minXRotationChanged(qreal rotation);
+ void minYRotationChanged(qreal rotation);
+ void maxXRotationChanged(qreal rotation);
+ void maxYRotationChanged(qreal rotation);
+ void zoomLevelChanged(int zoomLevel);
+ void viewMatrixChanged(QMatrix4x4 viewMatrix);
+ void cameraPresetChanged(QDataVis::CameraPreset preset);
+ void viewMatrixAutoUpdateChanged(bool enabled);
+ void wrapXRotationChanged(bool isEnabled);
+ void wrapYRotationChanged(bool isEnabled);
+
+protected:
+ void setMinXRotation(qreal rotation);
+ void setMinYRotation(qreal rotation);
+ void setMaxXRotation(qreal rotation);
+ void setMaxYRotation(qreal rotation);
+
+private:
+ QScopedPointer<Q3DCameraPrivate> d_ptr;
+
+ Q_DISABLE_COPY(Q3DCamera)
+
+ friend class Q3DCameraPrivate;
+ friend class Q3DScenePrivate;
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
+ friend class SelectionPointer;
+ friend class Q3DInputHandler;
+ friend class QTouch3DInputHandlerPrivate;
+ friend class QMac3DInputHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DCAMERA_H
diff --git a/src/datavisualization/engine/q3dcamera_p.h b/src/datavisualization/engine/q3dcamera_p.h
new file mode 100644
index 00000000..e0528dcc
--- /dev/null
+++ b/src/datavisualization/engine/q3dcamera_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DCAMERA_P_H
+#define Q3DCAMERA_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dcamera.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCamera;
+
+class Q3DCameraPrivate
+{
+public:
+ Q3DCameraPrivate(Q3DCamera *q);
+ ~Q3DCameraPrivate();
+
+ void sync(Q3DCamera &other);
+
+ void setXRotation(qreal rotation);
+ void setYRotation(qreal rotation);
+ void setMinXRotation(qreal rotation);
+ void setMinYRotation(qreal rotation);
+ void setMaxXRotation(qreal rotation);
+ void setMaxYRotation(qreal rotation);
+
+ void updateViewMatrix(qreal zoomAdjustment);
+
+public:
+ Q3DCamera *q_ptr;
+
+ QVector3D m_target;
+ QVector3D m_up;
+
+ QMatrix4x4 m_viewMatrix;
+ bool m_isViewMatrixUpdateActive;
+
+ GLfloat m_xRotation;
+ GLfloat m_yRotation;
+ GLfloat m_minXRotation;
+ GLfloat m_minYRotation;
+ GLfloat m_maxXRotation;
+ GLfloat m_maxYRotation;
+ bool m_wrapXRotation;
+ bool m_wrapYRotation;
+ int m_zoomLevel;
+ QDataVis::CameraPreset m_activePreset;
+
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
+ friend class SelectionPointer;
+ friend class Q3DInputHandler;
+ friend class QTouch3DInputHandler;
+ friend class QMac3DInputHandler;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DCAMERA_P_H
diff --git a/src/datavisualization/engine/q3dlight.cpp b/src/datavisualization/engine/q3dlight.cpp
new file mode 100644
index 00000000..c482e62a
--- /dev/null
+++ b/src/datavisualization/engine/q3dlight.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dlight.h"
+#include "q3dscene.h"
+#include "q3dlight_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DLight
+ \inmodule QtDataVisualization
+ \brief Representation of a light source in 3D space.
+ \since 1.0.0
+
+ Q3DLight represents a monochrome non variable light source in 3D space.
+*/
+
+/*!
+ * Constructs a new 3D light located at origo. An optional \a parent parameter can be given
+ * and is then passed to QObject constructor.
+ */
+Q3DLight::Q3DLight(QObject *parent) :
+ Q3DObject(parent),
+ d_ptr(new Q3DLightPrivate(this))
+{
+}
+
+/*!
+ * Copies the properties of the 3D light from the given source \a source light to this light instance.
+ */
+void Q3DLight::copyValuesFrom(const Q3DLight &source)
+{
+ Q3DObject::copyValuesFrom(source);
+}
+
+/*!
+ * Destroys the light object.
+ */
+Q3DLight::~Q3DLight()
+{
+}
+
+Q3DLightPrivate::Q3DLightPrivate(Q3DLight *q) :
+ q_ptr(q)
+{
+}
+
+Q3DLightPrivate::~Q3DLightPrivate()
+{
+}
+
+void Q3DLightPrivate::sync(Q3DLight &other)
+{
+ // Copies changed values from this light to the other light. If the other light had same changes,
+ // those changes are discarded.
+ if (q_ptr->isDirty()) {
+ other.copyValuesFrom(*q_ptr);
+ q_ptr->setDirty(false);
+ other.setDirty(false);
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dlight.h b/src/datavisualization/engine/q3dlight.h
new file mode 100644
index 00000000..0a4ba174
--- /dev/null
+++ b/src/datavisualization/engine/q3dlight.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DLIGHT_H
+#define Q3DLIGHT_H
+
+#include <QtDataVisualization/q3dobject.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DLightPrivate;
+class Q3DScene;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DLight : public Q3DObject
+{
+ Q_OBJECT
+
+public:
+ Q3DLight(QObject *parent = 0);
+ virtual ~Q3DLight();
+
+ void copyValuesFrom(const Q3DLight &source);
+
+private:
+ QScopedPointer<Q3DLightPrivate> d_ptr;
+
+ Q_DISABLE_COPY(Q3DLight)
+
+ friend class Q3DLightPrivate;
+ friend class Q3DScenePrivate;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DLIGHT_H
diff --git a/src/datavisualization/engine/q3dlight_p.h b/src/datavisualization/engine/q3dlight_p.h
new file mode 100644
index 00000000..dad6d670
--- /dev/null
+++ b/src/datavisualization/engine/q3dlight_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DLIGHT_P_H
+#define Q3DLIGHT_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dlight.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DScene;
+class Q3DLight;
+
+class Q3DLightPrivate
+{
+public:
+ Q3DLightPrivate(Q3DLight *q);
+ ~Q3DLightPrivate();
+
+ void sync(Q3DLight &other);
+
+public:
+ Q3DLight *q_ptr;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DLIGHT_P_H
+
+
+
+
+
diff --git a/src/datavisualization/engine/q3dobject.cpp b/src/datavisualization/engine/q3dobject.cpp
new file mode 100644
index 00000000..ae13af7d
--- /dev/null
+++ b/src/datavisualization/engine/q3dobject.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dobject.h"
+#include "q3dobject_p.h"
+#include "q3dscene.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DObject
+ \inmodule QtDataVisualization
+ \brief Simple baseclass for all the objects in the 3D scene.
+ \since 1.0.0
+
+ Q3DObject is a baseclass that contains only position information for an object in 3D scene.
+ The object is considered to be a single point in the coordinate space without dimensions.
+*/
+
+/*!
+ * Constructs a new 3D object with position set to origo by default. An
+ * optional \a parent parameter can be given and is then passed to QObject constructor.
+ */
+Q3DObject::Q3DObject(QObject *parent) :
+ QObject(parent),
+ d_ptr(new Q3DObjectPrivate(this))
+{
+}
+
+/*!
+ * Destroys the 3D object.
+ */
+Q3DObject::~Q3DObject()
+{
+}
+
+/*!
+ * Copies the 3D object position from the given \a source 3D object to this 3D object instance.
+ */
+void Q3DObject::copyValuesFrom(const Q3DObject &source)
+{
+ d_ptr->m_position.setX(source.d_ptr->m_position.x());
+ d_ptr->m_position.setY(source.d_ptr->m_position.y());
+ d_ptr->m_position.setZ(source.d_ptr->m_position.z());
+ setDirty(true);
+}
+
+/*!
+ * \property Q3DObject::parentScene
+ *
+ * This property contains the parent scene as read only value.
+ * If the object has no parent scene the value is 0.
+ */
+Q3DScene *Q3DObject::parentScene()
+{
+ return qobject_cast<Q3DScene *>(parent());
+}
+
+/*!
+ * \property Q3DObject::position
+ *
+ * This property contains the 3D position of the object.
+ */
+QVector3D Q3DObject::position() const
+{
+ return d_ptr->m_position;
+}
+
+void Q3DObject::setPosition(const QVector3D &position)
+{
+ if (d_ptr->m_position != position) {
+ d_ptr->m_position = position;
+ setDirty(true);
+ emit positionChanged(d_ptr->m_position);
+ }
+}
+
+/*!
+ * Sets and clears the \a dirty flag that is used to track
+ * when the 3D object has changed since last update.
+ */
+void Q3DObject::setDirty(bool dirty)
+{
+ d_ptr->m_isDirty = dirty;
+}
+
+/*!
+ * \return flag that indicates if the 3D object has changed.
+ */
+bool Q3DObject::isDirty() const
+{
+ return d_ptr->m_isDirty;
+}
+
+Q3DObjectPrivate::Q3DObjectPrivate(Q3DObject *q) :
+ q_ptr(q),
+ m_isDirty(true)
+{
+}
+
+Q3DObjectPrivate::~Q3DObjectPrivate()
+{
+
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dobject.h b/src/datavisualization/engine/q3dobject.h
new file mode 100644
index 00000000..930bb022
--- /dev/null
+++ b/src/datavisualization/engine/q3dobject.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DOBJECT_H
+#define Q3DOBJECT_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/q3dscene.h>
+
+#include <QObject>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+class Q3DObjectPrivate;
+
+class Q3DObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Q3DScene* parentScene READ parentScene)
+ Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
+
+public:
+ Q3DObject(QObject *parent = 0);
+ virtual ~Q3DObject();
+
+ void copyValuesFrom(const Q3DObject &source);
+
+ Q3DScene *parentScene();
+
+ QVector3D position() const;
+ void setPosition(const QVector3D &position);
+
+signals:
+ void positionChanged(QVector3D position);
+
+protected:
+ void setDirty(bool dirty);
+ bool isDirty() const;
+
+private:
+ QScopedPointer<Q3DObjectPrivate> d_ptr;
+
+ Q_DISABLE_COPY(Q3DObject)
+
+ friend class Q3DScenePrivate;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DOBJECT_H
diff --git a/src/datavisualization/engine/q3dobject_p.h b/src/datavisualization/engine/q3dobject_p.h
new file mode 100644
index 00000000..bac18cfe
--- /dev/null
+++ b/src/datavisualization/engine/q3dobject_p.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DOBJECT_P_H
+#define Q3DOBJECT_P_H
+
+#include "datavisualizationglobal_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DObject;
+class Q3DScene;
+
+class Q3DObjectPrivate
+{
+public:
+ Q3DObjectPrivate(Q3DObject *q);
+ ~Q3DObjectPrivate();
+
+public:
+ Q3DObject *q_ptr;
+ QVector3D m_position;
+ bool m_isDirty;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DOBJECT_P_H
diff --git a/src/datavisualization/engine/q3dscatter.cpp b/src/datavisualization/engine/q3dscatter.cpp
new file mode 100644
index 00000000..a5053bf3
--- /dev/null
+++ b/src/datavisualization/engine/q3dscatter.cpp
@@ -0,0 +1,568 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dscatter.h"
+#include "q3dscatter_p.h"
+#include "scatter3dcontroller_p.h"
+#include "q3dvalueaxis.h"
+#include "qscatterdataproxy.h"
+#include "q3dcamera.h"
+
+#include <QMouseEvent>
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DScatter
+ * \inmodule QtDataVisualization
+ * \brief The Q3DScatter class provides methods for rendering 3D scatter graphs.
+ * \since 1.0.0
+ *
+ * This class enables developers to render scatter graphs in 3D and to view them by rotating the scene
+ * freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming
+ * is done by mouse wheel. Selection, if enabled, is done by left mouse button. The scene can be
+ * reset to default camera view by clicking mouse wheel. In touch devices rotation is done
+ * by tap-and-move, selection by tap-and-hold and zoom by pinch.
+ *
+ * If no axes are explicitly set to Q3DScatter, temporary default axes with no labels are created.
+ * These default axes can be modified via axis accessors, but as soon any axis is explicitly
+ * set for the orientation, the default axis for that orientation is destroyed.
+ *
+ * Data proxies work similarly: If no data proxy is explicitly set, Q3DScatter creates a default
+ * proxy. If any other proxy is set as active data proxy later, the default proxy and all data
+ * added to it is destroyed.
+ *
+ * Methods are provided for changing item styles, themes, item selection modes and so on. See the
+ * methods for more detailed descriptions.
+ *
+ * \section1 How to construct a minimal Q3DScatter graph
+ *
+ * First, construct Q3DScatter:
+ *
+ * \snippet doc_src_q3dscatter_construction.cpp 0
+ *
+ * Now Q3DScatter is ready to receive data to be rendered. Add one set of 3 QVector3D items:
+ *
+ * \snippet doc_src_q3dscatter_construction.cpp 1
+ *
+ * Finally you will need to set it visible:
+ *
+ * \snippet doc_src_q3dscatter_construction.cpp 2
+ *
+ * The complete code needed to create and display this graph is:
+ *
+ * \snippet doc_src_q3dscatter_construction.cpp 3
+ *
+ * And this is what those few lines of code produce:
+ *
+ * \image q3dscatter-minimal.png
+ *
+ * The scene can be rotated and zoomed into, but no other interaction is included in this minimal
+ * code example. You can learn more by familiarizing yourself with the examples provided, like
+ * the \l{Scatter Example}.
+ *
+ * \sa Q3DBars, Q3DSurface, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs a new 3D scatter window.
+ */
+Q3DScatter::Q3DScatter()
+ : d_ptr(new Q3DScatterPrivate(this, geometry()))
+{
+ setVisualController(d_ptr->m_shared);
+ d_ptr->m_shared->initializeOpenGL();
+ QObject::connect(d_ptr->m_shared, &Scatter3DController::selectedItemIndexChanged, this,
+ &Q3DScatter::selectedItemIndexChanged);
+ QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this,
+ &Q3DWindow::renderLater);
+}
+
+/*!
+ * Destroys the 3D scatter window.
+ */
+Q3DScatter::~Q3DScatter()
+{
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseDoubleClickEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::touchEvent(QTouchEvent *event)
+{
+ d_ptr->m_shared->touchEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::mousePressEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mousePressEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::mouseReleaseEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseReleaseEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::mouseMoveEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseMoveEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::wheelEvent(QWheelEvent *event)
+{
+ d_ptr->m_shared->wheelEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DScatter::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+ d_ptr->m_shared->setSize(width(), height());
+}
+
+/*!
+ * Sets window \a width.
+ */
+void Q3DScatter::setWidth(const int width)
+{
+ d_ptr->m_shared->setWidth(width);
+ QWindow::setWidth(width);
+}
+
+/*!
+ * Sets window \a height.
+ */
+void Q3DScatter::setHeight(const int height)
+{
+ d_ptr->m_shared->setHeight(height);
+ QWindow::setHeight(height);
+}
+
+/*!
+ * Sets the item \a style to one of the values in \c QDataVis::MeshStyle. It is preset to
+ * \c QDataVis::MeshStyleSpheres by default. A \a smooth flag can be used to set shading to smooth.
+ * It is \c false by default.
+ *
+ * \sa setMeshFileName()
+ */
+void Q3DScatter::setObjectType(QDataVis::MeshStyle style, bool smooth)
+{
+ d_ptr->m_shared->setObjectType(style, smooth);
+}
+
+/*!
+ * Sets a predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by
+ * default. Theme affects bar colors, label colors, text color, background color, window color and
+ * grid color. Lighting is also adjusted by themes.
+ *
+ * \sa setObjectColor()
+ *
+ * \warning This method is subject to change.
+ */
+void Q3DScatter::setTheme(QDataVis::Theme theme)
+{
+ d_ptr->m_shared->setTheme(theme);
+}
+
+/*!
+ * Set item color using your own colors. \a baseColor sets the base color of a item. The \a uniform
+ * -flag is used to define if color needs to be uniform throughout item's length, or will the colors
+ * be applied by height. It is \c true by default.
+ *
+ * Calling this method overrides colors from theme.
+ *
+ * \sa setTheme()
+ *
+ * \warning This method is subject to change.
+ */
+void Q3DScatter::setObjectColor(const QColor &baseColor, bool uniform)
+{
+ d_ptr->m_shared->setObjectColor(baseColor, uniform);
+}
+
+/*!
+ * \return item color in use.
+ */
+QColor Q3DScatter::objectColor() const
+{
+ return d_ptr->m_shared->objectColor();
+}
+
+/*!
+ * \property Q3DScatter::selectionMode
+ *
+ * Sets item selection \a mode to one of \c QDataVis::SelectionMode. It is preset to
+ * \c QDataVis::SelectionModeItem by default.
+ */
+void Q3DScatter::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ d_ptr->m_shared->setSelectionMode(mode);
+}
+
+QDataVis::SelectionMode Q3DScatter::selectionMode() const
+{
+ return d_ptr->m_shared->selectionMode();
+}
+
+/*!
+ * \property Q3DScatter::meshFileName
+ *
+ * Override item type with a mesh object located in \a objFileName.
+ * \note Object needs to be in Wavefront obj format and include vertices, normals and UVs.
+ * It also needs to be in triangles.
+ *
+ * \sa setObjectType()
+ */
+void Q3DScatter::setMeshFileName(const QString &objFileName)
+{
+ d_ptr->m_shared->setMeshFileName(objFileName);
+}
+
+QString Q3DScatter::meshFileName() const
+{
+ return d_ptr->m_shared->meshFileName();
+}
+
+/*!
+ * \property Q3DScatter::font
+ *
+ * Sets the \a font for labels. It is preset to \c Arial by default.
+ */
+void Q3DScatter::setFont(const QFont &font)
+{
+ d_ptr->m_shared->setFont(font);
+}
+
+QFont Q3DScatter::font() const
+{
+ return d_ptr->m_shared->font();
+}
+
+/*!
+ * \property Q3DScatter::scene
+ *
+ * This property contains the read only Q3DScene that can be used to access e.g. camera object.
+ */
+Q3DScene *Q3DScatter::scene() const
+{
+ return d_ptr->m_shared->scene();
+}
+
+/*!
+ * \property Q3DScatter::labelStyle
+ *
+ * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to
+ * \c QDataVis::LabelStyleFromTheme by default.
+ */
+void Q3DScatter::setLabelStyle(QDataVis::LabelStyle style)
+{
+ d_ptr->m_shared->setLabelStyle(style);
+}
+
+QDataVis::LabelStyle Q3DScatter::labelStyle() const
+{
+ return d_ptr->m_shared->labelStyle();
+}
+
+/*!
+ * \property Q3DScatter::gridVisible
+ *
+ * Sets grid visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DScatter::setGridVisible(bool visible)
+{
+ d_ptr->m_shared->setGridEnabled(visible);
+}
+
+bool Q3DScatter::isGridVisible() const
+{
+ return d_ptr->m_shared->gridEnabled();
+}
+
+/*!
+ * \property Q3DScatter::backgroundVisible
+ *
+ * Sets background visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DScatter::setBackgroundVisible(bool visible)
+{
+ d_ptr->m_shared->setBackgroundEnabled(visible);
+}
+
+bool Q3DScatter::isBackgroundVisible() const
+{
+ return d_ptr->m_shared->backgroundEnabled();
+}
+
+/*!
+ * \property Q3DScatter::selectedItemIndex
+ *
+ * Selects an item in the \a index. Only one item can be selected at a time.
+ * To clear selection, specify an illegal \a index, e.g. -1.
+ */
+void Q3DScatter::setSelectedItemIndex(int index)
+{
+ d_ptr->m_shared->setSelectedItemIndex(index);
+}
+
+int Q3DScatter::selectedItemIndex() const
+{
+ return d_ptr->m_shared->selectedItemIndex();
+}
+
+/*!
+ * \property Q3DScatter::shadowQuality
+ *
+ * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to
+ * \c QDataVis::ShadowQualityMedium by default.
+ *
+ * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered
+ * until it is successful and shadowQualityChanged signal is emitted for each time the change is
+ * done.
+ */
+void Q3DScatter::setShadowQuality(QDataVis::ShadowQuality quality)
+{
+ return d_ptr->m_shared->setShadowQuality(quality);
+}
+
+QDataVis::ShadowQuality Q3DScatter::shadowQuality() const
+{
+ return d_ptr->m_shared->shadowQuality();
+}
+
+/*!
+ * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DScatter::setAxisX(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisX(axis);
+}
+
+/*!
+ * \return used X-axis.
+ */
+Q3DValueAxis *Q3DScatter::axisX() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisX());
+}
+
+/*!
+ * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DScatter::setAxisY(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisY(axis);
+}
+
+/*!
+ * \return used Y-axis.
+ */
+Q3DValueAxis *Q3DScatter::axisY() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY());
+}
+
+/*!
+ * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DScatter::setAxisZ(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisZ(axis);
+}
+
+/*!
+ * \return used Z-axis.
+ */
+Q3DValueAxis *Q3DScatter::axisZ() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisZ());
+}
+
+/*!
+ * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use,
+ * addAxis is simply used to give the ownership of the \a axis to the graph.
+ * The \a axis must not be null or added to another graph.
+ *
+ * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ()
+ */
+void Q3DScatter::addAxis(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->addAxis(axis);
+}
+
+/*!
+ * Releases the ownership of the \a axis back to the caller, if it is added to this graph.
+ * If the released \a axis is in use, a new default axis will be created and set active.
+ *
+ * If the default axis is released and added back later, it behaves as any other axis would.
+ *
+ * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ()
+ */
+void Q3DScatter::releaseAxis(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->releaseAxis(axis);
+}
+
+/*!
+ * \return list of all added axes.
+ *
+ * \sa addAxis()
+ */
+QList<Q3DValueAxis *> Q3DScatter::axes() const
+{
+ QList<Q3DAbstractAxis *> abstractAxes = d_ptr->m_shared->axes();
+ QList<Q3DValueAxis *> retList;
+ foreach (Q3DAbstractAxis *axis, abstractAxes)
+ retList.append(static_cast<Q3DValueAxis *>(axis));
+
+ return retList;
+}
+
+/*!
+ * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of
+ * the \a proxy to this graph.
+ *
+ * If the \a proxy is null, a temporary default proxy is created and activated.
+ * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method.
+ *
+ * \sa addDataProxy(), releaseDataProxy()
+ */
+void Q3DScatter::setActiveDataProxy(QScatterDataProxy *proxy)
+{
+ d_ptr->m_shared->setActiveDataProxy(proxy);
+}
+
+/*!
+ * \return active data proxy.
+ */
+QScatterDataProxy *Q3DScatter::activeDataProxy() const
+{
+ return static_cast<QScatterDataProxy *>(d_ptr->m_shared->activeDataProxy());
+}
+
+/*!
+ * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use,
+ * addDataProxy is simply used to give the ownership of the data \a proxy to the graph.
+ * The \a proxy must not be null or added to another graph.
+ *
+ * \sa releaseDataProxy(), setActiveDataProxy()
+ */
+void Q3DScatter::addDataProxy(QScatterDataProxy *proxy)
+{
+ d_ptr->m_shared->addDataProxy(proxy);
+}
+
+/*!
+ * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph.
+ * If the released \a proxy is in use, a new empty default proxy is created and taken to use.
+ *
+ * If the default \a proxy is released and added back later, it behaves as any other proxy would.
+ *
+ * \sa addDataProxy(), setActiveDataProxy()
+ */
+void Q3DScatter::releaseDataProxy(QScatterDataProxy *proxy)
+{
+ d_ptr->m_shared->releaseDataProxy(proxy);
+}
+
+/*!
+ * \return list of all added data proxies.
+ *
+ * \sa addDataProxy()
+ */
+QList<QScatterDataProxy *> Q3DScatter::dataProxies() const
+{
+ QList<QScatterDataProxy *> retList;
+ QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies();
+ foreach (QAbstractDataProxy *proxy, abstractList)
+ retList.append(static_cast<QScatterDataProxy *>(proxy));
+
+ return retList;
+}
+
+/*!
+ * \fn void Q3DScatter::shadowQualityChanged(QDataVis::ShadowQuality quality)
+ *
+ * This signal is emitted when shadow \a quality changes.
+ */
+
+Q3DScatterPrivate::Q3DScatterPrivate(Q3DScatter *q, QRect rect)
+ : q_ptr(q),
+ m_shared(new Scatter3DController(rect))
+{
+ QObject::connect(m_shared, &Abstract3DController::shadowQualityChanged, this,
+ &Q3DScatterPrivate::handleShadowQualityUpdate);
+}
+
+Q3DScatterPrivate::~Q3DScatterPrivate()
+{
+ qDebug() << "Destroying Q3DScatterPrivate";
+ delete m_shared;
+}
+
+void Q3DScatterPrivate::handleShadowQualityUpdate(QDataVis::ShadowQuality quality)
+{
+ emit q_ptr->shadowQualityChanged(quality);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
diff --git a/src/datavisualization/engine/q3dscatter.h b/src/datavisualization/engine/q3dscatter.h
new file mode 100644
index 00000000..fdea604e
--- /dev/null
+++ b/src/datavisualization/engine/q3dscatter.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCATTER_H
+#define Q3DSCATTER_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/q3dwindow.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QFont>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DScatterPrivate;
+class LabelItem;
+class Q3DValueAxis;
+class Q3DCategoryAxis;
+class QScatterDataProxy;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DScatter : public Q3DWindow
+{
+ Q_OBJECT
+ Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
+ Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle)
+ Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality)
+ Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName)
+ Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible)
+ Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible)
+ Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged)
+ Q_PROPERTY(Q3DScene* scene READ scene)
+ Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode)
+ Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality)
+ Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle)
+ Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset)
+
+public:
+ explicit Q3DScatter();
+ ~Q3DScatter();
+
+ void setObjectType(QDataVis::MeshStyle style, bool smooth = false);
+
+ void setTheme(QDataVis::Theme theme);
+
+ void setObjectColor(const QColor &baseColor, bool uniform = true);
+ QColor objectColor() const;
+
+ void setMeshFileName(const QString &objFileName);
+ QString meshFileName() const;
+
+ void setSelectionMode(QDataVis::SelectionMode mode);
+ QDataVis::SelectionMode selectionMode() const;
+
+ void setFont(const QFont &font);
+ QFont font() const;
+
+ Q3DScene *scene() const;
+
+ void setLabelStyle(QDataVis::LabelStyle style);
+ QDataVis::LabelStyle labelStyle() const;
+
+ void setGridVisible(bool visible);
+ bool isGridVisible() const;
+
+ void setWidth(const int width);
+ void setHeight(const int height);
+
+ void setBackgroundVisible(bool visible);
+ bool isBackgroundVisible() const;
+
+ void setSelectedItemIndex(int index);
+ int selectedItemIndex() const;
+
+ void setShadowQuality(QDataVis::ShadowQuality quality);
+ QDataVis::ShadowQuality shadowQuality() const;
+
+ void setAxisX(Q3DValueAxis *axis);
+ Q3DValueAxis *axisX() const;
+ void setAxisY(Q3DValueAxis *axis);
+ Q3DValueAxis *axisY() const;
+ void setAxisZ(Q3DValueAxis *axis);
+ Q3DValueAxis *axisZ() const;
+ void addAxis(Q3DValueAxis *axis);
+ void releaseAxis(Q3DValueAxis *axis);
+ QList<Q3DValueAxis *> axes() const;
+
+ void setActiveDataProxy(QScatterDataProxy *proxy);
+ QScatterDataProxy *activeDataProxy() const;
+ void addDataProxy(QScatterDataProxy *proxy);
+ void releaseDataProxy(QScatterDataProxy *proxy);
+ QList<QScatterDataProxy *> dataProxies() const;
+
+signals:
+ void shadowQualityChanged(QDataVis::ShadowQuality quality);
+ void selectedItemIndexChanged(int index);
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void touchEvent(QTouchEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ QScopedPointer<Q3DScatterPrivate> d_ptr;
+ Q_DISABLE_COPY(Q3DScatter)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dscatter_p.h b/src/datavisualization/engine/q3dscatter_p.h
new file mode 100644
index 00000000..775344d0
--- /dev/null
+++ b/src/datavisualization/engine/q3dscatter_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCATTER_p_H
+#define Q3DSCATTER_p_H
+
+#include "scatter3dcontroller_p.h"
+#include "qdatavisualizationenums.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DScatter;
+
+class Q3DScatterPrivate : public QObject
+{
+public:
+ Q3DScatterPrivate(Q3DScatter *q, QRect rect);
+ ~Q3DScatterPrivate();
+
+ // Used to detect when shadow quality changes autonomously due to e.g. resizing.
+ void handleShadowQualityUpdate(QDataVis::ShadowQuality quality);
+
+ Q3DScatter *q_ptr;
+ Scatter3DController *m_shared;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dscene.cpp b/src/datavisualization/engine/q3dscene.cpp
new file mode 100644
index 00000000..4908bde4
--- /dev/null
+++ b/src/datavisualization/engine/q3dscene.cpp
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 <qmath.h>
+
+#include "datavisualizationglobal_p.h"
+
+#include "q3dscene.h"
+#include "q3dscene_p.h"
+#include "q3dcamera_p.h"
+#include "q3dlight_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+/*!
+ * \class Q3DScene
+ * \inmodule QtDataVisualization
+ * \brief Q3DScene class provides description of the 3D scene being visualized.
+ * \since 1.0.0
+ *
+ * The 3D scene contains a single active camera and a single active light source.
+ * Visualized data is assumed to be at a fixed location.
+ *
+ * The 3D scene also keeps track of the viewport in which visualization rendering is done,
+ * the primary subviewport inside the viewport where the main 3D data visualization view resides
+ * and the secondary subviewport where the 2D sliced view of the data resides.
+ *
+ * Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not.
+ * \note Not all visualizations support the secondary 2D slicing view.
+ */
+
+/*!
+ * Constructs a basic scene with one light and one camera in it. An
+ * optional \a parent parameter can be given and is then passed to QObject constructor.
+ */
+Q3DScene::Q3DScene(QObject *parent) :
+ QObject(parent),
+ d_ptr(new Q3DScenePrivate(this))
+{
+ setActiveCamera(new Q3DCamera(0));
+ setActiveLight(new Q3DLight(0));
+}
+
+/*!
+ * Destroys the 3D scene and all the objects contained within it.
+ */
+Q3DScene::~Q3DScene()
+{
+}
+
+/*!
+ * \property Q3DScene::viewport
+ *
+ * This property contains the current viewport rectangle where all 3D rendering
+ * is targeted.
+ */
+QRect Q3DScene::viewport() const
+{
+ return d_ptr->m_viewport;
+}
+
+void Q3DScene::setViewport(const QRect &viewport)
+{
+ if (d_ptr->m_viewport.width() != viewport.width()
+ || d_ptr->m_viewport.height() != viewport.height()) {
+ d_ptr->m_viewport = viewport;
+ d_ptr->m_viewport.setX(0);
+ d_ptr->m_viewport.setY(0);
+ d_ptr->m_changeTracker.viewportChanged = true;
+ emit viewportChanged(viewport);
+ }
+}
+
+/*!
+ * Sets the \a width and \a height of the viewport only, without changing its location.
+ */
+void Q3DScene::setViewportSize(int width, int height)
+{
+ if (d_ptr->m_viewport.width() != width
+ || d_ptr->m_viewport.height() != height) {
+ d_ptr->m_viewport.setWidth(width);
+ d_ptr->m_viewport.setHeight(height);
+ d_ptr->m_changeTracker.viewportChanged = true;
+ emit viewportChanged(d_ptr->m_viewport);
+ }
+}
+
+/*!
+ * \property Q3DScene::primarySubViewport
+ *
+ * This property contains the current main viewport rectangle inside the viewport where the
+ * primary view of the data visualization is targeted to.
+ */
+QRect Q3DScene::primarySubViewport() const
+{
+ return d_ptr->m_primarySubViewport;
+}
+
+void Q3DScene::setPrimarySubViewport(const QRect &primarySubViewport)
+{
+ if (d_ptr->m_primarySubViewport != primarySubViewport) {
+ d_ptr->m_primarySubViewport = primarySubViewport;
+ d_ptr->m_changeTracker.primarySubViewportChanged = true;
+ emit primarySubViewportChanged(primarySubViewport);
+ }
+}
+
+/*!
+ * Returns whether the given \a point resides inside the primary subview or not.
+ * The method takes care of correctly mapping between OpenGL coordinates used in the
+ * viewport definitions and the Qt event coordinate system used in the input system.
+ * \return true if the point is inside the primary subview.
+ */
+bool Q3DScene::isPointInPrimarySubView(const QPoint &point)
+{
+ // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently.
+ int x = point.x();
+ int y = point.y();
+ int areaMinX = d_ptr->m_primarySubViewport.x();
+ int areaMaxX = d_ptr->m_primarySubViewport.x() + d_ptr->m_primarySubViewport.width();
+ int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_primarySubViewport.y();
+ int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_primarySubViewport.y() + d_ptr->m_primarySubViewport.height());
+
+ return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY );
+}
+
+/*!
+ * Returns whether the given \a point resides inside the secondary subview or not.
+ * The method takes care of correctly mapping between OpenGL coordinates used in the
+ * viewport definitions and the Qt event coordinate system used in the input system.
+ * \return true if the point is inside the secondary subview.
+ */
+bool Q3DScene::isPointInSecondarySubView(const QPoint &point)
+{
+ // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently.
+ int x = point.x();
+ int y = point.y();
+ int areaMinX = d_ptr->m_secondarySubViewport.x();
+ int areaMaxX = d_ptr->m_secondarySubViewport.x() + d_ptr->m_secondarySubViewport.width();
+ int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_secondarySubViewport.y();
+ int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_secondarySubViewport.y() + d_ptr->m_secondarySubViewport.height());
+
+ return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY );
+}
+
+/*!
+ * \property Q3DScene::secondarySubViewport
+ *
+ * This property contains the secondary viewport rectangle inside the viewport. The secondary
+ * viewport is used for drawing the 2D slice view in some visualizations.
+ */
+QRect Q3DScene::secondarySubViewport() const
+{
+ return d_ptr->m_secondarySubViewport;
+}
+
+void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport)
+{
+ if (d_ptr->m_secondarySubViewport != secondarySubViewport) {
+ d_ptr->m_secondarySubViewport = secondarySubViewport;
+ d_ptr->m_changeTracker.secondarySubViewportChanged = true;
+ emit secondarySubViewportChanged(secondarySubViewport);
+ }
+}
+
+/*!
+ * \property Q3DScene::slicingActive
+ *
+ * This property contains whether 2D slicing view is currently active or not.
+ * \note Not all visualizations support the 2D slicing view.
+ */
+bool Q3DScene::isSlicingActive() const
+{
+ return d_ptr->m_isSlicingActive;
+}
+
+void Q3DScene::setSlicingActive(bool isSlicing)
+{
+ if (d_ptr->m_isSlicingActive != isSlicing) {
+ d_ptr->m_isSlicingActive = isSlicing;
+ d_ptr->m_changeTracker.slicingActivatedChanged = true;
+ emit slicingActiveChanged(isSlicing);
+ emitNeedRender();
+ }
+}
+
+/*!
+ * \property Q3DScene::activeCamera
+ *
+ * This property contains the currently active camera in the 3D scene.
+ * When a new Q3DCamera objects is set in the property it gets automatically added as child of the scene.
+ */
+Q3DCamera *Q3DScene::activeCamera() const
+{
+ return d_ptr->m_camera;
+}
+
+void Q3DScene::setActiveCamera(Q3DCamera *camera)
+{
+ Q_ASSERT(camera);
+
+ // Add new camera as child of the scene
+ if (camera->parent() != this)
+ camera->setParent(this);
+
+ if (camera != d_ptr->m_camera) {
+ if (d_ptr->m_camera) {
+ disconnect(d_ptr->m_camera, &Q3DCamera::xRotationChanged, this,
+ &Q3DScene::emitNeedRender);
+ disconnect(d_ptr->m_camera, &Q3DCamera::yRotationChanged, this,
+ &Q3DScene::emitNeedRender);
+ }
+
+ d_ptr->m_camera = camera;
+ d_ptr->m_changeTracker.cameraChanged = true;
+
+ if (camera) {
+ connect(camera, &Q3DCamera::xRotationChanged, this,
+ &Q3DScene::emitNeedRender);
+ connect(camera, &Q3DCamera::yRotationChanged, this,
+ &Q3DScene::emitNeedRender);
+ }
+
+ emit activeCameraChanged(camera);
+ emitNeedRender();
+ }
+}
+
+void Q3DScene::emitNeedRender()
+{
+ emit needRender();
+}
+
+/*!
+ * \property Q3DScene::activeLight
+ *
+ * This property contains the currently active light in the 3D scene.
+ * When a new Q3DLight objects is set in the property it gets automatically added as child of the scene.
+ */
+Q3DLight *Q3DScene::activeLight() const
+{
+ return d_ptr->m_light;
+}
+
+void Q3DScene::setActiveLight(Q3DLight *light)
+{
+ Q_ASSERT(light);
+
+ // Add new light as child of the scene
+ if (light->parent() != this)
+ light->setParent(this);
+
+ if (light != d_ptr->m_light) {
+ d_ptr->m_light = light;
+ d_ptr->m_changeTracker.lightChanged = true;
+ emit activeLightChanged(light);
+ }
+}
+
+/*!
+ * \property Q3DScene::devicePixelRatio
+ *
+ * This property contains the current device pixel ratio that is used when mapping input
+ * coordinates to pixel coordinates.
+ */
+qreal Q3DScene::devicePixelRatio() const
+{
+ return d_ptr->m_devicePixelRatio;
+}
+
+void Q3DScene::setDevicePixelRatio(qreal pixelRatio)
+{
+ if (d_ptr->m_devicePixelRatio != pixelRatio) {
+ d_ptr->m_devicePixelRatio = pixelRatio;
+ emit devicePixelRatioChanged(pixelRatio);
+ }
+}
+
+/*!
+ * Calculates and sets the light position relative to the currently active camera using the given parameters.
+ * \a relativePosition defines the relative 3D offset to the current camera position.
+ * Optional \a fixedRotation fixes the light rotation around the data visualization area to the given value in degrees.
+ * Optional \a distanceModifier modifies the distance of the light from the data visualization.
+ */
+void Q3DScene::setLightPositionRelativeToCamera(const QVector3D &relativePosition,
+ qreal fixedRotation, qreal distanceModifier)
+{
+ d_ptr->m_light->setPosition(
+ d_ptr->m_camera->calculatePositionRelativeToCamera(relativePosition,
+ fixedRotation,
+ distanceModifier));
+}
+
+/*!
+ * \fn Q3DScene::needRender()
+ * \internal
+ */
+
+Q3DScenePrivate::Q3DScenePrivate(Q3DScene *q) :
+ q_ptr(q),
+ m_devicePixelRatio(1.f),
+ m_camera(),
+ m_light(),
+ m_isUnderSideCameraEnabled(false),
+ m_isSlicingActive(false)
+{
+}
+
+Q3DScenePrivate::~Q3DScenePrivate()
+{
+ delete m_camera;
+ delete m_light;
+}
+
+// Copies changed values from this scene to the other scene. If the other scene had same changes,
+// those changes are discarded.
+void Q3DScenePrivate::sync(Q3DScenePrivate &other)
+{
+ if (m_changeTracker.viewportChanged) {
+ other.q_ptr->setViewport(q_ptr->viewport());
+ m_changeTracker.viewportChanged = false;
+ other.m_changeTracker.viewportChanged = false;
+ }
+ if (m_changeTracker.primarySubViewportChanged) {
+ other.q_ptr->setPrimarySubViewport(q_ptr->primarySubViewport());
+ m_changeTracker.primarySubViewportChanged = false;
+ other.m_changeTracker.primarySubViewportChanged = false;
+ }
+ if (m_changeTracker.secondarySubViewportChanged) {
+ other.q_ptr->setSecondarySubViewport(q_ptr->secondarySubViewport());
+ m_changeTracker.secondarySubViewportChanged = false;
+ other.m_changeTracker.secondarySubViewportChanged = false;
+ }
+ if (m_changeTracker.cameraChanged) {
+ m_camera->setDirty(true);
+ m_changeTracker.cameraChanged = false;
+ other.m_changeTracker.cameraChanged = false;
+ }
+ m_camera->d_ptr->sync(*other.m_camera);
+
+ if (m_changeTracker.lightChanged) {
+ m_light->setDirty(true);
+ m_changeTracker.lightChanged = false;
+ other.m_changeTracker.lightChanged = false;
+ }
+ m_light->d_ptr->sync(*other.m_light);
+
+ if (m_changeTracker.slicingActivatedChanged) {
+ other.q_ptr->setSlicingActive(q_ptr->isSlicingActive());
+ m_changeTracker.slicingActivatedChanged = false;
+ other.m_changeTracker.slicingActivatedChanged = false;
+ }
+
+ if (m_changeTracker.devicePixelRatioChanged) {
+ other.q_ptr->setDevicePixelRatio(q_ptr->devicePixelRatio());
+ m_changeTracker.devicePixelRatioChanged = false;
+ other.m_changeTracker.devicePixelRatioChanged = false;
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dscene.h b/src/datavisualization/engine/q3dscene.h
new file mode 100644
index 00000000..745cef72
--- /dev/null
+++ b/src/datavisualization/engine/q3dscene.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCENE_H
+#define Q3DSCENE_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QObject>
+#include <QRect>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCamera;
+class Q3DBox;
+class Q3DLight;
+class Q3DScenePrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DScene : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QRect viewport READ viewport WRITE setViewport NOTIFY viewportChanged)
+ Q_PROPERTY(QRect primarySubViewport READ primarySubViewport WRITE setPrimarySubViewport NOTIFY primarySubViewportChanged)
+ Q_PROPERTY(QRect secondarySubViewport READ secondarySubViewport WRITE setSecondarySubViewport NOTIFY secondarySubViewportChanged)
+ Q_PROPERTY(bool slicingActive READ isSlicingActive WRITE setSlicingActive NOTIFY slicingActiveChanged)
+ Q_PROPERTY(Q3DCamera* activeCamera READ activeCamera WRITE setActiveCamera NOTIFY activeCameraChanged)
+ Q_PROPERTY(Q3DLight* activeLight READ activeLight WRITE setActiveLight NOTIFY activeLightChanged)
+ Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged)
+
+public:
+ Q3DScene(QObject *parent = 0);
+ ~Q3DScene();
+
+ QRect viewport() const;
+ void setViewport(const QRect &viewport);
+ void setViewportSize(int width, int height);
+
+ QRect primarySubViewport() const;
+ void setPrimarySubViewport(const QRect &primarySubViewport);
+ bool isPointInPrimarySubView(const QPoint &point);
+
+ QRect secondarySubViewport() const;
+ void setSecondarySubViewport(const QRect &secondarySubViewport);
+ bool isPointInSecondarySubView(const QPoint &point);
+
+ void setSlicingActive(bool isSlicing);
+ bool isSlicingActive() const;
+
+ Q3DCamera *activeCamera() const;
+ void setActiveCamera(Q3DCamera *camera);
+
+ Q3DLight *activeLight() const;
+ void setActiveLight(Q3DLight *light);
+
+ qreal devicePixelRatio() const;
+ void setDevicePixelRatio(qreal pixelRatio);
+
+ void setLightPositionRelativeToCamera(const QVector3D &relativePosition,
+ qreal fixedRotation = 0.0,
+ qreal distanceModifier = 0.0);
+private:
+ void emitNeedRender();
+
+signals:
+ void viewportChanged(QRect viewport);
+ void primarySubViewportChanged(QRect subViewport);
+ void secondarySubViewportChanged(QRect subViewport);
+ void slicingActiveChanged(bool isSlicingActive);
+ void activeCameraChanged(const Q3DCamera *camera);
+ void activeLightChanged(const Q3DLight *light);
+ void devicePixelRatioChanged(qreal pixelRatio);
+ void needRender();
+
+private:
+ QScopedPointer<Q3DScenePrivate> d_ptr;
+
+ Q_DISABLE_COPY(Q3DScene)
+
+ friend class Q3DScenePrivate;
+ friend class Abstract3DRenderer;
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
+ friend class Q3DCameraPrivate;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DSCENE_H
diff --git a/src/datavisualization/engine/q3dscene_p.h b/src/datavisualization/engine/q3dscene_p.h
new file mode 100644
index 00000000..b28baaae
--- /dev/null
+++ b/src/datavisualization/engine/q3dscene_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCENE_P_H
+#define Q3DSCENE_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QRect>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DCamera;
+class Q3DLight;
+class Q3DScene;
+
+struct Q3DSceneChangeBitField {
+ bool viewportChanged : 1;
+ bool primarySubViewportChanged : 1;
+ bool secondarySubViewportChanged : 1;
+ bool cameraChanged : 1;
+ bool lightChanged : 1;
+ bool slicingActivatedChanged : 1;
+ bool devicePixelRatioChanged : 1;
+
+ Q3DSceneChangeBitField()
+ : viewportChanged(true),
+ primarySubViewportChanged(true),
+ secondarySubViewportChanged(true),
+ cameraChanged(true),
+ lightChanged(true),
+ slicingActivatedChanged(true),
+ devicePixelRatioChanged(true)
+ {
+ }
+};
+
+class Q3DScenePrivate
+{
+public:
+ Q3DScenePrivate(Q3DScene *q);
+ ~Q3DScenePrivate();
+
+ void sync(Q3DScenePrivate &other);
+
+ Q3DScene *q_ptr;
+ Q3DSceneChangeBitField m_changeTracker;
+
+ QRect m_viewport;
+ QRect m_primarySubViewport;
+ QRect m_secondarySubViewport;
+ qreal m_devicePixelRatio;
+ Q3DCamera *m_camera;
+ Q3DLight *m_light;
+ bool m_isUnderSideCameraEnabled;
+ bool m_isSlicingActive;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DSCENE_P_H
diff --git a/src/datavisualization/engine/q3dsurface.cpp b/src/datavisualization/engine/q3dsurface.cpp
new file mode 100644
index 00000000..7990f362
--- /dev/null
+++ b/src/datavisualization/engine/q3dsurface.cpp
@@ -0,0 +1,542 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dsurface.h"
+#include "q3dsurface_p.h"
+#include "q3dvalueaxis.h"
+#include "qsurfacedataproxy.h"
+#include "q3dcamera.h"
+
+#include <QMouseEvent>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DSurface
+ * \inmodule QtDataVisualization
+ * \brief The Q3DSurface class provides methods for rendering 3D surface plots.
+ * \since 1.0.0
+ *
+ * This class enables developers to render 3D surface plots and to view them by rotating the scene
+ * freely. The class provides configurable gradient texture to illustrate the height on the data. The
+ * surface plotting includes also gridline that can be set on or off. The visual appearance of the
+ * surface can be changed by controlling the smooth status.
+ *
+ * The Q3DSurface supports selection by showing a highlighted ball on the data point where the user has clicked
+ * with left mouse button (when default input handler is in use). The selection pointer is accompanied with
+ * a label which in default case shows the value of the data point and the coordinates of the point.
+ *
+ * The value range and the label format shown on the axis can be controlled through Q3DValueAxis.
+ * The Q3DSurface supports only a grid with fixed steps, so when setting ranges set a value that matches
+ * the grid step. To calculate the steps divide the whole data range with the number of segments.
+ *
+ * To rotate the graph, hold down the right mouse button and move the mouse. Zooming is done using mouse
+ * wheel. Both assume the default input handler is in use.
+ *
+ * If no axes are explicitly set to Q3DSurface, temporary default axes with no labels are created.
+ * These default axes can be modified via axis accessors, but as soon any axis is explicitly
+ * set for the orientation, the default axis for that orientation is destroyed.
+ *
+ * Data proxies work similarly: If no data proxy is explicitly set, Q3DSurface creates a default
+ * proxy. If any other proxy is set as active data proxy later, the default proxy and all data
+ * added to it is destroyed.
+ *
+ * \section1 How to construct a minimal Q3DSurface graph
+ *
+ * First, construct Q3DSurface:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 0
+ *
+ * Now Q3DSurface is ready to receive data to be rendered. Create data elements to receive values:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 1
+ *
+ * First feed the data to the row element and then add it's pointer to the data element:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 2
+ *
+ * For the active data proxy set pointer of the data element:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 3
+ *
+ * Finally you will need to set it visible:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 4
+ *
+ * The complete code needed to create and display this graph is:
+ *
+ * \snippet doc_src_q3dsurface_construction.cpp 5
+ *
+ * And this is what those few lines of code produce:
+ *
+ * \image q3dsurface-minimal.png
+ *
+ * The scene can be rotated and zoomed into, but no other interaction is included in this minimal
+ * code example.
+ *
+ *
+ * \sa Q3DBars, Q3DScatter, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs a new 3D surface window.
+ */
+Q3DSurface::Q3DSurface()
+ : d_ptr(new Q3DSurfacePrivate(this, geometry()))
+{
+ setVisualController(d_ptr->m_shared);
+ d_ptr->m_shared->initializeOpenGL();
+ QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this,
+ &Q3DWindow::renderLater);
+}
+
+/*!
+ * Destroys the 3D surface window.
+ */
+Q3DSurface::~Q3DSurface()
+{
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseDoubleClickEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::touchEvent(QTouchEvent *event)
+{
+ d_ptr->m_shared->touchEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::mousePressEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mousePressEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::mouseReleaseEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseReleaseEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::mouseMoveEvent(QMouseEvent *event)
+{
+ d_ptr->m_shared->mouseMoveEvent(event, event->pos());
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::wheelEvent(QWheelEvent *event)
+{
+ d_ptr->m_shared->wheelEvent(event);
+}
+
+/*!
+ * \internal
+ */
+void Q3DSurface::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+ d_ptr->m_shared->setWidth(width());
+ d_ptr->m_shared->setHeight(height());
+}
+
+/*!
+ * \property Q3DSurface::gridVisible
+ *
+ * Sets grid visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DSurface::setGridVisible(bool visible)
+{
+ d_ptr->m_shared->setGridEnabled(visible);
+}
+
+bool Q3DSurface::isGridVisible() const
+{
+ return d_ptr->m_shared->gridEnabled();
+}
+
+/*!
+ * \property Q3DSurface::backgroundVisible
+ *
+ * Sets background visibility to \a visible. It is preset to \c true by default.
+ */
+void Q3DSurface::setBackgroundVisible(bool visible)
+{
+ d_ptr->m_shared->setBackgroundEnabled(visible);
+}
+
+bool Q3DSurface::isBackgroundVisible() const
+{
+ return d_ptr->m_shared->backgroundEnabled();
+}
+
+/*!
+ * \property Q3DSurface::theme
+ *
+ * A predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by
+ * default. Theme affects label colors, text color, background color, window color and
+ * grid color. Lighting is also adjusted by themes.
+ *
+ * \warning This property is subject to change.
+ */
+void Q3DSurface::setTheme(QDataVis::Theme theme)
+{
+ d_ptr->m_shared->setTheme(theme);
+}
+
+QDataVis::Theme Q3DSurface::theme() const
+{
+ return d_ptr->m_shared->theme().theme();
+}
+
+/*!
+ * \property Q3DSurface::shadowQuality
+ *
+ * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to
+ * \c QDataVis::ShadowQualityMedium by default.
+ *
+ * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered
+ * until it is successful and shadowQualityChanged signal is emitted for each time the change is
+ * done.
+ */
+void Q3DSurface::setShadowQuality(QDataVis::ShadowQuality quality)
+{
+ return d_ptr->m_shared->setShadowQuality(quality);
+}
+
+QDataVis::ShadowQuality Q3DSurface::shadowQuality() const
+{
+ return d_ptr->m_shared->shadowQuality();
+}
+
+/*!
+ * \property Q3DSurface::smoothSurfaceEnabled
+ *
+ * Sets surface smoothing to \a enabled. It is preset to \c false by default.
+ * When enabled the normals on the surface are interpolated making edges looking round. If turned
+ * off the normals are kept same on a triangle making the color of the triangle solid. This makes
+ * the data more readable from the model.
+ */
+void Q3DSurface::setSmoothSurfaceEnabled(bool enabled)
+{
+ d_ptr->m_shared->setSmoothSurface(enabled);
+}
+
+bool Q3DSurface::isSmoothSurfaceEnabled() const
+{
+ return d_ptr->m_shared->smoothSurface();
+}
+
+/*!
+ * \property Q3DSurface::selectionMode
+ *
+ * Sets point selection \a mode to one of \c QDataVis::SelectionMode. Surface supports SelectionModeItem,
+ * SelectionModeSliceRow and SelectionModeSliceColumn. It is preset to \c QDataVis::SelectionModeItem by default.
+ */
+void Q3DSurface::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ d_ptr->m_shared->setSelectionMode(mode);
+}
+
+QDataVis::SelectionMode Q3DSurface::selectionMode() const
+{
+ return d_ptr->m_shared->selectionMode();
+}
+
+
+/*!
+ * \property Q3DSurface::surfaceGridEnabled
+ *
+ * Sets surface grid to \a enabled. It is preset to \c true by default.
+ */
+void Q3DSurface::setSurfaceGridEnabled(bool enabled)
+{
+ d_ptr->m_shared->setSurfaceGrid(enabled);
+}
+
+bool Q3DSurface::isSurfaceGridEnabled() const
+{
+ return d_ptr->m_shared->surfaceGrid();
+}
+
+/*!
+ * \property Q3DSurface::gradient
+ *
+ * The current surface gradient. Setting this property replaces the previous gradient with
+ * the given \a gradient.
+ */
+void Q3DSurface::setGradient(const QLinearGradient &gradient)
+{
+ d_ptr->m_shared->setGradient(gradient);
+}
+
+QLinearGradient Q3DSurface::gradient() const
+{
+ return d_ptr->m_shared->gradient();
+}
+
+/*!
+ * \property Q3DSurface::font
+ *
+ * Sets the \a font for labels. It is preset to \c Arial by default.
+ */
+void Q3DSurface::setFont(const QFont &font)
+{
+ d_ptr->m_shared->setFont(font);
+}
+
+QFont Q3DSurface::font() const
+{
+ return d_ptr->m_shared->font();
+}
+
+/*!
+ * \property Q3DSurface::scene
+ *
+ * This property contains the read only Q3DScene that can be used to access e.g. camera object.
+ */
+Q3DScene *Q3DSurface::scene() const
+{
+ return d_ptr->m_shared->scene();
+}
+
+/*!
+ * \property Q3DSurface::labelStyle
+ *
+ * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to
+ * \c QDataVis::LabelStyleFromTheme by default.
+ */
+void Q3DSurface::setLabelStyle(QDataVis::LabelStyle style)
+{
+ d_ptr->m_shared->setLabelStyle(style);
+}
+
+QDataVis::LabelStyle Q3DSurface::labelStyle() const
+{
+ return d_ptr->m_shared->labelStyle();
+}
+
+/*!
+ * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DSurface::setAxisX(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisX(axis);
+}
+
+/*!
+ * \return used X-axis.
+ */
+Q3DValueAxis *Q3DSurface::axisX() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisX());
+}
+
+/*!
+ * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DSurface::setAxisY(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisY(axis);
+}
+
+/*!
+ * \return used Y-axis.
+ */
+Q3DValueAxis *Q3DSurface::axisY() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY());
+}
+
+/*!
+ * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership
+ * of the \a axis to this graph.
+ *
+ * If the \a axis is null, a temporary default axis with no labels and automatically adjusting
+ * range is created.
+ * This temporary axis is destroyed if another \a axis is explicitly set to same orientation.
+ *
+ * \sa addAxis(), releaseAxis()
+ */
+void Q3DSurface::setAxisZ(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->setAxisZ(axis);
+}
+
+/*!
+ * \return used Z-axis.
+ */
+Q3DValueAxis *Q3DSurface::axisZ() const
+{
+ return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisZ());
+}
+
+/*!
+ * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use,
+ * addAxis is simply used to give the ownership of the \a axis to the graph.
+ * The \a axis must not be null or added to another graph.
+ *
+ * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ()
+ */
+void Q3DSurface::addAxis(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->addAxis(axis);
+}
+
+/*!
+ * Releases the ownership of the \a axis back to the caller, if it is added to this graph.
+ * If the released \a axis is in use, a new default axis will be created and set active.
+ *
+ * If the default axis is released and added back later, it behaves as any other axis would.
+ *
+ * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ()
+ */
+void Q3DSurface::releaseAxis(Q3DValueAxis *axis)
+{
+ d_ptr->m_shared->releaseAxis(axis);
+}
+
+/*!
+ * \return list of all added axes.
+ *
+ * \sa addAxis()
+ */
+QList<Q3DValueAxis *> Q3DSurface::axes() const
+{
+ QList<Q3DAbstractAxis *> abstractAxes = d_ptr->m_shared->axes();
+ QList<Q3DValueAxis *> retList;
+ foreach (Q3DAbstractAxis *axis, abstractAxes)
+ retList.append(static_cast<Q3DValueAxis *>(axis));
+
+ return retList;
+}
+
+/*!
+ * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of
+ * the \a proxy to this graph.
+ *
+ * If the \a proxy is null, a temporary default proxy is created and activated.
+ * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method.
+ *
+ * \sa addDataProxy(), releaseDataProxy()
+ */
+void Q3DSurface::setActiveDataProxy(QSurfaceDataProxy *proxy)
+{
+ d_ptr->m_shared->setActiveDataProxy(proxy);
+}
+
+/*!
+ * \return active data proxy.
+ */
+QSurfaceDataProxy *Q3DSurface::activeDataProxy() const
+{
+ return static_cast<QSurfaceDataProxy *>(d_ptr->m_shared->activeDataProxy());
+}
+
+/*!
+ * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use,
+ * addDataProxy is simply used to give the ownership of the data \a proxy to the graph.
+ * The \a proxy must not be null or added to another graph.
+ *
+ * \sa releaseDataProxy(), setActiveDataProxy()
+ */
+void Q3DSurface::addDataProxy(QSurfaceDataProxy *proxy)
+{
+ d_ptr->m_shared->addDataProxy(proxy);
+}
+
+/*!
+ * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph.
+ * If the released \a proxy is in use, a new empty default proxy is created and taken to use.
+ *
+ * If the default \a proxy is released and added back later, it behaves as any other proxy would.
+ *
+ * \sa addDataProxy(), setActiveDataProxy()
+ */
+void Q3DSurface::releaseDataProxy(QSurfaceDataProxy *proxy)
+{
+ d_ptr->m_shared->releaseDataProxy(proxy);
+}
+
+/*!
+ * \return list of all added data proxies.
+ *
+ * \sa addDataProxy()
+ */
+QList<QSurfaceDataProxy *> Q3DSurface::dataProxies() const
+{
+ QList<QSurfaceDataProxy *> retList;
+ QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies();
+ foreach (QAbstractDataProxy *proxy, abstractList)
+ retList.append(static_cast<QSurfaceDataProxy *>(proxy));
+
+ return retList;
+}
+
+
+/*!
+ * Modifies the current surface gradient. Sets gradient color to \a color at \a pos.
+ */
+void Q3DSurface::setGradientColorAt(qreal pos, const QColor &color)
+{
+ d_ptr->m_shared->setGradientColorAt(pos, color);
+}
+
+/////////////////// PRIVATE ///////////////////////////////////
+
+Q3DSurfacePrivate::Q3DSurfacePrivate(Q3DSurface *q, QRect rect)
+ : q_ptr(q),
+ m_shared(new Surface3DController(rect))
+{
+}
+
+Q3DSurfacePrivate::~Q3DSurfacePrivate()
+{
+ delete m_shared;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dsurface.h b/src/datavisualization/engine/q3dsurface.h
new file mode 100644
index 00000000..1b572a36
--- /dev/null
+++ b/src/datavisualization/engine/q3dsurface.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSURFACE_H
+#define Q3DSURFACE_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/q3dwindow.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QFont>
+#include <QLinearGradient>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DSurfacePrivate;
+class Q3DValueAxis;
+class QSurfaceDataProxy;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DSurface : public Q3DWindow
+{
+ Q_OBJECT
+ Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
+ Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle)
+ Q_PROPERTY(QtDataVisualization::QDataVis::Theme theme READ theme WRITE setTheme)
+ Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality)
+ Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible)
+ Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible)
+ Q_PROPERTY(bool smoothSurfaceEnabled READ isSmoothSurfaceEnabled WRITE setSmoothSurfaceEnabled)
+ Q_PROPERTY(bool surfaceGridEnabled READ isSurfaceGridEnabled WRITE setSurfaceGridEnabled)
+ Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient)
+ Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(Q3DScene* scene READ scene)
+ Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode)
+ Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality)
+ Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle)
+ Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset)
+
+public:
+ explicit Q3DSurface();
+ ~Q3DSurface();
+
+ void setGridVisible(bool visible);
+ bool isGridVisible() const;
+
+ void setBackgroundVisible(bool visible);
+ bool isBackgroundVisible() const;
+
+ void setTheme(QDataVis::Theme theme);
+ QDataVis::Theme theme() const;
+
+ void setShadowQuality(QDataVis::ShadowQuality quality);
+ QDataVis::ShadowQuality shadowQuality() const;
+
+ void setSmoothSurfaceEnabled(bool enabled);
+ bool isSmoothSurfaceEnabled() const;
+
+ void setSelectionMode(QDataVis::SelectionMode mode);
+ QDataVis::SelectionMode selectionMode() const;
+ void setSurfaceGridEnabled(bool enabled);
+ bool isSurfaceGridEnabled() const;
+
+ void setGradient(const QLinearGradient &gradient);
+ QLinearGradient gradient() const;
+
+ void setGradientColorAt(qreal pos, const QColor &color);
+
+ // Axes
+ void setAxisX(Q3DValueAxis *axis);
+ Q3DValueAxis *axisX() const;
+ void setAxisY(Q3DValueAxis *axis);
+ Q3DValueAxis *axisY() const;
+ void setAxisZ(Q3DValueAxis *axis);
+ Q3DValueAxis *axisZ() const;
+ void addAxis(Q3DValueAxis *axis);
+ void releaseAxis(Q3DValueAxis *axis);
+ QList<Q3DValueAxis *> axes() const;
+
+ void setActiveDataProxy(QSurfaceDataProxy *proxy);
+ QSurfaceDataProxy *activeDataProxy() const;
+ void addDataProxy(QSurfaceDataProxy *proxy);
+ void releaseDataProxy(QSurfaceDataProxy *proxy);
+ QList<QSurfaceDataProxy *> dataProxies() const;
+
+ void setFont(const QFont &font);
+ QFont font() const;
+
+ Q3DScene *scene() const;
+
+ void setLabelStyle(QDataVis::LabelStyle style);
+ QDataVis::LabelStyle labelStyle() const;
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void touchEvent(QTouchEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ QScopedPointer<Q3DSurfacePrivate> d_ptr;
+ Q_DISABLE_COPY(Q3DSurface)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DSURFACE_H
diff --git a/src/datavisualization/engine/q3dsurface_p.h b/src/datavisualization/engine/q3dsurface_p.h
new file mode 100644
index 00000000..7c70d08c
--- /dev/null
+++ b/src/datavisualization/engine/q3dsurface_p.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSURFACE_P_H
+#define Q3DSURFACE_P_H
+
+#include "surface3dcontroller_p.h"
+#include "qdatavisualizationenums.h"
+
+#include <QList>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DSurface;
+
+class Q3DSurfacePrivate : public QObject
+{
+public:
+ Q3DSurfacePrivate(Q3DSurface *q, QRect rect);
+ ~Q3DSurfacePrivate();
+
+ Q3DSurface *q_ptr;
+ Surface3DController *m_shared;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DSURFACE_P_H
diff --git a/src/datavisualization/engine/q3dwindow.cpp b/src/datavisualization/engine/q3dwindow.cpp
new file mode 100644
index 00000000..9b607e1d
--- /dev/null
+++ b/src/datavisualization/engine/q3dwindow.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "q3dwindow.h"
+#include "q3dwindow_p.h"
+#include "abstract3dcontroller_p.h"
+#include <QGuiApplication>
+
+#include <QOpenGLContext>
+#include <QOpenGLPaintDevice>
+#include <QPainter>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ * \class Q3DWindow
+ * \inmodule QtDataVisualization
+ * \brief The Q3DWindow class provides a window and render loop.
+ * \since 1.0.0
+ *
+ * This class creates a QWindow and provides render loop for visualization types inheriting it.
+ * \warning This class is not intended to be used directly by developers.
+ *
+ * \sa Q3DBars, Q3DScatter, Q3DSurface, {Qt Data Visualization C++ Classes}
+ */
+
+/*!
+ * Constructs Q3DWindow with \a parent. It creates a QWindow and an OpenGL context. It also sets
+ * surface format and initializes OpenGL functions for use.
+ */
+Q3DWindow::Q3DWindow(QWindow *parent)
+ : QWindow(parent),
+ d_ptr(new Q3DWindowPrivate(this))
+{
+ setSurfaceType(QWindow::OpenGLSurface);
+ QSurfaceFormat surfaceFormat;
+ surfaceFormat.setDepthBufferSize(16);
+#if !defined(QT_OPENGL_ES_2)
+ surfaceFormat.setSamples(8);
+ surfaceFormat.setRenderableType(QSurfaceFormat::OpenGL);
+#else
+ surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+#endif
+ surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ setFormat(surfaceFormat);
+
+ create();
+
+ d_ptr->m_context->setFormat(requestedFormat());
+ d_ptr->m_context->create();
+ d_ptr->m_context->makeCurrent(this);
+
+ qDebug() << "initializeOpenGLFunctions()";
+ initializeOpenGLFunctions();
+
+ const GLubyte *version = glGetString(GL_VERSION);
+ qDebug() << "OpenGL version:" << (const char *)version;
+ version = glGetString(GL_SHADING_LANGUAGE_VERSION);
+ qDebug() << "GLSL version:" << (const char *)version;
+#if !defined(QT_OPENGL_ES_2)
+ // If we have real OpenGL, GLSL version must be 1.2 or over. Quit if not.
+ QStringList splitversionstr = QString::fromLatin1((const char *)version).split(QChar::fromLatin1(' '));
+ if (splitversionstr[0].toFloat() < 1.2)
+ qFatal("GLSL version must be 1.20 or higher. Try installing latest display drivers.");
+#endif
+ renderLater();
+}
+
+/*!
+ * Destroys Q3DWindow.
+ */
+Q3DWindow::~Q3DWindow()
+{
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::setVisualController(Abstract3DController *controller)
+{
+ d_ptr->m_visualController = controller;
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::handleDevicePixelRatioChange()
+{
+ if (QWindow::devicePixelRatio() == d_ptr->m_devicePixelRatio || !d_ptr->m_visualController)
+ return;
+
+ // Device pixel ratio changed, resize accordingly and inform the scene
+ d_ptr->m_devicePixelRatio = QWindow::devicePixelRatio();
+ d_ptr->m_visualController->updateDevicePixelRatio(d_ptr->m_devicePixelRatio);
+
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::render()
+{
+ handleDevicePixelRatioChange();
+ d_ptr->m_visualController->synchDataToRenderer();
+ d_ptr->m_visualController->render();
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::renderLater()
+{
+ if (!d_ptr->m_updatePending) {
+ d_ptr->m_updatePending = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+ }
+}
+
+/*!
+ * \internal
+ */
+bool Q3DWindow::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::UpdateRequest:
+ renderNow();
+ return true;
+ case QEvent::TouchBegin:
+ case QEvent::TouchCancel:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ d_ptr->m_visualController->touchEvent(static_cast<QTouchEvent *>(event));
+ return true;
+ default:
+ return QWindow::event(event);
+ }
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::exposeEvent(QExposeEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (isExposed())
+ renderNow();
+}
+
+/*!
+ * \internal
+ */
+void Q3DWindow::renderNow()
+{
+ if (!isExposed())
+ return;
+
+ d_ptr->m_updatePending = false;
+
+ d_ptr->m_context->makeCurrent(this);
+
+ render();
+
+ d_ptr->m_context->swapBuffers(this);
+}
+
+Q3DWindowPrivate::Q3DWindowPrivate(Q3DWindow *q)
+ : q_ptr(q),
+ m_updatePending(false),
+ m_context(new QOpenGLContext(q)),
+ m_visualController(0),
+ m_devicePixelRatio(1.f)
+{
+}
+
+Q3DWindowPrivate::~Q3DWindowPrivate()
+{
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/q3dwindow.h b/src/datavisualization/engine/q3dwindow.h
new file mode 100644
index 00000000..1848ff29
--- /dev/null
+++ b/src/datavisualization/engine/q3dwindow.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DWINDOW_H
+#define Q3DWINDOW_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+
+#include <QWindow>
+#include <QOpenGLFunctions>
+#include <QScreen>
+
+class QPainter;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DWindowPrivate;
+class Abstract3DController;
+
+class QT_DATAVISUALIZATION_EXPORT Q3DWindow : public QWindow, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ explicit Q3DWindow(QWindow *parent = 0);
+ virtual ~Q3DWindow();
+
+protected slots:
+ void renderLater();
+ void renderNow();
+
+protected:
+ virtual void render();
+
+ bool event(QEvent *event);
+ void exposeEvent(QExposeEvent *event);
+ void setVisualController(Abstract3DController *controller);
+ void handleDevicePixelRatioChange();
+
+private:
+ QScopedPointer<Q3DWindowPrivate> d_ptr;
+
+ friend class Q3DBars;
+ friend class Q3DScatter;
+ friend class Q3DSurface;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/q3dwindow_p.h b/src/datavisualization/engine/q3dwindow_p.h
new file mode 100644
index 00000000..6bef7e10
--- /dev/null
+++ b/src/datavisualization/engine/q3dwindow_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DWINDOW_p_H
+#define Q3DWINDOW_p_H
+
+#include "datavisualizationglobal_p.h"
+
+class QOpenGLContext;
+class QOpenGLPaintDevice;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DWindow;
+class Abstract3DController;
+
+class Q3DWindowPrivate
+{
+public:
+ Q3DWindowPrivate(Q3DWindow *q);
+ ~Q3DWindowPrivate();
+
+public:
+ Q3DWindow *q_ptr;
+
+ bool m_updatePending;
+ QOpenGLContext *m_context;
+ Abstract3DController *m_visualController;
+ qreal m_devicePixelRatio;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp
new file mode 100644
index 00000000..9f43d94e
--- /dev/null
+++ b/src/datavisualization/engine/scatter3dcontroller.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "scatter3dcontroller_p.h"
+#include "scatter3drenderer_p.h"
+#include "camerahelper_p.h"
+#include "q3dabstractaxis_p.h"
+#include "q3dvalueaxis_p.h"
+#include "qscatterdataproxy_p.h"
+
+#include <QMatrix4x4>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Scatter3DController::Scatter3DController(QRect boundRect)
+ : Abstract3DController(boundRect),
+ m_renderer(0),
+ m_selectedItemIndex(noSelectionIndex())
+{
+ // Default object type; specific to scatter
+ setObjectType(QDataVis::MeshStyleSpheres, false);
+
+ setActiveDataProxy(new QScatterDataProxy);
+
+ // Setting a null axis creates a new default axis according to orientation and graph type.
+ // Note: These cannot be set in Abstract3DController constructor, as they will call virtual
+ // functions implemented by subclasses.
+ setAxisX(0);
+ setAxisY(0);
+ setAxisZ(0);
+}
+
+Scatter3DController::~Scatter3DController()
+{
+}
+
+void Scatter3DController::initializeOpenGL()
+{
+ // Initialization is called multiple times when Qt Quick components are used
+ if (isInitialized())
+ return;
+
+ m_renderer = new Scatter3DRenderer(this);
+ setRenderer(m_renderer);
+ synchDataToRenderer();
+
+ QObject::connect(m_renderer, &Scatter3DRenderer::selectedItemIndexChanged, this,
+ &Scatter3DController::handleSelectedItemIndexChanged, Qt::QueuedConnection);
+ emitNeedRender();
+}
+
+void Scatter3DController::synchDataToRenderer()
+{
+ Abstract3DController::synchDataToRenderer();
+
+ if (!isInitialized())
+ return;
+
+ // Notify changes to renderer
+ if (m_changeTracker.slicingActiveChanged) {
+ // TODO: Add notification.
+ m_changeTracker.slicingActiveChanged = false;
+ }
+
+ if (m_changeTracker.selectedItemIndexChanged) {
+ m_renderer->updateSelectedItemIndex(m_selectedItemIndex);
+ m_changeTracker.selectedItemIndexChanged = false;
+ }
+
+ if (m_isDataDirty) {
+ m_renderer->updateDataModel(static_cast<QScatterDataProxy *>(m_data));
+ m_isDataDirty = false;
+ }
+}
+
+
+void Scatter3DController::setActiveDataProxy(QAbstractDataProxy *proxy)
+{
+ // Setting null proxy indicates default proxy
+ if (!proxy) {
+ proxy = new QScatterDataProxy;
+ proxy->d_ptr->setDefaultProxy(true);
+ }
+
+ Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeScatter);
+
+ Abstract3DController::setActiveDataProxy(proxy);
+
+ QScatterDataProxy *scatterDataProxy = static_cast<QScatterDataProxy *>(m_data);
+
+ QObject::connect(scatterDataProxy, &QScatterDataProxy::arrayReset,
+ this, &Scatter3DController::handleArrayReset);
+ QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsAdded,
+ this, &Scatter3DController::handleItemsAdded);
+ QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsChanged,
+ this, &Scatter3DController::handleItemsChanged);
+ QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsRemoved,
+ this, &Scatter3DController::handleItemsRemoved);
+ QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsInserted,
+ this, &Scatter3DController::handleItemsInserted);
+
+ adjustValueAxisRange();
+ setSelectedItemIndex(noSelectionIndex());
+ setSlicingActive(false);
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Scatter3DController::handleArrayReset()
+{
+ setSlicingActive(false);
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ setSelectedItemIndex(noSelectionIndex());
+ emitNeedRender();
+}
+
+void Scatter3DController::handleItemsAdded(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should dirty only affected values?
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Scatter3DController::handleItemsChanged(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should dirty only affected values?
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Scatter3DController::handleItemsRemoved(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should dirty only affected values?
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ if (startIndex >= static_cast<QScatterDataProxy *>(m_data)->itemCount())
+ setSelectedItemIndex(noSelectionIndex());
+ emitNeedRender();
+}
+
+void Scatter3DController::handleItemsInserted(int startIndex, int count)
+{
+ Q_UNUSED(startIndex)
+ Q_UNUSED(count)
+ // TODO should dirty only affected values?
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Scatter3DController::handleSelectedItemIndexChanged(int index)
+{
+ if (index != m_selectedItemIndex) {
+ m_selectedItemIndex = index;
+ emit selectedItemIndexChanged(index);
+ emitNeedRender();
+ }
+}
+
+void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation(
+ Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust)
+{
+ Q_UNUSED(orientation)
+ Q_UNUSED(autoAdjust)
+ adjustValueAxisRange();
+}
+
+void Scatter3DController::setObjectType(QDataVis::MeshStyle style, bool smooth)
+{
+ QString objFile;
+ if (style == QDataVis::MeshStyleSpheres) {
+ if (smooth)
+ objFile = QStringLiteral(":/defaultMeshes/sphereSmooth");
+ else
+ objFile = QStringLiteral(":/defaultMeshes/sphere");
+ } else {
+ if (smooth)
+ objFile = QStringLiteral(":/defaultMeshes/dotSmooth");
+ else
+ objFile = QStringLiteral(":/defaultMeshes/dot");
+ }
+ Abstract3DController::setMeshFileName(objFile);
+}
+
+void Scatter3DController::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ if (mode > QDataVis::SelectionModeItem) {
+ qWarning("Unsupported selection mode.");
+ return;
+ }
+ // Disable zoom if selection mode changes
+ setSlicingActive(false);
+ Abstract3DController::setSelectionMode(mode);
+}
+
+void Scatter3DController::setSelectedItemIndex(int index)
+{
+ // TODO If items not within axis ranges are culled from drawing, should they be
+ // TODO unselectable as well?
+ if (index < 0 || index >= static_cast<QScatterDataProxy *>(m_data)->itemCount())
+ index = noSelectionIndex();
+
+ if (index != m_selectedItemIndex) {
+ m_selectedItemIndex = index;
+ m_changeTracker.selectedItemIndexChanged = true;
+ emit selectedItemIndexChanged(index);
+ emitNeedRender();
+ }
+}
+
+int Scatter3DController::selectedItemIndex() const
+{
+ return m_selectedItemIndex;
+}
+
+void Scatter3DController::adjustValueAxisRange()
+{
+ if (m_data) {
+ QVector3D limits = static_cast<QScatterDataProxy *>(m_data)->dptr()->limitValues();
+ Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisX);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (limits.x() > 0)
+ valueAxis->dptr()->setRange(-limits.x(), limits.x());
+ else
+ valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default.
+ }
+
+ valueAxis = static_cast<Q3DValueAxis *>(m_axisY);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (limits.y() > 0)
+ valueAxis->dptr()->setRange(-limits.y(), limits.y());
+ else
+ valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default.
+ }
+
+ valueAxis = static_cast<Q3DValueAxis *>(m_axisZ);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (limits.z() > 0)
+ valueAxis->dptr()->setRange(-limits.z(), limits.z());
+ else
+ valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default.
+ }
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h
new file mode 100644
index 00000000..63735aca
--- /dev/null
+++ b/src/datavisualization/engine/scatter3dcontroller_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCATTERCONTROLLER_p_H
+#define Q3DSCATTERCONTROLLER_p_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstract3dcontroller_p.h"
+
+//#define DISPLAY_RENDER_SPEED
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Scatter3DRenderer;
+class QScatterDataProxy;
+
+struct Scatter3DChangeBitField {
+ bool slicingActiveChanged : 1;
+ bool selectedItemIndexChanged : 1;
+
+ Scatter3DChangeBitField() :
+ slicingActiveChanged(true),
+ selectedItemIndexChanged(true)
+ {
+ }
+};
+
+class QT_DATAVISUALIZATION_EXPORT Scatter3DController : public Abstract3DController
+{
+ Q_OBJECT
+
+private:
+ Scatter3DChangeBitField m_changeTracker;
+
+ // Rendering
+ Scatter3DRenderer *m_renderer;
+ int m_selectedItemIndex;
+
+public:
+ explicit Scatter3DController(QRect rect);
+ ~Scatter3DController();
+
+ void initializeOpenGL();
+
+ // Object type
+ void setObjectType(QDataVis::MeshStyle style, bool smooth = false);
+
+ // Change selection mode
+ void setSelectionMode(QDataVis::SelectionMode mode);
+
+ void setSelectedItemIndex(int index);
+ int selectedItemIndex() const;
+ static inline int noSelectionIndex() { return -1; }
+
+ virtual void setActiveDataProxy(QAbstractDataProxy *proxy);
+
+ void synchDataToRenderer();
+
+ virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust);
+
+public slots:
+ void handleArrayReset();
+ void handleItemsAdded(int startIndex, int count);
+ void handleItemsChanged(int startIndex, int count);
+ void handleItemsRemoved(int startIndex, int count);
+ void handleItemsInserted(int startIndex, int count);
+ void handleSelectedItemIndexChanged(int index);
+
+signals:
+ void selectedItemIndexChanged(int index);
+
+private:
+ void adjustValueAxisRange();
+
+ Q_DISABLE_COPY(Scatter3DController)
+};
+
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
new file mode 100644
index 00000000..a482cc42
--- /dev/null
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -0,0 +1,1623 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "scatter3drenderer_p.h"
+#include "scatter3dcontroller_p.h"
+#include "q3dcamera.h"
+#include "q3dcamera_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "texturehelper_p.h"
+#include "utils_p.h"
+#include "q3dlight.h"
+
+#include <QMatrix4x4>
+#include <QMouseEvent>
+#include <QThread>
+#include <qmath.h>
+#include <QDebug>
+
+// Commenting this draws the shadow map with perspective projection. Otherwise it's drawn in
+// orthographic projection.
+//#define USE_WIDER_SHADOWS
+
+// You can verify that depth buffer drawing works correctly by uncommenting this.
+// You should see the scene from where the light is
+//#define SHOW_DEPTH_TEXTURE_SCENE
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+//#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values
+
+const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd.
+const GLfloat labelMargin = 0.05f;
+// TODO: Make margin modifiable?
+const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background)
+const GLfloat gridLineWidth = 0.005f;
+static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color
+
+Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller)
+ : Abstract3DRenderer(controller),
+ m_controller(controller),
+ m_selectedItem(0),
+ m_xFlipped(false),
+ m_zFlipped(false),
+ m_yFlipped(false),
+ m_updateLabels(false),
+ m_dotShader(0),
+ m_depthShader(0),
+ m_selectionShader(0),
+ m_backgroundShader(0),
+ m_labelShader(0),
+ m_dotObj(0),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_bgrTexture(0),
+ m_depthTexture(0),
+ m_selectionTexture(0),
+ m_depthFrameBuffer(0),
+ m_selectionFrameBuffer(0),
+ m_selectionDepthBuffer(0),
+ m_shadowQualityToShader(100.0f),
+ m_shadowQualityMultiplier(3),
+ m_heightNormalizer(1.0f),
+ m_scaleFactor(0),
+ m_selection(selectionSkipColor),
+ m_previousSelection(selectionSkipColor),
+ m_areaSize(QSizeF(0.0, 0.0)),
+ m_dotSizeScale(1.0f),
+ m_hasHeightAdjustmentChanged(true)
+{
+ initializeOpenGLFunctions();
+ initializeOpenGL();
+}
+
+Scatter3DRenderer::~Scatter3DRenderer()
+{
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->deleteTexture(&m_bgrTexture);
+ delete m_dotShader;
+ delete m_depthShader;
+ delete m_selectionShader;
+ delete m_backgroundShader;
+ delete m_labelShader;
+ delete m_dotObj;
+ delete m_backgroundObj;
+ delete m_gridLineObj;
+ delete m_labelObj;
+}
+
+void Scatter3DRenderer::initializeOpenGL()
+{
+ Abstract3DRenderer::initializeOpenGL();
+
+ // Initialize shaders
+ handleShadowQualityChange();
+
+ initLabelShaders(QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+
+#if !defined(QT_OPENGL_ES_2)
+ // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api.
+ initDepthShader();
+#endif
+
+ // Init selection shader
+ initSelectionShader();
+
+ // Load grid line mesh
+ loadGridLineMesh();
+
+ // Load label mesh
+ loadLabelMesh();
+
+ // Set view port
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ // Load background mesh (we need to be initialized first)
+ loadBackgroundMesh();
+}
+
+void Scatter3DRenderer::updateDataModel(QScatterDataProxy *dataProxy)
+{
+ const QScatterDataArray &dataArray = *dataProxy->array();
+ calculateSceneScalingFactors();
+ int dataSize = dataArray.size();
+ float minX = float(m_axisCacheX.min());
+ float maxX = float(m_axisCacheX.max());
+ float minY = float(m_axisCacheY.min());
+ float maxY = float(m_axisCacheY.max());
+ float minZ = float(m_axisCacheZ.min());
+ float maxZ = float(m_axisCacheZ.max());
+
+ if (dataSize != m_renderItemArray.size())
+ m_renderItemArray.resize(dataSize);
+ for (int i = 0; i < dataSize ; i++) {
+ QVector3D dotPos = dataArray.at(i).position();
+ // TODO: Check if this still works always when ranges are no longer required to be zero centered
+ // TODO: qreal -> float conversion for axis min/max may cause issues like in surface
+ if ((dotPos.x() >= minX && dotPos.x() <= maxX )
+ && (dotPos.y() >= minY && dotPos.y() <= maxY)
+ && (dotPos.z() >= minZ && dotPos.z() <= maxZ)) {
+ m_renderItemArray[i].setPosition(dotPos);
+ m_renderItemArray[i].setVisible(true);
+ calculateTranslation(m_renderItemArray[i]);
+ } else {
+ m_renderItemArray[i].setVisible(false);
+ }
+ }
+ m_dotSizeScale = (GLfloat)qBound(0.01, (2.0 / qSqrt((qreal)dataSize)), 0.1);
+ m_selectedItem = 0;
+
+ Abstract3DRenderer::updateDataModel(dataProxy);
+}
+
+void Scatter3DRenderer::updateScene(Q3DScene *scene)
+{
+ // TODO: Move these to more suitable place e.g. controller should be controlling the viewports.
+ scene->setPrimarySubViewport(m_mainViewPort);
+
+ // TODO: See QTRD-2374
+ scene->activeCamera()->setMinYRotation(-90.0f);
+
+ if (m_hasHeightAdjustmentChanged) {
+ // Set initial m_cachedScene->activeCamera() position. Also update if height adjustment has changed.
+ scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ m_hasHeightAdjustmentChanged = false;
+ }
+
+ scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment);
+ // Set light position (rotate light with m_cachedScene->activeCamera(), a bit above it (as set in defaultLightPos))
+ scene->setLightPositionRelativeToCamera(defaultLightPos);
+
+ Abstract3DRenderer::updateScene(scene);
+}
+
+void Scatter3DRenderer::render(GLuint defaultFboHandle)
+{
+ // Handle GL state setup for FBO buffers and clearing of the render surface
+ Abstract3DRenderer::render(defaultFboHandle);
+
+ // Draw dots scene
+ drawScene(defaultFboHandle);
+}
+
+void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
+{
+ GLfloat backgroundRotation = 0;
+
+ // Specify viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f);
+
+ // Calculate view matrix
+ QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix();
+
+ // Calculate label flipping
+ if (viewMatrix.row(0).x() > 0)
+ m_zFlipped = false;
+ else
+ m_zFlipped = true;
+ if (viewMatrix.row(0).z() <= 0)
+ m_xFlipped = false;
+ else
+ m_xFlipped = true;
+
+ // Check if we're viewing the scene from below
+ if (viewMatrix.row(2).y() < 0)
+ m_yFlipped = true;
+ else
+ m_yFlipped = false;
+
+ // Calculate background rotation
+ if (!m_zFlipped && !m_xFlipped)
+ backgroundRotation = 270.0f;
+ else if (!m_zFlipped && m_xFlipped)
+ backgroundRotation = 180.0f;
+ else if (m_zFlipped && m_xFlipped)
+ backgroundRotation = 90.0f;
+ else if (m_zFlipped && !m_xFlipped)
+ backgroundRotation = 0.0f;
+
+ // Get light position from the scene
+ QVector3D lightPos = m_cachedScene->activeLight()->position();
+
+ // Map adjustment direction to model matrix scaling
+ // TODO: Let's use these for testing the autoscaling of dots based on their number
+ GLfloat heightMultiplier = m_dotSizeScale; //1.0f;
+ GLfloat widthMultiplier = m_dotSizeScale; //1.0f;
+ GLfloat depthMultiplier = m_dotSizeScale; //1.0f;
+ GLfloat heightScaler = 0.0f;
+ GLfloat widthScaler = 0.0f;
+ GLfloat depthScaler = 0.0f;
+
+ // Introduce regardless of shadow quality to simplify logic
+ QMatrix4x4 depthViewMatrix;
+ QMatrix4x4 depthProjectionMatrix;
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Render scene into a depth texture for using with shadow mapping
+ // Bind depth shader
+ m_depthShader->bind();
+
+ // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows.
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width() * m_shadowQualityMultiplier,
+ m_mainViewPort.height() * m_shadowQualityMultiplier);
+
+ // Enable drawing to framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Set front face culling to reduce self-shadowing issues
+ glCullFace(GL_FRONT);
+
+ // Get the depth view matrix
+ // It may be possible to hack lightPos here if we want to make some tweaks to shadow
+ QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera(
+ defaultLightPos, 0.0f, 1.0f / m_autoScaleAdjustment);
+ depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above?
+ // That causes the scene to be not drawn from above -> must be fixed
+ // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3);
+ // Set the depth projection matrix
+#ifndef USE_WIDER_SHADOWS
+ // Use this for perspective shadows
+ depthProjectionMatrix.perspective(15.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f);
+#else
+ // Use these for orthographic shadows
+ //depthProjectionMatrix.ortho(-aspectRatio * 2.0f, aspectRatio * 2.0f,
+ // -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f,
+ // 0.0f, 100.0f);
+ GLfloat testAspectRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
+ depthProjectionMatrix.ortho(-testAspectRatio * 2.0f, testAspectRatio * 2.0f,
+ -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f,
+ 0.0f, 100.0f);
+#endif
+ // Draw dots to depth buffer
+ for (int dot = 0; dot < m_renderItemArray.size(); dot++) {
+ const ScatterRenderItem &item = m_renderItemArray.at(dot);
+ if (!item.isVisible())
+ continue;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(item.translation().x(),
+ item.translation().y(),
+ item.translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier + widthScaler,
+ heightMultiplier + heightScaler,
+ depthMultiplier + depthScaler));
+ //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler,
+ // heightMultiplier * item.size() + heightScaler,
+ // depthMultiplier * item.size() + depthScaler));
+
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_dotObj->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_dotObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, m_dotObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+ }
+
+ // Disable drawing to framebuffer (= enable drawing to screen)
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Reset culling to normal
+ glCullFace(GL_BACK);
+
+ // Release depth shader
+ m_depthShader->release();
+
+ // Revert to original viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it)
+ m_labelShader->bind();
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+ m_drawer->drawObject(m_labelShader, m_labelObj,
+ m_depthTexture);
+ glDisable(GL_TEXTURE_2D);
+ m_labelShader->release();
+#endif
+ }
+#endif
+
+ // Skip selection mode drawing if we have no selection mode
+ if (m_cachedSelectionMode > QDataVis::SelectionModeNone) {
+ // Bind selection shader
+ m_selectionShader->bind();
+
+ // Draw dots to selection buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
+ glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (= skipColor)
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
+ glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
+
+ int arraySize = m_renderItemArray.size();
+ if (arraySize > 0xfffffe) // Max possible different selection colors, 0xffffff being skipColor
+ qFatal("Too many objects");
+
+ for (int dot = 0; dot < arraySize; dot++) {
+ const ScatterRenderItem &item = m_renderItemArray.at(dot);
+ if (!item.isVisible())
+ continue;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(item.translation().x(),
+ item.translation().y(),
+ item.translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier + widthScaler,
+ heightMultiplier + heightScaler,
+ depthMultiplier + depthScaler));
+ //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler,
+ // heightMultiplier * item.size() + heightScaler,
+ // depthMultiplier * item.size() + depthScaler));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ QVector3D dotColor = indexToSelectionColor(dot);
+ dotColor /= 255.0f;
+
+ m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
+ m_selectionShader->setUniformValue(m_selectionShader->color(), dotColor);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_selectionShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_dotObj->vertexBuf());
+ glVertexAttribPointer(m_selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_dotObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, m_dotObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_selectionShader->posAtt());
+ }
+ glEnable(GL_DITHER);
+
+ // Read color under cursor
+ if (QDataVis::InputStateOnScene == m_controller->inputState()) {
+ m_selection = Utils::getSelection(m_controller->inputPosition(),
+ m_cachedBoundingRect.height());
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Release selection shader
+ m_selectionShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+ m_drawer->drawObject(m_labelShader, m_labelObj,
+ m_selectionTexture);
+ glDisable(GL_TEXTURE_2D);
+ m_labelShader->release();
+#endif
+ }
+
+ // Bind dot shader
+ m_dotShader->bind();
+
+ // Enable texture
+ glEnable(GL_TEXTURE_2D);
+
+ // Draw dots
+ bool dotSelectionFound = false;
+ int selectedIndex;
+ if (m_selection == selectionSkipColor) {
+ selectedIndex = Scatter3DController::noSelectionIndex();
+ } else {
+ selectedIndex = int(m_selection.x())
+ + (int(m_selection.y()) << 8)
+ + (int(m_selection.z()) << 16);
+ }
+
+ if (m_selection != m_previousSelection) {
+ emit selectedItemIndexChanged(selectedIndex);
+ m_previousSelection = m_selection;
+ }
+
+ ScatterRenderItem *selectedItem(0);
+
+ for (int dot = 0; dot < m_renderItemArray.size(); dot++) {
+ ScatterRenderItem &item = m_renderItemArray[dot];
+ if (!item.isVisible())
+ continue;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(item.translation().x(),
+ item.translation().y(),
+ item.translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier + widthScaler,
+ heightMultiplier + heightScaler,
+ depthMultiplier + depthScaler));
+ //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler,
+ // heightMultiplier * item.size() + heightScaler,
+ // depthMultiplier * item.size() + depthScaler));
+ itModelMatrix.scale(QVector3D(widthMultiplier + widthScaler,
+ heightMultiplier + heightScaler,
+ depthMultiplier + depthScaler));
+ //itModelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler,
+ // heightMultiplier * item.size() + heightScaler,
+ // depthMultiplier * item.size() + depthScaler));
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+#if 0
+ QVector3D baseColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor);
+ QVector3D heightColor =
+ Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item.translation().y();
+
+ QVector3D dotColor = baseColor + heightColor;
+#else
+ QVector3D dotColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor);
+#endif
+
+ GLfloat lightStrength = m_cachedTheme.m_lightStrength;
+ if (m_cachedSelectionMode > QDataVis::SelectionModeNone && (selectedIndex == dot)) {
+ dotColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor);
+ lightStrength = m_cachedTheme.m_highlightLightStrength;
+ // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one
+ selectedItem = &item;
+ dotSelectionFound = true;
+ }
+
+ // Set shader bindings
+ m_dotShader->setUniformValue(m_dotShader->lightP(), lightPos);
+ m_dotShader->setUniformValue(m_dotShader->view(), viewMatrix);
+ m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix);
+ m_dotShader->setUniformValue(m_dotShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix);
+ m_dotShader->setUniformValue(m_dotShader->color(), dotColor);
+ m_dotShader->setUniformValue(m_dotShader->ambientS(), m_cachedTheme.m_ambientStrength);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader);
+ m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix);
+ m_dotShader->setUniformValue(m_dotShader->lightS(), lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(m_dotShader, m_dotObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_dotShader->setUniformValue(m_dotShader->lightS(), lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_dotShader, m_dotObj);
+ }
+ }
+
+ // Release dot shader
+ m_dotShader->release();
+
+ // Bind background shader
+ m_backgroundShader->bind();
+
+ glCullFace(GL_BACK);
+
+ // Draw background
+ if (m_cachedIsBackgroundEnabled && m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ QVector3D bgScale((aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor,
+ backgroundMargin,
+ (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor);
+#else // ..and this if we want uniform scaling based on largest dimension
+ QVector3D bgScale((aspectRatio * backgroundMargin),
+ backgroundMargin,
+ (aspectRatio * backgroundMargin));
+#endif
+ modelMatrix.translate(0.0f, 0.0f, zComp);
+ modelMatrix.scale(bgScale);
+ itModelMatrix.scale(bgScale);
+ // If we're viewing from below, background object must be flipped
+ if (m_yFlipped) {
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+ modelMatrix.rotate(270.0f - backgroundRotation, 0.0f, 1.0f, 0.0f);
+ } else {
+ modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f);
+ }
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor);
+
+ // Set shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
+ m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor);
+ m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(),
+ m_cachedTheme.m_ambientStrength * 2.0f);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(),
+ m_shadowQualityToShader);
+ m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj);
+ }
+ }
+
+ // Release background shader
+ m_backgroundShader->release();
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // Draw grid lines
+#ifdef USE_UNIFORM_SCALING
+ AxisRenderCache *axisCacheMax;
+ if (m_axisCacheZ.max() > m_axisCacheX.max())
+ axisCacheMax = &m_axisCacheZ;
+ else
+ axisCacheMax = &m_axisCacheX;
+#endif
+
+ if (m_cachedIsGridEnabled && m_heightNormalizer) {
+ ShaderHelper *lineShader = m_backgroundShader;
+ // Bind line shader
+ lineShader->bind();
+
+ // Set unchanging shader bindings
+ QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine);
+ lineShader->setUniformValue(lineShader->lightP(), lightPos);
+ lineShader->setUniformValue(lineShader->view(), viewMatrix);
+ lineShader->setUniformValue(lineShader->color(), lineColor);
+ lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength);
+
+ // Rows (= Z)
+ if (m_axisCacheZ.segmentCount() > 0) {
+ // Floor lines
+#ifndef USE_UNIFORM_SCALING
+ GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep();
+ GLfloat linePos = -aspectRatio * m_axisCacheZ.min(); // Start line
+ int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
+#else
+ GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep();
+ GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line
+ int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount();
+#endif
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_yFlipped)
+ modelMatrix.translate(0.0f, backgroundMargin, linePos / m_scaleFactor + zComp);
+ else
+ modelMatrix.translate(0.0f, -backgroundMargin, linePos / m_scaleFactor + zComp);
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ modelMatrix.scale(
+ QVector3D(
+ (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor,
+ gridLineWidth, gridLineWidth));
+ itModelMatrix.scale(
+ QVector3D(
+ (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor,
+ gridLineWidth, gridLineWidth));
+#else // ..and this if we want uniform scaling based on largest dimension
+ modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin),
+ gridLineWidth, gridLineWidth));
+ itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin,
+ gridLineWidth, gridLineWidth));
+#endif
+
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos -= lineStep;
+ }
+
+ // Side wall lines
+#ifndef USE_UNIFORM_SCALING
+ GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width())
+ / m_scaleFactor;
+ linePos = -aspectRatio * m_axisCacheZ.min(); // Start line
+#else
+ GLfloat lineXTrans = aspectRatio * backgroundMargin;
+ linePos = -aspectRatio * m_scaleFactor; // Start line
+#endif
+ if (!m_xFlipped)
+ lineXTrans = -lineXTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(lineXTrans, 0.0f, linePos / m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth));
+ itModelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos -= lineStep;
+ }
+ }
+
+ // Columns (= X)
+ if (m_axisCacheX.segmentCount() > 0) {
+ // Floor lines
+#ifndef USE_UNIFORM_SCALING
+ GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep();
+ GLfloat linePos = aspectRatio * m_axisCacheX.min();
+ int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
+#else
+ GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep();
+ GLfloat linePos = -aspectRatio * m_scaleFactor;
+ int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount();
+#endif
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_yFlipped)
+ modelMatrix.translate(linePos / m_scaleFactor, backgroundMargin, zComp);
+ else
+ modelMatrix.translate(linePos / m_scaleFactor, -backgroundMargin, zComp);
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ modelMatrix.scale(
+ QVector3D(
+ gridLineWidth, gridLineWidth,
+ (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor));
+ itModelMatrix.scale(
+ QVector3D(
+ gridLineWidth, gridLineWidth,
+ (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor));
+#else // ..and this if we want uniform scaling based on largest dimension
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ aspectRatio * backgroundMargin));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ aspectRatio * backgroundMargin));
+#endif
+
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+
+ // Back wall lines
+#ifndef USE_UNIFORM_SCALING
+ GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height())
+ / m_scaleFactor;
+ linePos = aspectRatio * m_axisCacheX.min();
+#else
+ GLfloat lineZTrans = aspectRatio * backgroundMargin;
+ linePos = -aspectRatio * m_scaleFactor;
+#endif
+ if (!m_zFlipped)
+ lineZTrans = -lineZTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(linePos / m_scaleFactor, 0.0f, lineZTrans + zComp);
+ modelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth));
+ itModelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+ }
+
+ // Horizontal wall lines
+ if (m_axisCacheY.segmentCount() > 0) {
+ // Back wall
+ GLfloat lineStep = m_axisCacheY.subSegmentStep();
+ GLfloat linePos = m_axisCacheY.min();
+ int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height())
+ / m_scaleFactor;
+#else // ..and this if we want uniform scaling based on largest dimension
+ GLfloat lineZTrans = aspectRatio * backgroundMargin;
+#endif
+ if (!m_zFlipped)
+ lineZTrans = -lineZTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, linePos / m_heightNormalizer, lineZTrans + zComp);
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ modelMatrix.scale(
+ QVector3D(
+ (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor),
+ gridLineWidth, gridLineWidth));
+ itModelMatrix.scale(
+ QVector3D(
+ (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor),
+ gridLineWidth, gridLineWidth));
+#else // ..and this if we want uniform scaling based on largest dimension
+ modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin),
+ gridLineWidth, gridLineWidth));
+ itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin,
+ gridLineWidth, gridLineWidth));
+#endif
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+
+ // Side wall
+ linePos = m_axisCacheY.min();
+ lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width())
+ / m_scaleFactor;
+#else // ..and this if we want uniform scaling based on largest dimension
+ GLfloat lineXTrans = aspectRatio * backgroundMargin;
+#endif
+ if (!m_xFlipped)
+ lineXTrans = -lineXTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(lineXTrans, linePos / m_heightNormalizer, zComp);
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ modelMatrix.scale(
+ QVector3D(
+ gridLineWidth, gridLineWidth,
+ (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor));
+ itModelMatrix.scale(
+ QVector3D(
+ gridLineWidth, gridLineWidth,
+ (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor));
+
+#else // ..and this if we want uniform scaling based on largest dimension
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ (aspectRatio * backgroundMargin)));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ aspectRatio * backgroundMargin));
+
+#endif
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+ }
+
+ // Release line shader
+ lineShader->release();
+ }
+
+ // Draw axis labels
+ // TODO: Calculations done temporarily here. Should be done when calculating lines to avoid
+ // extra for -loops?
+ // Bind label shader
+ m_labelShader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // Z Labels
+ if (m_axisCacheZ.segmentCount() > 0) {
+#ifndef USE_UNIFORM_SCALING
+ GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep();
+ GLfloat labelPos = -aspectRatio * m_axisCacheZ.min();
+ int lastSegment = m_axisCacheZ.segmentCount();
+#else
+ GLfloat posStep = aspectRatio * axisCacheMax->segmentStep();
+ GLfloat labelPos = aspectRatio * m_scaleFactor;
+ int lastSegment = axisCacheMax->segmentCount();
+#endif
+ int labelNbr = 0;
+ for (int segment = 0; segment <= lastSegment; segment++) {
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ if (m_axisCacheZ.labelItems().size() > labelNbr) {
+ GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width())
+ / m_scaleFactor + labelMargin;
+#else // ..and this if we want uniform scaling based on largest dimension
+ if (axisCacheMax->labelItems().size() > labelNbr) {
+ GLfloat labelXTrans = aspectRatio * backgroundMargin + labelMargin;
+#endif
+ GLfloat labelYTrans = -backgroundMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 0.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ if (m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ alignment = Qt::AlignLeft;
+ }
+ if (m_yFlipped) {
+ rotLabelZ += 180.0f;
+ rotLabelY += 180.0f;
+ labelYTrans = -labelYTrans;
+ }
+ QVector3D labelTrans = QVector3D(labelXTrans,
+ labelYTrans,
+ labelPos / m_scaleFactor + zComp);
+
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+#ifndef USE_UNIFORM_SCALING
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr);
+#else
+ const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr);
+#endif
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ labelNbr++;
+ labelPos -= posStep;
+ }
+ }
+ // X Labels
+ if (m_axisCacheX.segmentCount() > 0) {
+#ifndef USE_UNIFORM_SCALING
+ GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep();
+ GLfloat labelPos = aspectRatio * m_axisCacheX.min();
+ int lastSegment = m_axisCacheX.segmentCount();
+#else
+ GLfloat posStep = aspectRatio * axisCacheMax->segmentStep();
+ GLfloat labelPos = -aspectRatio * m_scaleFactor;
+ int lastSegment = axisCacheMax->segmentCount();
+#endif
+ int labelNbr = 0;
+ for (int segment = 0; segment <= lastSegment; segment++) {
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ if (m_axisCacheX.labelItems().size() > labelNbr) {
+ GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height())
+ / m_scaleFactor + labelMargin;
+#else // ..and this if we want uniform scaling based on largest dimension
+ if (axisCacheMax->labelItems().size() > labelNbr) {
+ GLfloat labelZTrans = aspectRatio * backgroundMargin + labelMargin;
+#endif
+ GLfloat labelYTrans = -backgroundMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (m_xFlipped)
+ rotLabelY = -90.0f;
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ alignment = Qt::AlignRight;
+ }
+ if (m_yFlipped) {
+ rotLabelZ += 180.0f;
+ rotLabelY += 180.0f;
+ labelYTrans = -labelYTrans;
+ }
+ QVector3D labelTrans = QVector3D(labelPos / m_scaleFactor,
+ labelYTrans,
+ labelZTrans + zComp);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+#ifndef USE_UNIFORM_SCALING
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr);
+#else
+ const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr);
+#endif
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+ }
+ // Y Labels
+ if (m_axisCacheY.segmentCount() > 0) {
+ GLfloat posStep = m_axisCacheY.segmentStep();
+ GLfloat labelPos = m_axisCacheY.min();
+ int labelNbr = 0;
+ for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
+ if (m_axisCacheY.labelItems().size() > labelNbr) {
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width())
+ / m_scaleFactor;
+ GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height())
+ / m_scaleFactor;
+#else // ..and this if we want uniform scaling based on largest dimension
+ GLfloat labelXTrans = aspectRatio * backgroundMargin;
+ GLfloat labelZTrans = labelXTrans;
+#endif
+ GLfloat labelMarginXTrans = labelMargin;
+ GLfloat labelMarginZTrans = labelMargin;
+ GLfloat labelYTrans = labelPos / m_heightNormalizer;
+ GLfloat rotLabelX = 0.0f;
+ GLfloat rotLabelY = -90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (!m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ labelMarginXTrans = -labelMargin;
+ rotLabelY = 90.0f;
+ }
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ labelMarginZTrans = -labelMargin;
+ alignment = Qt::AlignRight;
+ }
+
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+
+ // Back wall
+ QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans,
+ labelZTrans + labelMarginZTrans + zComp);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+
+ // Side wall
+ if (m_xFlipped)
+ alignment = Qt::AlignLeft;
+ else
+ alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ else
+ rotLabelY = 0.0f;
+
+ labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelYTrans,
+ -labelZTrans + zComp);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid,
+ alignment);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+ }
+
+ // Handle selection clearing and selection label drawing
+ if (!dotSelectionFound) {
+ // We have no ownership, don't delete. Just NULL the pointer.
+ m_selectedItem = NULL;
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ // Draw the selection label
+ LabelItem &labelItem = selectedItem->selectionLabelItem();
+ if (m_selectedItem != selectedItem || m_updateLabels
+ || !labelItem.textureId()) {
+ QString labelText = selectedItem->selectionLabel();
+ if (labelText.isNull()) {
+ static const QString xTitleTag(QStringLiteral("@xTitle"));
+ static const QString yTitleTag(QStringLiteral("@yTitle"));
+ static const QString zTitleTag(QStringLiteral("@zTitle"));
+ static const QString xLabelTag(QStringLiteral("@xLabel"));
+ static const QString yLabelTag(QStringLiteral("@yLabel"));
+ static const QString zLabelTag(QStringLiteral("@zLabel"));
+
+ labelText = itemLabelFormat();
+
+ labelText.replace(xTitleTag, m_axisCacheX.title());
+ labelText.replace(yTitleTag, m_axisCacheY.title());
+ labelText.replace(zTitleTag, m_axisCacheZ.title());
+
+ if (labelText.contains(xLabelTag)) {
+ QString labelFormat = m_axisCacheX.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat,
+ selectedItem->position().x());
+ labelText.replace(xLabelTag, valueLabelText);
+ }
+ if (labelText.contains(yLabelTag)) {
+ QString labelFormat = m_axisCacheY.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat,
+ selectedItem->position().y());
+ labelText.replace(yLabelTag, valueLabelText);
+ }
+ if (labelText.contains(zLabelTag)) {
+ QString labelFormat = m_axisCacheZ.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat,
+ selectedItem->position().z());
+ labelText.replace(zLabelTag, valueLabelText);
+ }
+
+ selectedItem->setSelectionLabel(labelText);
+ }
+ m_drawer->generateLabelItem(labelItem, labelText);
+ m_selectedItem = selectedItem;
+ }
+
+ m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), 0,
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(), true, false,
+ Drawer::LabelMid);
+
+ // Reset label update flag; they should have been updated when we get here
+ m_updateLabels = false;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ m_labelShader->release();
+}
+
+void Scatter3DRenderer::updateSelectedItemIndex(int index)
+{
+ if (index == Scatter3DController::noSelectionIndex())
+ m_selection = selectionSkipColor;
+ else
+ m_selection = indexToSelectionColor(index);
+}
+
+void Scatter3DRenderer::handleResize()
+{
+ if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0)
+ return;
+
+ // Set view port
+ m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+
+ Abstract3DRenderer::handleResize();
+}
+
+void Scatter3DRenderer::updateBackgroundEnabled(bool enable)
+{
+ if (enable != m_cachedIsBackgroundEnabled) {
+ Abstract3DRenderer::updateBackgroundEnabled(enable);
+ loadMeshFile(); // Load changed dot type
+ }
+}
+
+void Scatter3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality)
+{
+ m_cachedShadowQuality = quality;
+ switch (quality) {
+ case QDataVis::ShadowQualityLow:
+ m_shadowQualityToShader = 33.3f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualityMedium:
+ m_shadowQualityToShader = 100.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualityHigh:
+ m_shadowQualityToShader = 200.0f;
+ m_shadowQualityMultiplier = 5;
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ m_shadowQualityToShader = 5.0f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ m_shadowQualityToShader = 10.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ m_shadowQualityToShader = 15.0f;
+ m_shadowQualityMultiplier = 4;
+ break;
+ default:
+ m_shadowQualityToShader = 0.0f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ }
+
+ handleShadowQualityChange();
+
+#if !defined(QT_OPENGL_ES_2)
+ // Re-init depth buffer
+ updateDepthBuffer();
+#endif
+}
+
+void Scatter3DRenderer::loadMeshFile()
+{
+ QString objectFileName = m_cachedObjFile;
+ if (m_dotObj)
+ delete m_dotObj;
+ m_dotObj = new ObjectHelper(objectFileName);
+ m_dotObj->load();
+}
+
+void Scatter3DRenderer::loadBackgroundMesh()
+{
+ if (m_backgroundObj)
+ delete m_backgroundObj;
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
+ m_backgroundObj->load();
+}
+
+void Scatter3DRenderer::loadGridLineMesh()
+{
+ if (m_gridLineObj)
+ delete m_gridLineObj;
+ m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar"));
+ m_gridLineObj->load();
+}
+
+void Scatter3DRenderer::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void Scatter3DRenderer::updateTextures()
+{
+ // Drawer has changed; this flag needs to be checked when checking if we need to update labels
+ m_updateLabels = true;
+}
+
+void Scatter3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation,
+ qreal min, qreal max)
+{
+ Abstract3DRenderer::updateAxisRange(orientation, min, max);
+}
+
+void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item)
+{
+ // Origin should be in the center of scene, ie. both positive and negative values are drawn
+ // above background
+
+ // We need to normalize translations
+ GLfloat xTrans = (aspectRatio * item.position().x()) / m_scaleFactor;
+ GLfloat zTrans = -(aspectRatio * item.position().z()) / m_scaleFactor;
+ GLfloat yTrans = item.position().y() / m_heightNormalizer;
+ item.setTranslation(QVector3D(xTrans, yTrans, zTrans + zComp));
+ //qDebug() << item.translation();
+}
+
+void Scatter3DRenderer::calculateSceneScalingFactors()
+{
+ m_heightNormalizer = (GLfloat)qMax(qAbs(m_axisCacheY.max()), qAbs(m_axisCacheY.min()));
+ m_areaSize.setHeight(qMax(qAbs(m_axisCacheZ.max()), qAbs(m_axisCacheZ.min())));
+ m_areaSize.setWidth(qMax(qAbs(m_axisCacheX.max()), qAbs(m_axisCacheX.min())));
+ m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height());
+ //qDebug() << m_heightNormalizer << m_areaSize << m_scaleFactor << m_axisCacheY.max() << m_axisCacheX.max() << m_axisCacheZ.max();
+}
+
+QRect Scatter3DRenderer::mainViewPort()
+{
+ return m_mainViewPort;
+}
+
+void Scatter3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_dotShader)
+ delete m_dotShader;
+ m_dotShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_dotShader->initialize();
+}
+
+void Scatter3DRenderer::initSelectionShader()
+{
+ if (m_selectionShader)
+ delete m_selectionShader;
+ m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSelection"),
+ QStringLiteral(":/shaders/fragmentSelection"));
+ m_selectionShader->initialize();
+}
+
+void Scatter3DRenderer::initSelectionBuffer()
+{
+ if (m_selectionTexture)
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+
+ m_selectionTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(),
+ m_selectionFrameBuffer,
+ m_selectionDepthBuffer);
+}
+
+#if !defined(QT_OPENGL_ES_2)
+void Scatter3DRenderer::initDepthShader()
+{
+ if (m_depthShader)
+ delete m_depthShader;
+ m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"),
+ QStringLiteral(":/shaders/fragmentDepth"));
+ m_depthShader->initialize();
+}
+
+void Scatter3DRenderer::updateDepthBuffer()
+{
+ if (m_depthTexture) {
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_depthTexture = 0;
+ }
+
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(),
+ m_depthFrameBuffer,
+ m_shadowQualityMultiplier);
+ if (!m_depthTexture) {
+ switch (m_cachedShadowQuality) {
+ case QDataVis::ShadowQualityHigh:
+ qWarning("Creating high quality shadows failed. Changing to medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium);
+ updateShadowQuality(QDataVis::ShadowQualityMedium);
+ break;
+ case QDataVis::ShadowQualityMedium:
+ qWarning("Creating medium quality shadows failed. Changing to low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow);
+ updateShadowQuality(QDataVis::ShadowQualityLow);
+ break;
+ case QDataVis::ShadowQualityLow:
+ qWarning("Creating low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ qWarning("Creating soft high quality shadows failed. Changing to soft medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ updateShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ qWarning("Creating soft medium quality shadows failed. Changing to soft low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow);
+ updateShadowQuality(QDataVis::ShadowQualitySoftLow);
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ qWarning("Creating soft low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ default:
+ // You'll never get here
+ break;
+ }
+ }
+ }
+}
+#endif
+
+void Scatter3DRenderer::initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_backgroundShader)
+ delete m_backgroundShader;
+ m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_backgroundShader->initialize();
+}
+
+void Scatter3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_labelShader->initialize();
+}
+
+QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index)
+{
+ GLubyte dotIdxRed = index & 0xff;
+ GLubyte dotIdxGreen = (index & 0xff00) >> 8;
+ GLubyte dotIdxBlue = (index & 0xff0000) >> 16;
+
+ return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h
new file mode 100644
index 00000000..f444f891
--- /dev/null
+++ b/src/datavisualization/engine/scatter3drenderer_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DSCATTERRENDERER_P_H
+#define Q3DSCATTERRENDERER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "scatter3dcontroller_p.h"
+#include "abstract3drenderer_p.h"
+#include "qscatterdataproxy.h"
+#include "scatterrenderitem_p.h"
+
+class QPoint;
+class QSizeF;
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper;
+class ObjectHelper;
+class LabelItem;
+class Q3DScene;
+class QAbstractAxisPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT Scatter3DRenderer : public Abstract3DRenderer
+{
+ Q_OBJECT
+
+private:
+ // TODO: Filter to the set of attributes to be moved to the model object.
+ // * All GL rendering only related attribs should be moved out of this public set.
+ // * All attribs that are modifiable from QML need to e in this set.
+
+ Scatter3DController *m_controller;
+
+ // Internal state
+ ScatterRenderItem *m_selectedItem; // points to renderitem array
+ bool m_xFlipped;
+ bool m_zFlipped;
+ bool m_yFlipped;
+ QRect m_mainViewPort;
+ bool m_updateLabels;
+ ShaderHelper *m_dotShader;
+ ShaderHelper *m_depthShader;
+ ShaderHelper *m_selectionShader;
+ ShaderHelper *m_backgroundShader;
+ ShaderHelper *m_labelShader;
+ ObjectHelper *m_dotObj;
+ ObjectHelper *m_backgroundObj;
+ ObjectHelper *m_gridLineObj;
+ ObjectHelper *m_labelObj;
+ GLuint m_bgrTexture;
+ GLuint m_depthTexture;
+ GLuint m_selectionTexture;
+ GLuint m_depthFrameBuffer;
+ GLuint m_selectionFrameBuffer;
+ GLuint m_selectionDepthBuffer;
+ GLfloat m_shadowQualityToShader;
+ GLint m_shadowQualityMultiplier;
+ GLfloat m_heightNormalizer;
+ GLfloat m_scaleFactor;
+ QVector3D m_selection;
+ QVector3D m_previousSelection;
+ QSizeF m_areaSize;
+ GLfloat m_dotSizeScale;
+
+ bool m_hasHeightAdjustmentChanged;
+ ScatterRenderItem m_dummyRenderItem;
+
+ ScatterRenderItemArray m_renderItemArray;
+
+public:
+ explicit Scatter3DRenderer(Scatter3DController *controller);
+ ~Scatter3DRenderer();
+
+ void updateDataModel(QScatterDataProxy *dataProxy);
+ void updateScene(Q3DScene *scene);
+ void render(GLuint defaultFboHandle);
+
+ QRect mainViewPort();
+
+protected:
+ virtual void initializeOpenGL();
+ virtual void loadMeshFile();
+
+private:
+ virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
+ virtual void updateShadowQuality(QDataVis::ShadowQuality quality);
+ virtual void updateTextures();
+
+ void drawScene(GLuint defaultFboHandle);
+ void handleResize();
+
+ void loadBackgroundMesh();
+ void loadGridLineMesh();
+ void loadLabelMesh();
+ void initSelectionShader();
+ void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initSelectionBuffer();
+#if !defined(QT_OPENGL_ES_2)
+ void initDepthShader();
+ void updateDepthBuffer();
+#endif
+ void calculateTranslation(ScatterRenderItem &item);
+ void calculateSceneScalingFactors();
+
+ Q_DISABLE_COPY(Scatter3DRenderer)
+
+ friend class ScatterRenderItem;
+
+public slots:
+ void updateBackgroundEnabled(bool enable);
+
+ // Overloaded from abstract renderer
+ virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
+
+ void updateSelectedItemIndex(int index);
+
+signals:
+ void selectionUpdated(QVector3D selection);
+ void selectedItemIndexChanged(int index);
+
+private:
+ QVector3D indexToSelectionColor(GLint index);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/engine/selectionpointer.cpp b/src/datavisualization/engine/selectionpointer.cpp
new file mode 100644
index 00000000..6c3e0c8b
--- /dev/null
+++ b/src/datavisualization/engine/selectionpointer.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "selectionpointer_p.h"
+#include "surface3dcontroller_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "texturehelper_p.h"
+#include "q3dcamera.h"
+#include "q3dcamera_p.h"
+#include "drawer_p.h"
+#include "utils_p.h"
+#include "q3dlight.h"
+
+#include <QImage>
+#include <QMatrix4x4>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+const GLfloat sliceUnits = 2.5;
+
+SelectionPointer::SelectionPointer(Drawer *drawer)
+ : QObject(0),
+ m_labelShader(0),
+ m_pointShader(0),
+ m_labelObj(0),
+ m_pointObj(0),
+ m_textureHelper(0),
+ m_isInitialized(false),
+ m_cachedTheme(drawer->theme()),
+ m_labelStyle(QDataVis::LabelStyleFromTheme),
+ m_drawer(drawer),
+ m_cachedScene(0)
+{
+ initializeOpenGL();
+
+ QObject::connect(m_drawer, &Drawer::drawerChanged,
+ this, &SelectionPointer::handleDrawerChange);
+}
+
+SelectionPointer::~SelectionPointer()
+{
+ delete m_labelShader;
+ delete m_pointShader;
+ delete m_labelObj;
+ delete m_pointObj;
+ delete m_textureHelper;
+}
+
+void SelectionPointer::initializeOpenGL()
+{
+ if (m_isInitialized)
+ return;
+
+ initializeOpenGLFunctions();
+
+ m_textureHelper = new TextureHelper();
+ m_drawer->initializeOpenGL();
+
+ initShaders();
+
+ loadLabelMesh();
+ loadPointMesh();
+
+ // Set initialized -flag
+ m_isInitialized = true;
+}
+
+void SelectionPointer::updateScene(Q3DScene *scene)
+{
+ m_cachedScene = scene;
+}
+
+void SelectionPointer::render(GLuint defaultFboHandle)
+{
+ Q_UNUSED(defaultFboHandle)
+
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ Q3DCamera *camera = m_cachedScene->activeCamera();
+ QSize textureSize = m_labelItem.size();
+
+ QMatrix4x4 itModelMatrix;
+
+ // Get view matrix
+ QMatrix4x4 viewMatrix;
+ QMatrix4x4 projectionMatrix;
+ if (m_cachedIsSlicingActivated) {
+ GLfloat aspect = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
+ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, zComp + 1.0),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ projectionMatrix.ortho(-sliceUnits * aspect, sliceUnits * aspect,
+ -sliceUnits, sliceUnits, -1.0f, 14.0f);
+ } else {
+ viewMatrix = camera->viewMatrix();
+ projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f);
+ }
+
+ // Calculate scale factor to get uniform font size
+ GLfloat scaledFontSize = 0.05f + m_drawer->font().pointSizeF() / 500.0f;
+ GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ // Position the pointer ball
+ modelMatrix.translate(m_position + QVector3D(0.0f, 0.0f, zComp));
+
+ // Scale the point with fixed values (at this point)
+ modelMatrix.scale(QVector3D(0.05f, 0.05f, 0.05f));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ // Enable texturing
+ glEnable(GL_TEXTURE_2D);
+
+ QVector3D lightPos = m_cachedScene->activeLight()->position();
+
+ //
+ // Draw the point
+ //
+ m_pointShader->bind();
+ m_pointShader->setUniformValue(m_pointShader->lightP(), lightPos);
+ m_pointShader->setUniformValue(m_pointShader->view(), viewMatrix);
+ m_pointShader->setUniformValue(m_pointShader->model(), modelMatrix);
+ m_pointShader->setUniformValue(m_pointShader->nModel(), itModelMatrix.inverted().transposed());
+ m_pointShader->setUniformValue(m_pointShader->color(),
+ Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor));
+ m_pointShader->setUniformValue(m_pointShader->MVP(), MVPMatrix);
+ m_pointShader->setUniformValue(m_pointShader->ambientS(), m_cachedTheme.m_ambientStrength);
+ m_pointShader->setUniformValue(m_pointShader->lightS(), m_cachedTheme.m_lightStrength * 2.0f);
+
+ m_drawer->drawObject(m_pointShader, m_pointObj);
+
+ m_pointShader->release();
+
+ //
+ // Draw the label
+ //
+ QMatrix4x4 modelMatrixLabel;
+
+ // Position label
+ QVector3D labelAlign(0.0f, 1.0f * scaledFontSize + 0.05f, 0.0f);
+ modelMatrixLabel.translate(m_position + labelAlign + QVector3D(0.0f, 0.0f, zComp));
+
+ // Position the label towards the camera
+ qreal camRotationsX = camera->xRotation();
+ qreal camRotationsY = camera->yRotation();
+ if (!m_cachedIsSlicingActivated) {
+ modelMatrixLabel.rotate(-camRotationsX, 0.0f, 1.0f, 0.0f);
+ modelMatrixLabel.rotate(-camRotationsY, 1.0f, 0.0f, 0.0f);
+ }
+
+ // Scale label based on text size
+ modelMatrixLabel.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
+ scaledFontSize,
+ 0.0f));
+
+ // Make label to be always on top
+ glDisable(GL_DEPTH_TEST);
+
+ // Make label transparent
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ m_labelShader->bind();
+
+ // Set shader bindings
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrixLabel;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+
+ // Draw the object
+ m_drawer->drawObject(m_labelShader, m_labelObj, m_labelItem.textureId());
+
+ m_labelShader->release();
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // Disable transparency
+ glDisable(GL_BLEND);
+
+ // Depth test back to normal
+ glEnable(GL_DEPTH_TEST);
+}
+
+void SelectionPointer::setPosition(QVector3D position)
+{
+ m_position = position;
+}
+
+void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment)
+{
+ m_cachedIsSlicingActivated = sliceActivated;
+ m_autoScaleAdjustment = autoScaleAdjustment;
+}
+
+void SelectionPointer::setLabel(QString label)
+{
+ m_label = label;
+
+ m_drawer->generateLabelItem(m_labelItem, m_label);
+}
+
+void SelectionPointer::handleDrawerChange()
+{
+ m_cachedTheme = m_drawer->theme();
+ setLabel(m_label);
+}
+
+void SelectionPointer::updateBoundingRect(QRect rect)
+{
+ m_mainViewPort = rect;
+}
+
+void SelectionPointer::initShaders()
+{
+ // The shader for printing the text label
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+ m_labelShader->initialize();
+
+ // The shader for the small point ball
+ if (m_pointShader)
+ delete m_pointShader;
+#if defined (Q_OS_ANDROID)
+ m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexES2"),
+ QStringLiteral(":/shaders/fragmentES2"));
+#else
+ m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+#endif
+ m_pointShader->initialize();
+
+}
+
+void SelectionPointer::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void SelectionPointer::loadPointMesh()
+{
+ if (m_pointObj)
+ delete m_pointObj;
+ m_pointObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/sphereSmooth"));
+ m_pointObj->load();
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/selectionpointer_p.h b/src/datavisualization/engine/selectionpointer_p.h
new file mode 100644
index 00000000..0e766035
--- /dev/null
+++ b/src/datavisualization/engine/selectionpointer_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 NOTIFICATIONLABEL_P_H
+#define NOTIFICATIONLABEL_P_H
+
+#include <QtCore/QObject>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QFont>
+#include <QWindow>
+#include <QVector3D>
+
+#include "q3dscene.h"
+#include "datavisualizationglobal_p.h"
+#include "surface3dcontroller_p.h"
+
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper;
+class ObjectHelper;
+class SurfaceObject;
+class TextureHelper;
+class Theme;
+class Drawer;
+class Q3DCamera;
+
+class QT_DATAVISUALIZATION_EXPORT SelectionPointer : public QObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ explicit SelectionPointer(Drawer *drawer);
+ ~SelectionPointer();
+
+ void initializeOpenGL();
+ void render(GLuint defaultFboHandle = 0);
+ void setPosition(QVector3D position);
+ void setLabel(QString label);
+ void handleDrawerChange();
+ void updateBoundingRect(QRect rect);
+ void updateScene(Q3DScene *scene);
+ void updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment);
+
+private:
+ void initShaders();
+ void loadLabelMesh();
+ void loadPointMesh();
+
+private:
+ ShaderHelper *m_labelShader;
+ ShaderHelper *m_pointShader;
+ ObjectHelper *m_labelObj;
+ ObjectHelper *m_pointObj;
+ TextureHelper *m_textureHelper;
+ bool m_isInitialized;
+ Theme m_cachedTheme;
+ QDataVis::LabelStyle m_labelStyle;
+ LabelItem m_labelItem;
+ Drawer *m_drawer;
+ QRect m_mainViewPort;
+ QVector3D m_position;
+ Q3DScene *m_cachedScene;
+ QString m_label;
+ bool m_cachedIsSlicingActivated;
+ GLfloat m_autoScaleAdjustment;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // NOTIFICATIONLABEL_P_H
diff --git a/src/datavisualization/engine/shaders/ambient.frag b/src/datavisualization/engine/shaders/ambient.frag
new file mode 100644
index 00000000..88f850f3
--- /dev/null
+++ b/src/datavisualization/engine/shaders/ambient.frag
@@ -0,0 +1,32 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ highp vec3 lightColor = vec3(1.0, 1.0, 1.0);
+ highp float lightPower = 10.0;
+ highp vec3 materialAmbientColor = vec3(0.5, 0.5, 0.5) * color_mdl;
+ highp vec3 materialSpecularColor = vec3(0.3, 0.3, 0.3) * color_mdl;
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialSpecularColor * lightColor * lightPower * pow(cosAlpha, 5) / (distance * distance);
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/colorOnY.frag b/src/datavisualization/engine/shaders/colorOnY.frag
new file mode 100644
index 00000000..80e54a61
--- /dev/null
+++ b/src/datavisualization/engine/shaders/colorOnY.frag
@@ -0,0 +1,36 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom
+ highp vec3 materialDiffuseColor = heightMod * color_mdl;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance;
+ gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0);
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/colorOnY_ES2.frag b/src/datavisualization/engine/shaders/colorOnY_ES2.frag
new file mode 100644
index 00000000..aba52cfe
--- /dev/null
+++ b/src/datavisualization/engine/shaders/colorOnY_ES2.frag
@@ -0,0 +1,37 @@
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom
+ highp vec3 materialDiffuseColor = heightMod * color_mdl;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = dot(n, l);
+ if (cosTheta < 0.0) cosTheta = 0.0;
+ else if (cosTheta > 1.0) cosTheta = 1.0;
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = dot(E, R);
+ if (cosAlpha < 0.0) cosAlpha = 0.0;
+ else if (cosAlpha > 1.0) cosAlpha = 1.0;
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/default.frag b/src/datavisualization/engine/shaders/default.frag
new file mode 100644
index 00000000..fba1ce4a
--- /dev/null
+++ b/src/datavisualization/engine/shaders/default.frag
@@ -0,0 +1,36 @@
+#version 120
+
+varying highp vec2 UV;
+varying highp vec2 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/default.vert b/src/datavisualization/engine/shaders/default.vert
new file mode 100644
index 00000000..14f77773
--- /dev/null
+++ b/src/datavisualization/engine/shaders/default.vert
@@ -0,0 +1,28 @@
+#version 120
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl.xy;
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+}
diff --git a/src/datavisualization/engine/shaders/default_ES2.frag b/src/datavisualization/engine/shaders/default_ES2.frag
new file mode 100644
index 00000000..7d6214b2
--- /dev/null
+++ b/src/datavisualization/engine/shaders/default_ES2.frag
@@ -0,0 +1,38 @@
+varying highp vec2 UV;
+varying highp vec2 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = dot(n, l);
+ if (cosTheta < 0.0) cosTheta = 0.0;
+ else if (cosTheta > 1.0) cosTheta = 1.0;
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = dot(E, R);
+ if (cosAlpha < 0.0) cosAlpha = 0.0;
+ else if (cosAlpha > 1.0) cosAlpha = 1.0;
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/default_ES2.vert b/src/datavisualization/engine/shaders/default_ES2.vert
new file mode 100644
index 00000000..efb40862
--- /dev/null
+++ b/src/datavisualization/engine/shaders/default_ES2.vert
@@ -0,0 +1,26 @@
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl.xy;
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+}
diff --git a/src/datavisualization/engine/shaders/depth.frag b/src/datavisualization/engine/shaders/depth.frag
new file mode 100644
index 00000000..5cfd4b10
--- /dev/null
+++ b/src/datavisualization/engine/shaders/depth.frag
@@ -0,0 +1,3 @@
+void main() {
+ gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/src/datavisualization/engine/shaders/depth.vert b/src/datavisualization/engine/shaders/depth.vert
new file mode 100644
index 00000000..9fe5a193
--- /dev/null
+++ b/src/datavisualization/engine/shaders/depth.vert
@@ -0,0 +1,8 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+}
+
diff --git a/src/datavisualization/engine/shaders/label.frag b/src/datavisualization/engine/shaders/label.frag
new file mode 100644
index 00000000..86021410
--- /dev/null
+++ b/src/datavisualization/engine/shaders/label.frag
@@ -0,0 +1,8 @@
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_FragColor = texture2D(textureSampler, UV);
+}
+
diff --git a/src/datavisualization/engine/shaders/label.vert b/src/datavisualization/engine/shaders/label.vert
new file mode 100644
index 00000000..b4debe53
--- /dev/null
+++ b/src/datavisualization/engine/shaders/label.vert
@@ -0,0 +1,11 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ UV = vertexUV;
+}
diff --git a/src/datavisualization/engine/shaders/selection.frag b/src/datavisualization/engine/shaders/selection.frag
new file mode 100644
index 00000000..099c87a1
--- /dev/null
+++ b/src/datavisualization/engine/shaders/selection.frag
@@ -0,0 +1,7 @@
+uniform highp vec3 color_mdl;
+
+void main() {
+ gl_FragColor.rgb = color_mdl;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/selection.vert b/src/datavisualization/engine/shaders/selection.vert
new file mode 100644
index 00000000..64d17e15
--- /dev/null
+++ b/src/datavisualization/engine/shaders/selection.vert
@@ -0,0 +1,7 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+}
diff --git a/src/datavisualization/engine/shaders/shadow.frag b/src/datavisualization/engine/shaders/shadow.frag
new file mode 100644
index 00000000..5309b5bb
--- /dev/null
+++ b/src/datavisualization/engine/shaders/shadow.frag
@@ -0,0 +1,82 @@
+#version 120
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp sampler2D textureSampler;
+uniform highp sampler2DShadow shadowMap;
+
+varying highp vec4 shadowCoord;
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(0.2, 0.2, 0.2);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.6;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ // stratified poisson; produces noise but hides pixel edges well
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ */
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = texture2D(textureSampler, UV).a;
+}
diff --git a/src/datavisualization/engine/shaders/shadow.vert b/src/datavisualization/engine/shaders/shadow.vert
new file mode 100644
index 00000000..e29a8a30
--- /dev/null
+++ b/src/datavisualization/engine/shaders/shadow.vert
@@ -0,0 +1,37 @@
+#version 120
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp mat4 depthMVP;
+uniform highp vec3 lightPosition_wrld;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec3 vertexNormal_mdl;
+attribute highp vec2 vertexUV;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec4 shadowCoord;
+varying highp vec2 coords_mdl;
+
+const highp mat4 bias = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl.xy;
+ shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0);
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ lightDirection_cmr = (V * vec4(lightPosition_wrld, 0.0)).xyz;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ UV = vertexUV;
+}
diff --git a/src/datavisualization/engine/shaders/shadowNoTex.frag b/src/datavisualization/engine/shaders/shadowNoTex.frag
new file mode 100644
index 00000000..0252ba49
--- /dev/null
+++ b/src/datavisualization/engine/shaders/shadowNoTex.frag
@@ -0,0 +1,98 @@
+#version 120
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp vec3 color_mdl;
+uniform highp sampler2DShadow shadowMap;
+
+varying highp vec4 shadowCoord;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*highp vec2 poissonDisk[16] = vec2[16](vec2(-0.25, -0.25),
+ vec2(0.25, -0.25),
+ vec2(-0.25, 0.25),
+ vec2(0.25, 0.25),
+ vec2(-0.5, -0.5),
+ vec2(0.5, -0.5),
+ vec2(-0.5, 0.5),
+ vec2(0.5, 0.5),
+ vec2(-0.75, -0.75),
+ vec2(0.75, -0.75),
+ vec2(-0.75, 0.75),
+ vec2(0.75, 0.75),
+ vec2(-1.0, -1.0),
+ vec2(1.0, -1.0),
+ vec2(-1.0, 1.0),
+ vec2(1.0, 1.0));*/
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+void main() {
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.6;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ // stratified poisson; produces noise but hides pixel edges well
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ */
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = 1.0;
+}
diff --git a/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag
new file mode 100644
index 00000000..68ba2368
--- /dev/null
+++ b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag
@@ -0,0 +1,82 @@
+#version 120
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp vec3 color_mdl;
+uniform highp sampler2DShadow shadowMap;
+
+varying highp vec4 shadowCoord;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+void main() {
+ highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom
+ highp vec3 materialDiffuseColor = heightMod * color_mdl;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.6;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }*/
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0);
+ gl_FragColor.a = 1.0;
+}
diff --git a/src/datavisualization/engine/shaders/surface.frag b/src/datavisualization/engine/shaders/surface.frag
new file mode 100644
index 00000000..4b1357b1
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surface.frag
@@ -0,0 +1,36 @@
+#version 120
+
+varying highp vec3 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform sampler2D textureSampler;
+uniform highp vec3 lightPosition_wrld;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.001) / 2.0); // 1000 pixel texture, we need a margin for 1/1000 rounding error
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/surface.vert b/src/datavisualization/engine/shaders/surface.vert
new file mode 100644
index 00000000..28152abc
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surface.vert
@@ -0,0 +1,25 @@
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec3 vertexNormal_mdl;
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec3 coords_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl;
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+}
diff --git a/src/datavisualization/engine/shaders/surfaceFlat.frag b/src/datavisualization/engine/shaders/surfaceFlat.frag
new file mode 100644
index 00000000..a8a3dbb1
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surfaceFlat.frag
@@ -0,0 +1,36 @@
+#version 150
+
+varying highp vec3 coords_mdl;
+varying highp vec3 position_wrld;
+flat in highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform sampler2D textureSampler;
+uniform highp vec3 lightPosition_wrld;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.001) / 2.0); // 1000 pixel texture, we need a margin for 1/1000 rounding error
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/surfaceFlat.vert b/src/datavisualization/engine/shaders/surfaceFlat.vert
new file mode 100644
index 00000000..7e248d02
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surfaceFlat.vert
@@ -0,0 +1,27 @@
+#version 150
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec3 vertexNormal_mdl;
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+varying highp vec3 position_wrld;
+flat out highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec3 coords_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl;
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+}
diff --git a/src/datavisualization/engine/shaders/surfaceGrid.frag b/src/datavisualization/engine/shaders/surfaceGrid.frag
new file mode 100644
index 00000000..1658b316
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surfaceGrid.frag
@@ -0,0 +1,6 @@
+uniform highp vec3 color_mdl;
+
+void main() {
+ gl_FragColor.rgb = color_mdl;
+}
+
diff --git a/src/datavisualization/engine/shaders/surfaceGrid.vert b/src/datavisualization/engine/shaders/surfaceGrid.vert
new file mode 100644
index 00000000..5582d633
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surfaceGrid.vert
@@ -0,0 +1,6 @@
+attribute highp vec3 vertexPosition_mdl;
+uniform highp mat4 MVP;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+}
diff --git a/src/datavisualization/engine/shaders/surface_ES2.frag b/src/datavisualization/engine/shaders/surface_ES2.frag
new file mode 100644
index 00000000..a9aec528
--- /dev/null
+++ b/src/datavisualization/engine/shaders/surface_ES2.frag
@@ -0,0 +1,39 @@
+varying highp vec2 UV;
+varying highp vec3 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform sampler2D textureSampler;
+uniform highp vec3 lightPosition_wrld;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec2 gradientUV = vec2(0.5, (coords_mdl.y + 1.0) / 2.0);
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = dot(n, l);
+ if (cosTheta < 0.0) cosTheta = 0.0;
+ else if (cosTheta > 1.0) cosTheta = 1.0;
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = dot(E, R);
+ if (cosAlpha < 0.0) cosAlpha = 0.0;
+ else if (cosAlpha > 1.0) cosAlpha = 1.0;
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta * cosTheta / distance +
+ materialSpecularColor * lightStrength * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavisualization/engine/shaders/texture.frag b/src/datavisualization/engine/shaders/texture.frag
new file mode 100644
index 00000000..a6d7b2eb
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture.frag
@@ -0,0 +1,35 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = texture2D(textureSampler, UV).a;
+}
+
diff --git a/src/datavisualization/engine/shaders/texture.vert b/src/datavisualization/engine/shaders/texture.vert
new file mode 100644
index 00000000..01f922e0
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture.vert
@@ -0,0 +1,26 @@
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ UV = vertexUV;
+}
diff --git a/src/datavisualization/engine/shaders/texture_ES2.frag b/src/datavisualization/engine/shaders/texture_ES2.frag
new file mode 100644
index 00000000..58097ba5
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture_ES2.frag
@@ -0,0 +1,37 @@
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = dot(n, l);
+ if (cosTheta < 0.0) cosTheta = 0.0;
+ else if (cosTheta > 1.0) cosTheta = 1.0;
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = dot(E, R);
+ if (cosAlpha < 0.0) cosAlpha = 0.0;
+ else if (cosAlpha > 1.0) cosAlpha = 1.0;
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance;
+ gl_FragColor.a = texture2D(textureSampler, UV).a;
+}
+
diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp
new file mode 100644
index 00000000..2272b731
--- /dev/null
+++ b/src/datavisualization/engine/surface3dcontroller.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "surface3dcontroller_p.h"
+#include "surface3drenderer_p.h"
+#include "camerahelper_p.h"
+#include "q3dabstractaxis_p.h"
+#include "q3dvalueaxis_p.h"
+#include "q3dcategoryaxis.h"
+#include "qsurfacedataproxy_p.h"
+
+#include <QMatrix4x4>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Surface3DController::Surface3DController(QRect rect)
+ : Abstract3DController(rect),
+ m_renderer(0),
+ m_isSmoothSurfaceEnabled(false),
+ m_isSurfaceGridEnabled(true)
+{
+ setActiveDataProxy(0);
+
+ // Setting a null axis creates a new default axis according to orientation and graph type.
+ // Note: These cannot be set in Abstract3DController constructor, as they will call virtual
+ // functions implemented by subclasses.
+ setAxisX(0);
+ setAxisY(0);
+ setAxisZ(0);
+
+ // Set the default from the theme
+ m_userDefinedGradient = theme().m_surfaceGradient;
+}
+
+Surface3DController::~Surface3DController()
+{
+}
+
+void Surface3DController::initializeOpenGL()
+{
+ // Initialization is called multiple times when Qt Quick components are used
+ if (isInitialized())
+ return;
+
+ m_renderer = new Surface3DRenderer(this);
+ setRenderer(m_renderer);
+ synchDataToRenderer();
+ emitNeedRender();
+}
+
+void Surface3DController::synchDataToRenderer()
+{
+ Abstract3DController::synchDataToRenderer();
+
+ if (!isInitialized())
+ return;
+
+ // Notify changes to renderer
+ if (m_changeTracker.gradientColorChanged) {
+ m_renderer->updateSurfaceGradient(m_userDefinedGradient);
+ m_changeTracker.gradientColorChanged = false;
+ }
+
+ if (m_changeTracker.smoothStatusChanged) {
+ m_isSmoothSurfaceEnabled = m_renderer->updateSmoothStatus(m_isSmoothSurfaceEnabled);
+ m_changeTracker.smoothStatusChanged = false;
+ }
+
+ if (m_changeTracker.surfaceGridChanged) {
+ m_renderer->updateSurfaceGridStatus(m_isSurfaceGridEnabled);
+ m_changeTracker.surfaceGridChanged = false;
+ }
+
+ if (m_isDataDirty) {
+ m_renderer->updateDataModel(static_cast<QSurfaceDataProxy *>(m_data));
+ m_isDataDirty = false;
+ }
+}
+
+void Surface3DController::handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust)
+{
+ Q_UNUSED(orientation)
+ Q_UNUSED(autoAdjust)
+
+ adjustValueAxisRange();
+}
+
+void Surface3DController::handleAxisRangeChangedBySender(QObject *sender)
+{
+ scene()->setSlicingActive(false);
+ Abstract3DController::handleAxisRangeChangedBySender(sender);
+}
+
+void Surface3DController::setSmoothSurface(bool enable)
+{
+ m_isSmoothSurfaceEnabled = enable;
+ m_changeTracker.smoothStatusChanged = true;
+ emitNeedRender();
+}
+
+bool Surface3DController::smoothSurface()
+{
+ return m_isSmoothSurfaceEnabled;
+}
+
+void Surface3DController::setSurfaceGrid(bool enable)
+{
+ m_isSurfaceGridEnabled = enable;
+ m_changeTracker.surfaceGridChanged = true;
+ emitNeedRender();
+}
+
+bool Surface3DController::surfaceGrid()
+{
+ return m_isSurfaceGridEnabled;
+}
+
+void Surface3DController::setGradient(const QLinearGradient &gradient)
+{
+ m_userDefinedGradient = gradient;
+ m_userDefinedGradient.setStart(1, 1000);
+ m_userDefinedGradient.setFinalStop(0, 0);
+ m_changeTracker.gradientColorChanged = true;
+ emitNeedRender();
+}
+
+QLinearGradient Surface3DController::gradient() const
+{
+ return m_userDefinedGradient;
+}
+
+void Surface3DController::setGradientColorAt(qreal pos, const QColor &color)
+{
+ m_userDefinedGradient.setColorAt(pos, color);
+ m_changeTracker.gradientColorChanged = true;
+ emitNeedRender();
+}
+
+void Surface3DController::setSelectionMode(QDataVis::SelectionMode mode)
+{
+ if (!(mode == QDataVis::SelectionModeNone || mode == QDataVis::SelectionModeItem
+ || mode == QDataVis::SelectionModeSliceRow
+ || mode == QDataVis::SelectionModeSliceColumn)) {
+ qWarning("Unsupported selection mode.");
+ return;
+ }
+ // Disable zoom if selection mode changes
+ setSlicingActive(false);
+ Abstract3DController::setSelectionMode(mode);
+}
+
+
+void Surface3DController::setActiveDataProxy(QAbstractDataProxy *proxy)
+{
+ // Setting null proxy indicates default proxy
+ if (!proxy) {
+ proxy = new QSurfaceDataProxy;
+ proxy->d_ptr->setDefaultProxy(true);
+ }
+
+ Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeSurface);
+
+ Abstract3DController::setActiveDataProxy(proxy);
+
+ QSurfaceDataProxy *surfaceDataProxy = static_cast<QSurfaceDataProxy *>(m_data);
+
+ QObject::connect(surfaceDataProxy, &QSurfaceDataProxy::arrayReset,
+ this, &Surface3DController::handleArrayReset);
+
+ scene()->setSlicingActive(false);
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Surface3DController::handleArrayReset()
+{
+ scene()->setSlicingActive(false);
+ adjustValueAxisRange();
+ m_isDataDirty = true;
+ emitNeedRender();
+}
+
+void Surface3DController::adjustValueAxisRange()
+{
+ if (m_data) {
+ QVector3D minLimits;
+ QVector3D maxLimits;
+ static_cast<QSurfaceDataProxy *>(m_data)->dptr()->limitValues(minLimits, maxLimits);
+ Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisX);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (minLimits.x() != maxLimits.x())
+ valueAxis->dptr()->setRange(minLimits.x(), maxLimits.x());
+ else
+ valueAxis->dptr()->setRange(minLimits.x() - 1.0f, minLimits.x() + 1.0f); // Default to some valid range
+ }
+
+ valueAxis = static_cast<Q3DValueAxis *>(m_axisY);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (minLimits.y() != maxLimits.y())
+ valueAxis->dptr()->setRange(minLimits.y(), maxLimits.y());
+ else
+ valueAxis->dptr()->setRange(minLimits.y() - 1.0f, minLimits.y() + 1.0f); // Default to some valid range
+ }
+
+ valueAxis = static_cast<Q3DValueAxis *>(m_axisZ);
+ if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (minLimits.z() != maxLimits.z())
+ valueAxis->dptr()->setRange(minLimits.z(), maxLimits.z());
+ else
+ valueAxis->dptr()->setRange(minLimits.z() - 1.0f, minLimits.z() + 1.0f); // Default to some valid range
+ }
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/surface3dcontroller_p.h b/src/datavisualization/engine/surface3dcontroller_p.h
new file mode 100644
index 00000000..0efece97
--- /dev/null
+++ b/src/datavisualization/engine/surface3dcontroller_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SURFACE3DCONTROLLER_P_H
+#define SURFACE3DCONTROLLER_P_H
+
+#include "abstract3dcontroller_p.h"
+#include "datavisualizationglobal_p.h"
+
+#include <QLinearGradient>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Surface3DRenderer;
+
+struct Surface3DChangeBitField {
+ bool gradientColorChanged : 1;
+ bool smoothStatusChanged : 1;
+ bool surfaceGridChanged : 1;
+
+ Surface3DChangeBitField() :
+ gradientColorChanged(true),
+ smoothStatusChanged(true),
+ surfaceGridChanged(true)
+ {
+ }
+};
+
+class QT_DATAVISUALIZATION_EXPORT Surface3DController : public Abstract3DController
+{
+ Q_OBJECT
+
+private:
+ Surface3DChangeBitField m_changeTracker;
+
+ // Rendering
+ Surface3DRenderer *m_renderer;
+ bool m_isSmoothSurfaceEnabled;
+ bool m_isSurfaceGridEnabled;
+ QLinearGradient m_userDefinedGradient;
+
+public:
+ explicit Surface3DController(QRect rect);
+ ~Surface3DController();
+
+ void initializeOpenGL();
+ virtual void synchDataToRenderer();
+
+ void setSmoothSurface(bool enable);
+ bool smoothSurface();
+
+ void setSurfaceGrid(bool enable);
+ bool surfaceGrid();
+
+ void setGradient(const QLinearGradient &gradient);
+ QLinearGradient gradient() const;
+
+ void setGradientColorAt(qreal pos, const QColor &color);
+
+ void setSelectionMode(QDataVis::SelectionMode mode);
+
+ virtual void setActiveDataProxy(QAbstractDataProxy *proxy);
+
+ virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust);
+ virtual void handleAxisRangeChangedBySender(QObject *sender);
+
+public slots:
+ void handleArrayReset();
+
+signals:
+ void smoothStatusChanged(bool enable);
+ void surfaceGridChanged(bool enable);
+ void segmentCountChanged(GLint segmentCount, GLfloat step, GLfloat minimum);
+
+private:
+ void adjustValueAxisRange();
+
+ Q_DISABLE_COPY(Surface3DController)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // SURFACE3DCONTROLLER_P_H
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
new file mode 100644
index 00000000..a1dfc7e8
--- /dev/null
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -0,0 +1,2185 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "surface3dcontroller_p.h"
+#include "surface3drenderer_p.h"
+#include "q3dcamera.h"
+#include "q3dcamera_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "surfaceobject_p.h"
+#include "texturehelper_p.h"
+#include "selectionpointer_p.h"
+#include "theme_p.h"
+#include "utils_p.h"
+#include "drawer_p.h"
+#include "q3dlight.h"
+
+#include <QMatrix4x4>
+#include <QMouseEvent>
+#include <qmath.h>
+
+#include <QLinearGradient>
+#include <QPainter>
+
+#include <QDebug>
+
+static const int ID_TO_RGBA_MASK = 0xff;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+//#define SHOW_DEPTH_TEXTURE_SCENE
+
+// TODO Uniform scaling is broken on surface
+//#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values
+
+const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd.
+const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background)
+const GLfloat labelMargin = 0.05f;
+const GLfloat backgroundBottom = 1.0f;
+const GLfloat gridLineWidth = 0.005f;
+const GLfloat sliceZScale = 0.1f;
+const GLfloat surfaceGridYOffsetValue = 0.001f;
+const GLfloat sliceUnits = 2.5f;
+const int subViewDivider = 5;
+// The second offset to opposite direction is double because same matrix is translated twice
+const GLfloat surfaceGridYOffset[2] = {-surfaceGridYOffsetValue, 2.0f * surfaceGridYOffsetValue};
+
+Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
+ : Abstract3DRenderer(controller),
+ m_controller(controller),
+ m_labelStyle(QDataVis::LabelStyleFromTheme),
+ m_font(QFont(QStringLiteral("Arial"))),
+ m_isGridEnabled(true),
+ m_shader(0),
+ m_depthShader(0),
+ m_backgroundShader(0),
+ m_surfaceShader(0),
+ m_surfaceGridShader(0),
+ m_selectionShader(0),
+ m_labelShader(0),
+ m_heightNormalizer(0.0f),
+ m_scaleFactor(0.0f),
+ m_scaleX(0.0f),
+ m_scaleZ(0.0f),
+ m_scaleXWithBackground(0.0f),
+ m_scaleZWithBackground(0.0f),
+ m_surfaceScaleX(0.0f),
+ m_surfaceScaleZ(0.0f),
+ m_surfaceOffsetX(0.0f),
+ m_surfaceOffsetZ(0.0f),
+ m_minVisibleColumnValue(0.0f),
+ m_maxVisibleColumnValue(0.0f),
+ m_minVisibleRowValue(0.0f),
+ m_maxVisibleRowValue(0.0f),
+ m_visibleColumnRange(0.0f),
+ m_visibleRowRange(0.0f),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_surfaceObj(0),
+ m_sliceSurfaceObj(0),
+ m_depthTexture(0),
+ m_depthFrameBuffer(0),
+ m_selectionFrameBuffer(0),
+ m_selectionDepthBuffer(0),
+ m_gradientTexture(0),
+ m_selectionTexture(0),
+ m_selectionResultTexture(0),
+ m_shadowQualityToShader(33.3f),
+ m_flatSupported(true),
+ m_selectionPointer(0),
+ m_selectionActive(false),
+ m_xFlipped(false),
+ m_zFlipped(false),
+ m_yFlipped(false),
+ m_sampleSpace(QRect(0, 0, 0, 0)),
+ m_shadowQualityMultiplier(3),
+ m_cachedSelectionId(0),
+ m_selectionModeChanged(false),
+ m_hasHeightAdjustmentChanged(true)
+{
+#if !defined(QT_OPENGL_ES_2)
+ // Check if flat feature is supported
+ ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
+ QStringLiteral(":/shaders/fragmentSurfaceFlat"));
+ if (!tester.testCompile()) {
+ m_flatSupported = false;
+ m_controller->setSmoothSurface(true);
+ }
+#endif
+
+ m_cachedSmoothSurface = m_controller->smoothSurface();
+ updateSurfaceGridStatus(m_controller->surfaceGrid());
+
+ // Shadows are disabled for Q3DSurface in Tech Preview
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+
+ initializeOpenGLFunctions();
+ initializeOpenGL();
+}
+
+Surface3DRenderer::~Surface3DRenderer()
+{
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_textureHelper->deleteTexture(&m_gradientTexture);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ m_textureHelper->deleteTexture(&m_selectionResultTexture);
+
+ delete m_shader;
+ delete m_depthShader;
+ delete m_backgroundShader;
+ delete m_selectionShader;
+ delete m_surfaceShader;
+ delete m_surfaceGridShader;
+ delete m_labelShader;
+
+ delete m_backgroundObj;
+ delete m_surfaceObj;
+ delete m_sliceSurfaceObj;
+ delete m_gridLineObj;
+ delete m_labelObj;
+
+ delete m_selectionPointer;
+
+ for (int i = 0; i < m_dataArray.size(); i++)
+ delete m_dataArray.at(i);
+ m_dataArray.clear();
+
+ for (int i = 0; i < m_sliceDataArray.size(); i++)
+ delete m_sliceDataArray.at(i);
+ m_sliceDataArray.clear();
+}
+
+void Surface3DRenderer::initializeOpenGL()
+{
+ Abstract3DRenderer::initializeOpenGL();
+
+ // Initialize shaders
+ handleShadowQualityChange();
+
+ initSurfaceShaders();
+
+ initLabelShaders(QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+
+#if !defined(QT_OPENGL_ES_2)
+ // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api.
+ initDepthShader();
+#endif
+
+ // Init selection shader
+ initSelectionShaders();
+
+ // Load grid line mesh
+ loadGridLineMesh();
+
+ // Load label mesh
+ loadLabelMesh();
+
+ // Resize in case we've missed resize events
+ // Resize calls initSelectionBuffer and initDepthBuffer, so they don't need to be called here
+ handleResize();
+
+ // Load background mesh (we need to be initialized first)
+ loadBackgroundMesh();
+}
+
+void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy)
+{
+ calculateSceneScalingFactors();
+
+ const QSurfaceDataArray &array = *dataProxy->array();
+
+ // Need minimum of 2x2 array to draw a surface
+ if (array.size() >= 2 && array.at(0)->size() >= 2) {
+ QRect sampleSpace = calculateSampleRect(array);
+
+ bool dimensionChanged = false;
+ if (m_sampleSpace != sampleSpace) {
+ dimensionChanged = true;
+ m_sampleSpace = sampleSpace;
+
+ for (int i = 0; i < m_dataArray.size(); i++)
+ delete m_dataArray.at(i);
+ m_dataArray.clear();
+ }
+
+ // TODO: Handle partial surface grids on the graph edges
+ if (sampleSpace.width() >= 2 && sampleSpace.height() >= 2) {
+ if (dimensionChanged) {
+ m_dataArray.reserve(sampleSpace.height());
+ for (int i = 0; i < sampleSpace.height(); i++)
+ m_dataArray << new QSurfaceDataRow(sampleSpace.width());
+ }
+ for (int i = 0; i < sampleSpace.height(); i++) {
+ for (int j = 0; j < sampleSpace.width(); j++)
+ (*(m_dataArray.at(i)))[j] = array.at(i + sampleSpace.y())->at(j + sampleSpace.x());
+ }
+
+ if (m_dataArray.size() > 0) {
+ if (!m_surfaceObj)
+ loadSurfaceObj();
+
+ // Note: Data setup can change samplespace (as min width/height is 1)
+ if (m_cachedSmoothSurface) {
+ m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer,
+ m_axisCacheY.min(), dimensionChanged);
+ } else {
+ m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer,
+ m_axisCacheY.min(), dimensionChanged);
+ }
+
+ if (dimensionChanged)
+ updateSelectionTexture();
+ }
+ }
+ }
+
+ m_selectionActive = false;
+ m_cachedSelectionId = 0;
+ for (int i = 0; i < m_sliceDataArray.size(); i++)
+ delete m_sliceDataArray.at(i);
+ m_sliceDataArray.clear();
+
+ Abstract3DRenderer::updateDataModel(dataProxy);
+}
+
+void Surface3DRenderer::updateSliceDataModel(int selectionId)
+{
+ int column = (selectionId - 1) % m_sampleSpace.width();
+ int row = (selectionId - 1) / m_sampleSpace.width();
+
+ for (int i = 0; i < m_sliceDataArray.size(); i++)
+ delete m_sliceDataArray.at(i);
+ m_sliceDataArray.clear();
+
+ m_sliceDataArray.reserve(2);
+ QSurfaceDataRow *sliceRow;
+
+ qreal adjust = (0.025 * m_heightNormalizer) / 2.0;
+ qreal stepDown = 2.0 * adjust;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ QSurfaceDataRow *src = m_dataArray.at(row);
+ sliceRow = new QSurfaceDataRow(src->size());
+ for (int i = 0; i < sliceRow->size(); i++)
+ (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, -1.0));
+ } else {
+ sliceRow = new QSurfaceDataRow(m_sampleSpace.height());
+ for (int i = 0; i < m_sampleSpace.height(); i++) {
+ (*sliceRow)[i].setPosition(QVector3D(m_dataArray.at(i)->at(column).z(),
+ m_dataArray.at(i)->at(column).y() + adjust,
+ -1.0));
+ }
+ }
+
+ m_sliceDataArray << sliceRow;
+
+ // Make a duplicate, so that we get a little bit depth
+ QSurfaceDataRow *duplicateRow = new QSurfaceDataRow(*sliceRow);
+ for (int i = 0; i < sliceRow->size(); i++)
+ (*sliceRow)[i].setPosition(QVector3D(sliceRow->at(i).x(), sliceRow->at(i).y() - stepDown, 1.0));
+
+ m_sliceDataArray << duplicateRow;
+
+ QRect sliceRect(0, 0, sliceRow->size(), 2);
+
+ if (sliceRow->size() > 0) {
+ if (!m_sliceSurfaceObj)
+ loadSliceSurfaceObj();
+
+ if (m_cachedSmoothSurface) {
+ m_sliceSurfaceObj->setUpSmoothData(m_sliceDataArray, sliceRect, m_heightNormalizer,
+ m_axisCacheY.min(), true);
+ } else {
+ m_sliceSurfaceObj->setUpData(m_sliceDataArray, sliceRect, m_heightNormalizer,
+ m_axisCacheY.min(), true);
+ }
+ }
+}
+
+QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array)
+{
+ QRect sampleSpace;
+
+ int rowCount = array.size();
+ int columnCount = array.at(0)->size();
+
+ int i;
+ bool found;
+ float axisMinX = float(m_axisCacheX.min());
+ float axisMaxX = float(m_axisCacheX.max());
+ float axisMinZ = float(m_axisCacheZ.min());
+ float axisMaxZ = float(m_axisCacheZ.max());
+
+ // Comparisons between float and double are not accurate, so fudge our comparison values
+ //a little to get all rows and columns into view that need to be visible.
+ const float fudgeFactor = 0.00001f;
+ float fudgedAxisXRange = (axisMaxX - axisMinX) * fudgeFactor;
+ float fudgedAxisZRange = (axisMaxZ - axisMinZ) * fudgeFactor;
+ axisMinX -= fudgedAxisXRange;
+ axisMinZ -= fudgedAxisZRange;
+ axisMaxX += fudgedAxisXRange;
+ axisMaxZ += fudgedAxisZRange;
+
+ // m_minVisibleColumnValue
+ for (i = 0, found = false; i < columnCount; i++) {
+ if (array.at(0)->at(i).x() >= axisMinX) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ m_minVisibleColumnValue = array.at(0)->at(i).x();
+ sampleSpace.setLeft(i);
+ } else {
+ sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
+ return sampleSpace;
+ }
+
+ // m_maxVisibleColumnValue
+ for (i = columnCount - 1, found = false; i >= 0; i--) {
+ if (array.at(0)->at(i).x() <= axisMaxX) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ m_maxVisibleColumnValue = array.at(0)->at(i).x();
+ sampleSpace.setRight(i);
+ } else {
+ sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
+ return sampleSpace;
+ }
+
+ // m_minVisibleRowValue
+ for (i = 0, found = false; i < rowCount; i++) {
+ if (array.at(i)->at(0).z() >= axisMinZ) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ m_minVisibleRowValue = array.at(i)->at(0).z();
+ sampleSpace.setTop(i);
+ } else {
+ sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
+ return sampleSpace;
+ }
+
+ // m_maxVisibleRowValue
+ for (i = rowCount - 1, found = false; i >= 0; i--) {
+ if (array.at(i)->at(0).z() <= axisMaxZ) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ m_maxVisibleRowValue = array.at(i)->at(0).z();
+ sampleSpace.setBottom(i);
+ } else {
+ sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
+ return sampleSpace;
+ }
+
+ m_visibleColumnRange = m_maxVisibleColumnValue - m_minVisibleColumnValue;
+ m_visibleRowRange = m_maxVisibleRowValue - m_minVisibleRowValue;
+ m_surfaceScaleX = m_scaleX * m_visibleColumnRange / m_areaSize.width();
+ m_surfaceScaleZ = m_scaleZ * m_visibleRowRange / m_areaSize.height();
+ GLfloat axis2XCenterX = axisMinX + axisMaxX;
+ GLfloat axis2XCenterZ = axisMinZ + axisMaxZ;
+ GLfloat data2XCenterX = GLfloat(m_minVisibleColumnValue + m_maxVisibleColumnValue);
+ GLfloat data2XCenterZ = GLfloat(m_minVisibleRowValue + m_maxVisibleRowValue);
+ m_surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width();
+ m_surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height();
+
+ return sampleSpace;
+}
+
+void Surface3DRenderer::updateScene(Q3DScene *scene)
+{
+ // TODO: Move these to more suitable place e.g. controller should be controlling the viewports.
+ scene->setSecondarySubViewport(m_sliceViewPort);
+ scene->setPrimarySubViewport(m_mainViewPort);
+
+ // Set initial camera position
+ // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later
+ if (m_hasHeightAdjustmentChanged) {
+ scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ // For now this is used just to make things once. Proper use will come
+ m_hasHeightAdjustmentChanged = false;
+ }
+
+ scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment);
+ scene->setLightPositionRelativeToCamera(defaultLightPos);
+
+ if (m_selectionPointer)
+ m_selectionPointer->updateScene(scene);
+
+ Abstract3DRenderer::updateScene(scene);
+}
+
+void Surface3DRenderer::render(GLuint defaultFboHandle)
+{
+ bool slicingActivated = m_cachedScene->isSlicingActive();
+ bool slicingChanged = m_cachedIsSlicingActivated != slicingActivated;
+
+ updateSlicingActive(slicingActivated);
+
+ // Handle GL state setup for FBO buffers and clearing of the render surface
+ Abstract3DRenderer::render(defaultFboHandle);
+
+ // In slice mode; draw slice and render selection ball
+ if (m_cachedIsSlicingActivated && m_selectionPointer && m_selectionActive) {
+ drawSlicedScene();
+ m_selectionPointer->render(defaultFboHandle);
+ }
+
+ // Draw the surface scene
+ drawScene(defaultFboHandle);
+
+ // Render selection ball if not in slice mode
+ if (!m_cachedIsSlicingActivated && m_selectionPointer && m_selectionActive)
+ m_selectionPointer->render(defaultFboHandle);
+
+ // If slicing has been activated by this render pass, we need another render
+ // Also trigger another render always when slicing changes in general to ensure
+ // final draw is correct.
+ if (slicingActivated != m_cachedScene->isSlicingActive() || slicingChanged)
+ emit needRender();
+}
+
+void Surface3DRenderer::drawSlicedScene()
+{
+ QVector3D lightPos;
+
+ // Specify viewport
+ glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(),
+ m_sliceViewPort.width(), m_sliceViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+
+ GLfloat aspect = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
+ projectionMatrix.ortho(-sliceUnits * aspect, sliceUnits * aspect,
+ -sliceUnits, sliceUnits, -1.0f, 14.0f); // 14.0 because of zComp
+
+ // Set view matrix
+ QMatrix4x4 viewMatrix;
+ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, zComp + 1.0f),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // Set light position
+ lightPos = m_cachedScene->activeLight()->position();
+
+ QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix;
+
+ GLfloat scaleX = 0.0f;
+ GLfloat scaleXBackground = 0.0f;
+ GLfloat offset = 0.0f;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ scaleX = m_surfaceScaleX;
+ scaleXBackground = m_scaleXWithBackground;
+ offset = m_surfaceOffsetX;
+ } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) {
+ scaleX = m_surfaceScaleZ;
+ scaleXBackground = m_scaleZWithBackground;
+ offset = -m_surfaceOffsetZ;
+ }
+
+ if (m_surfaceObj) {
+ ShaderHelper *surfaceShader = m_shader;
+ surfaceShader->bind();
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(offset, 0.0f, zComp);
+ QVector3D scaling(scaleX, 1.0f, sliceZScale);
+ modelMatrix.scale(scaling);
+ itModelMatrix.scale(scaling);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ QVector3D color;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)
+ color = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor);
+ else
+ color = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor);
+
+ // Set shader bindings
+ surfaceShader->setUniformValue(surfaceShader->lightP(), lightPos);
+ surfaceShader->setUniformValue(surfaceShader->view(), viewMatrix);
+ surfaceShader->setUniformValue(surfaceShader->model(), modelMatrix);
+ surfaceShader->setUniformValue(surfaceShader->nModel(), itModelMatrix.inverted().transposed());
+ surfaceShader->setUniformValue(surfaceShader->MVP(), MVPMatrix);
+ surfaceShader->setUniformValue(surfaceShader->color(), color);
+ surfaceShader->setUniformValue(surfaceShader->lightS(), 0.25f);
+ surfaceShader->setUniformValue(surfaceShader->ambientS(),
+ m_cachedTheme.m_ambientStrength * 2.0f);
+
+ m_drawer->drawObject(surfaceShader, m_sliceSurfaceObj);
+
+ surfaceShader->release();
+
+ // Draw surface grid
+ if (m_cachedSurfaceGridOn) {
+ m_surfaceGridShader->bind();
+
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(),
+ Utils::vectorFromColor(m_cachedTheme.m_gridLine));
+ // Draw the grid twice, with slight offset on Y axis to each direction
+ for (int i = 0; i < 2; i++) {
+ MVPMatrix.translate(0.0f, surfaceGridYOffset[i], 0.0f);
+
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), MVPMatrix);
+ m_drawer->drawSurfaceGrid(m_surfaceGridShader, m_sliceSurfaceObj);
+ }
+ m_surfaceGridShader->release();
+ }
+ }
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // lines to the back
+ if (m_cachedIsGridEnabled && m_heightNormalizer) {
+ ShaderHelper *lineShader = m_backgroundShader;
+ // Bind line shader
+ lineShader->bind();
+
+ if (m_axisCacheY.segmentCount() > 0) {
+ QVector3D gridLineScaleX(scaleXBackground, gridLineWidth, gridLineWidth);
+
+ // Set unchanging shader bindings
+ QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine);
+ lineShader->setUniformValue(lineShader->lightP(), lightPos);
+ lineShader->setUniformValue(lineShader->view(), viewMatrix);
+ lineShader->setUniformValue(lineShader->color(), lineColor);
+ lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength * 2.0f);
+ lineShader->setUniformValue(lineShader->lightS(), 0.25f);
+
+ // Back wall
+ GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer;
+ GLfloat linePos = -1.0f;
+ int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, linePos, zComp - sliceZScale);
+
+ modelMatrix.scale(gridLineScaleX);
+ itModelMatrix.scale(gridLineScaleX);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+
+ linePos += lineStep;
+ }
+ }
+
+ // Floor lines
+ QVector3D gridLineScaleZ(gridLineWidth, gridLineWidth, sliceZScale);
+ QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth);
+
+ int lastSegment;
+ GLfloat lineStep;
+ GLfloat linePos;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor;
+ lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
+ linePos = m_scaleX;
+ } else {
+ lineStep = -2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor;
+ lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
+ linePos = m_scaleZ;
+ }
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(linePos, -backgroundMargin, zComp);
+
+ modelMatrix.scale(gridLineScaleZ);
+ itModelMatrix.scale(gridLineScaleZ);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+
+ linePos += lineStep;
+ }
+
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)
+ linePos = m_scaleX;
+ else
+ linePos = m_scaleZ;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(linePos, 0.0f, zComp - sliceZScale);
+ modelMatrix.scale(gridLineScaleY);
+ itModelMatrix.scale(gridLineScaleY);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+
+ linePos += lineStep;
+ }
+
+ // Release line shader
+ lineShader->release();
+ }
+
+ // Draw axis labels
+ m_labelShader->bind();
+ glEnable(GL_TEXTURE_2D);
+ glDisable(GL_DEPTH_TEST);
+ glCullFace(GL_BACK);
+ if (m_cachedLabelStyle > QDataVis::LabelStyleOpaque) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ // Y Labels to back wall
+ GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer;
+ GLfloat labelPos = -1.0f;
+ int labelNbr = 0;
+
+ QVector3D positionComp(0.0f, 0.0f, zComp);
+ QVector3D rotation(0.0f, 0.0f, 0.0f);
+ QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, labelPos, zComp);
+ for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
+ if (m_axisCacheY.labelItems().size() > labelNbr) {
+ labelTrans.setY(labelPos);
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionComp, rotation, 0, m_cachedSelectionMode, m_labelShader,
+ m_labelObj, m_cachedScene->activeCamera(),
+ true, true, Drawer::LabelMid, Qt::AlignRight);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+
+ // X Labels to ground
+ int countLabelItems;
+ int lastSegment;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor;
+ labelPos = -m_scaleX;
+ lastSegment = m_axisCacheX.segmentCount();
+ countLabelItems = m_axisCacheX.labelItems().size();
+ } else {
+ posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor;
+ labelPos = -m_scaleZ;
+ lastSegment = m_axisCacheZ.segmentCount();
+ countLabelItems = m_axisCacheZ.labelItems().size();
+ }
+
+ labelNbr = 0;
+ positionComp.setY(backgroundMargin);
+ rotation.setZ(-45.0f);
+ labelTrans.setY(-backgroundMargin);
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ if (countLabelItems > labelNbr) {
+ // Draw the label here
+ labelTrans.setX(labelPos);
+
+ m_dummyRenderItem.setTranslation(labelTrans);
+
+ LabelItem *axisLabelItem;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)
+ axisLabelItem = m_axisCacheX.labelItems().at(labelNbr);
+ else
+ axisLabelItem = m_axisCacheZ.labelItems().at(labelNbr);
+
+ m_drawer->drawLabel(m_dummyRenderItem, *axisLabelItem, viewMatrix, projectionMatrix,
+ positionComp, rotation, 0, QDataVis::SelectionModeSliceRow,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(),
+ false, false, Drawer::LabelBelow, Qt::AlignTop);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_DEPTH_TEST);
+ if (m_cachedLabelStyle > QDataVis::LabelStyleOpaque)
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ m_labelShader->release();
+}
+
+void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
+{
+ GLfloat backgroundRotation = 0;
+ uint selectionId = 0;
+
+ // Specify viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f);
+
+ // Calculate view matrix
+ QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix();
+
+ QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix;
+
+ // Calculate flipping indicators
+ if (viewMatrix.row(0).x() > 0)
+ m_zFlipped = false;
+ else
+ m_zFlipped = true;
+ if (viewMatrix.row(0).z() <= 0)
+ m_xFlipped = false;
+ else
+ m_xFlipped = true;
+
+ // calculate background rotation based on view matrix rotation
+ if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() <= 0)
+ backgroundRotation = 270.0f;
+ else if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() > 0)
+ backgroundRotation = 180.0f;
+ else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() > 0)
+ backgroundRotation = 90.0f;
+ else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() <= 0)
+ backgroundRotation = 0.0f;
+
+ QVector3D lightPos = m_cachedScene->activeLight()->position();
+
+ QMatrix4x4 depthViewMatrix;
+ QMatrix4x4 depthProjectionMatrix;
+ QMatrix4x4 depthProjectionViewMatrix;
+
+ GLfloat adjustedLightStrength = m_cachedTheme.m_lightStrength / 10.0f;
+
+ QVector3D surfaceScaler(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);
+ QVector3D surfaceOffset(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ + zComp);
+
+ // Draw depth buffer
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone && m_surfaceObj) {
+ // Render scene into a depth texture for using with shadow mapping
+ // Enable drawing to depth framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Bind depth shader
+ m_depthShader->bind();
+
+ // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows.
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width() * m_shadowQualityMultiplier,
+ m_mainViewPort.height() * m_shadowQualityMultiplier);
+
+ // Get the depth view matrix
+ // It may be possible to hack lightPos here if we want to make some tweaks to shadow
+ QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera(
+ QVector3D(0.0f, 0.0f, zComp), 0.0f, 1.5f / m_autoScaleAdjustment);
+ depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above?
+ // That causes the scene to be not drawn from above -> must be fixed
+ // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3);
+ // Set the depth projection matrix
+#ifndef USE_WIDER_SHADOWS
+ // Use this for perspective shadows
+ depthProjectionMatrix.perspective(10.0f, (GLfloat)m_mainViewPort.width()
+ / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f);
+#else
+ // Use these for orthographic shadows
+ depthProjectionMatrix.ortho(-2.0f * 2.0f, 2.0f * 2.0f,
+ -2.0f, 2.0f,
+ 0.0f, 100.0f);
+#endif
+ depthProjectionViewMatrix = depthProjectionMatrix * depthViewMatrix;
+
+ glCullFace(GL_FRONT);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
+
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_surfaceObj->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_surfaceObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, m_surfaceObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+
+ // Disable drawing to depth framebuffer (= enable drawing to screen)
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Release depth shader
+ m_depthShader->release();
+
+ // Revert to original viewport
+ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
+ m_mainViewPort.width(), m_mainViewPort.height());
+
+ // Reset culling to normal
+ glCullFace(GL_BACK);
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it)
+ {
+ m_labelShader->bind();
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
+ m_drawer->drawObject(m_labelShader, m_labelObj, m_depthTexture);
+ glDisable(GL_TEXTURE_2D);
+ m_labelShader->release();
+ }
+#endif
+ }
+#endif
+
+ bool selectionDirty = false;
+
+ // Enable texturing
+ glEnable(GL_TEXTURE_2D);
+
+ // Draw selection buffer
+ if (!m_cachedIsSlicingActivated && m_controller->inputState() == QDataVis::InputStateOnScene
+ && m_surfaceObj && m_cachedSelectionMode > QDataVis::SelectionModeNone) {
+ m_selectionShader->bind();
+ glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
+ glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
+ glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
+
+ glDisable(GL_CULL_FACE);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
+
+ m_drawer->drawObject(m_selectionShader, m_surfaceObj, m_selectionTexture);
+
+ glEnable(GL_DITHER);
+
+ QPoint point = m_controller->inputPosition();
+ GLubyte pixel[4] = {0};
+ glReadPixels(point.x(), m_cachedBoundingRect.height() - point.y(), 1, 1,
+ GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixel);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
+
+ // Release selection shader
+ m_selectionShader->release();
+
+ // Put the RGBA value back to uint
+#if defined (Q_OS_ANDROID)
+ selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536;
+#else
+ selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536 + pixel[3] * 16777216;
+#endif
+
+ selectionDirty = true;
+ }
+
+ // Draw the surface
+ if (m_surfaceObj && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) {
+ m_surfaceShader->bind();
+
+ // For surface we can see climpses from underneath
+ glDisable(GL_CULL_FACE);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
+ itModelMatrix.scale(surfaceScaler);
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set shader bindings
+ m_surfaceShader->setUniformValue(m_surfaceShader->lightP(), lightPos);
+ m_surfaceShader->setUniformValue(m_surfaceShader->view(), viewMatrix);
+ m_surfaceShader->setUniformValue(m_surfaceShader->model(), modelMatrix);
+ m_surfaceShader->setUniformValue(m_surfaceShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_surfaceShader->setUniformValue(m_surfaceShader->MVP(), MVPMatrix);
+ m_surfaceShader->setUniformValue(m_surfaceShader->ambientS(),
+ m_cachedTheme.m_ambientStrength);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ m_surfaceShader->setUniformValue(m_surfaceShader->shadowQ(), m_shadowQualityToShader);
+ m_surfaceShader->setUniformValue(m_surfaceShader->depth(), depthMVPMatrix);
+ m_surfaceShader->setUniformValue(m_surfaceShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_surfaceShader, m_surfaceObj, m_gradientTexture, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_surfaceShader->setUniformValue(m_surfaceShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_surfaceShader, m_surfaceObj, m_gradientTexture);
+ }
+
+ m_surfaceShader->release();
+
+ glEnable(GL_CULL_FACE);
+
+ // Draw surface grid
+ if (m_cachedSurfaceGridOn) {
+ m_surfaceGridShader->bind();
+
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(),
+ Utils::vectorFromColor(m_cachedTheme.m_gridLine));
+ // Draw the grid twice, with slight offset on Y axis to each direction
+ for (int i = 0; i < 2; i++) {
+ MVPMatrix.translate(0.0f, surfaceGridYOffset[i], 0.0f);
+
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), MVPMatrix);
+ m_drawer->drawSurfaceGrid(m_surfaceGridShader, m_surfaceObj);
+ }
+ m_surfaceGridShader->release();
+ }
+ }
+
+ // Bind background shader
+ m_backgroundShader->bind();
+ glCullFace(GL_BACK);
+
+ // Draw background
+ if (m_cachedIsBackgroundEnabled && m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, 0.0f, zComp);
+ QVector3D bgScale(m_scaleXWithBackground, backgroundMargin, m_scaleZWithBackground);
+ modelMatrix.scale(bgScale);
+ itModelMatrix.scale(bgScale);
+
+ // If we're viewing from below, background object must be flipped
+ if (m_yFlipped) {
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+ modelMatrix.rotate(270.0f - backgroundRotation, 0.0f, 1.0f, 0.0f);
+ } else {
+ modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f);
+ }
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor);
+
+ // Set shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
+ m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor);
+ m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(),
+ m_cachedTheme.m_ambientStrength * 2.0f);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(),
+ m_shadowQualityToShader);
+ m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_backgroundObj);
+ }
+ }
+
+ // Release background shader
+ m_backgroundShader->release();
+
+ // Draw grid lines
+ QVector3D gridLineScaleX(m_scaleXWithBackground, gridLineWidth, gridLineWidth);
+ QVector3D gridLineScaleZ(gridLineWidth, gridLineWidth, m_scaleZWithBackground);
+ QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth);
+
+ if (m_cachedIsGridEnabled && m_heightNormalizer) {
+ ShaderHelper *lineShader = m_backgroundShader;
+ // Bind line shader
+ lineShader->bind();
+
+ // Set unchanging shader bindings
+ QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine);
+ lineShader->setUniformValue(lineShader->lightP(), lightPos);
+ lineShader->setUniformValue(lineShader->view(), viewMatrix);
+ lineShader->setUniformValue(lineShader->color(), lineColor);
+ lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength);
+
+ // Rows (= Z)
+ if (m_axisCacheZ.segmentCount() > 0) {
+ // Floor lines
+ GLfloat lineStep = 2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor;
+ GLfloat linePos = m_scaleZ + zComp; // Start line
+ int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_yFlipped)
+ modelMatrix.translate(0.0f, backgroundMargin, linePos);
+ else
+ modelMatrix.translate(0.0f, -backgroundMargin, linePos);
+
+ modelMatrix.scale(gridLineScaleX);
+ itModelMatrix.scale(gridLineScaleX);
+
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos -= lineStep;
+ }
+
+ // Side wall lines
+ GLfloat lineXTrans = m_scaleXWithBackground;
+ linePos = m_scaleZ + zComp; // Start line
+
+ if (!m_xFlipped)
+ lineXTrans = -lineXTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(lineXTrans, 0.0f, linePos);
+ modelMatrix.scale(gridLineScaleY);
+ itModelMatrix.scale(gridLineScaleY);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(),
+ adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos -= lineStep;
+ }
+ }
+
+ // Columns (= X)
+ if (m_axisCacheX.segmentCount() > 0) {
+ // Floor lines
+ GLfloat lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor;
+ GLfloat linePos = m_scaleX;
+ int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (m_yFlipped)
+ modelMatrix.translate(linePos, backgroundMargin, zComp);
+ else
+ modelMatrix.translate(linePos, -backgroundMargin, zComp);
+
+ modelMatrix.scale(gridLineScaleZ);
+ itModelMatrix.scale(gridLineScaleZ);
+
+ // If we're viewing from below, grid line object must be flipped
+ if (m_yFlipped)
+ modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+
+ // Back wall lines
+ GLfloat lineZTrans = m_scaleZWithBackground + zComp;
+ linePos = m_scaleX;
+
+ if (!m_zFlipped)
+ lineZTrans = -lineZTrans + zComp + zComp;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(linePos, 0.0f, lineZTrans);
+ modelMatrix.scale(gridLineScaleY);
+ itModelMatrix.scale(gridLineScaleY);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+ }
+
+ // Horizontal wall lines
+ if (m_axisCacheY.segmentCount() > 0) {
+ // Back wall
+ GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer;
+ GLfloat linePos = -1.0f;
+ int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+
+ GLfloat lineZTrans = m_scaleZWithBackground + zComp;
+
+ if (!m_zFlipped)
+ lineZTrans = -lineZTrans + zComp + zComp;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, linePos, lineZTrans);
+
+ modelMatrix.scale(gridLineScaleX);
+ itModelMatrix.scale(gridLineScaleX);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+
+ // Side wall
+ linePos = -1.0f;
+ lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+ GLfloat lineXTrans = m_scaleXWithBackground;
+
+ if (!m_xFlipped)
+ lineXTrans = -lineXTrans;
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(lineXTrans, linePos, zComp);
+
+ modelMatrix.scale(gridLineScaleZ);
+ itModelMatrix.scale(gridLineScaleZ);
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ lineShader->setUniformValue(lineShader->model(), modelMatrix);
+ lineShader->setUniformValue(lineShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ // Set shadow shader bindings
+ lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader);
+ lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
+ lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
+ } else
+#endif
+ {
+ // Set shadowless shader bindings
+ lineShader->setUniformValue(lineShader->lightS(),
+ m_cachedTheme.m_lightStrength);
+
+ // Draw the object
+ m_drawer->drawObject(lineShader, m_gridLineObj);
+ }
+ linePos += lineStep;
+ }
+ }
+
+ // Release line shader
+ lineShader->release();
+ }
+
+ // Draw axis labels
+ m_labelShader->bind();
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // Z Labels
+ QVector3D positionZComp(0.0f, 0.0f, zComp);
+ if (m_axisCacheZ.segmentCount() > 0) {
+ GLfloat posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor;
+ GLfloat labelPos = m_scaleZ + zComp;
+ int lastSegment = m_axisCacheZ.segmentCount();
+ int labelNbr = 0;
+ GLfloat labelXTrans = m_scaleXWithBackground + labelMargin;
+ GLfloat labelYTrans = -backgroundMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 0.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ if (m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ alignment = Qt::AlignLeft;
+ }
+ if (m_yFlipped) {
+ rotLabelZ += 180.0f;
+ rotLabelY += 180.0f;
+ labelYTrans = -labelYTrans;
+ }
+ QVector3D labelTrans = QVector3D(labelXTrans,
+ labelYTrans,
+ labelPos);
+ QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ);
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ if (m_axisCacheZ.labelItems().size() > labelNbr) {
+ labelTrans.setZ(labelPos);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr);
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, rotation, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(),
+ true, true, Drawer::LabelMid, alignment);
+ }
+ labelNbr++;
+ labelPos -= posStep;
+ }
+ }
+ // X Labels
+ if (m_axisCacheX.segmentCount() > 0) {
+ GLfloat posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor;
+ GLfloat labelPos = -m_scaleX;
+ int lastSegment = m_axisCacheX.segmentCount();
+
+ int labelNbr = 0;
+ GLfloat labelZTrans = m_scaleZWithBackground + labelMargin;
+ GLfloat labelYTrans = -backgroundMargin;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (m_xFlipped)
+ rotLabelY = -90.0f;
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ alignment = Qt::AlignRight;
+ }
+ if (m_yFlipped) {
+ rotLabelZ += 180.0f;
+ rotLabelY += 180.0f;
+ labelYTrans = -labelYTrans;
+ }
+ QVector3D labelTrans = QVector3D(labelPos,
+ labelYTrans,
+ labelZTrans + zComp);
+ QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ);
+
+ for (int segment = 0; segment <= lastSegment; segment++) {
+ if (m_axisCacheX.labelItems().size() > labelNbr) {
+ // Draw the label here
+ labelTrans.setX(labelPos);
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr);
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, rotation, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(),
+ true, true, Drawer::LabelMid, alignment);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+ }
+ // Y Labels
+ if (m_axisCacheY.segmentCount() > 0) {
+ GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer;
+ GLfloat labelPos = -1.0f;
+ int labelNbr = 0;
+ GLfloat labelXTrans = m_scaleXWithBackground;
+ GLfloat labelZTrans = m_scaleZWithBackground;
+
+ GLfloat labelMarginXTrans = labelMargin;
+ GLfloat labelMarginZTrans = labelMargin;
+ GLfloat rotLabelX = 0.0f;
+ GLfloat rotLabelY = -90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (!m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ labelMarginXTrans = -labelMargin;
+ rotLabelY = 90.0f;
+ }
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ labelMarginZTrans = -labelMargin;
+ alignment = Qt::AlignRight;
+ }
+
+ // Back wall
+ QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ);
+
+ for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
+ if (m_axisCacheY.labelItems().size() > labelNbr) {
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+
+ // Side wall
+ QVector3D labelTrans = QVector3D(labelXTrans, labelPos,
+ labelZTrans + labelMarginZTrans + zComp);
+ if (m_xFlipped)
+ rotation.setY(-90.0f);
+ else
+ rotation.setY(90.0f);
+ if (m_zFlipped)
+ alignment = Qt::AlignRight;
+ else
+ alignment = Qt::AlignLeft;
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, rotation, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(),
+ true, true, Drawer::LabelMid, alignment);
+
+ // Back wall
+ if (m_xFlipped)
+ alignment = Qt::AlignLeft;
+ else
+ alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotation.setY(180.0f);
+ else
+ rotation.setY(0.0f);
+
+ labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelPos,
+ -labelZTrans + zComp);
+
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, rotation, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, m_cachedScene->activeCamera(),
+ true, true, Drawer::LabelMid, alignment);
+ }
+ labelNbr++;
+ labelPos += posStep;
+ }
+ }
+
+ glDisable(GL_TEXTURE_2D);
+
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ m_labelShader->release();
+
+ // Selection handling
+ if (m_selectionModeChanged || selectionDirty) {
+ if (selectionDirty)
+ m_cachedSelectionId = selectionId;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeNone) {
+ m_cachedSelectionId = 0;
+ m_selectionActive = false;
+ }
+ if (m_cachedSelectionMode == QDataVis::SelectionModeItem) {
+ if (m_cachedSelectionId)
+ surfacePointSelected(m_cachedSelectionId);
+ else
+ m_selectionActive = false;
+ }
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow
+ || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) {
+ if (m_cachedSelectionId) {
+ updateSliceDataModel(m_cachedSelectionId);
+ m_cachedScene->setSlicingActive(true);
+
+ surfacePointSelected(m_cachedSelectionId);
+
+ emit needRender();
+ }
+ }
+
+ m_selectionModeChanged = false;
+ }
+ if (m_controller->inputState() == QDataVis::InputStateOnOverview) {
+ if (m_cachedIsSlicingActivated) {
+ m_cachedScene->setSlicingActive(false);
+ m_selectionActive = false;
+ m_cachedSelectionId = 0;
+ }
+ }
+}
+
+void Surface3DRenderer::updateSurfaceGradient(const QLinearGradient &gradient)
+{
+ QImage image(QSize(1, 1000), QImage::Format_RGB32);
+ QPainter pmp(&image);
+ pmp.setBrush(QBrush(gradient));
+ pmp.setPen(Qt::NoPen);
+ pmp.drawRect(0, 0, 1, 1000);
+
+ if (m_gradientTexture) {
+ m_textureHelper->deleteTexture(&m_gradientTexture);
+ m_gradientTexture = 0;
+ }
+
+ m_gradientTexture = m_textureHelper->create2DTexture(image, false, true);
+}
+
+// This one needs to be called when the data size changes
+void Surface3DRenderer::updateSelectionTexture()
+{
+ // Create the selection ID image. Each grid corner gets 2x2 pixel area of
+ // ID color so that each vertex (data point) has 4x4 pixel area of ID color
+ int idImageWidth = (m_sampleSpace.width() - 1) * 4;
+ int idImageHeight = (m_sampleSpace.height() - 1) * 4;
+ int stride = idImageWidth * 4 * sizeof(uchar); // 4 = number of color components (rgba)
+
+ uchar *bits = new uchar[idImageWidth * idImageHeight * 4 * sizeof(uchar)];
+ uint id = 1;
+ for (int i = 0; i < idImageHeight; i += 4) {
+ for (int j = 0; j < idImageWidth; j += 4) {
+ int p = (i * idImageWidth + j) * 4;
+ uchar r, g, b, a;
+ idToRGBA(id, &r, &g, &b, &a);
+ fillIdCorner(&bits[p], r, g, b, a, stride);
+
+ idToRGBA(id + 1, &r, &g, &b, &a);
+ fillIdCorner(&bits[p + 8], r, g, b, a, stride);
+
+ idToRGBA(id + m_sampleSpace.width(), &r, &g, &b, &a);
+ fillIdCorner(&bits[p + 2 * stride], r, g, b, a, stride);
+
+ idToRGBA(id + m_sampleSpace.width() + 1, &r, &g, &b, &a);
+ fillIdCorner(&bits[p + 2 * stride + 8], r, g, b, a, stride);
+
+ id++;
+ }
+ id++;
+ }
+
+ // If old texture exists, delete it
+ if (m_selectionTexture) {
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ m_selectionTexture = 0;
+ }
+
+ // Move the ID image (bits) to the texture
+ QImage image = QImage(bits, idImageWidth, idImageHeight, QImage::Format_RGB32);
+ m_selectionTexture = m_textureHelper->create2DTexture(image, false, false, false);
+
+ // Release the temp bits allocation
+ delete[] bits;
+}
+
+void Surface3DRenderer::initSelectionBuffer()
+{
+ // Create the result selection texture and buffers
+ if (m_selectionResultTexture) {
+ m_textureHelper->deleteTexture(&m_selectionResultTexture);
+ m_selectionResultTexture = 0;
+ }
+
+ m_selectionResultTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(),
+ m_selectionFrameBuffer,
+ m_selectionDepthBuffer);
+}
+
+void Surface3DRenderer::fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride)
+{
+ p[0] = r;
+ p[1] = g;
+ p[2] = b;
+ p[3] = a;
+ p[4] = r;
+ p[5] = g;
+ p[6] = b;
+ p[7] = a;
+ p[stride + 0] = r;
+ p[stride + 1] = g;
+ p[stride + 2] = b;
+ p[stride + 3] = a;
+ p[stride + 4] = r;
+ p[stride + 5] = g;
+ p[stride + 6] = b;
+ p[stride + 7] = a;
+}
+
+void Surface3DRenderer::idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a)
+{
+ *r = id & ID_TO_RGBA_MASK;
+ *g = (id >> 8) & ID_TO_RGBA_MASK;
+ *b = (id >> 16) & ID_TO_RGBA_MASK;
+ *a = (id >> 24) & ID_TO_RGBA_MASK;
+}
+
+void Surface3DRenderer::updateTextures()
+{
+ updateSurfaceGradient(m_cachedTheme.m_surfaceGradient);
+}
+
+void Surface3DRenderer::calculateSceneScalingFactors()
+{
+ // Calculate scene scaling and translation factors
+ m_heightNormalizer = GLfloat(m_axisCacheY.max() - m_axisCacheY.min());
+ m_areaSize.setHeight(m_axisCacheZ.max() - m_axisCacheZ.min());
+ m_areaSize.setWidth(m_axisCacheX.max() - m_axisCacheX.min());
+ m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height());
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ m_scaleX = aspectRatio * m_areaSize.width() / m_scaleFactor;
+ m_scaleZ = aspectRatio * m_areaSize.height() / m_scaleFactor;
+ m_scaleXWithBackground = m_scaleX * backgroundMargin;
+ m_scaleZWithBackground = m_scaleZ * backgroundMargin;
+#else // ..and this if we want uniform scaling based on largest dimension
+ m_scaleX = aspectRatio / m_scaleFactor;
+ m_scaleZ = aspectRatio / m_scaleFactor;
+ m_scaleXWithBackground = aspectRatio * backgroundMargin;
+ m_scaleZWithBackground = aspectRatio * backgroundMargin;
+#endif
+}
+
+bool Surface3DRenderer::updateSmoothStatus(bool enable)
+{
+ if (!enable && !m_flatSupported) {
+ qWarning() << "Warning: Flat qualifier not supported on your platform's GLSL language."
+ " Requires at least GLSL version 1.5.";
+ enable = true;
+ }
+
+ bool changed = false;
+ if (enable != m_cachedSmoothSurface) {
+ m_cachedSmoothSurface = enable;
+ changed = true;
+ initSurfaceShaders();
+ }
+
+ // If no surface object created yet, don't try to update the object
+ if (m_surfaceObj && changed && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) {
+ if (m_cachedSmoothSurface) {
+ m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer,
+ m_axisCacheY.min(), true);
+ } else {
+ m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer,
+ m_axisCacheY.min(), true);
+ }
+ }
+
+ return m_cachedSmoothSurface;
+}
+
+void Surface3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode)
+{
+ if (mode != m_cachedSelectionMode)
+ m_selectionModeChanged = true;
+
+ Abstract3DRenderer::updateSelectionMode(mode);
+}
+
+void Surface3DRenderer::updateSurfaceGridStatus(bool enable)
+{
+ m_cachedSurfaceGridOn = enable;
+}
+
+void Surface3DRenderer::loadBackgroundMesh()
+{
+ if (m_backgroundObj)
+ delete m_backgroundObj;
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
+ m_backgroundObj->load();
+}
+
+void Surface3DRenderer::loadSurfaceObj()
+{
+ if (m_surfaceObj)
+ delete m_surfaceObj;
+ m_surfaceObj = new SurfaceObject();
+}
+
+void Surface3DRenderer::loadSliceSurfaceObj()
+{
+ if (m_sliceSurfaceObj)
+ delete m_sliceSurfaceObj;
+ m_sliceSurfaceObj = new SurfaceObject();
+}
+
+void Surface3DRenderer::loadGridLineMesh()
+{
+ if (m_gridLineObj)
+ delete m_gridLineObj;
+ m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar"));
+ m_gridLineObj->load();
+}
+
+void Surface3DRenderer::handleResize()
+{
+ if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0)
+ return;
+
+ // Set view port
+ if (m_cachedIsSlicingActivated) {
+ m_mainViewPort = QRect(0,
+ m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / subViewDivider,
+ m_cachedBoundingRect.width() / subViewDivider,
+ m_cachedBoundingRect.height() / subViewDivider);
+ } else {
+ m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+ }
+ m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height());
+
+ if (m_selectionPointer) {
+ if (m_cachedIsSlicingActivated)
+ m_selectionPointer->updateBoundingRect(m_sliceViewPort);
+ else
+ m_selectionPointer->updateBoundingRect(m_mainViewPort);
+ }
+
+ Abstract3DRenderer::handleResize();
+}
+
+void Surface3DRenderer::surfacePointSelected(int id)
+{
+ int column = (id - 1) % m_sampleSpace.width();
+ int row = (id - 1) / m_sampleSpace.width();
+
+ if (row < 0 || column < 0 || m_dataArray.size() < row || m_dataArray.at(row)->size() < column)
+ return;
+
+ qreal value = qreal(m_dataArray.at(row)->at(column).y());
+
+ if (!m_selectionPointer)
+ m_selectionPointer = new SelectionPointer(m_drawer);
+
+ QVector3D pos;
+ if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) {
+ pos = m_sliceSurfaceObj->vertexAt(column, 0);
+ pos *= QVector3D(m_surfaceScaleX, 1.0f, 0.0f);
+ pos += QVector3D(m_surfaceOffsetX, 0.0f, 0.0f);
+ m_selectionPointer->updateBoundingRect(m_sliceViewPort);
+ m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment);
+ } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) {
+ pos = m_sliceSurfaceObj->vertexAt(row, 0);
+ pos *= QVector3D(m_surfaceScaleZ, 1.0f, 0.0f);
+ pos += QVector3D(-m_surfaceOffsetZ, 0.0f, 0.0f);
+ m_selectionPointer->updateBoundingRect(m_sliceViewPort);
+ m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment);
+ } else {
+ pos = m_surfaceObj->vertexAt(column, row);
+ pos *= QVector3D(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);;
+ pos += QVector3D(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ);
+ m_selectionPointer->updateBoundingRect(m_mainViewPort);
+ m_selectionPointer->updateSliceData(false, m_autoScaleAdjustment);
+ }
+
+ m_selectionPointer->setPosition(pos);
+ m_selectionPointer->setLabel(createSelectionLabel(value, column, row));
+ m_selectionPointer->updateScene(m_cachedScene);
+
+ //Put the selection pointer flag active
+ m_selectionActive = true;
+}
+
+QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row)
+{
+ QString labelText = itemLabelFormat();
+ static const QString xTitleTag(QStringLiteral("@xTitle"));
+ static const QString yTitleTag(QStringLiteral("@yTitle"));
+ static const QString zTitleTag(QStringLiteral("@zTitle"));
+ static const QString xLabelTag(QStringLiteral("@xLabel"));
+ static const QString yLabelTag(QStringLiteral("@yLabel"));
+ static const QString zLabelTag(QStringLiteral("@zLabel"));
+
+ labelText.replace(xTitleTag, m_axisCacheX.title());
+ labelText.replace(yTitleTag, m_axisCacheY.title());
+ labelText.replace(zTitleTag, m_axisCacheZ.title());
+
+ if (labelText.contains(xLabelTag)) {
+ QString labelFormat = m_axisCacheX.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat,
+ m_dataArray.at(row)->at(column).x());
+ labelText.replace(xLabelTag, valueLabelText);
+ }
+ if (labelText.contains(yLabelTag)) {
+ QString labelFormat = m_axisCacheY.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat, value);
+ labelText.replace(yLabelTag, valueLabelText);
+ }
+ if (labelText.contains(zLabelTag)) {
+ QString labelFormat = m_axisCacheZ.labelFormat();
+ if (labelFormat.isEmpty())
+ labelFormat = Utils::defaultLabelFormat();
+ QString valueLabelText = generateValueLabel(labelFormat,
+ m_dataArray.at(row)->at(column).z());
+ labelText.replace(zLabelTag, valueLabelText);
+ }
+
+ return labelText;
+}
+
+void Surface3DRenderer::loadMeshFile()
+{
+ qDebug() << __FUNCTION__ << "should we do something";
+}
+
+void Surface3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality)
+{
+ qWarning() << "Shadows have been disabled for Q3DSurface in technology preview";
+ m_cachedShadowQuality = QDataVis::ShadowQualityNone; //quality;
+ switch (quality) {
+ case QDataVis::ShadowQualityLow:
+ m_shadowQualityToShader = 33.3f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualityMedium:
+ m_shadowQualityToShader = 100.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualityHigh:
+ m_shadowQualityToShader = 200.0f;
+ m_shadowQualityMultiplier = 5;
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ m_shadowQualityToShader = 5.0f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ m_shadowQualityToShader = 10.0f;
+ m_shadowQualityMultiplier = 3;
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ m_shadowQualityToShader = 15.0f;
+ m_shadowQualityMultiplier = 4;
+ break;
+ default:
+ m_shadowQualityToShader = 0.0f;
+ m_shadowQualityMultiplier = 1;
+ break;
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ updateDepthBuffer();
+#endif
+}
+
+void Surface3DRenderer::updateSlicingActive(bool isSlicing)
+{
+ if (isSlicing == m_cachedIsSlicingActivated)
+ return;
+
+ m_cachedIsSlicingActivated = isSlicing;
+ if (isSlicing) {
+ m_mainViewPort = QRect(0, m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / subViewDivider,
+ m_cachedBoundingRect.width() / subViewDivider, m_cachedBoundingRect.height() / subViewDivider);
+ if (m_depthTexture) {
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_depthTexture = 0;
+ }
+ } else {
+ m_mainViewPort = QRect(0, 0, this->m_cachedBoundingRect.width(),
+ this->m_cachedBoundingRect.height());
+ initSelectionBuffer(); // We need to re-init selection buffer in case there has been a resize
+#if !defined(QT_OPENGL_ES_2)
+ updateDepthBuffer(); // Re-init depth buffer as well
+#endif
+ }
+}
+
+void Surface3DRenderer::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void Surface3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_shader)
+ delete m_shader;
+ m_shader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_shader->initialize();
+}
+
+void Surface3DRenderer::initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_backgroundShader)
+ delete m_backgroundShader;
+ m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_backgroundShader->initialize();
+}
+
+void Surface3DRenderer::initSelectionShaders()
+{
+ if (m_selectionShader)
+ delete m_selectionShader;
+ m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+ m_selectionShader->initialize();
+}
+
+void Surface3DRenderer::initSurfaceShaders()
+{
+ if (m_surfaceShader)
+ delete m_surfaceShader;
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedSmoothSurface) {
+ m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurface"),
+ QStringLiteral(":/shaders/fragmentSurface"));
+ } else {
+ m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
+ QStringLiteral(":/shaders/fragmentSurfaceFlat"));
+ }
+#else
+ m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurface"),
+ QStringLiteral(":/shaders/fragmentSurfaceES2"));
+#endif
+ m_surfaceShader->initialize();
+
+ if (m_surfaceGridShader)
+ delete m_surfaceGridShader;
+
+ m_surfaceGridShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceGrid"),
+ QStringLiteral(":/shaders/fragmentSurfaceGrid"));
+
+ m_surfaceGridShader->initialize();
+}
+
+void Surface3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_labelShader->initialize();
+}
+
+#if !defined(QT_OPENGL_ES_2)
+void Surface3DRenderer::initDepthShader()
+{
+ // TODO: Implement a depth shader for surface after technology preview
+ if (m_depthShader)
+ delete m_depthShader;
+ m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"),
+ QStringLiteral(":/shaders/fragmentDepth"));
+ m_depthShader->initialize();
+}
+
+void Surface3DRenderer::updateDepthBuffer()
+{
+ if (m_depthTexture) {
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_depthTexture = 0;
+ }
+
+ if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) {
+ m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(),
+ m_depthFrameBuffer,
+ m_shadowQualityMultiplier);
+ if (!m_depthTexture) {
+ switch (m_cachedShadowQuality) {
+ case QDataVis::ShadowQualityHigh:
+ qWarning("Creating high quality shadows failed. Changing to medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium);
+ updateShadowQuality(QDataVis::ShadowQualityMedium);
+ break;
+ case QDataVis::ShadowQualityMedium:
+ qWarning("Creating medium quality shadows failed. Changing to low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow);
+ updateShadowQuality(QDataVis::ShadowQualityLow);
+ break;
+ case QDataVis::ShadowQualityLow:
+ qWarning("Creating low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ case QDataVis::ShadowQualitySoftHigh:
+ qWarning("Creating soft high quality shadows failed. Changing to soft medium quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ updateShadowQuality(QDataVis::ShadowQualitySoftMedium);
+ break;
+ case QDataVis::ShadowQualitySoftMedium:
+ qWarning("Creating soft medium quality shadows failed. Changing to soft low quality.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow);
+ updateShadowQuality(QDataVis::ShadowQualitySoftLow);
+ break;
+ case QDataVis::ShadowQualitySoftLow:
+ qWarning("Creating soft low quality shadows failed. Switching shadows off.");
+ (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone);
+ updateShadowQuality(QDataVis::ShadowQualityNone);
+ break;
+ default:
+ // You'll never get here
+ break;
+ }
+ }
+ }
+}
+#endif
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h
new file mode 100644
index 00000000..e42e820a
--- /dev/null
+++ b/src/datavisualization/engine/surface3drenderer_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SURFACE3DRENDERER_P_H
+#define SURFACE3DRENDERER_P_H
+
+#include <QtCore/QSize>
+#include <QtCore/QObject>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QFont>
+#include <QLinearGradient>
+#include <QWindow>
+
+#include "datavisualizationglobal_p.h"
+#include "surface3dcontroller_p.h"
+#include "abstract3drenderer_p.h"
+#include "scatterrenderitem_p.h"
+#include "qsurfacedataproxy.h"
+
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper;
+class ObjectHelper;
+class SurfaceObject;
+class TextureHelper;
+class Theme;
+class Drawer;
+class Q3DScene;
+class SelectionPointer;
+
+class QT_DATAVISUALIZATION_EXPORT Surface3DRenderer : public Abstract3DRenderer
+{
+ Q_OBJECT
+
+public:
+ Surface3DController *m_controller;
+
+ // Visual parameters
+ QRect m_boundingRect;
+ QDataVis::LabelStyle m_labelStyle;
+ QFont m_font;
+ bool m_isGridEnabled;
+
+private:
+ bool m_cachedIsSlicingActivated;
+
+ // Internal attributes purely related to how the scene is drawn with GL.
+ QRect m_mainViewPort;
+ QRect m_sliceViewPort;
+ ShaderHelper *m_shader;
+ ShaderHelper *m_depthShader;
+ ShaderHelper *m_backgroundShader;
+ ShaderHelper *m_surfaceShader;
+ ShaderHelper *m_surfaceGridShader;
+ ShaderHelper *m_selectionShader;
+ ShaderHelper *m_labelShader;
+ GLfloat m_heightNormalizer;
+ GLfloat m_scaleFactor;
+ GLfloat m_scaleX;
+ GLfloat m_scaleZ;
+ GLfloat m_scaleXWithBackground;
+ GLfloat m_scaleZWithBackground;
+ GLfloat m_surfaceScaleX;
+ GLfloat m_surfaceScaleZ;
+ GLfloat m_surfaceOffsetX;
+ GLfloat m_surfaceOffsetZ;
+ GLfloat m_minVisibleColumnValue;
+ GLfloat m_maxVisibleColumnValue;
+ GLfloat m_minVisibleRowValue;
+ GLfloat m_maxVisibleRowValue;
+ GLfloat m_visibleColumnRange;
+ GLfloat m_visibleRowRange;
+ ObjectHelper *m_backgroundObj;
+ ObjectHelper *m_gridLineObj;
+ ObjectHelper *m_labelObj;
+ SurfaceObject *m_surfaceObj;
+ SurfaceObject *m_sliceSurfaceObj;
+ GLuint m_depthTexture;
+ GLuint m_depthFrameBuffer;
+ GLuint m_selectionFrameBuffer;
+ GLuint m_selectionDepthBuffer;
+ GLuint m_gradientTexture;
+ GLuint m_selectionTexture;
+ GLuint m_selectionResultTexture;
+ GLfloat m_shadowQualityToShader;
+ bool m_cachedSmoothSurface;
+ bool m_flatSupported;
+ bool m_cachedSurfaceGridOn;
+ SelectionPointer *m_selectionPointer;
+ bool m_selectionActive;
+ bool m_xFlipped;
+ bool m_zFlipped;
+ bool m_yFlipped;
+ AbstractRenderItem m_dummyRenderItem;
+ QSurfaceDataArray m_dataArray;
+ QSurfaceDataArray m_sliceDataArray;
+ QRect m_sampleSpace;
+ GLint m_shadowQualityMultiplier;
+ QSizeF m_areaSize;
+ uint m_cachedSelectionId;
+ bool m_selectionModeChanged;
+ bool m_hasHeightAdjustmentChanged;
+
+public:
+ explicit Surface3DRenderer(Surface3DController *controller);
+ ~Surface3DRenderer();
+
+ void updateDataModel(QSurfaceDataProxy *dataProxy);
+ void updateScene(Q3DScene *scene);
+ void drawSlicedScene();
+ void render(GLuint defaultFboHandle = 0);
+
+protected:
+ void initializeOpenGL();
+ virtual void loadMeshFile();
+
+public slots:
+ bool updateSmoothStatus(bool enable);
+ void updateSurfaceGridStatus(bool enable);
+ void updateSurfaceGradient(const QLinearGradient &gradient);
+ void updateSlicingActive(bool isSlicing);
+ void updateSelectionMode(QDataVis::SelectionMode mode);
+
+private:
+ void updateSliceDataModel(int selectionId);
+ virtual void updateShadowQuality(QDataVis::ShadowQuality quality);
+ virtual void updateTextures();
+ virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
+ QRect calculateSampleRect(const QSurfaceDataArray &array);
+ void loadBackgroundMesh();
+ void loadGridLineMesh();
+ void loadLabelMesh();
+ void loadSurfaceObj();
+ void loadSliceSurfaceObj();
+ void drawScene(GLuint defaultFboHandle);
+ void handleResize();
+ void calculateSceneScalingFactors();
+ void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initSelectionShaders();
+ void initSurfaceShaders();
+ void initSelectionBuffer();
+ void initDepthShader();
+ void updateSelectionTexture();
+ void idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a);
+ void fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride);
+ void surfacePointSelected(int id);
+ QString createSelectionLabel(qreal value, int column, int row);
+#if !defined(QT_OPENGL_ES_2)
+ void updateDepthBuffer();
+#endif
+
+ Q_DISABLE_COPY(Surface3DRenderer)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // SURFACE3DRENDERER_P_H
diff --git a/src/datavisualization/engine/theme.cpp b/src/datavisualization/engine/theme.cpp
new file mode 100644
index 00000000..d9f2974a
--- /dev/null
+++ b/src/datavisualization/engine/theme.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "theme_p.h"
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#include <stdio.h>
+#endif
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+Theme::Theme()
+ : m_baseColor(QColor(Qt::gray)),
+ m_heightColor(QColor(Qt::black)),
+ m_depthColor(QColor(Qt::black)),
+ m_backgroundColor(QColor(Qt::gray)),
+ m_windowColor(QColor(Qt::gray)),
+ m_textColor(QColor(Qt::white)),
+ m_textBackgroundColor(QColor(0x00, 0x00, 0x00, 0xa0)),
+ m_gridLine(QColor(Qt::black)),
+ m_highlightBarColor(QColor(Qt::red)),
+ m_highlightRowColor(QColor(Qt::darkRed)),
+ m_highlightColumnColor(QColor(Qt::darkMagenta)),
+ m_surfaceGradient(QLinearGradient(1, 1000, 0, 0)),
+ m_lightStrength(4.0f),
+ m_ambientStrength(0.3f),
+ m_highlightLightStrength(8.0f),
+ m_uniformColor(true),
+ m_labelBorders(false)
+{
+ // Default values for surface gradient
+}
+
+Theme::~Theme()
+{
+}
+
+QDataVis::Theme Theme::theme()
+{
+ return m_theme;
+}
+
+void Theme::useTheme(QDataVis::Theme theme)
+{
+ m_theme = theme;
+ switch (theme) {
+ case QDataVis::ThemeQt: {
+ m_baseColor = QColor(QRgb(0x80c342));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x35322f));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x99);
+ m_gridLine = QColor(QRgb(0xd7d6d5));
+ m_highlightBarColor = QColor(QRgb(0x14aaff));
+ m_highlightRowColor = QColor(QRgb(0x6400aa));
+ m_highlightColumnColor = QColor(QRgb(0x6400aa));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = true;
+ m_labelBorders = true;
+ break;
+ }
+ case QDataVis::ThemePrimaryColors: {
+ m_baseColor = QColor(QRgb(0xffe400));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x000000));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x99);
+ m_gridLine = QColor(QRgb(0xd7d6d5));
+ m_highlightBarColor = QColor(QRgb(0x27beee));
+ m_highlightRowColor = QColor(QRgb(0xee1414));
+ m_highlightColumnColor = QColor(QRgb(0xee1414));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = true;
+ m_labelBorders = false;
+ break;
+ }
+ case QDataVis::ThemeDigia: {
+ m_baseColor = QColor(QRgb(0xcccccc));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x000000));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x80);
+ m_gridLine = QColor(QRgb(0xd7d6d5));
+ m_highlightBarColor = QColor(QRgb(0xfa0000));
+ m_highlightRowColor = QColor(QRgb(0x555555));
+ m_highlightColumnColor = QColor(QRgb(0x555555));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = false;
+ m_labelBorders = false;
+ break;
+ }
+ case QDataVis::ThemeStoneMoss: {
+ m_baseColor = QColor(QRgb(0xbeb32b));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0x4d4d4f));
+ m_windowColor = QColor(QRgb(0x4d4d4f));
+ m_textColor = QColor(QRgb(0xffffff));
+ m_textBackgroundColor = QColor(0x4d, 0x4d, 0x4f, 0xcd);
+ m_gridLine = QColor(QRgb(0x3e3e40));
+ m_highlightBarColor = QColor(QRgb(0xfbf6d6));
+ m_highlightRowColor = QColor(QRgb(0x442f20));
+ m_highlightColumnColor = QColor(QRgb(0x442f20));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = true;
+ m_labelBorders = true;
+ break;
+ }
+ case QDataVis::ThemeArmyBlue: {
+ m_baseColor = QColor(QRgb(0x495f76));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0xd5d6d7));
+ m_windowColor = QColor(QRgb(0xd5d6d7));
+ m_textColor = QColor(QRgb(0x000000));
+ m_textBackgroundColor = QColor(0xd5, 0xd6, 0xd7, 0xcd);
+ m_gridLine = QColor(QRgb(0xaeadac));
+ m_highlightBarColor = QColor(QRgb(0x2aa2f9));
+ m_highlightRowColor = QColor(QRgb(0x103753));
+ m_highlightColumnColor = QColor(QRgb(0x103753));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = false;
+ m_labelBorders = false;
+ break;
+ }
+ case QDataVis::ThemeRetro: {
+ m_baseColor = QColor(QRgb(0x533b23));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0xe9e2ce));
+ m_windowColor = QColor(QRgb(0xe9e2ce));
+ m_textColor = QColor(QRgb(0x000000));
+ m_textBackgroundColor = QColor(0xe9, 0xe2, 0xce, 0xc0);
+ m_gridLine = QColor(QRgb(0xd0c0b0));
+ m_highlightBarColor = QColor(QRgb(0x8ea317));
+ m_highlightRowColor = QColor(QRgb(0xc25708));
+ m_highlightColumnColor = QColor(QRgb(0xc25708));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = false;
+ m_labelBorders = false;
+ break;
+ }
+ case QDataVis::ThemeEbony: {
+ m_baseColor = QColor(QRgb(0xffffff));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0x000000));
+ m_windowColor = QColor(QRgb(0x000000));
+ m_textColor = QColor(QRgb(0xaeadac));
+ m_textBackgroundColor = QColor(0x00, 0x00, 0x00, 0xcd);
+ m_gridLine = QColor(QRgb(0x35322f));
+ m_highlightBarColor = QColor(QRgb(0xf5dc0d));
+ m_highlightRowColor = QColor(QRgb(0xd72222));
+ m_highlightColumnColor = QColor(QRgb(0xd72222));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = true;
+ m_labelBorders = false;
+ break;
+ }
+ case QDataVis::ThemeIsabelle: {
+ m_baseColor = QColor(QRgb(0xf9d900));
+ //m_heightColor = QColor(QRgb(0x));
+ //m_depthColor = QColor(QRgb(0x));
+ m_backgroundColor = QColor(QRgb(0x000000));
+ m_windowColor = QColor(QRgb(0x000000));
+ m_textColor = QColor(QRgb(0xaeadac));
+ m_textBackgroundColor = QColor(0x00, 0x00, 0x00, 0xc0);
+ m_gridLine = QColor(QRgb(0x35322f));
+ m_highlightBarColor = QColor(QRgb(0xfff7cc));
+ m_highlightRowColor = QColor(QRgb(0xde0a0a));
+ m_highlightColumnColor = QColor(QRgb(0xde0a0a));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.5f;
+ m_highlightLightStrength = 5.0f;
+ m_uniformColor = true;
+ m_labelBorders = false;
+ break;
+ }
+ default:
+ break;
+ }
+ if (m_uniformColor) {
+ m_surfaceGradient.setColorAt(0.0, m_baseColor);
+ } else {
+ m_surfaceGradient.setColorAt(0.0, QColor(m_baseColor.redF() * 0.7,
+ m_baseColor.greenF() * 0.7,
+ m_baseColor.blueF() * 0.7));
+ }
+ m_surfaceGradient.setColorAt(1.0, m_baseColor);
+}
+
+void Theme::setFromTheme(Theme &theme)
+{
+ m_theme = theme.m_theme;
+ m_baseColor = theme.m_baseColor;
+ m_heightColor = theme.m_heightColor;
+ m_depthColor = theme.m_depthColor;
+ m_backgroundColor = theme.m_backgroundColor;
+ m_windowColor = theme.m_windowColor;
+ m_textColor = theme.m_textColor;
+ m_textBackgroundColor = theme.m_textBackgroundColor;
+ m_gridLine = theme.m_gridLine;
+ m_highlightBarColor = theme.m_highlightBarColor;
+ m_highlightRowColor = theme.m_highlightRowColor;
+ m_highlightColumnColor = theme.m_highlightColumnColor;
+ m_surfaceGradient = theme.m_surfaceGradient;
+ m_lightStrength = theme.m_lightStrength;
+ m_ambientStrength = theme.m_ambientStrength;
+ m_highlightLightStrength = theme.m_highlightLightStrength;
+ m_uniformColor = theme.m_uniformColor;
+ m_labelBorders = theme.m_labelBorders;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/engine/theme_p.h b/src/datavisualization/engine/theme_p.h
new file mode 100644
index 00000000..ec689f63
--- /dev/null
+++ b/src/datavisualization/engine/theme_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 THEME_P_H
+#define THEME_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+#include <QLinearGradient>
+
+class QColor;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QT_DATAVISUALIZATION_EXPORT Theme
+{
+public:
+ explicit Theme();
+ ~Theme();
+
+ void useTheme(QDataVis::Theme theme);
+ QDataVis::Theme theme();
+ void setFromTheme(Theme &theme);
+
+private:
+ friend class Abstract3DController;
+ friend class Abstract3DRenderer;
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Surface3DController;
+ friend class Scatter3DRenderer;
+ friend class SelectionPointer;
+ friend class Drawer;
+
+ QDataVis::Theme m_theme;
+ QColor m_baseColor;
+ QColor m_heightColor;
+ QColor m_depthColor;
+ QColor m_backgroundColor;
+ QColor m_windowColor;
+ QColor m_textColor;
+ QColor m_textBackgroundColor;
+ QColor m_gridLine;
+ QColor m_highlightBarColor;
+ QColor m_highlightRowColor;
+ QColor m_highlightColumnColor;
+ QLinearGradient m_surfaceGradient;
+ float m_lightStrength;
+ float m_ambientStrength;
+ float m_highlightLightStrength;
+ bool m_uniformColor;
+ bool m_labelBorders;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/global/datavisualizationglobal_p.h b/src/datavisualization/global/datavisualizationglobal_p.h
new file mode 100644
index 00000000..4da1023c
--- /dev/null
+++ b/src/datavisualization/global/datavisualizationglobal_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 DATAVISUALIZATIONGLOBAL_P_H
+#define DATAVISUALIZATIONGLOBAL_P_H
+
+#include "qdatavisualizationglobal.h"
+#include "qdatavisualizationenums.h"
+#include <QOpenGLFunctions>
+#include <QVector3D>
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+// Constants used in several files
+// Compensation for z position; move all objects to positive z, as shader can't handle negative values correctly
+const GLfloat zComp = 10.0f;
+// Distance from camera to origin
+const GLfloat cameraDistance = 6.0f;
+// Size of font to be used in label texture rendering. Doesn't affect the actual font size.
+const int textureFontSize = 50;
+// Default light position. To have shadows working correctly, light should be as far as camera, or a bit further
+// y position is added to the minimum height (or can be thought to be that much above or below the camera)
+const QVector3D defaultLightPos = QVector3D(0.0f, 0.5f, zComp);
+const GLfloat defaultRatio = 1.0f / 1.6f; // default aspect ratio 16:10
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // DATAVISUALIZATIONGLOBAL_P_H
diff --git a/src/datavisualization/global/global.pri b/src/datavisualization/global/global.pri
new file mode 100644
index 00000000..0fd7c576
--- /dev/null
+++ b/src/datavisualization/global/global.pri
@@ -0,0 +1,4 @@
+HEADERS += \
+ $$PWD/qdatavisualizationglobal.h \
+ $$PWD/qdatavisualizationenums.h \
+ $$PWD/datavisualizationglobal_p.h
diff --git a/src/datavisualization/global/qdatavisualizationenums.h b/src/datavisualization/global/qdatavisualizationenums.h
new file mode 100644
index 00000000..3d765ff2
--- /dev/null
+++ b/src/datavisualization/global/qdatavisualizationenums.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QDATAVISUALIZATIONENUMS_H
+#define QDATAVISUALIZATIONENUMS_H
+
+#include <QtDataVisualization/qdatavisualizationglobal.h>
+#include <QObject>
+
+// namespace must be declared without using macros for qdoc
+namespace QtDataVisualization {
+
+class QT_DATAVISUALIZATION_EXPORT QDataVis : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MeshStyle)
+ Q_ENUMS(CameraPreset)
+ Q_ENUMS(Theme)
+ Q_ENUMS(SelectionMode)
+ Q_ENUMS(ShadowQuality)
+ Q_ENUMS(LabelStyle)
+
+public:
+ enum InputState {
+ InputStateNone = 0,
+ InputStateOnScene,
+ InputStateOnOverview,
+ InputStateOnSlice,
+ InputStateRotating,
+ InputStateOnPinch
+ };
+
+ enum MeshStyle {
+ MeshStyleBars = 0,
+ MeshStylePyramids,
+ MeshStyleCones,
+ MeshStyleCylinders,
+ MeshStyleBevelBars,
+ MeshStyleSpheres,
+ MeshStyleDots
+ };
+
+ enum CameraPreset {
+ CameraPresetNone = -1,
+ CameraPresetFrontLow = 0,
+ CameraPresetFront,
+ CameraPresetFrontHigh,
+ CameraPresetLeftLow,
+ CameraPresetLeft,
+ CameraPresetLeftHigh,
+ CameraPresetRightLow,
+ CameraPresetRight,
+ CameraPresetRightHigh,
+ CameraPresetBehindLow,
+ CameraPresetBehind,
+ CameraPresetBehindHigh,
+ CameraPresetIsometricLeft,
+ CameraPresetIsometricLeftHigh,
+ CameraPresetIsometricRight,
+ CameraPresetIsometricRightHigh,
+ CameraPresetDirectlyAbove,
+ CameraPresetDirectlyAboveCW45,
+ CameraPresetDirectlyAboveCCW45,
+ CameraPresetFrontBelow,
+ CameraPresetLeftBelow,
+ CameraPresetRightBelow,
+ CameraPresetBehindBelow,
+ CameraPresetDirectlyBelow
+ };
+
+ enum Theme {
+ ThemeDefault = -1,
+ ThemeQt,
+ ThemePrimaryColors,
+ ThemeDigia,
+ ThemeStoneMoss,
+ ThemeArmyBlue,
+ ThemeRetro,
+ ThemeEbony,
+ ThemeIsabelle
+ };
+
+ enum SelectionMode {
+ SelectionModeNone = 0,
+ SelectionModeItem,
+ SelectionModeItemAndRow,
+ SelectionModeItemAndColumn,
+ SelectionModeItemRowAndColumn,
+ SelectionModeSliceRow,
+ SelectionModeSliceColumn
+ };
+
+ enum ShadowQuality {
+ ShadowQualityNone = 0,
+ ShadowQualityLow,
+ ShadowQualityMedium,
+ ShadowQualityHigh,
+ ShadowQualitySoftLow,
+ ShadowQualitySoftMedium,
+ ShadowQualitySoftHigh
+ };
+
+ enum LabelStyle {
+ LabelStyleOpaque = 0,
+ LabelStyleFromTheme,
+ LabelStyleTransparent
+ };
+};
+}
+
+#endif
diff --git a/src/datavisualization/global/qdatavisualizationglobal.h b/src/datavisualization/global/qdatavisualizationglobal.h
new file mode 100644
index 00000000..ac734960
--- /dev/null
+++ b/src/datavisualization/global/qdatavisualizationglobal.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QDATAVISUALIZATIONGLOBAL_H
+#define QDATAVISUALIZATIONGLOBAL_H
+
+#include <qglobal.h>
+
+#define QT_DATAVISUALIZATION_VERSION_STR "0.0.1"
+/*
+ QT_DATAVISUALIZATION_VERSION is (major << 16) + (minor << 8) + patch.
+*/
+#define QT_DATAVISUALIZATION_VERSION 0x000001
+/*
+ can be used like #if (QT_DATAVISUALIZATION_VERSION >= QT_DATAVISUALIZATION_VERSION_CHECK(1, 1, 0))
+*/
+#define QT_DATAVISUALIZATION_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
+
+#if defined(QT_DATAVISUALIZATION_LIBRARY)
+# define QT_DATAVISUALIZATION_EXPORT Q_DECL_EXPORT
+#else
+# define QT_DATAVISUALIZATION_EXPORT Q_DECL_IMPORT
+#endif
+
+#if defined(BUILD_PRIVATE_UNIT_TESTS) && defined(QT_DATAVISUALIZATION_LIBRARY)
+# define QT_DATAVISUALIZATION_AUTOTEST_EXPORT Q_DECL_EXPORT
+#elif defined(BUILD_PRIVATE_UNIT_TESTS) && !defined(QT_DATAVISUALIZATION_LIBRARY)
+# define QT_DATAVISUALIZATION_AUTOTEST_EXPORT Q_DECL_IMPORT
+#else
+# define QT_DATAVISUALIZATION_AUTOTEST_EXPORT
+#endif
+
+#ifdef QT_DATAVISUALIZATION_STATICLIB
+# undef QT_DATAVISUALIZATION_EXPORT
+# undef QT_DATAVISUALIZATION_AUTOTEST_EXPORT
+# define QT_DATAVISUALIZATION_EXPORT
+# define QT_DATAVISUALIZATION_AUTOTEST_EXPORT
+#endif
+
+#define QT_DATAVISUALIZATION_NAMESPACE QtDataVisualization
+
+#ifdef QT_DATAVISUALIZATION_NAMESPACE
+# define QT_DATAVISUALIZATION_BEGIN_NAMESPACE namespace QT_DATAVISUALIZATION_NAMESPACE {
+# define QT_DATAVISUALIZATION_END_NAMESPACE }
+# define QT_DATAVISUALIZATION_USE_NAMESPACE using namespace QT_DATAVISUALIZATION_NAMESPACE;
+#else
+# define QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+# define QT_DATAVISUALIZATION_END_NAMESPACE
+# define QT_DATAVISUALIZATION_USE_NAMESPACE
+#endif
+
+#endif // QVIS3DGLOBAL_H
diff --git a/src/datavisualization/global/qtdatavisualizationenums.qdoc b/src/datavisualization/global/qtdatavisualizationenums.qdoc
new file mode 100644
index 00000000..fde6a258
--- /dev/null
+++ b/src/datavisualization/global/qtdatavisualizationenums.qdoc
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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
+**
+****************************************************************************/
+
+/*!
+ \namespace QtDataVisualization
+ \inmodule QtDataVisualization
+ \target QtDataVisualization Enums
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::InputState
+
+ Predefined input states for mouse and touch based input handlers. All states are not valid with all input handlers.
+
+ \value InputStateNone
+ Default "no input received" state.
+ \value InputStateOnScene
+ Mouse or touch input received on the 3D scene.
+ \value InputStateOnOverview
+ Mouse or touch input received on the overview area.
+ \value InputStateOnSlice
+ Mouse or touch input received on the slice view area.
+ \value InputStateRotating
+ Rotation of the 3D geometry ongoing.
+ \value InputStateOnPinch
+ Pinch/punch multitouch input received.
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::MeshStyle
+
+ Predefined mesh types. All styles are not usable with all visualization types.
+
+ \value MeshStyleBars
+ Basic cubic bar.
+ \value MeshStylePyramids
+ Four-sided pyramid.
+ \value MeshStyleCones
+ Basic cone.
+ \value MeshStyleCylinders
+ Basic cylinder.
+ \value MeshStyleBevelBars
+ Slightly beveled (rounded) cubic bar.
+ \value MeshStyleSpheres
+ Sphere. Not usable in Q3DBars.
+ \value MeshStyleDots
+ Triangular pyramid. Usable only with Q3DScatter.
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::CameraPreset
+
+ Predefined positions for camera.
+
+ \value CameraPresetNone
+ Used to indicate a preset has not been set, or the scene has been rotated freely.
+ \value CameraPresetFrontLow
+ \value CameraPresetFront
+ \value CameraPresetFrontHigh
+ \value CameraPresetLeftLow
+ \value CameraPresetLeft
+ \value CameraPresetLeftHigh
+ \value CameraPresetRightLow
+ \value CameraPresetRight
+ \value CameraPresetRightHigh
+ \value CameraPresetBehindLow
+ \value CameraPresetBehind
+ \value CameraPresetBehindHigh
+ \value CameraPresetIsometricLeft
+ \value CameraPresetIsometricLeftHigh
+ \value CameraPresetIsometricRight
+ \value CameraPresetIsometricRightHigh
+ \value CameraPresetDirectlyAbove
+ \value CameraPresetDirectlyAboveCW45
+ \value CameraPresetDirectlyAboveCCW45
+ \value CameraPresetFrontBelow
+ In Q3DBars from CameraPresetFrontBelow onward these only work for graphs including negative
+ values. They act as Preset...Low for positive-only values.
+ \value CameraPresetLeftBelow
+ \value CameraPresetRightBelow
+ \value CameraPresetBehindBelow
+ \value CameraPresetDirectlyBelow
+ Acts as CameraPresetFrontLow for positive -only bars.
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::Theme
+
+ Predefined themes.
+
+ \value ThemeDefault
+ Used only in QML to indicate a theme has not been set.
+ \value ThemeQt
+ \value ThemePrimaryColors
+ \value ThemeDigia
+ \value ThemeStoneMoss
+ \value ThemeArmyBlue
+ \value ThemeRetro
+ \value ThemeEbony
+ \value ThemeIsabelle
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::SelectionMode
+
+ Item selection modes.
+
+ \value SelectionModeNone
+ Selection mode disabled.
+ \value SelectionModeItem
+ Selection selects a single item.
+ \value SelectionModeItemAndRow
+ Selection selects a single item and highlights the row it is on. In Q3DBars only.
+ \value SelectionModeItemAndColumn
+ Selection selects a single item and highlights the column it is on. In Q3DBars only.
+ \value SelectionModeItemRowAndColumn
+ Selection selects a single item and highlights the row and the column it is on. In
+ Q3DBars only.
+ \value SelectionModeSliceRow
+ Selection selects a single item and displays the row it is on in a separate view. The
+ original view is shrunk into upper left corner. Original view is restored by clicking
+ on it. In Q3DBars only.
+ \value SelectionModeSliceColumn
+ Selection selects a single item and displays the column it is on in a separate view. The
+ original view is shrunk into upper left corner. Original view is restored by clicking
+ on it. In Q3DBars only.
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::ShadowQuality
+
+ Quality of shadows.
+
+ \value ShadowQualityNone
+ Shadows are disabled.
+ \value ShadowQualityLow
+ Shadows are rendered in low quality.
+ \value ShadowQualityMedium
+ Shadows are rendered in medium quality.
+ \value ShadowQualityHigh
+ Shadows are rendered in high quality.
+ \value ShadowQualitySoftLow
+ Shadows are rendered in low quality with softened edges.
+ \value ShadowQualitySoftMedium
+ Shadows are rendered in medium quality with softened edges.
+ \value ShadowQualitySoftHigh
+ Shadows are rendered in high quality with softened edges.
+*/
+
+/*!
+ \enum QtDataVisualization::QDataVis::LabelStyle
+
+ Label styles.
+
+ \value LabelStyleOpaque
+ Fully opaque background, using colors and borders from theme.
+ \value LabelStyleFromTheme
+ Use transparencies, colors and borders from theme.
+ \value LabelStyleTransparent
+ Fully transparent background, using text color from theme.
+*/
diff --git a/src/datavisualization/input/input.pri b/src/datavisualization/input/input.pri
new file mode 100644
index 00000000..5a4c4a76
--- /dev/null
+++ b/src/datavisualization/input/input.pri
@@ -0,0 +1,12 @@
+HEADERS += \
+ $$PWD/qabstract3dinputhandler.h \
+ $$PWD/q3dinputhandler.h \
+ $$PWD/qtouch3dinputhandler.h \
+ $$PWD/qabstract3dinputhandler_p.h \
+ $$PWD/q3dinputhandler_p.h \
+ $$PWD/qtouch3dinputhandler_p.h
+
+SOURCES += \
+ $$PWD/qabstract3dinputhandler.cpp \
+ $$PWD/q3dinputhandler.cpp \
+ $$PWD/qtouch3dinputhandler.cpp
diff --git a/src/datavisualization/input/q3dinputhandler.cpp b/src/datavisualization/input/q3dinputhandler.cpp
new file mode 100644
index 00000000..5267568c
--- /dev/null
+++ b/src/datavisualization/input/q3dinputhandler.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "datavisualizationglobal_p.h"
+#include "q3dinputhandler.h"
+#include "q3dcamera_p.h"
+#include "q3dlight.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+const int minZoomLevel = 10;
+const int halfSizeZoomLevel = 50;
+const int oneToOneZoomLevel = 100;
+const int maxZoomLevel = 500;
+
+const int nearZoomRangeDivider = 12;
+const int midZoomRangeDivider = 60;
+const int farZoomRangeDivider = 120;
+
+const float rotationSpeed = 100.0f;
+
+/*!
+ * \class Q3DInputHandler
+ * \inmodule QtDataVisualization
+ * \brief Basic wheel mouse based input handler.
+ * \since 1.0.0
+ *
+ * Q3DInputHandler is the basic input handler for wheel mouse type of input devices.
+ *
+ * Default input handler has the following functionalty:
+ * \table
+ * \header
+ * \li Mouse action \li Action
+ * \row
+ * \li Right button pressed \li Rotate graph within limits set for Q3DCamera
+ * \row
+ * \li Left click \li Select item under cursor or remove selection if none
+ * \row
+ * \li Mouse wheel \li Zoom in/out within default range (10...500%)
+ * \row
+ * \li Left click on secodanry view \li Return to primary view when in slice mode
+ * \note Slice mode is available in Q3DBars and Q3DSurface only
+ * \endtable
+ */
+
+/*!
+ * Constructs the basic mouse input handler. An optional \a parent parameter can be given
+ * and is then passed to QObject constructor.
+ */
+Q3DInputHandler::Q3DInputHandler(QObject *parent) :
+ QAbstract3DInputHandler(parent)
+{
+}
+
+/*!
+ * Destroys the input handler.
+ */
+Q3DInputHandler::~Q3DInputHandler()
+{
+}
+
+// Input event listeners
+/*!
+ * Override this to change handling of mouse press events.
+ * Mouse press event is given in the \a event and the mouse position in \a mousePos.
+ */
+void Q3DInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+#if defined(Q_OS_ANDROID)
+ Q_UNUSED(event);
+ Q_UNUSED(mousePos);
+#else
+ if (Qt::LeftButton == event->button()) {
+ if (scene()->isSlicingActive()) {
+ if (scene()->isPointInPrimarySubView(mousePos)) {
+ setInputState(QDataVis::InputStateOnOverview);
+ } else if (scene()->isPointInSecondarySubView(mousePos)) {
+ setInputState(QDataVis::InputStateOnSlice);
+ } else {
+ setInputState(QDataVis::InputStateNone);
+ }
+ } else {
+ setInputState(QDataVis::InputStateOnScene);
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ setInputPosition(mousePos);
+ }
+ } else if (Qt::MiddleButton == event->button()) {
+ // reset rotations
+ setInputPosition(QPoint(0, 0));
+ } else if (Qt::RightButton == event->button()) {
+ // disable rotating when in slice view
+ if (!scene()->isSlicingActive())
+ setInputState(QDataVis::InputStateRotating);
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ setInputPosition(mousePos);
+ }
+#endif
+}
+
+/*!
+ * Override this to change handling of mouse release events.
+ * Mouse release event is given in the \a event and the mouse position in \a mousePos.
+ */
+void Q3DInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q_UNUSED(event);
+#if defined (Q_OS_ANDROID)
+ Q_UNUSED(mousePos);
+#else
+ if (QDataVis::InputStateRotating == inputState()) {
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ setInputPosition(mousePos);
+ }
+ setInputState(QDataVis::InputStateNone);
+#endif
+}
+
+/*!
+ * Override this to change handling of mouse move events.
+ * Mouse move event is given in the \a event and the mouse position in \a mousePos.
+ */
+void Q3DInputHandler::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q_UNUSED(event);
+#if defined (Q_OS_ANDROID)
+ Q_UNUSED(mousePos);
+#else
+ if (QDataVis::InputStateRotating == inputState()) {
+ // Calculate mouse movement since last frame
+ qreal xRotation = scene()->activeCamera()->xRotation();
+ qreal yRotation = scene()->activeCamera()->yRotation();
+ float mouseMoveX = float(inputPosition().x() - mousePos.x())
+ / (scene()->viewport().width() / rotationSpeed);
+ float mouseMoveY = float(inputPosition().y() - mousePos.y())
+ / (scene()->viewport().height() / rotationSpeed);
+ // Apply to rotations
+ xRotation -= mouseMoveX;
+ yRotation -= mouseMoveY;
+ scene()->activeCamera()->setXRotation(xRotation);
+ scene()->activeCamera()->setYRotation(yRotation);
+ scene()->activeCamera()->d_ptr->updateViewMatrix(1.0f);
+
+ setPreviousInputPos(inputPosition());
+ setInputPosition(mousePos);
+ }
+#endif
+}
+
+/*!
+ * Override this to change handling of wheel events.
+ * The wheel event is given in the \a event.
+ */
+void Q3DInputHandler::wheelEvent(QWheelEvent *event)
+{
+ // disable zooming if in slice view
+ if (scene()->isSlicingActive())
+ return;
+
+ // Adjust zoom level based on what zoom range we're in.
+ int zoomLevel = scene()->activeCamera()->zoomLevel();
+ if (zoomLevel > oneToOneZoomLevel)
+ zoomLevel += event->angleDelta().y() / nearZoomRangeDivider;
+ else if (zoomLevel > halfSizeZoomLevel)
+ zoomLevel += event->angleDelta().y() / midZoomRangeDivider;
+ else
+ zoomLevel += event->angleDelta().y() / farZoomRangeDivider;
+ if (zoomLevel > maxZoomLevel)
+ zoomLevel = maxZoomLevel;
+ else if (zoomLevel < minZoomLevel)
+ zoomLevel = minZoomLevel;
+
+ scene()->activeCamera()->setZoomLevel(zoomLevel);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/input/q3dinputhandler.h b/src/datavisualization/input/q3dinputhandler.h
new file mode 100644
index 00000000..a7fa0573
--- /dev/null
+++ b/src/datavisualization/input/q3dinputhandler.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QDEFAULT3DINPUTHANDLER_H
+#define QDEFAULT3DINPUTHANDLER_H
+
+#include <QtDataVisualization/qabstract3dinputhandler.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DInputHandler; // Workaround for qdoc bug, removing this will cause qdoc compiler to not find the class.
+
+class QT_DATAVISUALIZATION_EXPORT Q3DInputHandler : public QAbstract3DInputHandler
+{
+ Q_OBJECT
+
+public:
+ explicit Q3DInputHandler(QObject *parent = 0);
+ virtual ~Q3DInputHandler();
+
+ // Input event listeners
+ virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void wheelEvent(QWheelEvent *event);
+
+private:
+ Q_DISABLE_COPY(Q3DInputHandler)
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QDEFAULT3DINPUTHANDLER_H
diff --git a/src/datavisualization/input/q3dinputhandler_p.h b/src/datavisualization/input/q3dinputhandler_p.h
new file mode 100644
index 00000000..af8bef5f
--- /dev/null
+++ b/src/datavisualization/input/q3dinputhandler_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 Q3DINPUTHANDLER_P_H
+#define Q3DINPUTHANDLER_P_H
+
+#include "datavisualizationglobal_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Q3DInputHandler;
+
+class Q3DInputHandlerPrivate
+{
+public:
+ Q3DInputHandlerPrivate(Q3DInputHandler *q);
+ ~Q3DInputHandlerPrivate();
+
+public:
+ Q3DInputHandler *q_ptr;
+
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // Q3DINPUTHANDLER_P_H
diff --git a/src/datavisualization/input/qabstract3dinputhandler.cpp b/src/datavisualization/input/qabstract3dinputhandler.cpp
new file mode 100644
index 00000000..e111ff42
--- /dev/null
+++ b/src/datavisualization/input/qabstract3dinputhandler.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qabstract3dinputhandler_p.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstract3DInputHandler
+ \inmodule QtDataVisualization
+ \brief Baseclass for implementations of input handlers.
+ \since 1.0.0
+
+ QAbstract3DInputHandler is a baseclass that is subclassed by different input handling implementations
+ that take input events and translate those to camera and light movements. Input handlers also translate
+ raw input events to slicing and selection events in the scene.
+*/
+
+/*!
+ * Constructs the baseclass. An optional \a parent parameter can be given
+ * and is then passed to QObject constructor.
+ */
+QAbstract3DInputHandler::QAbstract3DInputHandler(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QAbstract3DInputHandlerPrivate(this))
+{
+}
+
+/*!
+ * Destroys the baseclass.
+ */
+QAbstract3DInputHandler::~QAbstract3DInputHandler()
+{
+}
+
+// Input event listeners
+/*!
+ * Override this to handle mouse double click events.
+ * Mouse double click event is given in the \a event.
+ */
+void QAbstract3DInputHandler::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ * Override this to handle touch input events.
+ * Touch event is given in the \a event.
+ */
+void QAbstract3DInputHandler::touchEvent(QTouchEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ * Override this to handle mouse press events.
+ * Mouse press event is given in the \a event and the mouse position in \a mousePos.
+ */
+void QAbstract3DInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(mousePos);
+}
+
+/*!
+ * Override this to handle mouse release events.
+ * Mouse release event is given in the \a event and the mouse position in \a mousePos.
+ */
+void QAbstract3DInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(mousePos);
+}
+
+/*!
+ * Override this to handle mouse move events.
+ * Mouse move event is given in the \a event and the mouse position in \a mousePos.
+ */
+void QAbstract3DInputHandler::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(mousePos);
+}
+
+/*!
+ * Override this to handle wheel events.
+ * Wheel event is given in the \a event.
+ */
+void QAbstract3DInputHandler::wheelEvent(QWheelEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+// Property get/set
+/*!
+ * \property QAbstract3DInputHandler::inputState
+ *
+ * Current enumerated input state based on the processed input events.
+ * When the state changes inputStateChanged() is emitted.
+ */
+QDataVis::InputState QAbstract3DInputHandler::inputState()
+{
+ return d_ptr->m_inputState;
+}
+
+void QAbstract3DInputHandler::setInputState(QDataVis::InputState inputState)
+{
+ if (inputState != d_ptr->m_inputState) {
+ d_ptr->m_inputState = inputState;
+ emit inputStateChanged(inputState);
+ }
+}
+
+/*!
+ * \property QAbstract3DInputHandler::inputPosition
+ *
+ * Last input position based on the processed input events.
+ */
+QPoint QAbstract3DInputHandler::inputPosition() const
+{
+ return d_ptr->m_inputPosition;
+}
+
+void QAbstract3DInputHandler::setInputPosition(const QPoint &position)
+{
+ if (position != d_ptr->m_inputPosition) {
+ d_ptr->m_inputPosition = position;
+ emit positionChanged(position);
+ }
+}
+
+/*!
+ * \return the manhattan length between last two input positions.
+ */
+int QAbstract3DInputHandler::prevDistance() const
+{
+ return d_ptr->m_prevDistance;
+}
+
+/*!
+ * Sets the \a distance (manhattan length) between last two input positions.
+ */
+void QAbstract3DInputHandler::setPrevDistance(int distance)
+{
+ d_ptr->m_prevDistance = distance;
+}
+
+/*!
+ * \property QAbstract3DInputHandler::scene
+ *
+ * The 3D scene this abstract inputhandler is controlling. Only one scene can be controlled by one input handler.
+ */
+Q3DScene *QAbstract3DInputHandler::scene() const
+{
+ return d_ptr->m_scene;
+}
+
+void QAbstract3DInputHandler::setScene(Q3DScene *scene)
+{
+ d_ptr->m_scene = scene;
+}
+
+/*!
+ * Sets the previous input position to the point given by \a position.
+ */
+void QAbstract3DInputHandler::setPreviousInputPos(const QPoint &position)
+{
+ d_ptr->m_previousInputPos = position;
+}
+
+/*!
+ * Returns the previous input position.
+ * \return Previous input position.
+ */
+QPoint QAbstract3DInputHandler::previousInputPos() const
+{
+ return d_ptr->m_previousInputPos;
+}
+
+
+QAbstract3DInputHandlerPrivate::QAbstract3DInputHandlerPrivate(QAbstract3DInputHandler *q) :
+ q_ptr(q),
+ m_prevDistance(0),
+ m_previousInputPos(QPoint(0,0)),
+ m_inputState(QDataVis::InputStateNone),
+ m_inputPosition(QPoint(0,0)),
+ m_scene(0)
+{
+}
+
+QAbstract3DInputHandlerPrivate::~QAbstract3DInputHandlerPrivate()
+{
+
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/input/qabstract3dinputhandler.h b/src/datavisualization/input/qabstract3dinputhandler.h
new file mode 100644
index 00000000..d7bf3aee
--- /dev/null
+++ b/src/datavisualization/input/qabstract3dinputhandler.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QABSTRACT3DINPUTHANDLER_H
+#define QABSTRACT3DINPUTHANDLER_H
+
+#include <QtDataVisualization/qdatavisualizationenums.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QMouseEvent>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstract3DInputHandlerPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QAbstract3DInputHandler : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QtDataVisualization::QDataVis::InputState inputState READ inputState WRITE setInputState NOTIFY inputStateChanged)
+ Q_PROPERTY(QPoint inputPosition READ inputPosition WRITE setInputPosition NOTIFY positionChanged)
+ Q_PROPERTY(Q3DScene *scene READ scene WRITE setScene NOTIFY sceneChanged)
+
+public:
+ explicit QAbstract3DInputHandler(QObject *parent = 0);
+ virtual ~QAbstract3DInputHandler();
+
+ // Input event listeners
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+ virtual void touchEvent(QTouchEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void wheelEvent(QWheelEvent *event);
+
+public:
+ // TODO: Check if the inputState needs to be visible outside of subclasses in the final architecture
+ QDataVis::InputState inputState();
+ void setInputState(QDataVis::InputState inputState);
+
+ QPoint inputPosition() const;
+ void setInputPosition(const QPoint &position);
+
+ Q3DScene *scene() const;
+ void setScene(Q3DScene *scene);
+
+signals:
+ void positionChanged(const QPoint &position);
+ void inputStateChanged(QDataVis::InputState state);
+ void sceneChanged(const Q3DScene *scene);
+
+protected:
+ void setPrevDistance(int distance);
+ int prevDistance() const;
+ void setPreviousInputPos(const QPoint &position);
+ QPoint previousInputPos() const;
+
+private:
+ Q_DISABLE_COPY(QAbstract3DInputHandler)
+
+ QScopedPointer<QAbstract3DInputHandlerPrivate> d_ptr;
+
+ friend class Abstract3DController;
+ friend class QTouch3DInputHandlerPrivate;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACT3DINPUTHANDLER_H
diff --git a/src/datavisualization/input/qabstract3dinputhandler_p.h b/src/datavisualization/input/qabstract3dinputhandler_p.h
new file mode 100644
index 00000000..cad1c667
--- /dev/null
+++ b/src/datavisualization/input/qabstract3dinputhandler_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QABSTRACT3DINPUTHANDLER_P_H
+#define QABSTRACT3DINPUTHANDLER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qabstract3dinputhandler.h"
+#include <QRect>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstract3DInputHandler;
+class Q3DScene;
+
+class QAbstract3DInputHandlerPrivate
+{
+public:
+ QAbstract3DInputHandlerPrivate(QAbstract3DInputHandler *q);
+ ~QAbstract3DInputHandlerPrivate();
+
+public:
+ QAbstract3DInputHandler *q_ptr;
+ int m_prevDistance;
+ QPoint m_previousInputPos;
+
+ GLfloat m_defaultXRotation;
+ GLfloat m_defaultYRotation;
+
+private:
+ QDataVis::InputState m_inputState;
+ QPoint m_inputPosition;
+ QRect m_mainViewPort;
+
+ // TODO: Check if this could be avoided with signals/slots or some other way.
+ Q3DScene *m_scene;
+ bool m_isDefaultHandler;
+
+ friend class QAbstract3DInputHandler;
+ friend class Abstract3DController;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QABSTRACT3DINPUTHANDLER_P_H
diff --git a/src/datavisualization/input/qtouch3dinputhandler.cpp b/src/datavisualization/input/qtouch3dinputhandler.cpp
new file mode 100644
index 00000000..fd079e88
--- /dev/null
+++ b/src/datavisualization/input/qtouch3dinputhandler.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qtouch3dinputhandler_p.h"
+#include "q3dcamera_p.h"
+#include <QTimer>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+const qreal maxTapAndHoldJitter = 20;
+const int maxPinchJitter = 10;
+#if defined (Q_OS_ANDROID)
+const int maxSelectionJitter = 10;
+#else
+const int maxSelectionJitter = 5;
+#endif
+const int tapAndHoldTime = 250;
+const float rotationSpeed = 200.0f;
+const int minZoomLevel = 10;
+const int maxZoomLevel = 500;
+
+/*!
+ * \class QTouch3DInputHandler
+ * \inmodule QtDataVisualization
+ * \brief Basic touch display based input handler.
+ * \since 1.0.0
+ *
+ * QTouch3DInputHandler is the basic input handler for touch screen devices.
+ *
+ * Default touch input handler has the following functionalty:
+ * \table
+ * \header
+ * \li Gesture \li Action
+ * \row
+ * \li Touch-And-Move \li Rotate graph within limits set for Q3DCamera
+ * \row
+ * \li Tap \li Select item under pointer or remove selection if none
+ * \row
+ * \li Tap-And-Hold \li Select item under pointer or remove selection if none
+ * \row
+ * \li Pinch \li Zoom in/out within default range (10...500%)
+ * \row
+ * \li Tap on secondary view \li Return to primary view when in slice mode
+ * \note Slice mode is available in Q3DBars and Q3DSurface only
+ * \endtable
+ */
+
+/*!
+ * Constructs the basic touch display input handler. An optional \a parent parameter can be given
+ * and is then passed to QObject constructor.
+ */
+QTouch3DInputHandler::QTouch3DInputHandler(QObject *parent)
+ : Q3DInputHandler(parent),
+ d_ptr(new QTouch3DInputHandlerPrivate(this))
+{
+}
+
+/*!
+ * Destroys the input handler.
+ */
+QTouch3DInputHandler::~QTouch3DInputHandler()
+{
+}
+
+/*!
+ * Override this to change handling of touch events.
+ * Touch event is given in the \a event.
+ */
+void QTouch3DInputHandler::touchEvent(QTouchEvent *event)
+{
+ QList<QTouchEvent::TouchPoint> points;
+ points = event->touchPoints();
+
+ if (!scene()->isSlicingActive() && points.count() == 2) {
+ d_ptr->m_holdTimer->stop();
+ QPointF distance = points.at(0).pos() - points.at(1).pos();
+ d_ptr->handlePinchZoom(distance.manhattanLength());
+ } else if (points.count() == 1) {
+ QPointF pointerPos = points.at(0).pos();
+ if (event->type() == QEvent::TouchBegin) {
+ if (scene()->isSlicingActive()) {
+ if (scene()->isPointInPrimarySubView(pointerPos.toPoint()))
+ setInputState(QDataVis::InputStateOnOverview);
+ else if (scene()->isPointInSecondarySubView(pointerPos.toPoint()))
+ setInputState(QDataVis::InputStateOnSlice);
+ else
+ setInputState(QDataVis::InputStateNone);
+ } else {
+ // Handle possible tap-and-hold selection
+ d_ptr->m_startHoldPos = pointerPos;
+ d_ptr->m_touchHoldPos = d_ptr->m_startHoldPos;
+ d_ptr->m_holdTimer->start();
+ // Start rotating
+ setInputState(QDataVis::InputStateRotating);
+ setInputPosition(pointerPos.toPoint());
+ }
+ } else if (event->type() == QEvent::TouchEnd) {
+ d_ptr->m_holdTimer->stop();
+ // Handle possible selection
+ d_ptr->handleSelection(pointerPos);
+ } else if (event->type() == QEvent::TouchUpdate) {
+ if (!scene()->isSlicingActive()) {
+ d_ptr->m_touchHoldPos = pointerPos;
+ // Handle rotation
+ d_ptr->handleRotation(pointerPos);
+ }
+ }
+ } else {
+ d_ptr->m_holdTimer->stop();
+ }
+}
+
+QTouch3DInputHandlerPrivate::QTouch3DInputHandlerPrivate(QTouch3DInputHandler *q)
+ : q_ptr(q),
+ m_holdTimer(0)
+{
+ m_holdTimer = new QTimer();
+ m_holdTimer->setSingleShot(true);
+ m_holdTimer->setInterval(tapAndHoldTime);
+ connect(m_holdTimer, &QTimer::timeout, this, &QTouch3DInputHandlerPrivate::handleTapAndHold);
+}
+
+QTouch3DInputHandlerPrivate::~QTouch3DInputHandlerPrivate()
+{
+ m_holdTimer->stop();
+ delete m_holdTimer;
+}
+
+void QTouch3DInputHandlerPrivate::handlePinchZoom(qreal distance)
+{
+ int newDistance = distance;
+ int prevDist = q_ptr->prevDistance();
+ if (prevDist > 0 && qAbs(prevDist - newDistance) < maxPinchJitter)
+ return;
+ q_ptr->setInputState(QDataVis::InputStateOnPinch);
+ Q3DCamera *camera = q_ptr->scene()->activeCamera();
+ int zoomLevel = camera->zoomLevel();
+ qreal zoomRate = qSqrt(qSqrt(zoomLevel));
+ if (newDistance > prevDist)
+ zoomLevel += zoomRate;
+ else
+ zoomLevel -= zoomRate;
+ if (zoomLevel > maxZoomLevel)
+ zoomLevel = maxZoomLevel;
+ else if (zoomLevel < minZoomLevel)
+ zoomLevel = minZoomLevel;
+ camera->setZoomLevel(zoomLevel);
+ q_ptr->setPrevDistance(newDistance);
+}
+
+void QTouch3DInputHandlerPrivate::handleTapAndHold()
+{
+ QPointF distance = m_startHoldPos - m_touchHoldPos;
+ if (distance.manhattanLength() < maxTapAndHoldJitter) {
+ q_ptr->setInputPosition(m_touchHoldPos.toPoint());
+ q_ptr->setInputState(QDataVis::InputStateOnScene);
+ }
+}
+
+void QTouch3DInputHandlerPrivate::handleSelection(const QPointF &position)
+{
+ QPointF distance = m_startHoldPos - position;
+ if (distance.manhattanLength() < maxSelectionJitter)
+ q_ptr->setInputState(QDataVis::InputStateOnScene);
+ else
+ q_ptr->setInputState(QDataVis::InputStateNone);
+ q_ptr->setPreviousInputPos(position.toPoint());
+}
+
+void QTouch3DInputHandlerPrivate::handleRotation(const QPointF &position)
+{
+ if (QDataVis::InputStateRotating == q_ptr->inputState()) {
+ Q3DScene *scene = q_ptr->scene();
+ Q3DCamera *camera = scene->activeCamera();
+ float xRotation = camera->xRotation();
+ float yRotation = camera->yRotation();
+ QPointF inputPos = q_ptr->inputPosition();
+ float mouseMoveX = float(inputPos.x() - position.x())
+ / (scene->viewport().width() / rotationSpeed);
+ float mouseMoveY = float(inputPos.y() - position.y())
+ / (scene->viewport().height() / rotationSpeed);
+ xRotation -= mouseMoveX;
+ yRotation -= mouseMoveY;
+ camera->setXRotation(xRotation);
+ camera->setYRotation(yRotation);
+ camera->d_ptr->updateViewMatrix(1.0f);
+
+ q_ptr->setPreviousInputPos(inputPos.toPoint());
+ q_ptr->setInputPosition(position.toPoint());
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/input/qtouch3dinputhandler.h b/src/datavisualization/input/qtouch3dinputhandler.h
new file mode 100644
index 00000000..1c366926
--- /dev/null
+++ b/src/datavisualization/input/qtouch3dinputhandler.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QTOUCH3DINPUTHANDLER_H
+#define QTOUCH3DINPUTHANDLER_H
+
+#include <QtDataVisualization/q3dinputhandler.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QTouch3DInputHandlerPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QTouch3DInputHandler : public Q3DInputHandler
+{
+ Q_OBJECT
+
+public:
+ explicit QTouch3DInputHandler(QObject *parent = 0);
+ virtual ~QTouch3DInputHandler();
+
+ // Input event listeners
+ virtual void touchEvent(QTouchEvent *event);
+
+private:
+ Q_DISABLE_COPY(QTouch3DInputHandler)
+
+ QScopedPointer<QTouch3DInputHandlerPrivate> d_ptr;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QTOUCH3DINPUTHANDLER_H
diff --git a/src/datavisualization/input/qtouch3dinputhandler_p.h b/src/datavisualization/input/qtouch3dinputhandler_p.h
new file mode 100644
index 00000000..1c5b81c7
--- /dev/null
+++ b/src/datavisualization/input/qtouch3dinputhandler_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QTOUCH3DINPUTHANDLER_P_H
+#define QTOUCH3DINPUTHANDLER_P_H
+
+#include "qtouch3dinputhandler.h"
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class QAbstract3DInputHandler;
+
+class QTouch3DInputHandlerPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QTouch3DInputHandlerPrivate(QTouch3DInputHandler *q);
+ ~QTouch3DInputHandlerPrivate();
+
+ void handlePinchZoom(qreal distance);
+ void handleTapAndHold();
+ void handleSelection(const QPointF &position);
+ void handleRotation(const QPointF &position);
+
+public:
+ QTouch3DInputHandler *q_ptr;
+ QTimer *m_holdTimer;
+ QPointF m_startHoldPos;
+ QPointF m_touchHoldPos;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // QTOUCH3DINPUTHANDLER_H
diff --git a/src/datavisualization/utils/abstractobjecthelper.cpp b/src/datavisualization/utils/abstractobjecthelper.cpp
new file mode 100644
index 00000000..d47f2fe6
--- /dev/null
+++ b/src/datavisualization/utils/abstractobjecthelper.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstractobjecthelper_p.h"
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+AbstractObjectHelper::AbstractObjectHelper()
+ : m_vertexbuffer(0),
+ m_normalbuffer(0),
+ m_uvbuffer(0),
+ m_elementbuffer(0),
+ m_indexCount(0),
+ m_meshDataLoaded(false)
+{
+}
+
+AbstractObjectHelper::~AbstractObjectHelper()
+{
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+}
+
+GLuint AbstractObjectHelper::vertexBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_vertexbuffer;
+}
+
+GLuint AbstractObjectHelper::normalBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_normalbuffer;
+}
+
+GLuint AbstractObjectHelper::uvBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_uvbuffer;
+}
+
+GLuint AbstractObjectHelper::elementBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_elementbuffer;
+}
+
+GLuint AbstractObjectHelper::indexCount()
+{
+ return m_indexCount;
+}
+
+GLuint AbstractObjectHelper::indicesType()
+{
+ return m_indicesType;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/abstractobjecthelper_p.h b/src/datavisualization/utils/abstractobjecthelper_p.h
new file mode 100644
index 00000000..a6de6941
--- /dev/null
+++ b/src/datavisualization/utils/abstractobjecthelper_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 ABSTRACTOBJECTHELPER_H
+#define ABSTRACTOBJECTHELPER_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class AbstractObjectHelper: protected QOpenGLFunctions
+{
+protected:
+ AbstractObjectHelper();
+public:
+ ~AbstractObjectHelper();
+
+ GLuint vertexBuf();
+ GLuint normalBuf();
+ GLuint uvBuf();
+ GLuint elementBuf();
+ GLuint indexCount();
+ GLuint indicesType();
+
+public:
+ GLuint m_vertexbuffer;
+ GLuint m_normalbuffer;
+ GLuint m_uvbuffer;
+ GLuint m_elementbuffer;
+
+ GLuint m_indexCount;
+ GLboolean m_meshDataLoaded;
+
+ GLuint m_indicesType;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // ABSTRACTOBJECTHELPER_H
diff --git a/src/datavisualization/utils/camerahelper.cpp b/src/datavisualization/utils/camerahelper.cpp
new file mode 100644
index 00000000..29ed4d57
--- /dev/null
+++ b/src/datavisualization/utils/camerahelper.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "camerahelper_p.h"
+
+#include <qmath.h>
+#include <QMatrix4x4>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+CameraHelper::CameraHelper(QObject *parent) :
+ QObject(parent),
+ m_position(0, 0.25, 3),
+ m_target(0, 0, 0),
+ m_up(0, 1, 0),
+ m_previousMousePos(0,0),
+ m_xRotation(0),
+ m_yRotation(0),
+ m_defaultXRotation(0),
+ m_defaultYRotation(0),
+ m_rotationSpeed(100)
+{
+}
+
+CameraHelper::~CameraHelper()
+{
+}
+
+
+// FUNCTIONS
+void CameraHelper::setRotationSpeed(int speed)
+{
+ // increase for faster rotation
+ m_rotationSpeed = speed;
+}
+
+void CameraHelper::setCameraRotation(const QPointF &rotation)
+{
+ m_xRotation = rotation.x();
+ m_defaultXRotation = m_xRotation;
+ m_yRotation = rotation.y();
+ m_defaultYRotation = m_yRotation;
+}
+
+void CameraHelper::setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp)
+{
+ m_position = defaultPosition;
+ m_target = defaultTarget;
+ m_up = defaultUp;
+}
+
+QMatrix4x4 CameraHelper::calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight, bool showUnder)
+{
+ QMatrix4x4 viewMatrix;
+ GLfloat lowerLimit = 0.0f;
+
+ if (showUnder)
+ lowerLimit = -90.0f;
+
+ // Calculate mouse movement since last frame
+ GLfloat mouseMoveX = GLfloat(m_previousMousePos.x() - mousePos.x())
+ / (screenWidth / m_rotationSpeed);
+ GLfloat mouseMoveY = GLfloat(m_previousMousePos.y() - mousePos.y())
+ / (screenHeight / m_rotationSpeed);
+ // Apply to rotations
+ m_xRotation -= mouseMoveX;
+ m_yRotation -= mouseMoveY;
+ // Reset at 360 in x and limit to 0...90 in y
+ if (qAbs(m_xRotation) >= 360.0f)
+ m_xRotation = 0.0f;
+ if (m_yRotation >= 90.0f)
+ m_yRotation = 90.0f;
+ else if (m_yRotation <= lowerLimit)
+ m_yRotation = lowerLimit;
+
+ // Apply to view matrix
+ viewMatrix.lookAt(m_position, m_target, m_up);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(m_target.x(), m_target.y(), m_target.z());
+ // Apply rotations
+ // Handle x and z rotation when y -angle is other than 0
+ viewMatrix.rotate(m_xRotation, 0, qCos(qDegreesToRadians(m_yRotation)),
+ qSin(qDegreesToRadians(m_yRotation)));
+ // y rotation is always "clean"
+ viewMatrix.rotate(m_yRotation, 1.0f, 0.0f, 0.0f);
+ // handle zoom by scaling
+ viewMatrix.scale((GLfloat)zoom / 100.0f);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(-m_target.x(), -m_target.y(), -m_target.z());
+ //qDebug() << m_xRotation << m_yRotation;
+
+ m_previousMousePos = mousePos;
+ return viewMatrix;
+}
+
+QVector3D CameraHelper::calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation, GLfloat distanceModifier)
+{
+ // Move light with camera
+ QVector3D newLightPosition;
+ GLfloat radiusFactor = lightPosition.z() * (1.5f + distanceModifier); // for making sure light is outside the scene at its lowest point
+ GLfloat xAngle;
+ GLfloat yAngle;
+ if (!fixedRotation) {
+ xAngle = qDegreesToRadians(m_xRotation);
+ yAngle = qDegreesToRadians(m_yRotation);
+ } else {
+ xAngle = qDegreesToRadians(fixedRotation);
+ yAngle = 0;
+ }
+ GLfloat radius = (radiusFactor + lightPosition.y()); // set radius to match the highest height of the light
+ GLfloat zPos = radius * qCos(xAngle) * qCos(yAngle);
+ GLfloat xPos = radius * qSin(xAngle) * qCos(yAngle);
+ GLfloat yPos = (radiusFactor + lightPosition.y()) * qSin(yAngle);
+ // Keep light in the set position in relation to camera
+ newLightPosition = QVector3D(-xPos + lightPosition.x(),
+ yPos + lightPosition.y(),
+ zPos + lightPosition.z());
+ //qDebug() << newLightPosition << xAngle << yAngle << fixedRotation;
+ return newLightPosition;
+}
+
+void CameraHelper::updateMousePos(const QPoint &mousePos)
+{
+ m_previousMousePos = mousePos;
+ // if mouse position is set to (0, 0), reset rotations
+ if (QPoint(0, 0) == mousePos) {
+ m_xRotation = m_defaultXRotation;
+ m_yRotation = m_defaultYRotation;
+ }
+}
+
+QPointF CameraHelper::getCameraRotations()
+{
+ QPointF rotations(m_xRotation, m_yRotation);
+ return rotations;
+}
+
+void CameraHelper::setCameraPreset(QDataVis::CameraPreset preset)
+{
+ switch (preset) {
+ case QDataVis::CameraPresetFrontLow: {
+ qDebug("CameraPresetFrontLow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 0.0f));
+ break;
+ }
+ case QDataVis::CameraPresetFront: {
+ qDebug("CameraPresetFront");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetFrontHigh: {
+ qDebug("CameraPresetFrontHigh");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetLeftLow: {
+ qDebug("CameraPresetLeftLow");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 0.0f));
+ break;
+ }
+ case QDataVis::CameraPresetLeft: {
+ qDebug("CameraPresetLeft");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetLeftHigh: {
+ qDebug("CameraPresetLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetRightLow: {
+ qDebug("CameraPresetRightLow");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 0.0f));
+ break;
+ }
+ case QDataVis::CameraPresetRight: {
+ qDebug("CameraPresetRight");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetRightHigh: {
+ qDebug("CameraPresetRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetBehindLow: {
+ qDebug("CameraPresetBehindLow");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 0.0f));
+ break;
+ }
+ case QDataVis::CameraPresetBehind: {
+ qDebug("CameraPresetBehind");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetBehindHigh: {
+ qDebug("CameraPresetBehindHigh");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetIsometricLeft: {
+ qDebug("CameraPresetIsometricLeft");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetIsometricLeftHigh: {
+ qDebug("CameraPresetIsometricLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetIsometricRight: {
+ qDebug("CameraPresetIsometricRight");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 22.5f));
+ break;
+ }
+ case QDataVis::CameraPresetIsometricRightHigh: {
+ qDebug("CameraPresetIsometricRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAbove: {
+ qDebug("CameraPresetDirectlyAbove");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 90.0f));
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAboveCW45: {
+ qDebug("CameraPresetDirectlyAboveCW45");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 90.0f));
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyAboveCCW45: {
+ qDebug("CameraPresetDirectlyAboveCCW45");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 90.0f));
+ break;
+ }
+ case QDataVis::CameraPresetFrontBelow: {
+ qDebug("CameraPresetFrontBelow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, -45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetLeftBelow: {
+ qDebug("CameraPresetLeftBelow");
+ CameraHelper::setCameraRotation(QPointF(90.0f, -45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetRightBelow: {
+ qDebug("CameraPresetRightBelow");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, -45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetBehindBelow: {
+ qDebug("CameraPresetBehindBelow");
+ CameraHelper::setCameraRotation(QPointF(180.0f, -45.0f));
+ break;
+ }
+ case QDataVis::CameraPresetDirectlyBelow: {
+ qDebug("CameraPresetDirectlyBelow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, -90.0f));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/camerahelper_p.h b/src/datavisualization/utils/camerahelper_p.h
new file mode 100644
index 00000000..1ef4d257
--- /dev/null
+++ b/src/datavisualization/utils/camerahelper_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 CAMERAPOSITIONER_P_H
+#define CAMERAPOSITIONER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+#include <QObject>
+
+class QMatrix4x4;
+class QVector3D;
+class QPoint;
+class QPointF;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class CameraHelper : public QObject
+{
+ Q_OBJECT
+
+private:
+ QVector3D m_position;
+ QVector3D m_target;
+ QVector3D m_up;
+
+ QPoint m_previousMousePos;
+
+ GLfloat m_xRotation;
+ GLfloat m_yRotation;
+ GLfloat m_defaultXRotation;
+ GLfloat m_defaultYRotation;
+
+ GLfloat m_rotationSpeed;
+
+public:
+ explicit CameraHelper(QObject *parent = 0);
+ ~CameraHelper();
+
+ // How fast camera rotates when mouse is dragged. Default is 100.
+ void setRotationSpeed(int speed);
+ // Set camera rotation in degrees
+ void setCameraRotation(const QPointF &rotation);
+ // Get camera rotations
+ QPointF getCameraRotations();
+ // Set default camera orientation. Position's x and y should be 0.
+ void setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp);
+ // Calculate view matrix based on rotation and zoom
+ QMatrix4x4 calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight,
+ bool showUnder = false);
+ // Calcluate light position based on rotation. Call after calling calculateViewMatrix to get
+ // up-to-date position
+ QVector3D calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation = 0.0f,
+ GLfloat distanceModifier = 0.0f);
+ void updateMousePos(const QPoint &mousePos);
+ void setCameraPreset(QDataVis::CameraPreset preset);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/meshloader.cpp b/src/datavisualization/utils/meshloader.cpp
new file mode 100644
index 00000000..119cde3a
--- /dev/null
+++ b/src/datavisualization/utils/meshloader.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "meshloader_p.h"
+
+#include <QFile>
+#include <QStringList>
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+QString slashTag = QStringLiteral("/");
+
+bool MeshLoader::loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ //qDebug() << "Loading OBJ file" << path;
+
+ QVector<unsigned int> vertexIndices, uvIndices, normalIndices;
+ QVector<QVector3D> temp_vertices;
+ QVector<QVector2D> temp_uvs;
+ QVector<QVector3D> temp_normals;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning("Cannot open the file");
+ return false;
+ }
+
+ QTextStream textIn(&file);
+ while (!textIn.atEnd()) {
+ QString line = textIn.readLine();
+ QStringList lineContents = line.split(QStringLiteral(" "));
+ if (!lineContents.at(0).compare(QStringLiteral("v"))) {
+ QVector3D vertex;
+ vertex.setX(lineContents.at(1).toFloat());
+ vertex.setY(lineContents.at(2).toFloat());
+ vertex.setZ(lineContents.at(3).toFloat());
+ temp_vertices.append(vertex);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vt"))) {
+ QVector2D uv;
+ uv.setX(lineContents.at(1).toFloat());
+ uv.setY(lineContents.at(2).toFloat()); // invert this if using DDS textures
+ temp_uvs.append(uv);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vn"))) {
+ QVector3D normal;
+ normal.setX(lineContents.at(1).toFloat());
+ normal.setY(lineContents.at(2).toFloat());
+ normal.setZ(lineContents.at(3).toFloat());
+ temp_normals.append(normal);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("f"))) {
+ unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
+ QStringList set1 = lineContents.at(1).split(slashTag);
+ QStringList set2 = lineContents.at(2).split(slashTag);
+ QStringList set3 = lineContents.at(3).split(slashTag);
+ vertexIndex[0] = set1.at(0).toUInt();
+ vertexIndex[1] = set2.at(0).toUInt();
+ vertexIndex[2] = set3.at(0).toUInt();
+ uvIndex[0] = set1.at(1).toUInt();
+ uvIndex[1] = set2.at(1).toUInt();
+ uvIndex[2] = set3.at(1).toUInt();
+ normalIndex[0] = set1.at(2).toUInt();
+ normalIndex[1] = set2.at(2).toUInt();
+ normalIndex[2] = set3.at(2).toUInt();
+ vertexIndices.append(vertexIndex[0]);
+ vertexIndices.append(vertexIndex[1]);
+ vertexIndices.append(vertexIndex[2]);
+ uvIndices.append(uvIndex[0]);
+ uvIndices.append(uvIndex[1]);
+ uvIndices.append(uvIndex[2]);
+ normalIndices.append(normalIndex[0]);
+ normalIndices.append(normalIndex[1]);
+ normalIndices.append(normalIndex[2]);
+ }
+ else {
+ //qWarning("Line did not contain usable data");
+ }
+ }
+
+ // For each vertex of each triangle
+ for (int i = 0; i < vertexIndices.size(); i++) {
+ // Get the indices of its attributes
+ unsigned int vertexIndex = vertexIndices[i];
+ unsigned int uvIndex = uvIndices[i];
+ unsigned int normalIndex = normalIndices[i];
+
+ // Get the attributes thanks to the index
+ QVector3D vertex = temp_vertices[vertexIndex - 1];
+ QVector2D uv = temp_uvs[uvIndex - 1];
+ QVector3D normal = temp_normals[normalIndex - 1];
+
+ // Put the attributes in buffers
+ out_vertices.append(vertex);
+ out_uvs.append(uv);
+ out_normals.append(normal);
+ }
+
+ return true;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/meshloader_p.h b/src/datavisualization/utils/meshloader_p.h
new file mode 100644
index 00000000..48551fff
--- /dev/null
+++ b/src/datavisualization/utils/meshloader_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 MESHLOADER_P_H
+#define MESHLOADER_P_H
+
+#include "datavisualizationglobal_p.h"
+
+class QVector2D;
+class QVector3D;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class MeshLoader
+{
+ public:
+ static bool loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+ // TODO: add loaders for other formats?
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/objecthelper.cpp b/src/datavisualization/utils/objecthelper.cpp
new file mode 100644
index 00000000..9660c215
--- /dev/null
+++ b/src/datavisualization/utils/objecthelper.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "meshloader_p.h"
+#include "vertexindexer_p.h"
+#include "objecthelper_p.h"
+#include "abstractobjecthelper_p.h"
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ObjectHelper::ObjectHelper(const QString &objectFile)
+ : m_objectFile(objectFile)
+{
+ m_indicesType = GL_UNSIGNED_SHORT;
+}
+
+ObjectHelper::~ObjectHelper()
+{
+}
+
+void ObjectHelper::setObjectFile(const QString &objectFile)
+{
+ m_objectFile = objectFile;
+}
+
+void ObjectHelper::load()
+{
+ initializeOpenGLFunctions();
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+ }
+ QVector<QVector3D> vertices;
+ QVector<QVector2D> uvs;
+ QVector<QVector3D> normals;
+ bool loadOk = MeshLoader::loadOBJ(m_objectFile, vertices, uvs, normals);
+ if (!loadOk)
+ qFatal("loading failed");
+
+ //qDebug() << "vertex count" << vertices.size();;
+
+ // Index vertices
+ QVector<unsigned short> indices;
+ QVector<QVector3D> indexed_vertices;
+ QVector<QVector2D> indexed_uvs;
+ QVector<QVector3D> indexed_normals;
+ VertexIndexer::indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs,
+ indexed_normals);
+
+ m_indexCount = indices.size();
+ //qDebug() << "index count" << m_indexCount;
+
+ glGenBuffers(1, &m_vertexbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(QVector3D),
+ &indexed_vertices.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_normalbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(QVector3D),
+ &indexed_normals.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_uvbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(QVector2D),
+ &indexed_uvs.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_elementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short),
+ &indices.at(0), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/objecthelper_p.h b/src/datavisualization/utils/objecthelper_p.h
new file mode 100644
index 00000000..9d643fdd
--- /dev/null
+++ b/src/datavisualization/utils/objecthelper_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 OBJECTHELPER_P_H
+#define OBJECTHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include <QOpenGLFunctions>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ObjectHelper : public AbstractObjectHelper
+{
+public:
+ ObjectHelper(const QString &objectFile = QString());
+ ~ObjectHelper();
+
+ void setObjectFile(const QString &objectFile);
+
+ void load();
+
+private:
+ QString m_objectFile;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp
new file mode 100644
index 00000000..7df1736c
--- /dev/null
+++ b/src/datavisualization/utils/shaderhelper.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "shaderhelper_p.h"
+
+#include <QOpenGLShader>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ShaderHelper::ShaderHelper(QObject *parent,
+ const QString &vertexShader,
+ const QString &fragmentShader,
+ const QString &texture,
+ const QString &depthTexture)
+ : m_caller(parent),
+ m_program(0),
+ m_vertexShaderFile(vertexShader),
+ m_fragmentShaderFile(fragmentShader),
+ m_textureFile(texture),
+ m_depthTextureFile(depthTexture)
+{
+}
+
+ShaderHelper::~ShaderHelper()
+{
+ delete m_program;
+}
+
+void ShaderHelper::setShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ m_vertexShaderFile = vertexShader;
+ m_fragmentShaderFile = fragmentShader;
+}
+
+void ShaderHelper::setTextures(const QString &texture,
+ const QString &depthTexture)
+{
+ m_textureFile = texture;
+ m_depthTextureFile = depthTexture;
+}
+
+void ShaderHelper::initialize()
+{
+ if (m_program)
+ delete m_program;
+ m_program = new QOpenGLShaderProgram(m_caller);
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, m_vertexShaderFile))
+ qFatal("Compiling Vertex shader failed");
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, m_fragmentShaderFile))
+ qFatal("Compiling Fragment shader failed");
+ m_program->link();
+
+ m_positionAttr = m_program->attributeLocation("vertexPosition_mdl");
+ m_normalAttr = m_program->attributeLocation("vertexNormal_mdl");
+ m_uvAttr = m_program->attributeLocation("vertexUV");
+
+ m_mvpMatrixUniform = m_program->uniformLocation("MVP");
+ m_viewMatrixUniform = m_program->uniformLocation("V");
+ m_modelMatrixUniform = m_program->uniformLocation("M");
+ m_invTransModelMatrixUniform = m_program->uniformLocation("itM");
+ m_depthMatrixUniform = m_program->uniformLocation("depthMVP");
+ m_lightPositionUniform = m_program->uniformLocation("lightPosition_wrld");
+ m_lightStrengthUniform = m_program->uniformLocation("lightStrength");
+ m_ambientStrengthUniform = m_program->uniformLocation("ambientStrength");
+ m_shadowQualityUniform = m_program->uniformLocation("shadowQuality");
+ m_colorUniform = m_program->uniformLocation("color_mdl");
+ m_textureUniform = m_program->uniformLocation("textureSampler");
+ m_shadowUniform = m_program->uniformLocation("shadowMap");
+
+ m_initialized = true;
+}
+
+bool ShaderHelper::testCompile()
+{
+ if (m_program)
+ delete m_program;
+ m_program = new QOpenGLShaderProgram(m_caller);
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, m_vertexShaderFile))
+ return false;
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, m_fragmentShaderFile))
+ return false;
+ return true;
+}
+
+void ShaderHelper::bind()
+{
+ m_program->bind();
+}
+
+void ShaderHelper::release()
+{
+ m_program->release();
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector3D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector4D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QMatrix4x4 &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLfloat value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLint value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+GLuint ShaderHelper::MVP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_mvpMatrixUniform;
+}
+
+GLuint ShaderHelper::view()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_viewMatrixUniform;
+}
+
+GLuint ShaderHelper::model()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_modelMatrixUniform;
+}
+
+GLuint ShaderHelper::nModel()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_invTransModelMatrixUniform;
+}
+
+GLuint ShaderHelper::depth()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_depthMatrixUniform;
+}
+
+GLuint ShaderHelper::lightP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightPositionUniform;
+}
+
+GLuint ShaderHelper::lightS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightStrengthUniform;
+}
+
+GLuint ShaderHelper::ambientS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_ambientStrengthUniform;
+}
+
+GLuint ShaderHelper::shadowQ()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowQualityUniform;
+}
+
+GLuint ShaderHelper::color()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_colorUniform;
+}
+
+GLuint ShaderHelper::texture()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_textureUniform;
+}
+
+GLuint ShaderHelper::shadow()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowUniform;
+}
+
+GLuint ShaderHelper::posAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_positionAttr;
+}
+
+GLuint ShaderHelper::uvAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_uvAttr;
+}
+
+GLuint ShaderHelper::normalAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_normalAttr;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
new file mode 100644
index 00000000..73e5b9ee
--- /dev/null
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SHADERHELPER_P_H
+#define SHADERHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper
+{
+ public:
+ ShaderHelper(QObject *parent,
+ const QString &vertexShader = QString(),
+ const QString &fragmentShader = QString(),
+ const QString &texture = QString(),
+ const QString &depthTexture = QString());
+ ~ShaderHelper();
+
+ void setShaders(const QString &vertexShader, const QString &fragmentShader);
+ void setTextures(const QString &texture, const QString &depthTexture);
+
+ void initialize();
+ bool testCompile();
+ void bind();
+ void release();
+ void setUniformValue(GLuint uniform, const QVector3D &value);
+ void setUniformValue(GLuint uniform, const QVector4D &value);
+ void setUniformValue(GLuint uniform, const QMatrix4x4 &value);
+ void setUniformValue(GLuint uniform, GLfloat value);
+ void setUniformValue(GLuint uniform, GLint value);
+
+ GLuint MVP();
+ GLuint view();
+ GLuint model();
+ GLuint nModel();
+ GLuint depth();
+ GLuint lightP();
+ GLuint lightS();
+ GLuint ambientS();
+ GLuint shadowQ();
+ GLuint color();
+ GLuint texture();
+ GLuint shadow();
+
+ GLuint posAtt();
+ GLuint uvAtt();
+ GLuint normalAtt();
+
+ private:
+ QObject *m_caller;
+ QOpenGLShaderProgram *m_program;
+
+ QString m_vertexShaderFile;
+ QString m_fragmentShaderFile;
+
+ QString m_textureFile;
+ QString m_depthTextureFile;
+
+ GLuint m_positionAttr;
+ GLuint m_uvAttr;
+ GLuint m_normalAttr;
+
+ GLuint m_colorUniform;
+ GLuint m_viewMatrixUniform;
+ GLuint m_modelMatrixUniform;
+ GLuint m_invTransModelMatrixUniform;
+ GLuint m_depthMatrixUniform;
+ GLuint m_mvpMatrixUniform;
+ GLuint m_lightPositionUniform;
+ GLuint m_lightStrengthUniform;
+ GLuint m_ambientStrengthUniform;
+ GLuint m_shadowQualityUniform;
+ GLuint m_textureUniform;
+ GLuint m_shadowUniform;
+
+ GLboolean m_initialized;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp
new file mode 100644
index 00000000..f78fcec3
--- /dev/null
+++ b/src/datavisualization/utils/surfaceobject.cpp
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "surfaceobject_p.h"
+#include "abstractobjecthelper_p.h"
+
+#include <QVector3D>
+#include <QVector2D>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+SurfaceObject::SurfaceObject()
+{
+ m_indicesType = GL_UNSIGNED_INT;
+ initializeOpenGLFunctions();
+ glGenBuffers(1, &m_vertexbuffer);
+ glGenBuffers(1, &m_normalbuffer);
+ glGenBuffers(1, &m_uvbuffer);
+ glGenBuffers(1, &m_elementbuffer);
+ glGenBuffers(1, &m_gridElementbuffer);
+}
+
+SurfaceObject::~SurfaceObject()
+{
+ glDeleteBuffers(1, &m_gridElementbuffer);
+}
+
+void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space,
+ GLfloat yRange, GLfloat yMin, bool changeGeometry)
+{
+ m_columns = space.width();
+ m_rows = space.height();
+ int totalSize = m_rows * m_columns;
+ GLfloat xMin = dataArray.at(0)->at(0).x();
+ GLfloat zMin = dataArray.at(0)->at(0).z();
+ GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
+ GLfloat yNormalizer = yRange / 2.0f;
+ GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
+ GLfloat uvX = 1.0 / GLfloat(m_columns - 1);
+ GLfloat uvY = 1.0 / GLfloat(m_rows - 1);
+
+ m_surfaceType = SurfaceSmooth;
+
+ // Create/populate vertice table
+ if (changeGeometry)
+ m_vertices.resize(totalSize);
+
+ QVector<QVector2D> uvs;
+ if (changeGeometry)
+ uvs.resize(totalSize);
+ int totalIndex = 0;
+ for (int i = 0; i < m_rows; i++) {
+ const QSurfaceDataRow &p = *dataArray.at(i);
+ for (int j = 0; j < m_columns; j++) {
+ const QSurfaceDataItem &data = p.at(j);
+ float normalizedX = ((data.x() - xMin) / xNormalizer);
+ float normalizedY = ((data.y() - yMin) / yNormalizer);
+ float normalizedZ = ((data.z() - zMin) / zNormalizer);
+ m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f);
+ if (changeGeometry)
+ uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
+ totalIndex++;
+ }
+ }
+
+ // Create normals
+ int rowLimit = m_rows - 1;
+ int colLimit = m_columns - 1;
+ int rowColLimit = rowLimit * m_columns;
+ int totalLimit = totalSize - 1;
+ if (changeGeometry)
+ m_normals.resize(totalSize);
+
+ totalIndex = 0;
+ for (int row = 0; row < rowColLimit; row += m_columns) {
+ for (int j = 0; j < colLimit; j++) {
+ m_normals[totalIndex++] = normal(m_vertices.at(row + j),
+ m_vertices.at(row + j + 1),
+ m_vertices.at(row + m_columns + j));
+ }
+ int p = row + colLimit;
+ m_normals[totalIndex++] = normal(m_vertices.at(p),
+ m_vertices.at(p + m_columns),
+ m_vertices.at(p - 1));
+ }
+ for (int j = rowColLimit; j < totalLimit; j++) {
+ m_normals[totalIndex++] = normal(m_vertices.at(j),
+ m_vertices.at(j - m_columns),
+ m_vertices.at(j + 1));
+ }
+ int p = m_rows * colLimit;
+ m_normals[totalIndex++] = normal(m_vertices.at(p),
+ m_vertices.at(p - 1),
+ m_vertices.at(p - m_columns - 1));
+
+ // Create indices table
+ GLint *indices = 0;
+ if (changeGeometry) {
+ m_indexCount = 6 * colLimit * rowLimit;
+ indices = new GLint[m_indexCount];
+ p = 0;
+ for (int row = 0; row < rowLimit * m_columns; row += m_columns) {
+ for (int j = 0; j < colLimit; j++) {
+ // Left triangle
+ indices[p++] = row + j + 1;
+ indices[p++] = row + m_columns + j;
+ indices[p++] = row + j;
+
+ // Right triangle
+ indices[p++] = row + m_columns + j + 1;
+ indices[p++] = row + m_columns + j;
+ indices[p++] = row + j + 1;
+ }
+ }
+ }
+
+ // Create line element indices
+ GLint *gridIndices = 0;
+ if (changeGeometry) {
+ m_gridIndexCount = 2 * m_columns * rowLimit + 2 * m_rows * colLimit;
+ gridIndices = new GLint[m_gridIndexCount];
+ p = 0;
+ for (int i = 0, row = 0; i < m_rows; i++, row += m_columns) {
+ for (int j = 0; j < colLimit; j++) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + 1;
+ }
+ }
+ for (int i = 0, row = 0; i < rowLimit; i++, row += m_columns) {
+ for (int j = 0; j < m_columns; j++) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + m_columns;
+ }
+ }
+ }
+
+ createBuffers(m_vertices, uvs, m_normals, indices, gridIndices, changeGeometry);
+
+ delete[] indices;
+ delete[] gridIndices;
+}
+
+
+void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space,
+ GLfloat yRange, GLfloat yMin, bool changeGeometry)
+{
+ m_columns = space.width();
+ m_rows = space.height();
+ int totalSize = m_rows * m_columns * 2;
+ GLfloat xMin = dataArray.at(0)->at(0).x();
+ GLfloat zMin = dataArray.at(0)->at(0).z();
+ GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
+ GLfloat yNormalizer = yRange / 2.0f;
+ GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
+ GLfloat uvX = 1.0 / GLfloat(m_columns - 1);
+ GLfloat uvY = 1.0 / GLfloat(m_rows - 1);
+
+ m_surfaceType = SurfaceFlat;
+
+ // Create vertice table
+ if (changeGeometry)
+ m_vertices.resize(totalSize);
+
+ QVector<QVector2D> uvs;
+ if (changeGeometry)
+ uvs.resize(totalSize);
+
+ int totalIndex = 0;
+ int rowLimit = m_rows - 1;
+ int colLimit = m_columns - 1;
+ int doubleColumns = m_columns * 2 - 2;
+ int rowColLimit = rowLimit * doubleColumns;
+
+ for (int i = 0; i < m_rows; i++) {
+ const QSurfaceDataRow &row = *dataArray.at(i);
+ for (int j = 0; j < m_columns; j++) {
+ const QSurfaceDataItem &data = row.at(j);
+ float normalizedX = ((data.x() - xMin) / xNormalizer);
+ float normalizedY = ((data.y() - yMin) / yNormalizer);
+ float normalizedZ = ((data.z() - zMin) / zNormalizer);
+ m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f);
+ if (changeGeometry)
+ uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
+
+ totalIndex++;
+
+ if (j > 0 && j < colLimit) {
+ m_vertices[totalIndex] = m_vertices[totalIndex - 1];
+ if (changeGeometry)
+ uvs[totalIndex] = uvs[totalIndex - 1];
+ totalIndex++;
+ }
+ }
+ }
+
+ // Create normals & indices table
+ GLint *indices = 0;
+ int p = 0;
+ if (changeGeometry) {
+ int normalCount = 2 * colLimit * rowLimit;
+ m_indexCount = 3 * normalCount;
+ indices = new GLint[m_indexCount];
+ m_normals.resize(normalCount);
+ }
+
+ totalIndex = 0;
+ for (int row = 0, upperRow = doubleColumns;
+ row < rowColLimit;
+ row += doubleColumns, upperRow += doubleColumns) {
+ for (int j = 0; j < doubleColumns; j += 2) {
+ // Normal for the left triangle
+ m_normals[totalIndex++] = normal(m_vertices.at(row + j),
+ m_vertices.at(row + j + 1),
+ m_vertices.at(upperRow + j));
+
+ // Normal for the right triangle
+ m_normals[totalIndex++] = normal(m_vertices.at(row + j + 1),
+ m_vertices.at(upperRow + j + 1),
+ m_vertices.at(upperRow + j));
+
+ if (changeGeometry) {
+ // Left triangle
+ indices[p++] = row + j + 1;
+ indices[p++] = upperRow + j;
+ indices[p++] = row + j;
+
+ // Right triangle
+ indices[p++] = upperRow + j + 1;
+ indices[p++] = upperRow + j;
+ indices[p++] = row + j + 1;
+ }
+ }
+ }
+
+ // Create grid line element indices
+ GLint *gridIndices = 0;
+ if (changeGeometry) {
+ m_gridIndexCount = 2 * m_columns * rowLimit + 2 * m_rows * colLimit;
+ gridIndices = new GLint[m_gridIndexCount];
+ p = 0;
+ int fullRowLimit = m_rows * doubleColumns;
+ for (int row = 0; row < fullRowLimit; row += doubleColumns) {
+ for (int j = 0; j < doubleColumns; j += 2) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + 1;
+
+ if (row < rowColLimit) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + doubleColumns;
+ }
+ }
+ }
+ for (int i = doubleColumns - 1; i < rowColLimit; i += doubleColumns) {
+ gridIndices[p++] = i;
+ gridIndices[p++] = i + doubleColumns;
+ }
+ }
+
+ createBuffers(m_vertices, uvs, m_normals, indices, gridIndices, changeGeometry);
+
+ delete[] indices;
+ delete[] gridIndices;
+}
+
+void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
+ const QVector<QVector3D> &normals, const GLint *indices,
+ const GLint *gridIndices, bool changeGeometry)
+{
+ // Move to buffers
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(QVector3D),
+ &vertices.at(0), GL_DYNAMIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(QVector3D),
+ &normals.at(0), GL_DYNAMIC_DRAW);
+
+ if (changeGeometry) {
+ if (uvs.size()) {
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D),
+ &uvs.at(0), GL_STATIC_DRAW);
+ }
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint),
+ indices, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gridElementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_gridIndexCount * sizeof(GLint),
+ gridIndices, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+GLuint SurfaceObject::gridElementBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_gridElementbuffer;
+}
+
+GLuint SurfaceObject::gridIndexCount()
+{
+ return m_gridIndexCount;
+}
+
+QVector3D SurfaceObject::vertexAt(int column, int row)
+{
+ int pos = 0;
+ if (m_surfaceType == SurfaceFlat)
+ pos = row * (m_columns * 2 - 2) + column * 2 - (column > 0);
+ else
+ pos = row * m_columns + column;
+ return m_vertices.at(pos);
+}
+
+QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c)
+{
+ QVector3D v1 = b - a;
+ QVector3D v2 = c - a;
+ return QVector3D::crossProduct(v1, v2);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h
new file mode 100644
index 00000000..4f30f7c0
--- /dev/null
+++ b/src/datavisualization/utils/surfaceobject_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 SURFACEOBJECT_P_H
+#define SURFACEOBJECT_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include "qsurfacedataproxy.h"
+
+#include <QOpenGLFunctions>
+#include <QRect>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class SurfaceObject : public AbstractObjectHelper
+{
+public:
+ SurfaceObject();
+ ~SurfaceObject();
+
+ void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange,
+ GLfloat yMin, bool changeGeometry);
+ void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange,
+ GLfloat yMin, bool changeGeometry);
+ GLuint gridElementBuf();
+ GLuint gridIndexCount();
+ QVector3D vertexAt(int column, int row);
+
+private:
+ QVector3D normal(const QVector3D &a, const QVector3D &b, const QVector3D &c);
+ void createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
+ const QVector<QVector3D> &normals, const GLint *indices,
+ const GLint *gridIndices, bool changeGeometry);
+
+private:
+ enum SurfaceType {
+ SurfaceSmooth,
+ SurfaceFlat
+ };
+ int m_surfaceType;
+ int m_columns;
+ int m_rows;
+ GLuint m_gridElementbuffer;
+ GLuint m_gridIndexCount;
+ QVector<QVector3D> m_vertices;
+ QVector<QVector3D> m_normals;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+#endif // SURFACEOBJECT_P_H
diff --git a/src/datavisualization/utils/texturehelper.cpp b/src/datavisualization/utils/texturehelper.cpp
new file mode 100644
index 00000000..25fe17ac
--- /dev/null
+++ b/src/datavisualization/utils/texturehelper.cpp
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "texturehelper_p.h"
+#include "utils_p.h"
+
+#include <QImage>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+TextureHelper::TextureHelper()
+{
+ initializeOpenGLFunctions();
+}
+
+TextureHelper::~TextureHelper()
+{
+}
+
+GLuint TextureHelper::create2DTexture(const QImage &image, bool useTrilinearFiltering,
+ bool convert, bool smoothScale)
+{
+ if (image.isNull())
+ return 0;
+
+ QImage texImage = image;
+
+#if defined(Q_OS_ANDROID)
+ GLuint temp;
+ //qDebug() << "old size" << image.size();
+ GLuint imageWidth = Utils::getNearestPowerOfTwo(image.width(), temp);
+ GLuint imageHeight = Utils::getNearestPowerOfTwo(image.height(), temp);
+ if (smoothScale) {
+ texImage = image.scaled(imageWidth, imageHeight, Qt::IgnoreAspectRatio,
+ Qt::SmoothTransformation);
+ } else {
+ texImage = image.scaled(imageWidth, imageHeight, Qt::IgnoreAspectRatio);
+ }
+ //qDebug() << "new size" << texImage.size();
+#endif
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ if (convert)
+ texImage = convertToGLFormat(texImage);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texImage.width(), texImage.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage.bits());
+ if (smoothScale)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createCubeMapTexture(const QImage &image, bool useTrilinearFiltering)
+{
+ if (image.isNull())
+ return 0;
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
+ QImage glTexture = convertToGLFormat(image);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, glTexture.width(), glTexture.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture.bits());
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ } else {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createSelectionBuffer(const QSize &size, GLuint &texture,
+ GLuint &depthTexture)
+{
+ GLuint framebuffer;
+
+ // Create frame buffer
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+//#if !defined(QT_OPENGL_ES_2)
+// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGB,
+// GL_UNSIGNED_BYTE, NULL);
+//#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+//#endif
+
+ // Create texture object for the depth buffer
+ glGenTextures(1, &depthTexture);
+ glBindTexture(GL_TEXTURE_2D, depthTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size.width(), size.height(),
+ 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return framebuffer;
+}
+
+GLuint TextureHelper::createSelectionTexture(const QSize &size, GLuint &frameBuffer,
+ GLuint &depthBuffer)
+{
+ GLuint textureid;
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &textureid);
+ glBindTexture(GL_TEXTURE_2D, textureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#if !defined(QT_OPENGL_ES_2)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+#endif
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create render buffer
+ if (!depthBuffer)
+ glGenRenderbuffers(1, &depthBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
+#if !defined(QT_OPENGL_ES_2)
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
+#else
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height());
+#endif
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ // Create frame buffer
+ if (!frameBuffer)
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid, 0);
+ // Attach renderbuffer to depth attachment
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return textureid;
+}
+
+#if !defined(QT_OPENGL_ES_2)
+GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize)
+{
+ GLuint depthtextureid;
+
+ // Create depth texture for the shadow mapping
+ glGenTextures(1, &depthtextureid);
+ glBindTexture(GL_TEXTURE_2D, depthtextureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, size.width() * textureSize,
+ size.height() * textureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create frame buffer
+ if (!frameBuffer)
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthtextureid, 0);
+
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return depthtextureid;
+}
+#endif
+
+void TextureHelper::deleteTexture(const GLuint *texture)
+{
+ glDeleteTextures(1, texture);
+}
+
+QImage TextureHelper::convertToGLFormat(const QImage &srcImage)
+{
+ QImage res(srcImage.size(), QImage::Format_ARGB32);
+ convertToGLFormatHelper(res, srcImage.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
+ return res;
+}
+
+void TextureHelper::convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage,
+ GLenum texture_format)
+{
+ Q_ASSERT(dstImage.depth() == 32);
+ Q_ASSERT(srcImage.depth() == 32);
+
+ if (dstImage.size() != srcImage.size()) {
+ int target_width = dstImage.width();
+ int target_height = dstImage.height();
+ qreal sx = target_width / qreal(srcImage.width());
+ qreal sy = target_height / qreal(srcImage.height());
+
+ quint32 *dest = (quint32 *) dstImage.scanLine(0); // NB! avoid detach here
+ uchar *srcPixels = (uchar *) srcImage.scanLine(srcImage.height() - 1);
+ int sbpl = srcImage.bytesPerLine();
+ int dbpl = dstImage.bytesPerLine();
+
+ int ix = int(0x00010000 / sx);
+ int iy = int(0x00010000 / sy);
+
+ quint32 basex = int(0.5 * ix);
+ quint32 srcy = int(0.5 * iy);
+
+ // scale, swizzle and mirror in one loop
+ while (target_height--) {
+ const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
+ int srcx = basex;
+ for (int x=0; x<target_width; ++x) {
+ dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
+ srcx += ix;
+ }
+ dest = (quint32 *)(((uchar *) dest) + dbpl);
+ srcy += iy;
+ }
+ } else {
+ const int width = srcImage.width();
+ const int height = srcImage.height();
+ const uint *p = (const uint*) srcImage.scanLine(srcImage.height() - 1);
+ uint *q = (uint*) dstImage.scanLine(0);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (texture_format == GL_BGRA) {
+#else
+ if (texture_format == GL_BGRA8_EXT) {
+#endif
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ // mirror + swizzle
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 24) & 0xff000000)
+ | ((*p >> 24) & 0x000000ff)
+ | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ const uint bytesPerLine = srcImage.bytesPerLine();
+ for (int i=0; i < height; ++i) {
+ memcpy(q, p, bytesPerLine);
+ q += width;
+ p -= width;
+ }
+ }
+ } else {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = (*p << 8) | ((*p >> 24) & 0xff);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ }
+ }
+ }
+}
+
+QRgb TextureHelper::qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
+{
+#if !defined(QT_OPENGL_ES_2)
+ if (texture_format == GL_BGRA) {
+#else
+ if (texture_format == GL_BGRA8_EXT) {
+#endif
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return ((src_pixel << 24) & 0xff000000)
+ | ((src_pixel >> 24) & 0x000000ff)
+ | ((src_pixel << 8) & 0x00ff0000)
+ | ((src_pixel >> 8) & 0x0000ff00);
+ } else {
+ return src_pixel;
+ }
+ } else { // GL_RGBA
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
+ } else {
+ return ((src_pixel << 16) & 0xff0000)
+ | ((src_pixel >> 16) & 0xff)
+ | (src_pixel & 0xff00ff00);
+ }
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/texturehelper_p.h b/src/datavisualization/utils/texturehelper_p.h
new file mode 100644
index 00000000..f7779b59
--- /dev/null
+++ b/src/datavisualization/utils/texturehelper_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 TEXTUREHELPER_P_H
+#define TEXTUREHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+#include <QRgb>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class TextureHelper : protected QOpenGLFunctions
+{
+ public:
+ TextureHelper();
+ ~TextureHelper();
+
+ // Ownership of created texture is transferred to caller
+ GLuint create2DTexture(const QImage &image, bool useTrilinearFiltering = false,
+ bool convert = true, bool smoothScale = true);
+ GLuint createCubeMapTexture(const QImage &image, bool useTrilinearFiltering = false);
+ // Returns selection framebuffer and inserts generated texture id to texture parameters
+ GLuint createSelectionBuffer(const QSize &size, GLuint &texture, GLuint &depthTexture);
+ // Returns selection texture and inserts generated framebuffers to framebuffer parameters
+ GLuint createSelectionTexture(const QSize &size, GLuint &frameBuffer, GLuint &depthBuffer);
+#if !defined(QT_OPENGL_ES_2)
+ // Returns depth texture and inserts generated framebuffer to parameter
+ GLuint createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize = 1);
+#endif
+ void deleteTexture(const GLuint *texture);
+
+ private:
+ QImage convertToGLFormat(const QImage &srcImage);
+ void convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage, GLenum texture_format);
+ QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format);
+
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/utils.cpp b/src/datavisualization/utils/utils.cpp
new file mode 100644
index 00000000..947dbfba
--- /dev/null
+++ b/src/datavisualization/utils/utils.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "utils_p.h"
+
+#include <QVector3D>
+#include <QColor>
+#include <QPainter>
+#include <QPoint>
+#include <QImage>
+#include <QRegExp>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+#define NUM_IN_POWER(y, x) for (;y<x;y<<=1)
+#define MIN_POWER 32
+
+GLuint Utils::getNearestPowerOfTwo(GLuint value, GLuint &padding)
+{
+ GLuint powOfTwoValue = MIN_POWER;
+ NUM_IN_POWER(powOfTwoValue, value);
+ padding = powOfTwoValue - value;
+ return powOfTwoValue;
+}
+
+QVector3D Utils::vectorFromColor(const QColor &color)
+{
+ return QVector3D(color.redF(), color.greenF(), color.blueF());
+}
+
+QImage Utils::printTextToImage(const QFont &font, const QString &text, const QColor &bgrColor,
+ const QColor &txtColor, QDataVis::LabelStyle style,
+ bool borders, int maxLabelWidth)
+{
+ GLuint paddingWidth = 20;
+ GLuint paddingHeight = 20;
+ // Calculate text dimensions
+ QFont valueFont = font;
+ valueFont.setPointSize(textureFontSize);
+ QFontMetrics valueFM(valueFont);
+ int valueStrWidth = valueFM.width(text);
+ if (maxLabelWidth && QDataVis::LabelStyleTransparent != style)
+ valueStrWidth = maxLabelWidth;
+ int valueStrHeight = valueFM.height();
+ valueStrWidth += paddingWidth / 2; // Fix clipping problem with skewed fonts (italic or italic-style)
+ QSize labelSize;
+
+#if defined(Q_OS_ANDROID)
+ // Android can't handle textures with dimensions not in power of 2. Resize labels accordingly.
+ // Add some padding before converting to power of two to avoid too tight fit
+ GLuint prePadding = 5;
+ // Android needs to use this always (when given) because of the power of 2 -issue.
+ if (maxLabelWidth)
+ valueStrWidth = maxLabelWidth + paddingWidth / 2;
+ labelSize = QSize(valueStrWidth + prePadding, valueStrHeight + prePadding);
+ //qDebug() << "label size before padding" << text << labelSize;
+ labelSize.setWidth(getNearestPowerOfTwo(labelSize.width(), paddingWidth));
+ labelSize.setHeight(getNearestPowerOfTwo(labelSize.height(), paddingHeight));
+ //qDebug() << "label size after padding" << labelSize << paddingWidth << paddingHeight;
+#else
+ if (QDataVis::LabelStyleTransparent == style)
+ labelSize = QSize(valueStrWidth, valueStrHeight);
+ else
+ labelSize = QSize(valueStrWidth + paddingWidth * 2, valueStrHeight + paddingHeight * 2);
+#endif
+
+ // Create image
+ QImage image = QImage(labelSize, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+
+ // Init painter
+ QPainter painter(&image);
+ // Paint text
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.setFont(valueFont);
+ switch (style) {
+ case QDataVis::LabelStyleTransparent: {
+ painter.setPen(txtColor);
+#if defined(Q_OS_ANDROID)
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#else
+ painter.drawText(0, 0,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#endif
+ break;
+ }
+ case QDataVis::LabelStyleFromTheme: {
+ painter.setBrush(QBrush(bgrColor));
+ if (borders) {
+ painter.setPen(QPen(QBrush(txtColor), 5, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin));
+ painter.drawRoundedRect(5, 5, labelSize.width() - 10, labelSize.height() - 10,
+ 10.0, 10.0);
+ } else {
+ painter.setPen(bgrColor);
+ painter.drawRoundedRect(0, 0, labelSize.width(), labelSize.height(), 10.0, 10.0);
+ }
+ painter.setPen(txtColor);
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ case QDataVis::LabelStyleOpaque: {
+ QColor labelColor = QColor(bgrColor);
+ labelColor.setAlphaF(1.0);
+ painter.setBrush(QBrush(labelColor));
+ if (borders) {
+ painter.setPen(QPen(QBrush(txtColor), 7, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));
+ painter.drawRect(7, 7, labelSize.width() - 14, labelSize.height() - 14);
+ } else {
+ painter.setPen(labelColor);
+ painter.drawRect(0, 0, labelSize.width(), labelSize.height());
+ }
+ painter.setPen(txtColor);
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ }
+ return image;
+}
+
+QVector3D Utils::getSelection(QPoint mousepos, int height)
+{
+ QVector3D selectedColor;
+
+ //#if defined(QT_OPENGL_ES_2)
+ // This is the only one that works with ANGLE (ES 2.0)
+ // Item count will be limited to 256*256*256
+ GLubyte pixel[4];
+ glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ (void *)pixel);
+
+ //qDebug() << "rgba" << pixel[0] << pixel[1] << pixel[2] << pixel[3] << "mousepos:" << mousepos << "height:" << height;
+
+ //#else
+ // These work with desktop OpenGL
+ // They offer a lot higher possible object count and a possibility to use object ids
+ //GLuint pixel[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_UNSIGNED_INT, (void *)pixel);
+ //qDebug() << "rgba" << pixel[0] << pixel[1] << pixel[2];// << pixel[3];
+
+ //GLfloat pixel3[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_FLOAT, (void *)pixel3);
+ //qDebug() << "rgba" << pixel3[0] << pixel3[1] << pixel3[2];// << pixel[3];
+ //#endif
+ selectedColor = QVector3D(pixel[0], pixel[1], pixel[2]);
+ //qDebug() << selectedColor;
+
+ return selectedColor;
+}
+
+Utils::ParamType Utils::mapFormatCharToParamType(const QChar &formatChar)
+{
+ ParamType retVal = ParamTypeUnknown;
+ if (formatChar == QLatin1Char('d')
+ || formatChar == QLatin1Char('i')
+ || formatChar == QLatin1Char('c')) {
+ retVal = ParamTypeInt;
+ } else if (formatChar == QLatin1Char('u')
+ || formatChar == QLatin1Char('o')
+ || formatChar == QLatin1Char('x')
+ || formatChar == QLatin1Char('X')) {
+ retVal = ParamTypeUInt;
+ } else if (formatChar == QLatin1Char('f')
+ || formatChar == QLatin1Char('F')
+ || formatChar == QLatin1Char('e')
+ || formatChar == QLatin1Char('E')
+ || formatChar == QLatin1Char('g')
+ || formatChar == QLatin1Char('G')) {
+ retVal = ParamTypeReal;
+ }
+
+ return retVal;
+}
+
+Utils::ParamType Utils::findFormatParamType(const QString &format)
+{
+ static QRegExp formatMatcher(QStringLiteral("%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])"));
+
+ if (formatMatcher.indexIn(format, 0) != -1) {
+ QString capStr = formatMatcher.cap(1);
+ if (capStr.isEmpty())
+ return ParamTypeUnknown;
+ else
+ return mapFormatCharToParamType(capStr.at(0));
+ }
+
+ return ParamTypeUnknown;
+}
+
+QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal value)
+{
+ switch (paramType) {
+ case ParamTypeInt:
+ return QString().sprintf(format, (qint64)value);
+ case ParamTypeUInt:
+ return QString().sprintf(format, (quint64)value);
+ case ParamTypeReal:
+ return QString().sprintf(format, value);
+ default:
+ return QString::fromUtf8(format); // To detect errors
+ }
+}
+
+QString Utils::defaultLabelFormat()
+{
+ static const QString defaultFormat(QStringLiteral("%.2f"));
+ return defaultFormat;
+}
+
+qreal Utils::wrapValue(qreal value, qreal min, qreal max)
+{
+ if (value > max) {
+ value = min + (value - max);
+
+ // In case single wrap fails, jump to opposite end.
+ if (value > max)
+ value = min;
+ }
+
+ if (value < min) {
+ value = max + (value - min);
+
+ // In case single wrap fails, jump to opposite end.
+ if (value < min)
+ value = max;
+ }
+
+ return value;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/utils.pri b/src/datavisualization/utils/utils.pri
new file mode 100644
index 00000000..cef5ebf0
--- /dev/null
+++ b/src/datavisualization/utils/utils.pri
@@ -0,0 +1,19 @@
+HEADERS += $$PWD/meshloader_p.h \
+ $$PWD/vertexindexer_p.h \
+ $$PWD/camerahelper_p.h \
+ $$PWD/shaderhelper_p.h \
+ $$PWD/objecthelper_p.h \
+ $$PWD/texturehelper_p.h \
+ $$PWD/utils_p.h \
+ $$PWD/abstractobjecthelper_p.h \
+ $$PWD/surfaceobject_p.h
+
+SOURCES += $$PWD/meshloader.cpp \
+ $$PWD/vertexindexer.cpp \
+ $$PWD/camerahelper.cpp \
+ $$PWD/shaderhelper.cpp \
+ $$PWD/objecthelper.cpp \
+ $$PWD/texturehelper.cpp \
+ $$PWD/utils.cpp \
+ $$PWD/abstractobjecthelper.cpp \
+ $$PWD/surfaceobject.cpp
diff --git a/src/datavisualization/utils/utils_p.h b/src/datavisualization/utils/utils_p.h
new file mode 100644
index 00000000..e74b590d
--- /dev/null
+++ b/src/datavisualization/utils/utils_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 UTILS_P_H
+#define UTILS_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+
+class QVector3D;
+class QColor;
+class QPainter;
+class QString;
+class QPoint;
+class QImage;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Utils
+{
+public:
+ enum ParamType {
+ ParamTypeUnknown = 0,
+ ParamTypeInt,
+ ParamTypeUInt,
+ ParamTypeReal
+ };
+
+ static GLuint getNearestPowerOfTwo(GLuint value, GLuint &padding);
+ static QVector3D vectorFromColor(const QColor &color);
+ static void printText(QPainter *painter, const QString &text, const QSize &position,
+ bool absoluteCoords = true, qreal rotation = 0, qreal scale = 1.0f);
+ static QImage printTextToImage(const QFont &font,
+ const QString &text,
+ const QColor &bgrColor,
+ const QColor &txtColor,
+ QDataVis::LabelStyle style,
+ bool borders = false,
+ int maxLabelWidth = 0);
+ static QVector3D getSelection(QPoint mousepos, int height);
+
+ static ParamType findFormatParamType(const QString &format);
+ static QString formatLabel(const QByteArray &format, ParamType paramType, qreal value);
+ static QString defaultLabelFormat();
+
+ static qreal wrapValue(qreal value, qreal min, qreal max);
+
+private:
+ static ParamType mapFormatCharToParamType(const QChar &formatChar);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/vertexindexer.cpp b/src/datavisualization/utils/vertexindexer.cpp
new file mode 100644
index 00000000..63b9faaf
--- /dev/null
+++ b/src/datavisualization/utils/vertexindexer.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "vertexindexer_p.h"
+
+#include <string.h> // for memcmp
+#include <qmath.h>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+int unique_vertices = 0;
+
+// Returns true if v1 can be considered equal to v2
+bool VertexIndexer::is_near(float v1, float v2)
+{
+ return qAbs(v1 - v2) < 0.01f;
+}
+
+// Searches through all already-exported vertices
+// for a similar one.
+// Similar = same position + same UVs + same normal
+bool VertexIndexer::getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result)
+{
+ // Lame linear search
+ for (int i = 0; i < out_vertices.size(); i++) {
+ if (is_near(in_vertex.x() , out_vertices[i].x())
+ && is_near(in_vertex.y() , out_vertices[i].y())
+ && is_near(in_vertex.z() , out_vertices[i].z())
+ && is_near(in_uv.x() , out_uvs [i].x())
+ && is_near(in_uv.y() , out_uvs [i].y())
+ && is_near(in_normal.x() , out_normals [i].x())
+ && is_near(in_normal.y() , out_normals [i].y())
+ && is_near(in_normal.z() , out_normals [i].z())) {
+ result = i;
+ return true;
+ }
+ }
+ // No other vertex could be used instead.
+ // Looks like we'll have to add it to the VBO.
+ return false;
+}
+
+bool VertexIndexer::getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result)
+{
+ QMap<PackedVertex, unsigned short>::iterator it = VertexToOutIndex.find(packed);
+ if (it == VertexToOutIndex.end()) {
+ return false;
+ } else {
+ result = it.value();
+ return true;
+ }
+}
+
+void VertexIndexer::indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ unique_vertices = 0;
+ QMap<PackedVertex, unsigned short> VertexToOutIndex;
+
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+ PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]};
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex_fast(packed, VertexToOutIndex, index);
+
+ if (found) {
+ out_indices.append(index);
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ unsigned short newindex = (unsigned short)out_vertices.size() - 1;
+ out_indices.append(newindex);
+ VertexToOutIndex[packed] = newindex;
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+void VertexIndexer::indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents)
+{
+ unique_vertices = 0;
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i],
+ out_vertices, out_uvs, out_normals, index);
+
+ if (found) {
+ out_indices.append(index);
+
+ // Average the tangents and the bitangents
+ out_tangents[index] += in_tangents[i];
+ out_bitangents[index] += in_bitangents[i];
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ out_tangents.append(in_tangents[i]);
+ out_bitangents.append(in_bitangents[i]);
+ out_indices.append((unsigned short)out_vertices.size() - 1);
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/vertexindexer_p.h b/src/datavisualization/utils/vertexindexer_p.h
new file mode 100644
index 00000000..0cf1857b
--- /dev/null
+++ b/src/datavisualization/utils/vertexindexer_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 VERTEXINDEXER_P_H
+#define VERTEXINDEXER_P_H
+
+#include "datavisualizationglobal_p.h"
+
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class VertexIndexer
+{
+ public:
+ struct PackedVertex {
+ QVector3D position;
+ QVector2D uv;
+ QVector3D normal;
+ bool operator<(const PackedVertex that) const {
+ return memcmp((void*)this, (void*)&that, sizeof(PackedVertex)) > 0;
+ }
+ };
+
+ static void indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+
+ static void indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents);
+
+ private:
+ static bool is_near(float v1, float v2);
+ static bool getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result);
+ static bool getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif