diff options
author | Tomi Korpipää <tomi.korpipaa@digia.com> | 2013-06-12 13:48:48 +0300 |
---|---|---|
committer | Tomi Korpipää <tomi.korpipaa@digia.com> | 2013-06-12 13:48:48 +0300 |
commit | b185e2c557bb987197ee9147f088724f6a06f4a0 (patch) | |
tree | 4c25116ae68193d14b18848d0db0ab1ed9780636 | |
parent | b61b63ff5e3b4ba7c4f4174c16b33bedadbfcfb8 (diff) | |
parent | 317f3f15fed855cfaa31a9b558bf1279583832e6 (diff) |
Merge remote-tracking branch 'origin/master' into develop
Conflicts:
examples/qmlbarchart/qml/qmlbarchart/main.qml
src/datavis3d/doc/snippets/doc_src_qtdatavis3d.pro
src/datavis3d/engine/q3dbars.cpp
src/datavis3d/engine/q3dwindow.cpp
src/datavis3dqml2/datavisview.cpp
Change-Id: Ida37fd44e7e58aec07af09a6d1dde4ac4adbd8a4
50 files changed, 4541 insertions, 2663 deletions
diff --git a/examples/barchart/doc/images/barchart-example.png b/examples/barchart/doc/images/barchart-example.png Binary files differnew file mode 100644 index 00000000..0f321c95 --- /dev/null +++ b/examples/barchart/doc/images/barchart-example.png diff --git a/examples/barchart/doc/src/barchart.qdoc b/examples/barchart/doc/src/barchart.qdoc new file mode 100644 index 00000000..498388bb --- /dev/null +++ b/examples/barchart/doc/src/barchart.qdoc @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example barchart + \title Barchart Example + + The barchart example shows how to make a simple 3D bar chart using Q3DBars. + + \image barchart-example.png + + TODO +*/ diff --git a/examples/barchart/main.cpp b/examples/barchart/main.cpp index f2862bfd..6887bb0b 100644 --- a/examples/barchart/main.cpp +++ b/examples/barchart/main.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the documentation of the Qt Toolkit. +** This file is part of the documentation of the QtDataVis3D module. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: diff --git a/examples/mapdata/doc/images/mapdata-example.png b/examples/mapdata/doc/images/mapdata-example.png Binary files differnew file mode 100644 index 00000000..8bd8fc18 --- /dev/null +++ b/examples/mapdata/doc/images/mapdata-example.png diff --git a/examples/mapdata/doc/src/mapdata.qdoc b/examples/mapdata/doc/src/mapdata.qdoc new file mode 100644 index 00000000..be424509 --- /dev/null +++ b/examples/mapdata/doc/src/mapdata.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example mapdata + \title Mapdata Example + + The mapdata example shows how to make a simple 3D maps visualization using Q3DMaps and + combining the use of widgets for adjusting several adjustable qualities. + + \image mapdata-example.png + + TODO +*/ diff --git a/examples/qmlbarchart/doc/src/qmlbarchart.qdoc b/examples/qmlbarchart/doc/src/qmlbarchart.qdoc new file mode 100644 index 00000000..42bb05aa --- /dev/null +++ b/examples/qmlbarchart/doc/src/qmlbarchart.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example qmlbarchart + \title Qt Quick 2 Barchart Example + + The Qt Quick 2 barchart example shows how to make a simple 3D bar chart using Q3DBars using Qt + Quick 2. + + \image qmlbarchart-example.png + + TODO +*/ diff --git a/examples/qmlbarchart/main.cpp b/examples/qmlbarchart/main.cpp index 37fd461e..d813443e 100644 --- a/examples/qmlbarchart/main.cpp +++ b/examples/qmlbarchart/main.cpp @@ -20,10 +20,12 @@ #include <QtGui/QGuiApplication> #include "qtquick2applicationviewer.h" +#include <QDebug> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); + qDebug() << "Hello world."; QtQuick2ApplicationViewer viewer; #ifdef Q_OS_ANDROID diff --git a/examples/qmlbarchart/qml/qmlbarchart/main.qml b/examples/qmlbarchart/qml/qmlbarchart/main.qml index f36aece6..990c78e6 100644 --- a/examples/qmlbarchart/qml/qmlbarchart/main.qml +++ b/examples/qmlbarchart/qml/qmlbarchart/main.qml @@ -23,15 +23,16 @@ import QtQuick.Window 2.1 import com.digia.QtDataVis3D 1.0 Item { - id: container - //anchors.fill: parent - width: 800 - height: 500 + id: mainview + //title: "My MainWindow" + width: 640 + height: 480 + visible: true - DataVisView { - id: mainview - anchors.fill: parent - antialiasing: true + Bars3D { + id: testchart + width: mainview.width + height: mainview.height DataItem { id: testitem @@ -43,56 +44,78 @@ Item { label: "Test2" value: -10 } + DataItem { + id: testitem3 + label: "Test3" + value: 5 + } + + DataItem { + id: testitem4 + label: "Test4" + value: -7 + } + DataItem { + id: testitem5 + label: "Test5" + value: 8 + } + DataItem { + id: testitem6 + label: "Test6" + value: 1 + } + DataRow { - id: testrow + id: testrow1 function addData() { - testrow.addItem(testitem); - testrow.addItem(testitem2); + testrow1.addItem(testitem); + testrow1.addItem(testitem2); + testrow1.addItem(testitem3); + testrow1.addItem(testitem4); + testrow1.addItem(testitem5); + testrow1.addItem(testitem6); } } -// Bars { -// id: testchart -// visible: true -// width: mainview.width -// height: mainview.height -// //x: mainview.x + mainview.width -// //y: mainview.y -// grid: false -// shadowQuality: Bars.ShadowNone -// selectionMode: Bars.ModeNone -// labelTransparency: Bars.TransparencyNone -// windowTitle: "QmlTest3DBars" + //visible: true + //x: mainview.x + mainview.width + //y: mainview.y -// function setUpBars() { -// /*console.log(parent) -// console.log(container.x) -// console.log(container.y) -// console.log(Window.x) -// console.log(Window.y) -// console.log(Screen.desktopAvailableHeight) -// console.log(Screen.desktopAvailableWidth) -// console.log(mainview.x) -// console.log(mainview.y) -// console.log(x) -// console.log(y)*/ -// testchart.setupSampleSpace(2, 1); -// testchart.addDataRow(testrow); -// } -// } + grid: false + shadowQuality: Bars3D.ShadowNone + selectionMode: Bars3D.ModeNone + labelTransparency: Bars3D.TransparencyNone - MouseArea { - anchors.fill: parent - onClicked: { -// testchart.destroy(); -// testchart.close(); - Qt.quit(); - } + function setUpBars3D() { + /*console.log(parent) + console.log(container.x) + console.log(container.y) + console.log(Window.x) + console.log(Window.y) + console.log(Screen.desktopAvailableHeight) + console.log(Screen.desktopAvailableWidth) + console.log(mainview.x) + console.log(mainview.y) + console.log(x) + console.log(y)*/ + testchart.setupSampleSpace(6, 1); + testchart.addDataRow(testrow1); + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + Qt.quit(); } + } -// Component.onCompleted: { -// testrow.addData(); -// testchart.setUpBars(); -// } + Component.onCompleted: { + // This allows us to flip the texture to be displayed correctly in scene graph + // TODO: Find a way to do it in code.. + //rotation.angle = 180 + testrow1.addData(); + testchart.setUpBars3D(); } } diff --git a/examples/rainfall/doc/images/rainfall-example.png b/examples/rainfall/doc/images/rainfall-example.png Binary files differnew file mode 100644 index 00000000..f4087927 --- /dev/null +++ b/examples/rainfall/doc/images/rainfall-example.png diff --git a/examples/rainfall/doc/src/rainfall.qdoc b/examples/rainfall/doc/src/rainfall.qdoc new file mode 100644 index 00000000..b1a4d8e0 --- /dev/null +++ b/examples/rainfall/doc/src/rainfall.qdoc @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example rainfall + \title Rainfall Example + + The barchart example shows how to make a simple 3D bar chart using Q3DBars. + + \image rainfall-example.png + + TODO +*/ diff --git a/examples/spectrum/doc/images/spectrum-example.png b/examples/spectrum/doc/images/spectrum-example.png Binary files differnew file mode 100644 index 00000000..2a703948 --- /dev/null +++ b/examples/spectrum/doc/images/spectrum-example.png diff --git a/examples/spectrum/doc/src/spectrum.qdoc b/examples/spectrum/doc/src/spectrum.qdoc new file mode 100644 index 00000000..87028e9c --- /dev/null +++ b/examples/spectrum/doc/src/spectrum.qdoc @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example spectrum + \title Spectrum Example + + The spectrum example shows how feed dynamic data to a graph using Q3DBars. + + \image spectrum-example.png + + TODO +*/ diff --git a/examples/widget/doc/images/widget-example.png b/examples/widget/doc/images/widget-example.png Binary files differnew file mode 100644 index 00000000..4fb43b42 --- /dev/null +++ b/examples/widget/doc/images/widget-example.png diff --git a/examples/widget/doc/src/widget.qdoc b/examples/widget/doc/src/widget.qdoc new file mode 100644 index 00000000..d8790a60 --- /dev/null +++ b/examples/widget/doc/src/widget.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example widget + \title Widget Example + + The widget example shows how to make a 3D bar chart using Q3DBars and combining the use of + widgets for adjusting several adjustable qualities. + + \image widget-example.png + + TODO +*/ diff --git a/src/datavis3d/doc/images/q3dbars-minimal.png b/src/datavis3d/doc/images/q3dbars-minimal.png Binary files differnew file mode 100644 index 00000000..63b77998 --- /dev/null +++ b/src/datavis3d/doc/images/q3dbars-minimal.png diff --git a/src/datavis3d/doc/qtdatavis3d.qdocconf b/src/datavis3d/doc/qtdatavis3d.qdocconf index c2c084b3..c3fd9826 100644 --- a/src/datavis3d/doc/qtdatavis3d.qdocconf +++ b/src/datavis3d/doc/qtdatavis3d.qdocconf @@ -1,47 +1,33 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) -# Name of the project which must match the outputdir. Determines the .index file -project = qtdatavis3d +project = QtDataVis3D +description = Qt Data Visualization 3D Reference Documentation +version = 1.0.0 -# Directories in which to search for files to document and images. -# By default set to the root directory of the project for sources -# and headers and qdoc will therefore generate output for each file. -# Images should be placed in <rootdir>/dic/images and examples in -# <rootdir>/examples. -# Paths are relative to the location of this file. exampledirs += ../../../examples \ snippets headerdirs += .. -imagedirs += images +imagedirs += ../images \ + images sourcedirs += .. -depends += qtcore qtgui - -# The following parameters are for creating a qhp file, the qhelpgenerator -# program can convert the qhp file into a qch file which can be opened in -# Qt Assistant and/or Qt Creator. - -# Defines the name of the project. You cannot use operators (+, =, -) in -# the name. Properties for this project are set using a qhp.<projectname>.property -# format. -qhp.projects = qtdatavis3d - -# Sets the name of the output qhp file. -qhp.qtdatavis3d.file = qtdatavis3d.qhp - -# Namespace for the output file. This namespace is used to distinguish between -# different documentation files in Creator/Assistant. -qhp.qtdatavis3d.namespace = org.qt-project.qtdatavis3d.501 - -# Title for the package, will be the main title for the package in -# Assistant/Creator. -qhp.qtdatavis3d.indexTitle = Qt Data Visualization 3D - -# Only update the name of the project for the next variables. -qhp.qtdatavis3d.virtualFolder = qtdatavis3d -qhp.qtdatavis3d.subprojects = classes -qhp.qtdatavis3d.subprojects.classes.title = C++ Classes -qhp.qtdatavis3d.subprojects.classes.indexTitle = Qt Data Visualization 3D C++ Classes -qhp.qtdatavis3d.subprojects.classes.selectors = class fake:headerfile -qhp.qtdatavis3d.subprojects.classes.sortPages = true +depends += qtcore \ + qtgui + +qhp.projects = QtDataVis3D + +qhp.qtdatavis3d.file = qtdatavis3d.qhp +qhp.qtdatavis3d.namespace = org.qt-project.qtdatavis3d.1.0.0 +qhp.qtdatavis3d.virtualFolder = qtdatavis3d +qhp.qtdatavis3d.indexTitle = Qt Data Visualization 3D +qhp.qtdatavis3d.indexRoot = + +qhp.qtdatavis3d.filterAttributes = qtdatavis3d 1.0.0 qtrefdoc +qhp.qtdatavis3d.customFilters.Qt.name = QtDataVis3D 1.0.0 +qhp.qtdatavis3d.customFilters.Qt.filterAttributes = qtdatavis3d 1.0.0 +qhp.qtdatavis3d.subprojects = classes +qhp.qtdatavis3d.subprojects.classes.title = C++ Classes +qhp.qtdatavis3d.subprojects.classes.indexTitle = Qt Data Visualization 3D C++ Classes +qhp.qtdatavis3d.subprojects.classes.selectors = class fake:headerfile +qhp.qtdatavis3d.subprojects.classes.sortPages = true diff --git a/src/datavis3d/doc/snippets/doc_src_q3dbars_construction.cpp b/src/datavis3d/doc/snippets/doc_src_q3dbars_construction.cpp new file mode 100644 index 00000000..0d94e0eb --- /dev/null +++ b/src/datavis3d/doc/snippets/doc_src_q3dbars_construction.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [3] +#include <QtDataVis3D> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + //! [0] + Q3DBars bars; + bars.setupSampleSpace(5, 5); + //! [0] + //! [1] + QVector<float> data; + data << 1.0f << 3.0f << 7.5f << 5.0f << 2.2f; + bars.addDataRow(data); + //! [1] + //! [2] + bars.show(); + //! [2] + + return app.exec(); +} +//! [3] diff --git a/src/datavis3dqml2/datavisview.h b/src/datavis3d/doc/snippets/doc_src_qtdatavis3d.cpp index 0edfd829..ac2f7f40 100644 --- a/src/datavis3dqml2/datavisview.h +++ b/src/datavis3d/doc/snippets/doc_src_qtdatavis3d.cpp @@ -39,34 +39,6 @@ ** ****************************************************************************/ -#ifndef DATAVISVIEW_H -#define DATAVISVIEW_H - -#include "QtDataVis3D/qdatavis3dglobal.h" - -#include <QQuickItem> - -QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE - -class DataVisView : public QQuickItem -{ - Q_OBJECT - Q_DISABLE_COPY(DataVisView) - -public: - DataVisView(QQuickItem *parent = 0); - ~DataVisView(); - -protected: - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); - -}; - -QTENTERPRISE_DATAVIS3D_END_NAMESPACE - -QTENTERPRISE_DATAVIS3D_USE_NAMESPACE - -QML_DECLARE_TYPE(DataVisView) - -#endif // DATAVISVIEW_H - +//! [0] +#include <QtDataVis3D> +//! [0] diff --git a/src/datavis3dqml2/datavisview.cpp b/src/datavis3d/doc/snippets/doc_src_qtdatavis3d.pro index bc7da610..4b670157 100644 --- a/src/datavis3dqml2/datavisview.cpp +++ b/src/datavis3d/doc/snippets/doc_src_qtdatavis3d.pro @@ -39,47 +39,6 @@ ** ****************************************************************************/ -#define TEST1 - -#include "datavisview.h" -#include "scenerenderernode_p.h" - -#include <QDebug> - -QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE - -DataVisView::DataVisView(QQuickItem *parent): - QQuickItem(parent) -{ - // By default, QQuickItem does not draw anything. If you subclass - // QQuickItem to create a visual item, you will need to uncomment the - // following line and re-implement updatePaintNode() - - setFlag(ItemHasContents, true); - setRotation(180.0); - setAntialiasing(true); - setSmooth(true); -} - -DataVisView::~DataVisView() -{ -} - -QSGNode *DataVisView::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) -{ -#ifdef TEST1 - // Delete old node and recreate it. This function gets called when window geometry changes. - if (oldNode) - delete oldNode; - - // We need to create a node class that does the rendering (ie. a node that "captures" the rendering we do) - SceneRendererNode *node = new SceneRendererNode(window()); - node->setRect(boundingRect()); - - return node; -#else - return NULL; -#endif -} - -QTENTERPRISE_DATAVIS3D_END_NAMESPACE +#! [0] +QT += datavis3d +#! [0] diff --git a/src/datavis3d/doc/src/qtdatavis3d-index.qdoc b/src/datavis3d/doc/src/qtdatavis3d-index.qdoc new file mode 100644 index 00000000..0c9cf8cc --- /dev/null +++ b/src/datavis3d/doc/src/qtdatavis3d-index.qdoc @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title Qt Data Visualization 3D + \page qtdatavis3d-index.html + \brief QtDataVis3D module provides functionality for 3D visualization. + + Qt Data Visualization module provides a way to visualize data in 3D. + It uses OpneGL for the data rendering. + + \section1 Getting Started + + Qt Data Visualization provides classes for rendering 3D data. To include + the definitions of the module's classes, use the following directive: + + \snippet doc_src_qtdatavis3d.cpp 0 + + To link against the module, add this line to your \l qmake \c + .pro file: + + \snippet doc_src_qtdatavis3d.pro 0 + + \section1 Articles + \list + \li \l{Qt Data Visualization 3D License Information}{License Information} + \endlist + + \section1 References + \list + \li \l{Qt Data Visualization 3D C++ Classes} + \endlist + + Qt Data Visualization 3D comes with the following examples: + + \list + \li \l{Barchart Example} + \li \l{Mapdata Example} + \li \l{Qt Quick 2 Barchart Example} + \li \l{Rainfall Example} + \li \l{Spectrum Example} + \li \l{Widget Example} + \endlist +*/ diff --git a/src/datavis3d/doc/src/qtdatavis3d.qdoc b/src/datavis3d/doc/src/qtdatavis3d.qdoc new file mode 100644 index 00000000..37e53161 --- /dev/null +++ b/src/datavis3d/doc/src/qtdatavis3d.qdoc @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module QtDataVis3D + \title Qt Data Visualization 3D C++ Classes + \ingroup modules + + \brief The QtDataVis3D module provides functionality for 3D visualization. +*/ + diff --git a/src/datavis3d/doc/src/qtdatavis3dlicense.qdoc b/src/datavis3d/doc/src/qtdatavis3dlicense.qdoc new file mode 100644 index 00000000..9821b26f --- /dev/null +++ b/src/datavis3d/doc/src/qtdatavis3dlicense.qdoc @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt SVG module. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtdatavis3dlicense.html + \title Qt Data Visualization 3D License Information + \ingroup licensing + \brief License information for Qt Data Visualization 3D + + TODO + + \legalese + TODO + \endlegalese + +*/ diff --git a/src/datavis3d/engine/bars3dshared.cpp b/src/datavis3d/engine/bars3dshared.cpp new file mode 100644 index 00000000..55efb7cc --- /dev/null +++ b/src/datavis3d/engine/bars3dshared.cpp @@ -0,0 +1,2421 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bars3dshared_p.h" +#include "camerahelper_p.h" +#include "qdataitem_p.h" +#include "qdatarow_p.h" +#include "qdataset_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 <QMatrix4x4> +#include <QOpenGLPaintDevice> +#include <QPainter> +#include <QScreen> +#include <QMouseEvent> + +#include <qmath.h> + +#include <QDebug> + +// Uncommenting this draws the shadow map with wider FOV than scene itself, making the light +// seem to be closer to scene than it actually is. This way shadows look slightly better (to me anyway) +#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 + +//#define DISPLAY_RENDER_SPEED + +#ifdef DISPLAY_RENDER_SPEED +#include <QTime> +#endif + +QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE + +//#define USE_HAX0R_SELECTION // keep this defined until the "real" method works +#define DISPLAY_FULL_DATA_ON_SELECTION // Append selection value text with row and column labels + +const GLfloat gridLineWidth = 0.005f; +static QVector3D skipColor = QVector3D(255, 255, 255); // Selection texture's background color + +Bars3dShared::Bars3dShared(QRect rect, GLuint fbohandle) + : m_boundingRect(rect.x(), rect.y(), rect.width(), rect.height()), + m_paintDevice(0), + 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_sampleCount(0, 0), + m_objFile(QStringLiteral(":/defaultMeshes/bar")), + m_mousePressed(MouseNone), + m_mousePos(QPoint(0, 0)), + m_zoomLevel(100), + m_zoomAdjustment(1.0f), + m_horizontalRotation(-45.0f), + m_verticalRotation(15.0f), + m_barThickness(QSizeF(0.75f, 0.75f)), + m_barSpacing(m_barThickness * 3.0f), + m_heightNormalizer(0.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_theme(new Theme()), + m_isInitialized(false), + m_selectionMode(ModeBar), + m_selectedBar(0), + m_zoomSelection(0), + m_dataSet(new QDataSet()), + m_axisLabelX(QStringLiteral("X")), + m_axisLabelZ(QStringLiteral("Z")), + m_axisLabelY(QStringLiteral("Y")), + m_sceneViewPort(rect.x(), rect.y(), rect.width(), rect.height()), + m_zoomViewPort(rect.x(), rect.y(), rect.width(), rect.height()), + m_zoomActivated(false), + m_labelTransparency(TransparencyFromTheme), + m_font(QFont(QStringLiteral("Arial"))), + m_drawer(new Drawer(*m_theme, m_font, m_labelTransparency)), + m_xFlipped(false), + m_zFlipped(false), + m_yFlipped(false), + m_bgrTexture(0), + m_depthTexture(0), + m_selectionTexture(0), + m_depthFrameBuffer(0), + m_selectionFrameBuffer(0), + m_selectionDepthBuffer(0), + m_updateLabels(false), + m_gridEnabled(true), + m_bgrEnabled(true), + m_shadowQuality(ShadowLow), + m_shadowQualityToShader(33.3f), + m_tickCount(0), + m_tickStep(0), + m_negativeValues(false), + m_fbohandle(fbohandle) +{ + m_theme = new Theme(); + m_dataSet->d_ptr->setDrawer(m_drawer); + QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Bars3dShared::updateTextures); +} + +Bars3dShared::~Bars3dShared() +{ +#ifndef USE_HAX0R_SELECTION + glDeleteFramebuffers(1, &m_selectionFrameBuffer); + glDeleteRenderbuffers(1, &m_selectionDepthBuffer); + m_textureHelper->deleteTexture(&m_selectionTexture); +#endif + glDeleteFramebuffers(1, &m_depthFrameBuffer); + m_textureHelper->deleteTexture(&m_bgrTexture); + delete m_dataSet; + if (m_zoomSelection) { + m_zoomSelection->d_ptr->clear(); + delete m_zoomSelection; + } + delete m_barShader; + delete m_depthShader; + delete m_selectionShader; + delete m_backgroundShader; + delete m_barObj; + delete m_backgroundObj; + delete m_gridLineObj; + delete m_textureHelper; + delete m_drawer; +} + + +void Bars3dShared::render() +{ + if (!m_isInitialized) + return; + +#ifdef DISPLAY_RENDER_SPEED + // For speed computation + static bool firstRender = true; + static QTime lastTime; + static GLint nbFrames = 0; + if (firstRender) { + lastTime.start(); + firstRender = false; + } + + // Measure speed (as milliseconds per frame) + nbFrames++; + if (lastTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago + qDebug() << qreal(lastTime.elapsed()) / qreal(nbFrames) << "ms/frame (=" << qreal(nbFrames) << "fps)"; + nbFrames = 0; + lastTime.restart(); + } +#endif + + // If zoom selection is on, draw zoom scene + drawZoomScene(); + // Draw bars scene + drawScene(); +} + +void Bars3dShared::initializeOpenGL() +{ + // Initialization is called multiple times when Qt Quick components are used + if (m_isInitialized) + return; + + initializeOpenGLFunctions(); + + m_textureHelper = new TextureHelper(); + m_drawer->initializeOpenGL(); + + // Resize in case we've missed resize events + resizeNotify(); + + // Initialize shaders +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + } + initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + // Init the depth buffer (for shadows) + initDepthBuffer(); + } else { + if (!m_theme->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_theme->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 + + 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(); + +#ifndef USE_HAX0R_SELECTION + // Init the selection buffer + initSelectionBuffer(); +#endif + + // Load default mesh + loadBarMesh(); + + // Load background mesh + loadBackgroundMesh(); + + // Load grid line mesh + loadGridLineMesh(); + + // Load label mesh + loadLabelMesh(); + + // 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 + + // Set initial camera position + // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later + CameraHelper::setDefaultCameraOrientation(QVector3D(0.0f, 0.0f, 6.0f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // Set view port + glViewport(0, 0, width(), height()); + + // Set initialized -flag + m_isInitialized = true; + + // Load background mesh + loadBackgroundMesh(); +} + +void Bars3dShared::drawZoomScene() +{ + // Set clear color + QVector3D clearColor = Utils::vectorFromColor(m_theme->m_windowColor); + glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // If no zoom, return + if (!m_zoomActivated) + return; + + GLfloat barPosX = 0; + GLint startBar = 0; + GLint stopBar = m_zoomSelection->d_ptr->row().size(); + GLint stepBar = 1; + QVector3D lightPos; + + // Specify viewport + glViewport(m_zoomViewPort.x(), m_zoomViewPort.y(), + m_zoomViewPort.width(), m_zoomViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_zoomViewPort.width() + / (GLfloat)m_zoomViewPort.height(), 0.1f, 100.0f); + +#ifdef ROTATE_ZOOM_SELECTION + // Calculate view matrix + QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(m_mousePos, + m_zoomLevel + * m_zoomAdjustment, + m_zoomViewPort.width(), + m_zoomViewPort.height()); + + // Get light position (rotate light with camera, a bit above it (as set in defaultLightPos)) + lightPos = CameraHelper::calculateLightPosition(defaultLightPos); + + if (viewMatrix.row(0).z() <= 0) { + startBar = m_zoomSelection->d_ptr->row().size() - 1; + stopBar = -1; + stepBar = -1; + } +#else + // Set view matrix + QMatrix4x4 viewMatrix; + + // Adjust scaling (zoom rate based on aspect ratio) + GLfloat camPosZoomed = 5.0f / m_zoomAdjustment + zComp; + + viewMatrix.lookAt(QVector3D(0.0f, 0.0f, camPosZoomed), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // Set light position a bit below the camera to reduce glare (depends on do we have row or column zoom) + QVector3D zoomLightPos = defaultLightPos; + zoomLightPos.setY(-10.0f); + if (ModeZoomColumn == m_selectionMode) + lightPos = CameraHelper::calculateLightPosition(zoomLightPos, -85.0f); + else + lightPos = CameraHelper::calculateLightPosition(zoomLightPos, 5.0f); +#endif + + // Bind bar shader + m_barShader->bind(); + + // Draw bars + // Draw the selected row / column + for (int bar = startBar; bar != stopBar; bar += stepBar) { + QDataItem *item = m_zoomSelection->d_ptr->getItem(bar); + if (!item) + continue; + + GLfloat barHeight = item->d_ptr->value() / m_heightNormalizer; + + if (barHeight < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + GLfloat barPosY = item->d_ptr->translation().y() - m_yAdjustment / 2.0f + 0.2f; // we need some room for labels underneath; add +0.2f + if (ModeZoomRow == m_selectionMode) + barPosX = item->d_ptr->translation().x(); + else + barPosX = -(item->d_ptr->translation().z() - zComp); // flip z; frontmost bar to the left + modelMatrix.translate(barPosX, barPosY, zComp); + modelMatrix.scale(QVector3D(m_scaleX, barHeight, m_scaleZ)); + itModelMatrix.scale(QVector3D(m_scaleX, barHeight, m_scaleZ)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + + QVector3D baseColor = Utils::vectorFromColor(m_theme->m_baseColor); + QVector3D heightColor = Utils::vectorFromColor(m_theme->m_heightColor) * barHeight; + + QVector3D barColor = baseColor + heightColor; + + GLfloat lightStrength = m_theme->m_lightStrength; + + if (barHeight != 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(), lightStrength); + m_barShader->setUniformValue(m_barShader->ambientS(), + m_theme->m_ambientStrength); + + // Draw the object + m_drawer->drawObject(m_barShader, m_barObj); + } + } + + // Release bar shader + m_barShader->release(); + + // Draw labels + m_labelShader->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + glCullFace(GL_BACK); + if (m_labelTransparency > TransparencyNone) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + // Draw labels for axes + QDataItem *dummyItem = NULL; + LabelItem x; + LabelItem z; + LabelItem y; + m_dataSet->d_ptr->axisLabelItems(&x, &z, &y); + LabelItem zoomSelectionLabel = m_zoomSelection->d_ptr->labelItem(); + if (ModeZoomRow == m_selectionMode) { + m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelTop); + m_drawer->drawLabel(*dummyItem, z, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelBottom); + } else { + m_drawer->drawLabel(*dummyItem, x, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelBottom); + m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelTop); + } + m_drawer->drawLabel(*dummyItem, y, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 90.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelLeft); + + // Draw labels for bars + for (int col = 0; col < m_zoomSelection->d_ptr->row().size(); col++) { + QDataItem *item = m_zoomSelection->d_ptr->getItem(col); + // Draw values + m_drawer->drawLabel(*item, item->d_ptr->label(), viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj); + // Draw labels + LabelItem labelItem; + if (ModeZoomRow == m_selectionMode) { + if (m_dataSet->d_ptr->columnLabelItems().size() > col) { + // If draw order of bars is flipped, label draw order should be too + if (m_xFlipped) { + labelItem = m_dataSet->d_ptr->columnLabelItems().at( + m_dataSet->d_ptr->columnLabelItems().size() - col - 1); + } else { + labelItem = m_dataSet->d_ptr->columnLabelItems().at(col); + } + } + } else { + if (m_dataSet->d_ptr->rowLabelItems().size() > col) { + // If draw order of bars is flipped, label draw order should be too + if (m_zFlipped) { + labelItem = m_dataSet->d_ptr->rowLabelItems().at( + m_dataSet->d_ptr->rowLabelItems().size() - col - 1); + } else { + labelItem = m_dataSet->d_ptr->rowLabelItems().at(col); + } + } + } + m_drawer->drawLabel(*item, labelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, -45.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, false, false, LabelBelow); + } + + glDisable(GL_TEXTURE_2D); + if (m_labelTransparency > TransparencyNone) + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + + // Release label shader + m_labelShader->release(); +} + +void Bars3dShared::drawScene() +{ + GLint startBar = 0; + GLint stopBar = 0; + GLint stepBar = 0; + + GLint startRow = 0; + GLint stopRow = 0; + GLint stepRow = 0; + + GLfloat backgroundRotation = 0; + + GLfloat barPos = 0; + GLfloat rowPos = 0; + + static QVector3D selection = skipColor; + + // Specify viewport + glViewport(m_sceneViewPort.x(), m_sceneViewPort.y(), + m_sceneViewPort.width(), m_sceneViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_sceneViewPort.width() + / (GLfloat)m_sceneViewPort.height(), 0.1f, 100.0f); + + // Calculate view matrix + QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(m_mousePos, + m_zoomLevel + * m_zoomAdjustment, + m_sceneViewPort.width(), + m_sceneViewPort.height(), + m_negativeValues); + + // 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_sampleCount.second; + stepRow = 1; + m_zFlipped = false; + } else { + startRow = m_sampleCount.second - 1; + stopRow = -1; + stepRow = -1; + m_zFlipped = true; + } + if (viewMatrix.row(0).z() <= 0) { + startBar = 0; + stopBar = m_sampleCount.first; + stepBar = 1; + m_xFlipped = false; + } else { + startBar = m_sampleCount.first - 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 (rotate light with camera, a bit above it (as set in defaultLightPos)) + QVector3D lightPos = CameraHelper::calculateLightPosition(defaultLightPos); + //lightPos = QVector3D(0.0f, 4.0f, zComp); // center of bars, 4.0f above - for testing + + // Skip depth rendering if we're in zoom mode + // TODO: Fix this, causes problems if depth rendering is off in zoom mode + // Introduce regardless of shadow quality to simplify logic + QMatrix4x4 depthViewMatrix; + QMatrix4x4 depthProjectionMatrix; + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone/*!m_zoomActivated*/) { + // 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_sceneViewPort.x(), m_sceneViewPort.y(), + m_sceneViewPort.width() * m_shadowQuality, + m_sceneViewPort.height() * m_shadowQuality); + + // Enable drawing to framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer); + glClear(GL_DEPTH_BUFFER_BIT); + + // Get the depth view matrix + // It may be possible to hack lightPos here if we want to make some tweaks to shadow + depthViewMatrix.lookAt(lightPos, 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 +#ifdef USE_WIDER_SHADOWS + // Use this for a bit exaggerated shadows + depthProjectionMatrix.perspective(20.0f, (GLfloat)m_sceneViewPort.width() + / (GLfloat)m_sceneViewPort.height(), 3.0f, 100.0f); +#else + // Use these for normal shadows, with the light further away + depthProjectionMatrix = projectionMatrix; +#endif + // Draw bars to depth buffer + for (int row = startRow; row != stopRow; row += stepRow) { + for (int bar = startBar; bar != stopBar; bar += stepBar) { + if (!m_dataSet->d_ptr->getRow(row)) + continue; + QDataItem *item = m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); + if (!item) + continue; + + GLfloat barHeight = item->d_ptr->value() / m_heightNormalizer; + + // skip shadows for 0 -height bars + if (barHeight == 0) + continue; + + // Set front face culling for positive valued bars and back face culling for + // negative valued bars to reduce self-shadowing issues + if (barHeight < 0) + glCullFace(GL_BACK); + else + glCullFace(GL_FRONT); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + barPos = (bar + 1) * (m_barSpacing.width()); + rowPos = (row + 1) * (m_barSpacing.height()); + + modelMatrix.translate((m_rowWidth - barPos) / m_scaleFactor, + barHeight - m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + + zComp); + modelMatrix.scale(QVector3D(m_scaleX, barHeight, m_scaleZ)); + + 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 framebuffer (= enable drawing to screen) + glBindFramebuffer(GL_FRAMEBUFFER, m_fbohandle); + + // 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_sceneViewPort.x(), m_sceneViewPort.y(), + m_sceneViewPort.width(), m_sceneViewPort.height()); + } +#endif + + // Skip selection mode drawing if we're zoomed or have no selection mode + if (!m_zoomActivated && m_selectionMode > ModeNone) { + // Bind selection shader + m_selectionShader->bind(); + + // Draw bars to selection buffer +#ifndef USE_HAX0R_SELECTION + glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); + glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used + glClearColor(skipColor.x() / 255, skipColor.y() / 255, skipColor.z() / 255, 1.0f); // Set clear color to white (= skipColor) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer +#endif + 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) { + if (!m_dataSet->d_ptr->getRow(row)) + continue; + QDataItem *item = m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); + if (!item) + continue; + + GLfloat barHeight = item->d_ptr->value() / m_heightNormalizer; + + if (barHeight < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + barPos = (bar + 1) * (m_barSpacing.width()); + rowPos = (row + 1) * (m_barSpacing.height()); + + modelMatrix.translate((m_rowWidth - barPos) / m_scaleFactor, + barHeight - m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + + zComp); + modelMatrix.scale(QVector3D(m_scaleX, barHeight, 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); + +#ifdef USE_HAX0R_SELECTION + // 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_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_selectionShader->posAtt()); +#else + // 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()); +#endif + } + } + glEnable(GL_DITHER); + + // Read color under cursor + if (Bars3dShared::MouseOnScene == m_mousePressed) + selection = Utils::getSelection(m_mousePos, height()); + +#ifndef USE_HAX0R_SELECTION + glBindFramebuffer(GL_FRAMEBUFFER, m_fbohandle); +#endif + + // 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 + +#ifdef USE_HAX0R_SELECTION + // Set clear color + QVector3D clearColor = Utils::vectorFromColor(m_theme->m_windowColor); + glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); + // Clear after selection + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#endif + } + + // Bind bar shader + m_barShader->bind(); + + // Enable texturing + glEnable(GL_TEXTURE_2D); + + // Draw bars + if (!m_zoomActivated && m_zoomSelection) + m_zoomSelection->d_ptr->clear(); + bool barSelectionFound = false; + for (int row = startRow; row != stopRow; row += stepRow) { + for (int bar = startBar; bar != stopBar; bar += stepBar) { + if (!m_dataSet->d_ptr->getRow(row)) + continue; + QDataItem *item = m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); + if (!item) + continue; + + GLfloat barHeight = item->d_ptr->value() / m_heightNormalizer; + + if (barHeight < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 itModelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + + barPos = (bar + 1) * (m_barSpacing.width()); + rowPos = (row + 1) * (m_barSpacing.height()); + modelMatrix.translate((m_rowWidth - barPos) / m_scaleFactor, + barHeight - m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + modelMatrix.scale(QVector3D(m_scaleX, barHeight, m_scaleZ)); + itModelMatrix.scale(QVector3D(m_scaleX, barHeight, m_scaleZ)); +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; +#else + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + QVector3D baseColor = Utils::vectorFromColor(m_theme->m_baseColor); + QVector3D heightColor = Utils::vectorFromColor(m_theme->m_heightColor) + * barHeight; + QVector3D depthColor = Utils::vectorFromColor(m_theme->m_depthColor) + * (float(row) / GLfloat(m_sampleCount.second)); + + QVector3D barColor = baseColor + heightColor + depthColor; + + GLfloat lightStrength = m_theme->m_lightStrength; + if (m_selectionMode > ModeNone) { + Bars3dShared::SelectionType selectionType = isSelected(row, bar, + selection); + switch (selectionType) { + case Bars3dShared::SelectionBar: { + barColor = Utils::vectorFromColor(m_theme->m_highlightBarColor); + lightStrength = m_theme->m_highlightLightStrength; + // Insert data to QDataItem. We have no ownership, don't delete the previous one + if (!m_zoomActivated) { + m_selectedBar = item; + if (m_dataSet->d_ptr->rowLabelItems().size() > row + && m_dataSet->d_ptr->columnLabelItems().size() > bar) { + m_selectedBar->setPosition( + QPoint(m_dataSet->d_ptr->rowLabelItems().size() + - row - 1, + m_dataSet->d_ptr->columnLabelItems().size() + - bar - 1)); + } + item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); + barSelectionFound = true; + if (m_selectionMode >= ModeZoomRow) { + item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); + m_zoomSelection->addItem(item); + } + } + break; + } + case Bars3dShared::SelectionRow: { + // Current bar is on the same row as the selected bar + barColor = Utils::vectorFromColor(m_theme->m_highlightRowColor); + lightStrength = m_theme->m_highlightLightStrength; + if (!m_zoomActivated && ModeZoomRow == m_selectionMode) { + item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); + m_zoomSelection->addItem(item); + if (m_dataSet->d_ptr->rowLabelItems().size() > row) { + m_zoomSelection->d_ptr->setLabelItem( + m_dataSet->d_ptr->rowLabelItems().at( + m_dataSet->d_ptr->rowLabelItems().size() + - row - 1)); + } + } + break; + } + case Bars3dShared::SelectionColumn: { + // Current bar is on the same column as the selected bar + barColor = Utils::vectorFromColor(m_theme->m_highlightColumnColor); + lightStrength = m_theme->m_highlightLightStrength; + if (!m_zoomActivated && ModeZoomColumn == m_selectionMode) { + item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); + m_zoomSelection->addItem(item); + if (m_dataSet->d_ptr->columnLabelItems().size() > bar) { + m_zoomSelection->d_ptr->setLabelItem( + m_dataSet->d_ptr->columnLabelItems().at( + m_dataSet->d_ptr->columnLabelItems().size() + - bar - 1)); + } + } + break; + } + case Bars3dShared::SelectionNone: { + // Current bar is not selected, nor on a row or column + // do nothing + break; + } + } + } + + if (barHeight != 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_theme->m_ambientStrength); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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 + m_drawer->drawObject(m_barShader, m_barObj); + } + } + } + } + + // Release bar shader + m_barShader->release(); + + // Bind background shader + m_backgroundShader->bind(); + + if (m_negativeValues) + glDisable(GL_CULL_FACE); + else + glCullFace(GL_BACK); + + // Draw background + if (m_bgrEnabled && 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_theme->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_theme->m_ambientStrength * 2.0f); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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_theme->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_theme->m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj); + } + } + + // Disable textures + glDisable(GL_TEXTURE_2D); + + // Release background shader + m_backgroundShader->release(); + + // Reset culling + if (m_negativeValues) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + // Draw grid lines + if (m_gridEnabled && m_heightNormalizer) { + // Bind bar shader + m_barShader->bind(); + + // Set unchanging shader bindings + QVector3D barColor = Utils::vectorFromColor(m_theme->m_gridLine); + m_barShader->setUniformValue(m_barShader->lightP(), lightPos); + m_barShader->setUniformValue(m_barShader->view(), viewMatrix); + m_barShader->setUniformValue(m_barShader->color(), barColor); + m_barShader->setUniformValue(m_barShader->ambientS(), + m_theme->m_ambientStrength); + + // Floor lines: rows + for (GLfloat row = 0.0f; row <= m_sampleCount.second; row++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + rowPos = (row + 0.5f) * (m_barSpacing.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 + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.inverted().transposed()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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(), + m_theme->m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj, + 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_barShader->setUniformValue(m_barShader->lightS(), + m_theme->m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj); + } + } + + // Floor lines: columns + for (GLfloat bar = 0.0f; bar <= m_sampleCount.first; bar++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + barPos = (bar + 0.5f) * (m_barSpacing.width()); + modelMatrix.translate((m_rowWidth - barPos) / 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 + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.inverted().transposed()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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(), + m_theme->m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj, + 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_barShader->setUniformValue(m_barShader->lightS(), + m_theme->m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj); + } + } + + // Wall lines: back wall + GLfloat heightStep = m_heightNormalizer / 5.0f; // default to 5 lines + GLfloat startLine; + + if (m_tickCount > 0) + heightStep = m_tickStep; + + if (m_negativeValues) + startLine = -m_heightNormalizer; + else + startLine = heightStep; + + 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 + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.inverted().transposed()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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(), + m_theme->m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj, + 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_barShader->setUniformValue(m_barShader->lightS(), + m_theme->m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_barShader, 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 + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.inverted().transposed()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // 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(), + m_theme->m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj, + 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_barShader->setUniformValue(m_barShader->lightS(), + m_theme->m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_barShader, m_gridLineObj); + } + } + + // Release bar shader + m_barShader->release(); + } + + // TODO: Draw y labels + + // Generate label textures for zoom selection if m_updateLabels is set + if (m_zoomActivated && m_updateLabels) { + // Create label textures + for (int col = 0; col < m_zoomSelection->d_ptr->row().size(); col++) { + QDataItem *item = m_zoomSelection->d_ptr->getItem(col); + m_drawer->generateLabelTexture(item); + } + } + + // Handle zoom activation and label drawing + if (!barSelectionFound) { + // We have no ownership, don't delete. Just NULL the pointer. + m_selectedBar = NULL; + if (m_zoomActivated && Bars3dShared::MouseOnOverview == m_mousePressed) { + m_sceneViewPort = QRect(0, 0, width(), height()); + m_zoomActivated = false; + } + } else if (m_selectionMode >= ModeZoomRow + && Bars3dShared::MouseOnScene == m_mousePressed) { + // Activate zoom mode + m_zoomActivated = true; + m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5); + + // Create label textures + for (int col = 0; col < m_zoomSelection->d_ptr->row().size(); col++) { + QDataItem *item = m_zoomSelection->d_ptr->getItem(col); + m_drawer->generateLabelTexture(item); + } + } else { + // Print value of selected bar + static QDataItem *prevItem = m_selectedBar; + m_labelShader->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + if (m_labelTransparency > TransparencyNone) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } +#ifndef DISPLAY_FULL_DATA_ON_SELECTION + // Draw just the value string of the selected bar + if (prevItem != m_selectedBar || m_updateLabels) { + m_drawer->generateLabelTexture(m_selectedBar); + prevItem = m_selectedBar; + } + + m_drawer->drawLabel(*m_selectedBar, m_selectedBar->label(), + viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, true); +#else + static bool firstSelection = true; + // Draw the value string followed by row label and column label + LabelItem labelItem = m_selectedBar->d_ptr->selectionLabel(); + if (firstSelection || prevItem != m_selectedBar || m_updateLabels) { + QString labelText = m_selectedBar->d_ptr->valueStr(); + if ((m_dataSet->d_ptr->columnLabels().size() + > m_selectedBar->position().y()) + && (m_dataSet->d_ptr->rowLabels().size() + > m_selectedBar->position().x())) { + labelText.append(QStringLiteral(" (")); + labelText.append(m_dataSet->d_ptr->rowLabels().at( + m_selectedBar->position().x())); + labelText.append(QStringLiteral(", ")); + labelText.append(m_dataSet->d_ptr->columnLabels().at( + m_selectedBar->position().y())); + labelText.append(QStringLiteral(")")); + //qDebug() << labelText; + } + m_drawer->generateLabelItem(&labelItem, labelText); + m_selectedBar->d_ptr->setSelectionLabel(labelItem); + prevItem = m_selectedBar; + firstSelection = false; + } + + m_drawer->drawLabel(*m_selectedBar, labelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), m_heightNormalizer, + m_selectionMode, m_labelShader, + m_labelObj, true, false); +#endif + glDisable(GL_TEXTURE_2D); + if (m_labelTransparency > TransparencyNone) + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + + // Release label shader + m_labelShader->release(); + + // Reset label update flag; they should have been updated when we get here + m_updateLabels = false; + } + + // 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); + if (m_labelTransparency > TransparencyNone) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + // Calculate the positions for row and column labels and store them into QDataItems (and QDataRows?) + for (int row = 0; row != m_sampleCount.second; row += 1) { + // 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 QDataSet. Just add LabelItems + rowPos = (row + 1) * (m_barSpacing.height()); + barPos = 0; + 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) { + barPos = (m_sampleCount.first + 1) * (m_barSpacing.width()); + alignment = Qt::AlignLeft; + } + if (m_yFlipped) { + if (m_zFlipped) + rotLabelY = 0.0f; + else + rotLabelY = 180.0f; + rotLabelZ = 180.0f; + } + QVector3D labelPos = QVector3D((m_rowWidth - barPos) / m_scaleFactor, + -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" + (m_columnDepth - rowPos) / m_scaleFactor + + zComp); + + // TODO: Try it; draw the label here + + // Create a data item + QDataItem *label = new QDataItem(); + label->d_ptr->setTranslation(labelPos); + if (m_dataSet->d_ptr->rowLabelItems().size() > row) { + label->d_ptr->setLabel(m_dataSet->d_ptr->rowLabelItems().at( + m_dataSet->d_ptr->rowLabelItems().size() - row - 1)); + } + + //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << m_dataSet->d_ptr->rowLabels().at(row); + + m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + m_heightNormalizer, m_selectionMode, + m_labelShader, m_labelObj, true, true, LabelMid, + alignment); + + delete label; + } + for (int bar = 0; bar != m_sampleCount.first; bar += 1) { + // 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 QDataSet. Just add LabelItems + barPos = (bar + 1) * (m_barSpacing.width()); + rowPos = 0; + 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_sampleCount.second + 1) * (m_barSpacing.height()); + alignment = Qt::AlignRight; + } + if (m_yFlipped) { + if (m_xFlipped) + rotLabelY = -90.0f; + else + rotLabelY = 90.0f; + rotLabelZ = 180.0f; + } + QVector3D labelPos = QVector3D((m_rowWidth - barPos) / m_scaleFactor, + -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" + (m_columnDepth - rowPos) / m_scaleFactor + + zComp); + + // TODO: Try it; draw the label here + + // Create a data item + QDataItem *label = new QDataItem(); + label->d_ptr->setTranslation(labelPos); + if (m_dataSet->d_ptr->columnLabelItems().size() > bar) { + label->d_ptr->setLabel(m_dataSet->d_ptr->columnLabelItems().at( + m_dataSet->d_ptr->columnLabelItems().size() + - bar - 1)); + } + + //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << m_dataSet->d_ptr->columnLabels().at(bar); + + m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + m_heightNormalizer, m_selectionMode, + m_labelShader, m_labelObj, true, true, LabelMid, + alignment); + + delete label; + } + glDisable(GL_TEXTURE_2D); + if (m_labelTransparency > TransparencyNone) + glDisable(GL_BLEND); + + // Release label shader + m_labelShader->release(); +} + +#if defined(Q_OS_ANDROID) +void Bars3dShared::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (!m_zoomActivated) { + m_mousePressed = Bars3dShared::MouseOnScene; + // update mouse positions to prevent jumping when releasing or repressing a button + m_mousePos = event->pos(); + } +} + +void Bars3dShared::touchEvent(QTouchEvent *event) +{ + static int prevDistance = 0; + + QList<QTouchEvent::TouchPoint> points; + points = event->touchPoints(); + + if (points.count() == 2) { + m_mousePressed = Bars3dShared::MouseOnPinch; + + QPointF distance = points.at(0).pos() - points.at(1).pos(); + int newDistance = distance.manhattanLength(); + int zoomRate = 1; + if (m_zoomLevel > 100) + zoomRate = 5; + if (newDistance > prevDistance) + m_zoomLevel += zoomRate; + else + m_zoomLevel -= zoomRate; + if (m_zoomLevel > 500) + m_zoomLevel = 500; + else if (m_zoomLevel < 10) + m_zoomLevel = 10; + prevDistance = newDistance; + //qDebug() << "distance" << distance.manhattanLength(); + } +} +#endif + +void Bars3dShared::mousePressEvent(QMouseEvent *event) +{ + if (Qt::LeftButton == event->button()) { + if (m_zoomActivated) { + if (event->pos().x() <= m_sceneViewPort.width() + && event->pos().y() <= m_sceneViewPort.height()) { + m_mousePressed = Bars3dShared::MouseOnOverview; + //qDebug() << "Mouse pressed on overview"; + } else { + m_mousePressed = Bars3dShared::MouseOnZoom; + //qDebug() << "Mouse pressed on zoom"; + } + } else { +#if !defined(Q_OS_ANDROID) + m_mousePressed = Bars3dShared::MouseOnScene; +#else + m_mousePressed = Bars3dShared::MouseRotating; +#endif + // update mouse positions to prevent jumping when releasing or repressing a button + m_mousePos = event->pos(); + //qDebug() << "Mouse pressed on scene"; + } + } else if (Qt::MiddleButton == event->button()) { + // reset rotations + m_mousePos = QPoint(0, 0); + } else if (Qt::RightButton == event->button()) { +#if !defined(Q_OS_ANDROID) + m_mousePressed = Bars3dShared::MouseRotating; +#else + m_mousePressed = Bars3dShared::MouseOnScene; +#endif + // update mouse positions to prevent jumping when releasing or repressing a button + m_mousePos = event->pos(); + } + CameraHelper::updateMousePos(m_mousePos); +} + +void Bars3dShared::mouseReleaseEvent(QMouseEvent *event) +{ + if (Bars3dShared::MouseRotating == m_mousePressed) { + // update mouse positions to prevent jumping when releasing or repressing a button + m_mousePos = event->pos(); + CameraHelper::updateMousePos(event->pos()); + } + m_mousePressed = Bars3dShared::MouseNone; +} + +void Bars3dShared::mouseMoveEvent(QMouseEvent *event) +{ + if (Bars3dShared::MouseRotating == m_mousePressed) + m_mousePos = event->pos(); +} + +void Bars3dShared::wheelEvent(QWheelEvent *event) +{ + if (m_zoomLevel > 100) + m_zoomLevel += event->angleDelta().y() / 12; + else if (m_zoomLevel > 50) + m_zoomLevel += event->angleDelta().y() / 60; + else + m_zoomLevel += event->angleDelta().y() / 120; + if (m_zoomLevel > 500) + m_zoomLevel = 500; + else if (m_zoomLevel < 10) + m_zoomLevel = 10; +} + +void Bars3dShared::resizeNotify() +{ + qDebug() << "Bars3dShared::resizeEvent " << width() << "x" <<height(); + + // Set view port + if (m_zoomActivated) + m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5); + else + m_sceneViewPort = QRect(0, 0, width(), height()); + m_zoomViewPort = QRect(0, 0, width(), height()); + + // Calculate zoom level based on aspect ratio + GLfloat div; + GLfloat zoomAdjustment; + div = qMin(width(), height()); + zoomAdjustment = defaultRatio * ((width() / div) / (height() / div)); + //qDebug() << "zoom adjustment" << zoomAdjustment; + m_zoomAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f + + // Re-init selection buffer + initSelectionBuffer(); + +#if !defined(QT_OPENGL_ES_2) + // Re-init depth buffer + if (m_isInitialized && m_shadowQuality > ShadowNone) + initDepthBuffer(); +#endif +} + +void Bars3dShared::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative) +{ + m_barThickness = thickness; + if (relative) { + m_barSpacing.setWidth((thickness.width() * 2) * (spacing.width() + 1.0f)); + m_barSpacing.setHeight((thickness.height() * 2) * (spacing.height() + 1.0f)); + } else { + m_barSpacing = thickness * 2 + spacing * 2; + } + // Calculate here and at setting sample space + calculateSceneScalingFactors(); +} + +void Bars3dShared::setBarType(BarStyle style, bool smooth) +{ + if (style == Bars) { + if (smooth) + m_objFile = QStringLiteral(":/defaultMeshes/barSmooth"); + else + m_objFile = QStringLiteral(":/defaultMeshes/bar"); + } else if (style == Pyramids) { + if (smooth) + m_objFile = QStringLiteral(":/defaultMeshes/pyramidSmooth"); + else + m_objFile = QStringLiteral(":/defaultMeshes/pyramid"); + } else if (style == Cones) { + if (smooth) + m_objFile = QStringLiteral(":/defaultMeshes/coneSmooth"); + else + m_objFile = QStringLiteral(":/defaultMeshes/cone"); + } else if (style == Cylinders) { + if (smooth) + m_objFile = QStringLiteral(":/defaultMeshes/cylinderSmooth"); + else + m_objFile = QStringLiteral(":/defaultMeshes/cylinder"); + } else if (style == BevelBars) { + if (smooth) + m_objFile = QStringLiteral(":/defaultMeshes/bevelbarSmooth"); + else + m_objFile = QStringLiteral(":/defaultMeshes/bevelbar"); + } + // Reload mesh data + if (m_isInitialized) + loadBarMesh(); +} + +void Bars3dShared::setMeshFileName(const QString &objFileName) +{ + m_objFile = objFileName; +} + +void Bars3dShared::setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow, + const QString &labelColumn, const QString &labelHeight) +{ + // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) + closeZoomMode(); + // Delete previous data set + delete m_dataSet; + m_dataSet = new QDataSet(); + m_sampleCount = qMakePair(samplesRow, samplesColumn); + m_dataSet->setLabels(labelRow, labelColumn, labelHeight); + // TODO: Invent "idiotproof" 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(samplesRow * samplesColumn); + //qDebug() << "maxSceneSize" << m_maxSceneSize; + // Calculate here and at setting bar specs + calculateSceneScalingFactors(); + m_axisLabelX = labelRow; + m_axisLabelZ = labelColumn; + m_axisLabelY = labelHeight; +} + +void Bars3dShared::setCameraPreset(CameraPreset preset) +{ + CameraHelper::setCameraPreset(preset); +} + +void Bars3dShared::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance) +{ + m_horizontalRotation = qBound(-180.0f, horizontal, 180.0f); + m_verticalRotation = qBound(0.0f, vertical, 90.0f); + m_zoomLevel = qBound(10, distance, 500); + CameraHelper::setCameraRotation(QPointF(m_horizontalRotation, + m_verticalRotation)); + //qDebug() << "camera rotation set to" << m_horizontalRotation << m_verticalRotation; +} + +void Bars3dShared::setTheme(ColorTheme theme) +{ + m_theme->useTheme(theme); + m_drawer->setTheme(*m_theme); + // Re-initialize shaders +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + } + } else { + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); + } + } +#else + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentColorOnYES2")); + } else { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentES2")); + } +#endif +} + +void Bars3dShared::setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, + bool uniform) +{ + m_theme->m_baseColor = baseColor; + m_theme->m_heightColor = heightColor; + m_theme->m_depthColor = depthColor; + //qDebug() << "colors:" << m_baseColor << m_heightColor << m_depthColor; + if (m_theme->m_uniformColor != uniform) { +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + } + } else { + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); + } + } +#else + if (!m_theme->m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentColorOnYES2")); + } else { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentES2")); + } +#endif + } + m_theme->m_uniformColor = uniform; +} + +void Bars3dShared::setSelectionMode(SelectionMode mode) +{ + m_selectionMode = mode; + // Disable zoom if selection mode changes + closeZoomMode(); + // Create zoom selection if there isn't one + if (mode >= ModeZoomRow && !m_zoomSelection) + m_zoomSelection = new QDataRow(); +} + +SelectionMode Bars3dShared::selectionMode() +{ + return m_selectionMode; +} + +void Bars3dShared::setFontSize(float fontsize) +{ + m_font.setPointSizeF(fontsize); + m_drawer->setFont(m_font); +} + +float Bars3dShared::fontSize() +{ + return m_font.pointSizeF(); +} + +void Bars3dShared::setFont(const QFont &font) +{ + m_font = font; + m_drawer->setFont(font); +} + +QFont Bars3dShared::font() +{ + return m_font; +} + +void Bars3dShared::setLabelTransparency(LabelTransparency transparency) +{ + m_labelTransparency = transparency; + m_drawer->setTransparency(transparency); +} + +LabelTransparency Bars3dShared::labelTransparency() +{ + return m_labelTransparency; +} + +void Bars3dShared::setGridEnabled(bool enable) +{ + m_gridEnabled = enable; +} + +bool Bars3dShared::gridEnabled() +{ + return m_gridEnabled; +} + +void Bars3dShared::setBackgroundEnabled(bool enable) +{ + if (m_bgrEnabled != enable) { + m_bgrEnabled = enable; + // Load changed bar type + loadBarMesh(); + } +} + +bool Bars3dShared::backgroundEnabled() +{ + return m_bgrEnabled; +} + +void Bars3dShared::setShadowQuality(ShadowQuality quality) +{ + m_shadowQuality = quality; + switch (quality) { + case ShadowLow: + m_shadowQualityToShader = 33.3f; + break; + case ShadowMedium: + m_shadowQualityToShader = 100.0f; + break; + case ShadowHigh: + m_shadowQualityToShader = 200.0f; + break; + default: + m_shadowQualityToShader = 0.0f; + break; + } + if (m_isInitialized) { +#if !defined(QT_OPENGL_ES_2) + if (m_shadowQuality > ShadowNone) { + // Re-init depth buffer + initDepthBuffer(); + // Re-init shaders + if (!m_theme->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 { + // Re-init shaders + if (!m_theme->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_theme->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 + } +} + +ShadowQuality Bars3dShared::shadowQuality() +{ + return m_shadowQuality; +} + +void Bars3dShared::setTickCount(GLint tickCount, GLfloat step, GLfloat minimum) +{ + m_tickCount = tickCount; + m_tickStep = step; + if (tickCount > 0 && step > 0) { + m_heightNormalizer = tickCount * step; + calculateHeightAdjustment(QPair<float, float>(minimum, m_heightNormalizer)); + } +} + +void Bars3dShared::addDataRow(const QVector<float> &dataRow, const QString &labelRow, + const QVector<QString> &labelsColumn) +{ + // Convert to QDataRow and add to QDataSet + QDataRow *row = new QDataRow(labelRow); + for (int i = 0; i < dataRow.size(); i++) + row->addItem(new QDataItem(dataRow.at(i))); + row->d_ptr->verifySize(m_sampleCount.first); + m_dataSet->addRow(row); + handleLimitChange(); + m_dataSet->setLabels(m_axisLabelX, m_axisLabelZ, m_axisLabelY, + QVector<QString>(), labelsColumn); + m_dataSet->d_ptr->verifySize(m_sampleCount.second); +} + +void Bars3dShared::addDataRow(const QVector<QDataItem*> &dataRow, const QString &labelRow, + const QVector<QString> &labelsColumn) +{ + // Convert to QDataRow and add to QDataSet + QDataRow *row = new QDataRow(labelRow); + for (int i = 0; i < dataRow.size(); i++) + row->addItem(dataRow.at(i)); + row->d_ptr->verifySize(m_sampleCount.first); + m_dataSet->addRow(row); + handleLimitChange(); + m_dataSet->setLabels(m_axisLabelX, m_axisLabelZ, m_axisLabelY, + QVector<QString>(), labelsColumn); + m_dataSet->d_ptr->verifySize(m_sampleCount.second); +} + +void Bars3dShared::addDataRow(QDataRow *dataRow) +{ + QDataRow *row = dataRow; + // Check that the input data fits into sample space, and resize if it doesn't + row->d_ptr->verifySize(m_sampleCount.first); + // With each new row, the previous data row must be moved back + // ie. we need as many vectors as we have rows in the sample space + m_dataSet->addRow(row); + // if the added data pushed us over sample space, remove the oldest data set + m_dataSet->d_ptr->verifySize(m_sampleCount.second); + handleLimitChange(); +} + +void Bars3dShared::addDataSet(const QVector< QVector<float> > &data, + const QVector<QString> &labelsRow, + const QVector<QString> &labelsColumn) +{ + // Copy axis labels + QString xAxis; + QString zAxis; + QString yAxis; + m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis); + // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) + closeZoomMode(); + // Delete old data set + delete m_dataSet; + m_dataSet = new QDataSet(); + // Give drawer to data set + m_dataSet->d_ptr->setDrawer(m_drawer); + // Convert to QDataRow and add to QDataSet + QDataRow *row; + for (int rowNr = 0; rowNr < data.size(); rowNr++) { + if (labelsRow.size() >= (rowNr + 1)) + row = new QDataRow(labelsRow.at(rowNr)); + else + row = new QDataRow(); + for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++) + row->addItem(new QDataItem(data.at(rowNr).at(colNr))); + row->d_ptr->verifySize(m_sampleCount.first); + m_dataSet->addRow(row); + row++; + } + handleLimitChange(); + m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); + m_dataSet->d_ptr->verifySize(m_sampleCount.second); +} + +void Bars3dShared::addDataSet(const QVector< QVector<QDataItem*> > &data, + const QVector<QString> &labelsRow, + const QVector<QString> &labelsColumn) +{ + // Copy axis labels + QString xAxis; + QString zAxis; + QString yAxis; + m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis); + // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) + closeZoomMode(); + // Delete old data set + delete m_dataSet; + m_dataSet = new QDataSet(); + // Give drawer to data set + m_dataSet->d_ptr->setDrawer(m_drawer); + // Convert to QDataRow and add to QDataSet + QDataRow *row; + for (int rowNr = 0; rowNr < data.size(); rowNr++) { + if (labelsRow.size() >= (rowNr + 1)) + row = new QDataRow(labelsRow.at(rowNr)); + else + row = new QDataRow(); + for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++) + row->addItem(data.at(rowNr).at(colNr)); + row->d_ptr->verifySize(m_sampleCount.first); + m_dataSet->addRow(row); + row++; + } + handleLimitChange(); + m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); + m_dataSet->d_ptr->verifySize(m_sampleCount.second); +} + +void Bars3dShared::addDataSet(QDataSet* dataSet) +{ + // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) + closeZoomMode(); + // Delete old data set + delete m_dataSet; + // Check sizes + dataSet->d_ptr->verifySize(m_sampleCount.second, m_sampleCount.first); + // Take ownership of given set + m_dataSet = dataSet; + handleLimitChange(); + // Give drawer to data set + m_dataSet->d_ptr->setDrawer(m_drawer); +} + +const QSize Bars3dShared::size() +{ + return m_boundingRect.size();; +} + +const QRect Bars3dShared::boundingRect() +{ + return m_boundingRect; +} + +void Bars3dShared::setBoundingRect(const QRect boundingRect) +{ + m_boundingRect = boundingRect; +} + +void Bars3dShared::setWidth(const int width) +{ + m_boundingRect.setWidth(width); +} + +int Bars3dShared::width() +{ + return m_boundingRect.width(); +} + +void Bars3dShared::setHeight(const int height) +{ + m_boundingRect.setHeight(height); +} + +int Bars3dShared::height() +{ + return m_boundingRect.height(); +} + +void Bars3dShared::setX(const int x) +{ + m_boundingRect.setX(x); +} + +int Bars3dShared::x() +{ + return m_boundingRect.x(); +} + +void Bars3dShared::setY(const int y) +{ + m_boundingRect.setY(y); +} + +int Bars3dShared::y() +{ + return m_boundingRect.y(); +} + +void Bars3dShared::loadBarMesh() +{ + QString objectFileName = m_objFile; + if (m_barObj) + delete m_barObj; + // If background is disabled, load full version of bar mesh + if (!m_bgrEnabled) + objectFileName.append(QStringLiteral("Full")); + m_barObj = new ObjectHelper(objectFileName); + m_barObj->load(); +} + +void Bars3dShared::loadBackgroundMesh() +{ + if (!m_isInitialized) + return; + + if (m_backgroundObj) + delete m_backgroundObj; + if (m_negativeValues) + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground")); + else + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); + m_backgroundObj->load(); +} + +void Bars3dShared::loadGridLineMesh() +{ + if (m_gridLineObj) + delete m_gridLineObj; + m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar")); + m_gridLineObj->load(); +} + +void Bars3dShared::loadLabelMesh() +{ + if (m_labelObj) + delete m_labelObj; + m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); + m_labelObj->load(); +} + +void Bars3dShared::initShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_barShader) + delete m_barShader; + m_barShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_barShader->initialize(); +} + +void Bars3dShared::initSelectionShader() +{ + if (m_selectionShader) + delete m_selectionShader; + m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSelection"), + QStringLiteral(":/shaders/fragmentSelection")); + m_selectionShader->initialize(); +} + +void Bars3dShared::initSelectionBuffer() +{ +#ifndef USE_HAX0R_SELECTION + if (m_selectionTexture) { + glDeleteFramebuffers(1, &m_selectionFrameBuffer); + glDeleteRenderbuffers(1, &m_selectionDepthBuffer); + m_textureHelper->deleteTexture(&m_selectionTexture); + } + m_selectionTexture = m_textureHelper->createSelectionTexture(this->size(), + m_selectionFrameBuffer, + m_selectionDepthBuffer); +#endif +} + +#if !defined(QT_OPENGL_ES_2) +void Bars3dShared::initDepthShader() +{ + if (m_depthShader) + delete m_depthShader; + m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), + QStringLiteral(":/shaders/fragmentDepth")); + m_depthShader->initialize(); +} + +void Bars3dShared::initDepthBuffer() +{ + if (m_depthTexture) { + glDeleteFramebuffers(1, &m_depthFrameBuffer); + m_textureHelper->deleteTexture(&m_depthTexture); + } + m_depthTexture = m_textureHelper->createDepthTexture(this->size(), m_depthFrameBuffer, + m_shadowQuality); +} +#endif + +void Bars3dShared::initBackgroundShaders(const QString &vertexShader, + const QString &fragmentShader) +{ + if (m_backgroundShader) + delete m_backgroundShader; + m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_backgroundShader->initialize(); +} + +void Bars3dShared::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_labelShader) + delete m_labelShader; + m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_labelShader->initialize(); +} + +void Bars3dShared::updateTextures() +{ + // Drawer has changed; this flag needs to be checked when checking if we need to update labels + m_updateLabels = true; +} + +void Bars3dShared::calculateSceneScalingFactors() +{ + // Calculate scene scaling and translation factors + m_rowWidth = ((m_sampleCount.first + 1) * m_barSpacing.width()) / 2.0f; + m_columnDepth = ((m_sampleCount.second + 1) * m_barSpacing.height()) / 2.0f; + m_maxDimension = qMax(m_rowWidth, m_columnDepth); + m_scaleFactor = qMin((m_sampleCount.first * (m_maxDimension / m_maxSceneSize)), + (m_sampleCount.second * (m_maxDimension / m_maxSceneSize))); + m_scaleX = m_barThickness.width() / m_scaleFactor; + m_scaleZ = m_barThickness.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 Bars3dShared::calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits) +{ + // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer + m_yAdjustment = 2.0f - ((limits.second - limits.first) / m_heightNormalizer); + //qDebug() << m_yAdjustment; +} + +Bars3dShared::SelectionType Bars3dShared::isSelected(GLint row, GLint bar, + const QVector3D &selection) +{ + //static QVector3D prevSel = selection; // TODO: For debugging + SelectionType isSelectedType = SelectionNone; +#ifdef USE_HAX0R_SELECTION + if (selection == Utils::vectorFromColor(m_theme->m_windowColor)) +#else + if (selection == skipColor) +#endif + 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 == selection) + isSelectedType = SelectionBar; + else if (current.y() == selection.y() && (m_selectionMode == ModeBarAndColumn + || m_selectionMode == ModeBarRowAndColumn + || m_selectionMode == ModeZoomColumn)) + isSelectedType = SelectionColumn; + else if (current.x() == selection.x() && (m_selectionMode == ModeBarAndRow + || m_selectionMode == ModeBarRowAndColumn + || m_selectionMode == ModeZoomRow)) + isSelectedType = SelectionRow; + return isSelectedType; +} + +void Bars3dShared::handleLimitChange() +{ + // Get the limits + QPair<GLfloat, GLfloat> limits = m_dataSet->d_ptr->limitValues(); + + // TODO: What if we have only negative values? + + // Check if we have negative values + if (limits.first < 0 && !m_negativeValues) { + m_negativeValues = true; + // Reload background + loadBackgroundMesh(); + } else if (limits.first >= 0 && m_negativeValues) { + m_negativeValues = false; + // Reload background + loadBackgroundMesh(); + } + + // Don't auto-adjust height if tick count is set + if (m_tickCount == 0) { + m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + calculateHeightAdjustment(limits); + } +} + +void Bars3dShared::closeZoomMode() +{ + m_zoomActivated = false; + m_sceneViewPort = QRect(0, 0, this->width(), this->height()); +} + +QTENTERPRISE_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/bars3dshared_p.h b/src/datavis3d/engine/bars3dshared_p.h new file mode 100644 index 00000000..2250b7c4 --- /dev/null +++ b/src/datavis3d/engine/bars3dshared_p.h @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtDataVis3D module. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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 Q3DBARSSHARED_p_H +#define Q3DBARSSHARED_p_H + +#include "QtDataVis3D/qdatavis3dglobal.h" +#include "QtDataVis3D/qdatavis3namespace.h" + +#include <QtCore/QSize> +#include <QtCore/QObject> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QFont> + +#include <QWindow> + +class QOpenGLPaintDevice; +class QPoint; +class QSizeF; +class QOpenGLShaderProgram; + +QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE + +class QDataItem; +class QDataRow; +class QDataSet; +class ShaderHelper; +class ObjectHelper; +class TextureHelper; +class Theme; +class Drawer; +class LabelItem; +class Bars3dSharedPrivate; + +class QTENTERPRISE_DATAVIS3D_EXPORT Bars3dShared : public QObject, public QOpenGLFunctions +{ + Q_OBJECT + +public: + enum SelectionType { + SelectionNone = 0, + SelectionBar, + SelectionRow, + SelectionColumn + }; + + enum MousePressType { + MouseNone = 0, + MouseOnScene, + MouseOnOverview, + MouseOnZoom, + MouseRotating, + MouseOnPinch + }; + + QRect m_boundingRect; + QOpenGLPaintDevice *m_paintDevice; + 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; + QPair<int, int> m_sampleCount; + QString m_objFile; + MousePressType m_mousePressed; + QPoint m_mousePos; + GLint m_zoomLevel; + GLfloat m_zoomAdjustment; + GLfloat m_horizontalRotation; + GLfloat m_verticalRotation; + QSizeF m_barThickness; + QSizeF m_barSpacing; + 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; + Theme *m_theme; + bool m_isInitialized; + SelectionMode m_selectionMode; + QDataItem *m_selectedBar; + QDataRow *m_zoomSelection; + QDataSet *m_dataSet; + QString m_axisLabelX; + QString m_axisLabelZ; + QString m_axisLabelY; + QRect m_sceneViewPort; + QRect m_zoomViewPort; + bool m_zoomActivated; + TextureHelper *m_textureHelper; + LabelTransparency m_labelTransparency; + QFont m_font; + Drawer *m_drawer; + bool m_xFlipped; + bool m_zFlipped; + bool m_yFlipped; + GLuint m_bgrTexture; + GLuint m_depthTexture; + GLuint m_selectionTexture; + GLuint m_depthFrameBuffer; + GLuint m_selectionFrameBuffer; + GLuint m_selectionDepthBuffer; + bool m_updateLabels; + bool m_gridEnabled; + bool m_bgrEnabled; + ShadowQuality m_shadowQuality; + GLfloat m_shadowQualityToShader; + GLint m_tickCount; + GLfloat m_tickStep; + bool m_negativeValues; + GLuint m_fbohandle; + QSize m_size; + +public: + explicit Bars3dShared(QRect rect, GLuint fbohandle=0); + ~Bars3dShared(); + + void initializeOpenGL(); + void render(); + + // Add a row of data. Each new row is added to the front of the sample space, moving previous + // rows back (if sample space is more than one row deep) + void addDataRow(const QVector<GLfloat> &dataRow, + const QString &labelRow = QString(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataItems is transferred + void addDataRow(const QVector<QDataItem*> &dataRow, + const QString &labelRow = QString(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataRow is transferred + void addDataRow(QDataRow *dataRow); + + // Add complete data set at a time, as a vector of data rows + void addDataSet(const QVector< QVector<GLfloat> > &data, + const QVector<QString> &labelsRow = QVector<QString>(), + const QVector<QString> &labelsColumn = QVector<QString>()); + + // ownership of dataItems is transferred + void addDataSet(const QVector< QVector<QDataItem*> > &data, + const QVector<QString> &labelsRow = QVector<QString>(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataSet is transferred + void addDataSet(QDataSet* dataSet); + + // 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(QSizeF thickness = QSizeF(1.0f, 1.0f), + QSizeF spacing = QSizeF(1.0f, 1.0f), + bool relative = true); + + // bar type; bars (=cubes), pyramids, cones, cylinders, etc. + void setBarType(BarStyle style, bool smooth = false); + + // override bar type with own mesh + void setMeshFileName(const QString &objFileName); + + // how many samples per row and column, and names for axes + void setupSampleSpace(int samplesRow, int samplesColumn, + const QString &labelRow = QString(), + const QString &labelColumn = QString(), + const QString &labelHeight = QString()); + + // Select preset camera placement + void setCameraPreset(CameraPreset preset); + + // Set camera rotation if you don't want to use the presets (in horizontal (-180...180) and + // vertical (0...90) (or (-90...90) if there are negative values) angles and distance in + // percentage (10...500)) + void setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance = 100); + + // Set theme (bar colors, shaders, window color, background colors, light intensity and text + // colors are affected) + void setTheme(ColorTheme theme); + + // Set color if you don't want to use themes. Set uniform to false if you want the (height) + // color to change from bottom to top + void setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, + bool uniform = true); + + // Set tick count and step. Note; tickCount * step should be the maximum possible value of data + // set. Minimum is the absolute minimum possible value a bar can have. This is especially + // important to set if values can be negative. + void setTickCount(GLint tickCount, GLfloat step, GLfloat minimum = 0.0f); + + // TODO: light placement API + + // Size + const QSize size(); + const QRect boundingRect(); + void setBoundingRect(const QRect boundingRect); + void setWidth(const int width); + int width(); + void setHeight(const int height); + int height(); + void setX(const int x); + int x(); + void setY(const int y); + int y(); + + // Change selection mode; single bar, bar and row, bar and column, or all + void setSelectionMode(SelectionMode mode); + SelectionMode selectionMode(); + + // Font size adjustment + void setFontSize(float fontsize); + float fontSize(); + + // Set font + void setFont(const QFont &font); + QFont font(); + + // Label transparency adjustment + void setLabelTransparency(LabelTransparency transparency); + LabelTransparency labelTransparency(); + + // Enable or disable background grid + void setGridEnabled(bool enable); + bool gridEnabled(); + + // Enable or disable background mesh + void setBackgroundEnabled(bool enable); + bool backgroundEnabled(); + + // Adjust shadow quality + void setShadowQuality(ShadowQuality quality); + ShadowQuality shadowQuality(); + +#if defined(Q_OS_ANDROID) + void mouseDoubleClickEvent(QMouseEvent *event); + void touchEvent(QTouchEvent *event); +#endif + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void resizeNotify(); + + void loadBarMesh(); + void loadBackgroundMesh(); + void loadGridLineMesh(); + void loadLabelMesh(); + void initShaders(const QString &vertexShader, const QString &fragmentShader); + 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 initDepthBuffer(); +#endif + void updateTextures(); + void calculateSceneScalingFactors(); + void calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits); + SelectionType isSelected(GLint row, GLint bar, const QVector3D &selection); + void handleLimitChange(); + void closeZoomMode(); + +private: + void drawZoomScene(); + void drawScene(); + Q_DISABLE_COPY(Bars3dShared) + + friend class DeclarativeBars; + friend class DeclarativeBarsRenderer; +}; + +QTENTERPRISE_DATAVIS3D_END_NAMESPACE + +#endif diff --git a/src/datavis3d/engine/drawer.cpp b/src/datavis3d/engine/drawer.cpp index d642b645..3c4d30cf 100644 --- a/src/datavis3d/engine/drawer.cpp +++ b/src/datavis3d/engine/drawer.cpp @@ -68,14 +68,20 @@ Drawer::Drawer(const Theme &theme, const QFont &font, LabelTransparency transpar : m_theme(theme), m_font(font), m_transparency(transparency), - m_textureHelper(new TextureHelper()) + m_textureHelper(0) { - initializeOpenGLFunctions(); } Drawer::~Drawer() { +} +void Drawer::initializeOpenGL() +{ + if (!m_textureHelper) { + initializeOpenGLFunctions(); + m_textureHelper = new TextureHelper(); + } } void Drawer::setTheme(const Theme &theme) @@ -289,6 +295,8 @@ void Drawer::generateLabelTexture(QDataItem *item) void Drawer::generateLabelItem(LabelItem *item, const QString &text) { + initializeOpenGL(); + // Delete previous texture, if there is one GLuint labelTexture = item->textureId(); if (labelTexture) diff --git a/src/datavis3d/engine/drawer_p.h b/src/datavis3d/engine/drawer_p.h index 5330a4aa..e31ab0cb 100644 --- a/src/datavis3d/engine/drawer_p.h +++ b/src/datavis3d/engine/drawer_p.h @@ -66,7 +66,7 @@ class ShaderHelper; class ObjectHelper; class TextureHelper; -class Drawer : public QObject, protected QOpenGLFunctions +class Drawer : public QObject, public QOpenGLFunctions { Q_OBJECT @@ -74,6 +74,8 @@ public: explicit Drawer(const Theme &theme, const QFont &font, LabelTransparency transparency); ~Drawer(); + void initializeOpenGL(); + void setTheme(const Theme &theme); void setFont(const QFont &font); void setTransparency(LabelTransparency transparency); diff --git a/src/datavis3d/engine/engine.pri b/src/datavis3d/engine/engine.pri index ba063186..b220120f 100644 --- a/src/datavis3d/engine/engine.pri +++ b/src/datavis3d/engine/engine.pri @@ -6,7 +6,8 @@ SOURCES += $$PWD/q3dwindow.cpp \ $$PWD/qdataset.cpp \ $$PWD/theme.cpp \ $$PWD/drawer.cpp \ - $$PWD/labelitem.cpp + $$PWD/labelitem.cpp \ + $$PWD/bars3dshared.cpp HEADERS += $$PWD/q3dwindow_p.h \ $$PWD/q3dwindow.h \ @@ -22,6 +23,7 @@ HEADERS += $$PWD/q3dwindow_p.h \ $$PWD/qdataset_p.h \ $$PWD/theme_p.h \ $$PWD/drawer_p.h \ - $$PWD/labelitem_p.h + $$PWD/labelitem_p.h \ + $$PWD/bars3dshared_p.h RESOURCES += engine/engine.qrc diff --git a/src/datavis3d/engine/q3dbars.cpp b/src/datavis3d/engine/q3dbars.cpp index 7ccab074..39750b38 100644 --- a/src/datavis3d/engine/q3dbars.cpp +++ b/src/datavis3d/engine/q3dbars.cpp @@ -41,18 +41,8 @@ #include "q3dbars.h" #include "q3dbars_p.h" -#include "camerahelper_p.h" -#include "qdataitem_p.h" -#include "qdatarow_p.h" -#include "qdataset_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 <QMatrix4x4> +#include "bars3dshared_p.h" + #include <QOpenGLPaintDevice> #include <QPainter> #include <QScreen> @@ -62,1765 +52,431 @@ #include <QDebug> -// Uncommenting this draws the shadow map with wider FOV than scene itself, making the light -// seem to be closer to scene than it actually is. This way shadows look slightly better (to me anyway) -#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 - -//#define DISPLAY_RENDER_SPEED - -#ifdef DISPLAY_RENDER_SPEED -#include <QTime> -#endif - QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE -//#define USE_HAX0R_SELECTION // keep this defined until the "real" method works -#define DISPLAY_FULL_DATA_ON_SELECTION // Append selection value text with row and column labels - -const GLfloat gridLineWidth = 0.005f; -static QVector3D skipColor = QVector3D(255, 255, 255); // Selection texture's background color - -Q3DBars::Q3DBars() - : d_ptr(new Q3DBarsPrivate(this)) -{ -} - +/*! + * \class Q3DBars + * \inmodule QtDataVis3D + * \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. + * + * 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 chart + * + * After constructing Q3DBars, you need to set up sample space using setupSampleSpace(). Let's + * set the sample space to 5 rows and 5 columns: + * + * \snippet doc_src_q3dbars_construction.cpp 0 + * + * Now Q3DBars is ready to receive data to be rendered. Add one row of 5 floats into the data + * set: + * + * \snippet doc_src_q3dbars_construction.cpp 1 + * + * \note We set the sample space 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 chart 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 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{Rainfall Example} or the \l{Widget Example}. + * + * \sa Q3DMaps, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + \enum BarStyle + + Predefined bar types. + + \value Bars + Basic cubic bar. + \value Pyramids + Four -sided pyramid. + \value Cones + Basic cone. + \value Cylinders + Basic cylinder. + \value BevelBars + Slilghtly beveled (rounded) cubic bar. + \value Spheres + Sphere. Not usable in Q3DBars. +*/ + +/*! + \enum CameraPreset + + Predefined positions for camera. + + \value PresetFrontLow + \value PresetFront + \value PresetFrontHigh + \value PresetLeftLow + \value PresetLeft + \value PresetLeftHigh + \value PresetRightLow + \value PresetRight + \value PresetRightHigh + \value PresetBehindLow + \value PresetBehind + \value PresetBehindHigh + \value PresetIsometricLeft + \value PresetIsometricLeftHigh + \value PresetIsometricRight + \value PresetIsometricRightHigh + \value PresetDirectlyAbove + \value PresetDirectlyAboveCW45 + \value PresetDirectlyAboveCCW45 + \value PresetFrontBelow + From PresetFrontBelow onward these only work for graphs including negative values. + They act as Preset...Low for positive-only values. + \value PresetLeftBelow + \value PresetRightBelow + \value PresetBehindBelow + \value PresetDirectlyBelow + Acts as PresetFrontLow for positive -only bars. +*/ + +/*! + \enum ColorTheme + + Predefined color themes. + + \value ThemeSystem + \value ThemeBlueCerulean + \value ThemeBlueIcy + \value ThemeBlueNcs + \value ThemeBrownSand + \value ThemeDark + \value ThemeHighContrast + \value ThemeLight +*/ + +/*! + \enum SelectionMode + + Bar selection modes. + + \value ModeNone + Selection mode disabled. + \value ModeBar + Selection selects a single bar. + \value ModeBarAndRow + Selection selects a single bar and highlights the row it is on. + \value ModeBarAndColumn + Selection selects a single bar and highlights the column it is on. + \value ModeBarRowAndColumn + Selection selects a single bar and highlights the row and the column it is on. + \value ModeZoomRow + Selection selects a single bar 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. + \value ModeZoomColumn + Selection selects a single bar 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. +*/ + +/*! + \enum ShadowQuality + + Quality of shadows. + + \value ShadowNone + Shadows are disabled. + \value ShadowLow + Shadows are rendered in low quality. + \value ShadowMedium + Shadows are rendered in medium quality. + \value ShadowHigh + Shadows are rendered in high quality. +*/ + +/*! + \enum LabelTransparency + + Label transparencies. + + \value TransparencyNone + Full solid, using colors from theme. + \value TransparencyFromTheme + Use colors and transparencies from theme. + \value TransparencyNoBackground + Draw just text on transparent background. +*/ + +/*! + * \a fbohandle Handle to QML2 scene graph's framebuffer object. Developers should not need to + * ever use this directly. Not used when using C++ API. + * + * \a windowsize QML2 window size Developers should not need to ever use this directly. Not + * used when using C++ API. + * + * Constructs a new 3D bar window. Parameters are not used unless instantiating from Qt Quick 2. + */ +Q3DBars::Q3DBars(GLuint fbohandle, const QSize &windowsize) + : d_ptr(new Q3DBarsPrivate(this, geometry(), fbohandle)) +{ +} + +/*! + * Destroys the 3d bar window. + */ Q3DBars::~Q3DBars() { } +/*! + * \internal + */ void Q3DBars::initialize() { - // Initialize shaders -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - // Init the depth buffer (for shadows) - d_ptr->initDepthBuffer(); - } else { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } -#else - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentColorOnYES2")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); -#endif - - d_ptr->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. - d_ptr->initDepthShader(); -#endif - - // Init selection shader - d_ptr->initSelectionShader(); - -#ifndef USE_HAX0R_SELECTION - // Init the selection buffer - d_ptr->initSelectionBuffer(); -#endif - - // Load default mesh - d_ptr->loadBarMesh(); - - // Load background mesh - d_ptr->loadBackgroundMesh(); - - // Load grid line mesh - d_ptr->loadGridLineMesh(); - - // Load label mesh - d_ptr->loadLabelMesh(); - - // 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 - - // Set initial camera position - // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later - CameraHelper::setDefaultCameraOrientation(QVector3D(0.0f, 0.0f, 6.0f + zComp), - QVector3D(0.0f, 0.0f, zComp), - QVector3D(0.0f, 1.0f, 0.0f)); - - // Set view port -#ifdef USE_QML2_VERSION - glViewport(0, 0, 800, 500); -#else - glViewport(0, 0, width(), height()); -#endif - - // Set initialized -flag - d_ptr->m_isInitialized = true; + d_ptr->m_shared->setWidth(width()); + d_ptr->m_shared->setHeight(height()); + d_ptr->m_shared->initializeOpenGL(); } +/*! + * \internal + */ void Q3DBars::render() { -#ifdef USE_QML2_VERSION - glDepthMask(true); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); -#endif - - if (!d_ptr->m_isInitialized) - return; - -#ifdef DISPLAY_RENDER_SPEED - // For speed computation - static bool firstRender = true; - static QTime lastTime; - static GLint nbFrames = 0; - if (firstRender) { - lastTime.start(); - firstRender = false; - } - - // Measure speed (as milliseconds per frame) - nbFrames++; - if (lastTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago - qDebug() << qreal(lastTime.elapsed()) / qreal(nbFrames) << "ms/frame (=" << qreal(nbFrames) << "fps)"; - nbFrames = 0; - lastTime.restart(); - } -#endif - - // If zoom selection is on, draw zoom scene - drawZoomScene(); - // Draw bars scene - drawScene(); -} - -void Q3DBars::drawZoomScene() -{ - // Set clear color - QVector3D clearColor = Utils::vectorFromColor(d_ptr->m_theme->m_windowColor); - glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // If no zoom, return - if (!d_ptr->m_zoomActivated) - return; - - GLfloat barPosX = 0; - GLint startBar = 0; - GLint stopBar = d_ptr->m_zoomSelection->d_ptr->row().size(); - GLint stepBar = 1; - QVector3D lightPos; - - // Specify viewport - glViewport(d_ptr->m_zoomViewPort.x(), d_ptr->m_zoomViewPort.y(), - d_ptr->m_zoomViewPort.width(), d_ptr->m_zoomViewPort.height()); - - // Set up projection matrix - QMatrix4x4 projectionMatrix; - projectionMatrix.perspective(45.0f, (GLfloat)d_ptr->m_zoomViewPort.width() - / (GLfloat)d_ptr->m_zoomViewPort.height(), 0.1f, 100.0f); - -#ifdef ROTATE_ZOOM_SELECTION - // Calculate view matrix - QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(d_ptr->m_mousePos, - d_ptr->m_zoomLevel - * d_ptr->m_zoomAdjustment, - d_ptr->m_zoomViewPort.width(), - d_ptr->m_zoomViewPort.height()); - - // Get light position (rotate light with camera, a bit above it (as set in defaultLightPos)) - lightPos = CameraHelper::calculateLightPosition(defaultLightPos); - - if (viewMatrix.row(0).z() <= 0) { - startBar = d_ptr->m_zoomSelection->d_ptr->row().size() - 1; - stopBar = -1; - stepBar = -1; - } -#else - // Set view matrix - QMatrix4x4 viewMatrix; - - // Adjust scaling (zoom rate based on aspect ratio) - GLfloat camPosZoomed = 5.0f / d_ptr->m_zoomAdjustment + zComp; - - viewMatrix.lookAt(QVector3D(0.0f, 0.0f, camPosZoomed), - QVector3D(0.0f, 0.0f, zComp), - QVector3D(0.0f, 1.0f, 0.0f)); - - // Set light position a bit below the camera to reduce glare (depends on do we have row or column zoom) - QVector3D zoomLightPos = defaultLightPos; - zoomLightPos.setY(-10.0f); - if (ModeZoomColumn == d_ptr->m_selectionMode) - lightPos = CameraHelper::calculateLightPosition(zoomLightPos, -85.0f); - else - lightPos = CameraHelper::calculateLightPosition(zoomLightPos, 5.0f); -#endif - - // Bind bar shader - d_ptr->m_barShader->bind(); - - // Draw bars - // Draw the selected row / column - for (int bar = startBar; bar != stopBar; bar += stepBar) { - QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(bar); - if (!item) - continue; - - GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer; - - if (barHeight < 0) - glCullFace(GL_FRONT); - else - glCullFace(GL_BACK); - - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 itModelMatrix; - - GLfloat barPosY = item->d_ptr->translation().y() - d_ptr->m_yAdjustment / 2.0f + 0.2f; // we need some room for labels underneath; add +0.2f - if (ModeZoomRow == d_ptr->m_selectionMode) - barPosX = item->d_ptr->translation().x(); - else - barPosX = -(item->d_ptr->translation().z() - zComp); // flip z; frontmost bar to the left - modelMatrix.translate(barPosX, barPosY, zComp); - modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ)); - itModelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ)); - - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - - QVector3D baseColor = Utils::vectorFromColor(d_ptr->m_theme->m_baseColor); - QVector3D heightColor = Utils::vectorFromColor(d_ptr->m_theme->m_heightColor) * barHeight; - - QVector3D barColor = baseColor + heightColor; - - GLfloat lightStrength = d_ptr->m_theme->m_lightStrength; - - if (barHeight != 0) { - // Set shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), lightStrength); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(), - d_ptr->m_theme->m_ambientStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj); - } - } - - // Release bar shader - d_ptr->m_barShader->release(); - - // Draw labels - d_ptr->m_labelShader->bind(); - glDisable(GL_DEPTH_TEST); - glEnable(GL_TEXTURE_2D); - glCullFace(GL_BACK); - if (d_ptr->m_labelTransparency > TransparencyNone) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - // Draw labels for axes - QDataItem *dummyItem = NULL; - LabelItem x; - LabelItem z; - LabelItem y; - d_ptr->m_dataSet->d_ptr->axisLabelItems(&x, &z, &y); - LabelItem zoomSelectionLabel = d_ptr->m_zoomSelection->d_ptr->labelItem(); - if (ModeZoomRow == d_ptr->m_selectionMode) { - d_ptr->m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelTop); - d_ptr->m_drawer->drawLabel(*dummyItem, z, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelBottom); - } else { - d_ptr->m_drawer->drawLabel(*dummyItem, x, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelBottom); - d_ptr->m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelTop); - } - d_ptr->m_drawer->drawLabel(*dummyItem, y, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 90.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelLeft); - - // Draw labels for bars - for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) { - QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col); - // Draw values - d_ptr->m_drawer->drawLabel(*item, item->d_ptr->label(), viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj); - // Draw labels - LabelItem labelItem; - if (ModeZoomRow == d_ptr->m_selectionMode) { - if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > col) { - // If draw order of bars is flipped, label draw order should be too - if (d_ptr->m_xFlipped) { - labelItem = d_ptr->m_dataSet->d_ptr->columnLabelItems().at( - d_ptr->m_dataSet->d_ptr->columnLabelItems().size() - col - 1); - } else { - labelItem = d_ptr->m_dataSet->d_ptr->columnLabelItems().at(col); - } - } - } else { - if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > col) { - // If draw order of bars is flipped, label draw order should be too - if (d_ptr->m_zFlipped) { - labelItem = d_ptr->m_dataSet->d_ptr->rowLabelItems().at( - d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - col - 1); - } else { - labelItem = d_ptr->m_dataSet->d_ptr->rowLabelItems().at(col); - } - } - } - d_ptr->m_drawer->drawLabel(*item, labelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, -45.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, false, false, LabelBelow); - } - - glDisable(GL_TEXTURE_2D); - if (d_ptr->m_labelTransparency > TransparencyNone) - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - - // Release label shader - d_ptr->m_labelShader->release(); -} - -void Q3DBars::drawScene() -{ - GLint startBar = 0; - GLint stopBar = 0; - GLint stepBar = 0; - - GLint startRow = 0; - GLint stopRow = 0; - GLint stepRow = 0; - - GLfloat backgroundRotation = 0; - - GLfloat barPos = 0; - GLfloat rowPos = 0; - - static QVector3D selection = skipColor; - -#ifdef USE_QML2_VERSION - d_ptr->m_sceneViewPort = QRect(0, 0, 800, 500); -#endif - - // Specify viewport - glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(), - d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height()); - - // Set up projection matrix - QMatrix4x4 projectionMatrix; - projectionMatrix.perspective(45.0f, (GLfloat)d_ptr->m_sceneViewPort.width() - / (GLfloat)d_ptr->m_sceneViewPort.height(), 0.1f, 100.0f); - - // Calculate view matrix -#ifdef USE_QML2_VERSION - static int rot = 0; - rot += 5; - if (rot > 2870) - rot = 0; - d_ptr->m_mousePos.setX(rot); - d_ptr->m_mousePos.setY(100); -#endif - QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(d_ptr->m_mousePos, - d_ptr->m_zoomLevel - * d_ptr->m_zoomAdjustment, - d_ptr->m_sceneViewPort.width(), - d_ptr->m_sceneViewPort.height(), - d_ptr->m_negativeValues); - - // 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 = d_ptr->m_sampleCount.second; - stepRow = 1; - d_ptr->m_zFlipped = false; - } else { - startRow = d_ptr->m_sampleCount.second - 1; - stopRow = -1; - stepRow = -1; - d_ptr->m_zFlipped = true; - } - if (viewMatrix.row(0).z() <= 0) { - startBar = 0; - stopBar = d_ptr->m_sampleCount.first; - stepBar = 1; - d_ptr->m_xFlipped = false; - } else { - startBar = d_ptr->m_sampleCount.first - 1; - stopBar = -1; - stepBar = -1; - d_ptr->m_xFlipped = true; - } - - // Check if we're viewing the scene from below - if (viewMatrix.row(2).y() < 0) - d_ptr->m_yFlipped = true; - else - d_ptr->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 (rotate light with camera, a bit above it (as set in defaultLightPos)) - QVector3D lightPos = CameraHelper::calculateLightPosition(defaultLightPos); - //lightPos = QVector3D(0.0f, 4.0f, zComp); // center of bars, 4.0f above - for testing - - // Skip depth rendering if we're in zoom mode - // TODO: Fix this, causes problems if depth rendering is off in zoom mode - // Introduce regardless of shadow quality to simplify logic - QMatrix4x4 depthViewMatrix; - QMatrix4x4 depthProjectionMatrix; - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone/*!d_ptr->m_zoomActivated*/) { - // Render scene into a depth texture for using with shadow mapping - // Bind depth shader - d_ptr->m_depthShader->bind(); - - // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows. - glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(), - d_ptr->m_sceneViewPort.width() * d_ptr->m_shadowQuality, - d_ptr->m_sceneViewPort.height() * d_ptr->m_shadowQuality); - - // Enable drawing to framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_depthFrameBuffer); - glClear(GL_DEPTH_BUFFER_BIT); - - // Get the depth view matrix - // It may be possible to hack lightPos here if we want to make some tweaks to shadow - depthViewMatrix.lookAt(lightPos, QVector3D(0.0f, -d_ptr->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 -#ifdef USE_WIDER_SHADOWS - // Use this for a bit exaggerated shadows - depthProjectionMatrix.perspective(20.0f, (GLfloat)d_ptr->m_sceneViewPort.width() - / (GLfloat)d_ptr->m_sceneViewPort.height(), 3.0f, 100.0f); -#else - // Use these for normal shadows, with the light further away - depthProjectionMatrix = projectionMatrix; -#endif - // Draw bars to depth buffer - for (int row = startRow; row != stopRow; row += stepRow) { - for (int bar = startBar; bar != stopBar; bar += stepBar) { - if (!d_ptr->m_dataSet->d_ptr->getRow(row)) - continue; - QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); - if (!item) - continue; - - GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer; - - // skip shadows for 0 -height bars - if (barHeight == 0) - continue; - - // Set front face culling for positive valued bars and back face culling for - // negative valued bars to reduce self-shadowing issues - if (barHeight < 0) - glCullFace(GL_BACK); - else - glCullFace(GL_FRONT); - - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - - barPos = (bar + 1) * (d_ptr->m_barSpacing.width()); - rowPos = (row + 1) * (d_ptr->m_barSpacing.height()); - - modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - barHeight - d_ptr->m_yAdjustment, - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor - + zComp); - modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ)); - - MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - - d_ptr->m_depthShader->setUniformValue(d_ptr->m_depthShader->MVP(), MVPMatrix); - - // 1st attribute buffer : vertices - glEnableVertexAttribArray(d_ptr->m_depthShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf()); - glVertexAttribPointer(d_ptr->m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, - (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT, - (void *)0); - - // Free buffers - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(d_ptr->m_depthShader->posAtt()); - } - } - - // Disable drawing to framebuffer (= enable drawing to screen) - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Release depth shader - d_ptr->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) - d_ptr->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; - d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix); - d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj, - d_ptr->m_depthTexture); - glDisable(GL_TEXTURE_2D); - d_ptr->m_labelShader->release(); -#endif - // Reset culling to normal - glCullFace(GL_BACK); - - // Revert to original viewport - glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(), - d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height()); - } -#endif - - // Skip selection mode drawing if we're zoomed or have no selection mode - if (!d_ptr->m_zoomActivated && d_ptr->m_selectionMode > ModeNone) { - // Bind selection shader - d_ptr->m_selectionShader->bind(); - - // Draw bars to selection buffer -#ifndef USE_HAX0R_SELECTION - glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_selectionFrameBuffer); - glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used - glClearColor(skipColor.x() / 255, skipColor.y() / 255, skipColor.z() / 255, 1.0f); // Set clear color to white (= skipColor) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer -#endif - 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) { - if (!d_ptr->m_dataSet->d_ptr->getRow(row)) - continue; - QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); - if (!item) - continue; - - GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer; - - if (barHeight < 0) - glCullFace(GL_FRONT); - else - glCullFace(GL_BACK); - - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - - barPos = (bar + 1) * (d_ptr->m_barSpacing.width()); - rowPos = (row + 1) * (d_ptr->m_barSpacing.height()); - - modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - barHeight - d_ptr->m_yAdjustment, - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor - + zComp); - modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->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 - - d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->MVP(), - MVPMatrix); - d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->color(), - barColor); - -#ifdef USE_HAX0R_SELECTION - // 1st attribute buffer : vertices - glEnableVertexAttribArray(d_ptr->m_selectionShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf()); - glVertexAttribPointer(d_ptr->m_selectionShader->posAtt(), - 3, GL_FLOAT, GL_FALSE, 0, (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), - GL_UNSIGNED_SHORT, (void *)0); - - // Free buffers - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(d_ptr->m_selectionShader->posAtt()); -#else - // 1st attribute buffer : vertices - glEnableVertexAttribArray(d_ptr->m_selectionShader->posAtt()); - glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf()); - glVertexAttribPointer(d_ptr->m_selectionShader->posAtt(), - 3, GL_FLOAT, GL_FALSE, 0, (void *)0); - - // Index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf()); - - // Draw the triangles - glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT, - (void *)0); - - // Free buffers - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(d_ptr->m_selectionShader->posAtt()); -#endif - } - } - glEnable(GL_DITHER); - - // Read color under cursor - if (Q3DBarsPrivate::MouseOnScene == d_ptr->m_mousePressed) - selection = Utils::getSelection(d_ptr->m_mousePos, height()); - -#ifndef USE_HAX0R_SELECTION - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif - - // Release selection shader - d_ptr->m_selectionShader->release(); - -#if 0 // Use this if you want to see what is being drawn to the framebuffer - glCullFace(GL_BACK); - d_ptr->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; - d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix); - d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj, true, - d_ptr->m_selectionTexture); - glDisable(GL_TEXTURE_2D); - d_ptr->m_labelShader->release(); -#endif - -#ifdef USE_HAX0R_SELECTION - // Set clear color - QVector3D clearColor = Utils::vectorFromColor(d_ptr->m_theme->m_windowColor); - glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); - // Clear after selection - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif - } - - // Bind bar shader - d_ptr->m_barShader->bind(); - - // Enable texturing - glEnable(GL_TEXTURE_2D); - - // Draw bars - if (!d_ptr->m_zoomActivated && d_ptr->m_zoomSelection) - d_ptr->m_zoomSelection->d_ptr->clear(); - bool barSelectionFound = false; - for (int row = startRow; row != stopRow; row += stepRow) { - for (int bar = startBar; bar != stopBar; bar += stepBar) { - if (!d_ptr->m_dataSet->d_ptr->getRow(row)) - continue; - QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar); - if (!item) - continue; - - GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer; - - if (barHeight < 0) - glCullFace(GL_FRONT); - else - glCullFace(GL_BACK); - - QMatrix4x4 modelMatrix; - QMatrix4x4 itModelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - - barPos = (bar + 1) * (d_ptr->m_barSpacing.width()); - rowPos = (row + 1) * (d_ptr->m_barSpacing.height()); - modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - barHeight - d_ptr->m_yAdjustment, - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor + zComp); - modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ)); - itModelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ)); -#ifdef SHOW_DEPTH_TEXTURE_SCENE - MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; -#else - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; -#endif - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - - QVector3D baseColor = Utils::vectorFromColor(d_ptr->m_theme->m_baseColor); - QVector3D heightColor = Utils::vectorFromColor(d_ptr->m_theme->m_heightColor) - * barHeight; - QVector3D depthColor = Utils::vectorFromColor(d_ptr->m_theme->m_depthColor) - * (float(row) / GLfloat(d_ptr->m_sampleCount.second)); - - QVector3D barColor = baseColor + heightColor + depthColor; - - GLfloat lightStrength = d_ptr->m_theme->m_lightStrength; - if (d_ptr->m_selectionMode > ModeNone) { - Q3DBarsPrivate::SelectionType selectionType = d_ptr->isSelected(row, bar, - selection); - switch (selectionType) { - case Q3DBarsPrivate::SelectionBar: { - barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightBarColor); - lightStrength = d_ptr->m_theme->m_highlightLightStrength; - // Insert data to QDataItem. We have no ownership, don't delete the previous one - if (!d_ptr->m_zoomActivated) { - d_ptr->m_selectedBar = item; - if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row - && d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) { - d_ptr->m_selectedBar->setPosition( - QPoint(d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - - row - 1, - d_ptr->m_dataSet->d_ptr->columnLabelItems().size() - - bar - 1)); - } - item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); - barSelectionFound = true; - if (d_ptr->m_selectionMode >= ModeZoomRow) { - item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); - d_ptr->m_zoomSelection->addItem(item); - } - } - break; - } - case Q3DBarsPrivate::SelectionRow: { - // Current bar is on the same row as the selected bar - barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightRowColor); - lightStrength = d_ptr->m_theme->m_highlightLightStrength; - if (!d_ptr->m_zoomActivated && ModeZoomRow == d_ptr->m_selectionMode) { - item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); - d_ptr->m_zoomSelection->addItem(item); - if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row) { - d_ptr->m_zoomSelection->d_ptr->setLabelItem( - d_ptr->m_dataSet->d_ptr->rowLabelItems().at( - d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - - row - 1)); - } - } - break; - } - case Q3DBarsPrivate::SelectionColumn: { - // Current bar is on the same column as the selected bar - barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightColumnColor); - lightStrength = d_ptr->m_theme->m_highlightLightStrength; - if (!d_ptr->m_zoomActivated && ModeZoomColumn == d_ptr->m_selectionMode) { - item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D()); - d_ptr->m_zoomSelection->addItem(item); - if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) { - d_ptr->m_zoomSelection->d_ptr->setLabelItem( - d_ptr->m_dataSet->d_ptr->columnLabelItems().at( - d_ptr->m_dataSet->d_ptr->columnLabelItems().size() - - bar - 1)); - } - } - break; - } - case Q3DBarsPrivate::SelectionNone: { - // Current bar is not selected, nor on a row or column - // do nothing - break; - } - } - } - - if (barHeight != 0) { - // Set shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.transposed().inverted()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(), - d_ptr->m_theme->m_ambientStrength); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(), - depthMVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj); - } - } - } - } - - // Release bar shader - d_ptr->m_barShader->release(); - - // Bind background shader - d_ptr->m_backgroundShader->bind(); - - if (d_ptr->m_negativeValues) - glDisable(GL_CULL_FACE); - else - glCullFace(GL_BACK); - - // Draw background - if (d_ptr->m_bgrEnabled && d_ptr->m_backgroundObj) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; - - modelMatrix.translate(0.0f, 1.0f - d_ptr->m_yAdjustment, zComp); - modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, - 1.0f, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); - modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); - itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, - 1.0f, - d_ptr->m_columnDepth / d_ptr->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(d_ptr->m_theme->m_backgroundColor); - - // Set shader bindings - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightP(), - lightPos); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->view(), - viewMatrix); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->model(), - modelMatrix); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->MVP(), - MVPMatrix); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->color(), - backgroundColor); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->ambientS(), - d_ptr->m_theme->m_ambientStrength * 2.0f); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->depth(), - depthMVPMatrix); - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(), - d_ptr->m_theme->m_lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(), - d_ptr->m_theme->m_lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj); - } - } - - // Disable textures - glDisable(GL_TEXTURE_2D); - - // Release background shader - d_ptr->m_backgroundShader->release(); - - // Reset culling - if (d_ptr->m_negativeValues) { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - } - - // Draw grid lines - if (d_ptr->m_gridEnabled && d_ptr->m_heightNormalizer) { - // Bind bar shader - d_ptr->m_barShader->bind(); - - // Set unchanging shader bindings - QVector3D barColor = Utils::vectorFromColor(d_ptr->m_theme->m_gridLine); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(), - d_ptr->m_theme->m_ambientStrength); - - // Floor lines: rows - for (GLfloat row = 0.0f; row <= d_ptr->m_sampleCount.second; row++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; - - rowPos = (row + 0.5f) * (d_ptr->m_barSpacing.height()); - modelMatrix.translate(0.0f, -d_ptr->m_yAdjustment, - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor + zComp); - modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth, - gridLineWidth)); - itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth, - gridLineWidth)); - // If we're viewing from below, grid line object must be flipped - if (d_ptr->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 - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(), - depthMVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj); - } - } - - // Floor lines: columns - for (GLfloat bar = 0.0f; bar <= d_ptr->m_sampleCount.first; bar++) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; - - barPos = (bar + 0.5f) * (d_ptr->m_barSpacing.width()); - modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - -d_ptr->m_yAdjustment, zComp); - modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); - itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); - - // If we're viewing from below, grid line object must be flipped - if (d_ptr->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 - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(), - depthMVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj); - } - } - - // Wall lines: back wall - GLfloat heightStep = d_ptr->m_heightNormalizer / 5.0f; // default to 5 lines - GLfloat startLine; - - if (d_ptr->m_tickCount > 0) - heightStep = d_ptr->m_tickStep; - - if (d_ptr->m_negativeValues) - startLine = -d_ptr->m_heightNormalizer; - else - startLine = heightStep; - - for (GLfloat lineHeight = startLine; lineHeight <= d_ptr->m_heightNormalizer; - lineHeight += heightStep) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; - - if (d_ptr->m_zFlipped) { - modelMatrix.translate(0.0f, - 2.0f * lineHeight / d_ptr->m_heightNormalizer - - d_ptr->m_yAdjustment, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor + zComp); - } else { - modelMatrix.translate(0.0f, - 2.0f * lineHeight / d_ptr->m_heightNormalizer - - d_ptr->m_yAdjustment, - -d_ptr->m_columnDepth / d_ptr->m_scaleFactor + zComp); - } - modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth, - gridLineWidth)); - itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth, - gridLineWidth)); - - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - - // Set the rest of the shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(), - depthMVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj); - } - } - - // Wall lines: side wall - for (GLfloat lineHeight = startLine; lineHeight <= d_ptr->m_heightNormalizer; - lineHeight += heightStep) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; - - if (d_ptr->m_xFlipped) { - modelMatrix.translate(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, - 2.0f * lineHeight / d_ptr->m_heightNormalizer - - d_ptr->m_yAdjustment, - zComp); - } else { - modelMatrix.translate(-d_ptr->m_rowWidth / d_ptr->m_scaleFactor, - 2.0f * lineHeight / d_ptr->m_heightNormalizer - - d_ptr->m_yAdjustment, - zComp); - } - modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); - itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); - - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - - // Set the rest of the shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(), - itModelMatrix.inverted().transposed()); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); - -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Set shadow shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(), - d_ptr->m_shadowQualityToShader); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(), - depthMVPMatrix); - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength / 10.0f); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj, - 0, d_ptr->m_depthTexture); - } else -#endif - { - // Set shadowless shader bindings - d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), - d_ptr->m_theme->m_lightStrength); - - // Draw the object - d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj); - } - } - - // Release bar shader - d_ptr->m_barShader->release(); - } - - // TODO: Draw y labels - - // Generate label textures for zoom selection if m_updateLabels is set - if (d_ptr->m_zoomActivated && d_ptr->m_updateLabels) { - // Create label textures - for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) { - QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col); - d_ptr->m_drawer->generateLabelTexture(item); - } - } - - // Handle zoom activation and label drawing - if (!barSelectionFound) { - // We have no ownership, don't delete. Just NULL the pointer. - d_ptr->m_selectedBar = NULL; - if (d_ptr->m_zoomActivated && Q3DBarsPrivate::MouseOnOverview == d_ptr->m_mousePressed) { - d_ptr->m_sceneViewPort = QRect(0, 0, width(), height()); - d_ptr->m_zoomActivated = false; - } - } else if (d_ptr->m_selectionMode >= ModeZoomRow - && Q3DBarsPrivate::MouseOnScene == d_ptr->m_mousePressed) { - // Activate zoom mode - d_ptr->m_zoomActivated = true; - d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5); - - // Create label textures - for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) { - QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col); - d_ptr->m_drawer->generateLabelTexture(item); - } - } else { - // Print value of selected bar - static QDataItem *prevItem = d_ptr->m_selectedBar; - d_ptr->m_labelShader->bind(); - glDisable(GL_DEPTH_TEST); - glEnable(GL_TEXTURE_2D); - if (d_ptr->m_labelTransparency > TransparencyNone) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } -#ifndef DISPLAY_FULL_DATA_ON_SELECTION - // Draw just the value string of the selected bar - if (prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) { - d_ptr->m_drawer->generateLabelTexture(d_ptr->m_selectedBar); - prevItem = d_ptr->m_selectedBar; - } - - d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, d_ptr->m_selectedBar->d_ptr->label(), - viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, true); -#else - static bool firstSelection = true; - // Draw the value string followed by row label and column label - LabelItem labelItem = d_ptr->m_selectedBar->d_ptr->selectionLabel(); - if (firstSelection || prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) { - QString labelText = d_ptr->m_selectedBar->d_ptr->valueStr(); - if ((d_ptr->m_dataSet->d_ptr->columnLabels().size() - > d_ptr->m_selectedBar->d_ptr->position().y()) - && (d_ptr->m_dataSet->d_ptr->rowLabels().size() - > d_ptr->m_selectedBar->d_ptr->position().x())) { - labelText.append(QStringLiteral(" (")); - labelText.append(d_ptr->m_dataSet->d_ptr->rowLabels().at( - d_ptr->m_selectedBar->d_ptr->position().x())); - labelText.append(QStringLiteral(", ")); - labelText.append(d_ptr->m_dataSet->d_ptr->columnLabels().at( - d_ptr->m_selectedBar->d_ptr->position().y())); - labelText.append(QStringLiteral(")")); - //qDebug() << labelText; - } - d_ptr->m_drawer->generateLabelItem(&labelItem, labelText); - d_ptr->m_selectedBar->d_ptr->setSelectionLabel(labelItem); - prevItem = d_ptr->m_selectedBar; - firstSelection = false; - } - - d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, labelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer, - d_ptr->m_selectionMode, d_ptr->m_labelShader, - d_ptr->m_labelObj, true, false); -#endif - glDisable(GL_TEXTURE_2D); - if (d_ptr->m_labelTransparency > TransparencyNone) - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - - // Release label shader - d_ptr->m_labelShader->release(); - - // Reset label update flag; they should have been updated when we get here - d_ptr->m_updateLabels = false; - } - - // TODO: Calculations done temporarily here. When optimizing, move to after data set addition? Keep drawing of the labels here. - // Bind label shader - d_ptr->m_labelShader->bind(); - - glEnable(GL_TEXTURE_2D); - if (d_ptr->m_labelTransparency > TransparencyNone) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - // Calculate the positions for row and column labels and store them into QDataItems (and QDataRows?) - for (int row = 0; row != d_ptr->m_sampleCount.second; row += 1) { - // 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 QDataSet. Just add LabelItems - rowPos = (row + 1) * (d_ptr->m_barSpacing.height()); - barPos = 0; - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 0.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignRight; - if (d_ptr->m_zFlipped) - rotLabelY = 180.0f; - if (d_ptr->m_xFlipped) { - barPos = (d_ptr->m_sampleCount.first + 1) * (d_ptr->m_barSpacing.width()); - alignment = Qt::AlignLeft; - } - if (d_ptr->m_yFlipped) { - if (d_ptr->m_zFlipped) - rotLabelY = 0.0f; - else - rotLabelY = 180.0f; - rotLabelZ = 180.0f; - } - QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor - + zComp); - - // TODO: Try it; draw the label here - - // Create a data item - QDataItem *label = new QDataItem(); - label->d_ptr->setTranslation(labelPos); - if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row) { - label->d_ptr->setLabel(d_ptr->m_dataSet->d_ptr->rowLabelItems().at( - d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - row - 1)); - } - - //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->rowLabels().at(row); - - d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - d_ptr->m_heightNormalizer, d_ptr->m_selectionMode, - d_ptr->m_labelShader, d_ptr->m_labelObj, true, true, LabelMid, - alignment); - - delete label; - } - for (int bar = 0; bar != d_ptr->m_sampleCount.first; bar += 1) { - // 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 QDataSet. Just add LabelItems - barPos = (bar + 1) * (d_ptr->m_barSpacing.width()); - rowPos = 0; - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 90.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignLeft; - if (d_ptr->m_xFlipped) - rotLabelY = -90.0f; - if (d_ptr->m_zFlipped) { - rowPos = (d_ptr->m_sampleCount.second + 1) * (d_ptr->m_barSpacing.height()); - alignment = Qt::AlignRight; - } - if (d_ptr->m_yFlipped) { - if (d_ptr->m_xFlipped) - rotLabelY = -90.0f; - else - rotLabelY = 90.0f; - rotLabelZ = 180.0f; - } - QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor, - -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" - (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor - + zComp); - - // TODO: Try it; draw the label here - - // Create a data item - QDataItem *label = new QDataItem(); - label->d_ptr->setTranslation(labelPos); - if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) { - label->d_ptr->setLabel(d_ptr->m_dataSet->d_ptr->columnLabelItems().at( - d_ptr->m_dataSet->d_ptr->columnLabelItems().size() - - bar - 1)); - } - - //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->columnLabels().at(bar); - - d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix, - QVector3D(0.0f, d_ptr->m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - d_ptr->m_heightNormalizer, d_ptr->m_selectionMode, - d_ptr->m_labelShader, d_ptr->m_labelObj, true, true, LabelMid, - alignment); - - delete label; - } - glDisable(GL_TEXTURE_2D); - if (d_ptr->m_labelTransparency > TransparencyNone) - glDisable(GL_BLEND); - - // Release label shader - d_ptr->m_labelShader->release(); + d_ptr->m_shared->render(); } #if defined(Q_OS_ANDROID) +/*! + * \internal + */ void Q3DBars::mouseDoubleClickEvent(QMouseEvent *event) { - if (!d_ptr->m_zoomActivated) { - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnScene; - // update mouse positions to prevent jumping when releasing or repressing a button - d_ptr->m_mousePos = event->pos(); - } + d_ptr->m_shared->mouseDoubleClickEvent(event); } +/*! + * \internal + */ void Q3DBars::touchEvent(QTouchEvent *event) { - static int prevDistance = 0; - - QList<QTouchEvent::TouchPoint> points; - points = event->touchPoints(); - - if (points.count() == 2) { - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnPinch; - - QPointF distance = points.at(0).pos() - points.at(1).pos(); - int newDistance = distance.manhattanLength(); - int zoomRate = 1; - if (d_ptr->m_zoomLevel > 100) - zoomRate = 5; - if (newDistance > prevDistance) - d_ptr->m_zoomLevel += zoomRate; - else - d_ptr->m_zoomLevel -= zoomRate; - if (d_ptr->m_zoomLevel > 500) - d_ptr->m_zoomLevel = 500; - else if (d_ptr->m_zoomLevel < 10) - d_ptr->m_zoomLevel = 10; - prevDistance = newDistance; - //qDebug() << "distance" << distance.manhattanLength(); - } + d_ptr->m_shared->touchEvent(event); } #endif +/*! + * \internal + */ void Q3DBars::mousePressEvent(QMouseEvent *event) { - if (Qt::LeftButton == event->button()) { - if (d_ptr->m_zoomActivated) { - if (event->pos().x() <= d_ptr->m_sceneViewPort.width() - && event->pos().y() <= d_ptr->m_sceneViewPort.height()) { - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnOverview; - //qDebug() << "Mouse pressed on overview"; - } else { - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnZoom; - //qDebug() << "Mouse pressed on zoom"; - } - } else { -#if !defined(Q_OS_ANDROID) - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnScene; -#else - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseRotating; -#endif - // update mouse positions to prevent jumping when releasing or repressing a button - d_ptr->m_mousePos = event->pos(); - //qDebug() << "Mouse pressed on scene"; - } - } else if (Qt::MiddleButton == event->button()) { - // reset rotations - d_ptr->m_mousePos = QPoint(0, 0); - } else if (Qt::RightButton == event->button()) { -#if !defined(Q_OS_ANDROID) - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseRotating; -#else - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnScene; -#endif - // update mouse positions to prevent jumping when releasing or repressing a button - d_ptr->m_mousePos = event->pos(); - } - CameraHelper::updateMousePos(d_ptr->m_mousePos); + d_ptr->m_shared->mousePressEvent(event); } +/*! + * \internal + */ void Q3DBars::mouseReleaseEvent(QMouseEvent *event) { - if (Q3DBarsPrivate::MouseRotating == d_ptr->m_mousePressed) { - // update mouse positions to prevent jumping when releasing or repressing a button - d_ptr->m_mousePos = event->pos(); - CameraHelper::updateMousePos(event->pos()); - } - d_ptr->m_mousePressed = Q3DBarsPrivate::MouseNone; + d_ptr->m_shared->mouseReleaseEvent(event); } +/*! + * \internal + */ void Q3DBars::mouseMoveEvent(QMouseEvent *event) { - if (Q3DBarsPrivate::MouseRotating == d_ptr->m_mousePressed) - d_ptr->m_mousePos = event->pos(); + d_ptr->m_shared->mouseMoveEvent(event); } +/*! + * \internal + */ void Q3DBars::wheelEvent(QWheelEvent *event) { - if (d_ptr->m_zoomLevel > 100) - d_ptr->m_zoomLevel += event->angleDelta().y() / 12; - else if (d_ptr->m_zoomLevel > 50) - d_ptr->m_zoomLevel += event->angleDelta().y() / 60; - else - d_ptr->m_zoomLevel += event->angleDelta().y() / 120; - if (d_ptr->m_zoomLevel > 500) - d_ptr->m_zoomLevel = 500; - else if (d_ptr->m_zoomLevel < 10) - d_ptr->m_zoomLevel = 10; + d_ptr->m_shared->wheelEvent(event); } +/*! + * \internal + */ void Q3DBars::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); - - // Set view port - if (d_ptr->m_zoomActivated) - d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5); - else - d_ptr->m_sceneViewPort = QRect(0, 0, width(), height()); - d_ptr->m_zoomViewPort = QRect(0, 0, width(), height()); - - // Calculate zoom level based on aspect ratio - GLfloat div; - GLfloat zoomAdjustment; - div = qMin(width(), height()); - zoomAdjustment = defaultRatio * ((width() / div) / (height() / div)); - //qDebug() << "zoom adjustment" << zoomAdjustment; - d_ptr->m_zoomAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f - - // Re-init selection buffer - d_ptr->initSelectionBuffer(); - -#if !defined(QT_OPENGL_ES_2) - // Re-init depth buffer - if (d_ptr->m_isInitialized && d_ptr->m_shadowQuality > ShadowNone) - d_ptr->initDepthBuffer(); -#endif + d_ptr->m_shared->setWidth(width()); + d_ptr->m_shared->setHeight(height()); + if (d_ptr->m_shared->m_isInitialized) + d_ptr->m_shared->resizeNotify(); } -void Q3DBars::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative) +// TODO: Document +// Size +void Q3DBars::setWidth(const int width) { - d_ptr->m_barThickness = thickness; - if (relative) { - d_ptr->m_barSpacing.setWidth((thickness.width() * 2) * (spacing.width() + 1.0f)); - d_ptr->m_barSpacing.setHeight((thickness.height() * 2) * (spacing.height() + 1.0f)); - } else { - d_ptr->m_barSpacing = thickness * 2 + spacing * 2; - } - // Calculate here and at setting sample space - d_ptr->calculateSceneScalingFactors(); + d_ptr->m_shared->setWidth(width); + QWindow::setWidth(width); } -void Q3DBars::setBarType(BarStyle style, bool smooth) +void Q3DBars::setHeight(const int height) { - if (style == Bars) { - if (smooth) - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/barSmooth"); - else - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/bar"); - } else if (style == Pyramids) { - if (smooth) - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramidSmooth"); - else - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramid"); - } else if (style == Cones) { - if (smooth) - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/coneSmooth"); - else - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cone"); - } else if (style == Cylinders) { - if (smooth) - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinderSmooth"); - else - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinder"); - } else if (style == BevelBars) { - if (smooth) - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/bevelbarSmooth"); - else - d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/bevelbar"); - } - // Reload mesh data - if (d_ptr->m_isInitialized) - d_ptr->loadBarMesh(); + d_ptr->m_shared->setHeight(height); + QWindow::setHeight(height); } -void Q3DBars::setMeshFileName(const QString &objFileName) +/*! + * \a thickness Thickness of a bar in x and z axes. + * + * \a spacing Spacing between bars in x and z axes. If relative -flag is true, value of 0.0f + * means the bars are side-to-side and for example 1.0f means there is one thickness in between the + * bars. + * + * \a relative A flag to indicate if spacing is meant to be absolute or relative. \c true by + * default. + * + * Sets bar specifications. Bar thickness is relative, as scene is automatically scaled to fit into + * the view. + */ +void Q3DBars::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative) { - d_ptr->m_objFile = objFileName; + d_ptr->m_shared->setBarSpecs(thickness, spacing, relative); } +/*! + * \a style One of the values in \c BarStyle. \c Bars by default. + * + * \a smooth A flag to set shading to smooth. \c false by default. + * + * Sets the bar type to one of the supplied ones. + * + * \sa setMeshFileName() + */ +void Q3DBars::setBarType(BarStyle style, bool smooth) +{ + d_ptr->m_shared->setBarType(style, smooth); +} + +/*! + * \a samplesRow How many rows of data there will be. + * + * \a samplesColumn How many items there are per row. + * + * \a labelRow QString label for the rows, ie. x -axis label. + * + * \a labelColumn QString label for the columns, ie. z -axis label. + * + * \a labelHeight QString label for height, ie. y -axis label. + * + * Set up sample space. This must be called to initialize the sample space before adding data to the + * Q3DBars. + * + * \sa addDataRow(), addDataSet() + */ void Q3DBars::setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow, const QString &labelColumn, const QString &labelHeight) { - // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) - d_ptr->closeZoomMode(); - // Delete previous data set - delete d_ptr->m_dataSet; - d_ptr->m_dataSet = new QDataSet(); - d_ptr->m_sampleCount = qMakePair(samplesRow, samplesColumn); - d_ptr->m_dataSet->setLabels(labelRow, labelColumn, labelHeight); - // TODO: Invent "idiotproof" 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) - d_ptr->m_maxSceneSize = 2 * qSqrt(samplesRow * samplesColumn); - //qDebug() << "maxSceneSize" << d_ptr->m_maxSceneSize; - // Calculate here and at setting bar specs - d_ptr->calculateSceneScalingFactors(); - d_ptr->m_axisLabelX = labelRow; - d_ptr->m_axisLabelZ = labelColumn; - d_ptr->m_axisLabelY = labelHeight; + d_ptr->m_shared->setupSampleSpace(samplesRow, samplesColumn, labelRow, labelColumn, + labelHeight); } +/*! + * \a preset Move camera to a predefined position from \c CameraPreset. + * + * Moves camera to a predefined position. + */ void Q3DBars::setCameraPreset(CameraPreset preset) { - CameraHelper::setCameraPreset(preset); -} - + d_ptr->m_shared->setCameraPreset(preset); +} + +/*! + * \a horizontal Horizontal angle for camera. + * + * \a vertical Vertical angle for camera. + * + * \a distance Distance from the center. \c 100 by default. + * + * Move camera to a wanted position based on horizontal and veritcal angles. Angles are limited + * to -180...180 in horizontal direction and either -90...90 or 0...90 in vertical, depending + * on data values. Negative vertical angles are allowed only if there are negative bar values. + * Distance is adjustable between 10 and 500. + */ void Q3DBars::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance) { - d_ptr->m_horizontalRotation = qBound(-180.0f, horizontal, 180.0f); - d_ptr->m_verticalRotation = qBound(0.0f, vertical, 90.0f); - d_ptr->m_zoomLevel = qBound(10, distance, 500); - CameraHelper::setCameraRotation(QPointF(d_ptr->m_horizontalRotation, - d_ptr->m_verticalRotation)); - //qDebug() << "camera rotation set to" << d_ptr->m_horizontalRotation << d_ptr->m_verticalRotation; + d_ptr->m_shared->setCameraPosition(horizontal, vertical, distance); } +/*! + * \a theme Apply a predefined theme from \c ColorTheme. + * + * Sets a predefined theme. Theme affects bar colors, label colors, text color, background color, + * window color and grid color. Lighting is also adjusted by themes. + */ void Q3DBars::setTheme(ColorTheme theme) { - d_ptr->m_theme->useTheme(theme); - d_ptr->m_drawer->setTheme(*d_ptr->m_theme); - // Re-initialize shaders -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - } - } else { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } - } -#else - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentColorOnYES2")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); - } -#endif -} - + d_ptr->m_shared->setTheme(theme); +} + +/*! + * \a baseColor The base color of a bar. If all other colors are black, this sets the final color of + * the bar. + * + * \a heightColor This color is added to the bar based on its height. The higher the bar, the more + * prominent this color becomes. Setting this black keeps the color unchanged regardless of height. + * + * \a depthColor This color becomes more prominent the further away from the first row the bar is. + * Setting this black keeps bars the same color regardless of "depth" in the set. + * + * \a uniform A flag to define if color needs to be uniform throughout bar's length, or will the + * colors be applied by height. \c true by default. + * + * Set bar color using your own colors. This overrides colors from theme. + */ void Q3DBars::setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform) { - d_ptr->m_theme->m_baseColor = baseColor; - d_ptr->m_theme->m_heightColor = heightColor; - d_ptr->m_theme->m_depthColor = depthColor; - //qDebug() << "colors:" << d_ptr->m_baseColor << d_ptr->m_heightColor << d_ptr->m_depthColor; - if (d_ptr->m_theme->m_uniformColor != uniform) { -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - } - } else { - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } - } -#else - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentColorOnYES2")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); - } -#endif - } - d_ptr->m_theme->m_uniformColor = uniform; + d_ptr->m_shared->setBarColor(baseColor, heightColor, depthColor, uniform); } +/*! + * \a mode Set bar selection mode from \c SelectionMode. \c ModeBar by default. + * + * Sets bar selection mode to be used. + */ void Q3DBars::setSelectionMode(SelectionMode mode) { - d_ptr->m_selectionMode = mode; - // Disable zoom if selection mode changes - d_ptr->closeZoomMode(); - // Create zoom selection if there isn't one - if (mode >= ModeZoomRow && !d_ptr->m_zoomSelection) - d_ptr->m_zoomSelection = new QDataRow(); + d_ptr->m_shared->setSelectionMode(mode); } +/*! + * \return \c SelectionMode. + */ SelectionMode Q3DBars::selectionMode() { - return d_ptr->m_selectionMode; + return d_ptr->m_shared->selectionMode(); } +/*! + * \property Q3DBars::windowTitle + * + * \a title QString label to be used as window title. + * + * Sets the window title. The default is application executable name. + */ void Q3DBars::setWindowTitle(const QString &title) { setTitle(title); @@ -1831,562 +487,239 @@ QString Q3DBars::windowTitle() return title(); } +/*! + * \a objFileName File name of a mesh object. Object needs to be in Wavefront obj format + * and include vertices, normals and UVs. It also needs to be in triangles. + * + * Override bar type with an object mesh. \sa setBarType() + */ +void Q3DBars::setMeshFileName(const QString &objFileName) +{ + d_ptr->m_shared->setMeshFileName(objFileName); +} + +/*! + * \property Q3DBars::fontSize + * + * \a fontsize Size of the font. + * + * Sets font size. + */ void Q3DBars::setFontSize(float fontsize) { - d_ptr->m_font.setPointSizeF(fontsize); - d_ptr->m_drawer->setFont(d_ptr->m_font); + d_ptr->m_shared->setFontSize(fontsize); } float Q3DBars::fontSize() { - return d_ptr->m_font.pointSizeF(); + return d_ptr->m_shared->fontSize(); } +/*! + * \property Q3DBars::font + * + * \a font QFont to be used for labels. \c Arial by default. + * + * Sets the font for labels. + */ void Q3DBars::setFont(const QFont &font) { - d_ptr->m_font = font; - d_ptr->m_drawer->setFont(font); + d_ptr->m_shared->setFont(font); } QFont Q3DBars::font() { - return d_ptr->m_font; + return d_ptr->m_shared->font(); } +/*! + * \a transparency Transparency level of labels from \c LabelTransparency. + * \c TransparencyFromTheme by default. + * + * Sets label transparency. + */ void Q3DBars::setLabelTransparency(LabelTransparency transparency) { - d_ptr->m_labelTransparency = transparency; - d_ptr->m_drawer->setTransparency(transparency); + d_ptr->m_shared->setLabelTransparency(transparency); } +/*! + * \return \c LabelTransparency. + */ LabelTransparency Q3DBars::labelTransparency() { - return d_ptr->m_labelTransparency; + return d_ptr->m_shared->labelTransparency(); } +/*! + * \property Q3DBars::grid + * + * \a enable Flag to enable or disable grid. \c true by default. + * + * Sets grid drawing on or off. + */ void Q3DBars::setGridEnabled(bool enable) { - d_ptr->m_gridEnabled = enable; + d_ptr->m_shared->setGridEnabled(enable); } bool Q3DBars::gridEnabled() { - return d_ptr->m_gridEnabled; + return d_ptr->m_shared->gridEnabled(); } +/*! + * \property Q3DBars::background + * + * \a enable Flag to enable or disable background. \c true by default. + * + * Sets backround rendering on or off. + */ void Q3DBars::setBackgroundEnabled(bool enable) { - if (d_ptr->m_bgrEnabled != enable) { - d_ptr->m_bgrEnabled = enable; - // Load changed bar type - d_ptr->loadBarMesh(); - } + d_ptr->m_shared->setBackgroundEnabled(enable); } bool Q3DBars::backgroundEnabled() { - return d_ptr->m_bgrEnabled; + return d_ptr->m_shared->backgroundEnabled(); } +/*! + * \a quality Shadow quality from \c ShadowQuality. \c ShadowLow by default. + */ void Q3DBars::setShadowQuality(ShadowQuality quality) { - d_ptr->m_shadowQuality = quality; - switch (quality) { - case ShadowLow: - d_ptr->m_shadowQualityToShader = 33.3f; - break; - case ShadowMedium: - d_ptr->m_shadowQualityToShader = 100.0f; - break; - case ShadowHigh: - d_ptr->m_shadowQualityToShader = 200.0f; - break; - default: - d_ptr->m_shadowQualityToShader = 0.0f; - break; - } - if (d_ptr->m_isInitialized) { -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->m_shadowQuality > ShadowNone) { - // Re-init depth buffer - d_ptr->initDepthBuffer(); - // Re-init shaders - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"), - QStringLiteral(":/shaders/fragmentShadowNoTex")); - } else { - // Re-init shaders - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragmentColorOnY")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertex"), - QStringLiteral(":/shaders/fragment")); - } -#else - if (!d_ptr->m_theme->m_uniformColor) { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentColorOnYES2")); - } else { - d_ptr->initShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); - } - d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexES2"), - QStringLiteral(":/shaders/fragmentES2")); -#endif - } + d_ptr->m_shared->setShadowQuality(quality); } +/*! + * \return \c ShadowQuality. + */ ShadowQuality Q3DBars::shadowQuality() { - return d_ptr->m_shadowQuality; + return d_ptr->m_shared->shadowQuality(); } +/*! + * \a tickCount How many ticks will be drawn. \c 5 by default. + * + * \a step How large a step each tick is. + * + * \a minimum Minimum value a bar in data set can have. Setting this correctly is especially + * important if values can be negative, or autoscaling won't work correctly. + * + * Sets tick count and step. Note; tickCount * step should be the maximum possible value of data + * set. + */ void Q3DBars::setTickCount(GLint tickCount, GLfloat step, GLfloat minimum) { - d_ptr->m_tickCount = tickCount; - d_ptr->m_tickStep = step; - if (tickCount > 0 && step > 0) { - d_ptr->m_heightNormalizer = tickCount * step; - d_ptr->calculateHeightAdjustment(QPair<float, float>(minimum, d_ptr->m_heightNormalizer)); - } + d_ptr->m_shared->setTickCount(tickCount, step, minimum); } +/*! + * \a dataRow A vector of floats representing a single row of data. Sample space must be large + * enough to hold the row. + * + * \a labelRow A QString label for the row. + * + * \a labelsColumn A vector of strings, one for each item in the row. + * + * Add a row of data. Each new row is added to the front of the sample space, moving previous + * rows back (if sample space is more than one row deep). + */ void Q3DBars::addDataRow(const QVector<float> &dataRow, const QString &labelRow, const QVector<QString> &labelsColumn) { - // Convert to QDataRow and add to QDataSet - QDataRow *row = new QDataRow(labelRow); - for (int i = 0; i < dataRow.size(); i++) - row->addItem(new QDataItem(dataRow.at(i))); - row->d_ptr->verifySize(d_ptr->m_sampleCount.first); - d_ptr->m_dataSet->addRow(row); - d_ptr->handleLimitChange(); - d_ptr->m_dataSet->setLabels(d_ptr->m_axisLabelX, d_ptr->m_axisLabelZ, d_ptr->m_axisLabelY, - QVector<QString>(), labelsColumn); - d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); + d_ptr->m_shared->addDataRow(dataRow, labelRow, labelsColumn); } +/*! + * \a dataRow A vector of QDataItems representing a single row of data. Sample space must be + * large enough to hold the row. Ownership of QDataItems is transferred to Q3DBars. + * + * \a labelRow A QString label for the row. + * + * \a labelsColumn A vector of strings, one for each item in the row. + * + * Add a row of data. Each new row is added to the front of the sample space, moving previous + * rows back (if sample space is more than one row deep). + */ void Q3DBars::addDataRow(const QVector<QDataItem*> &dataRow, const QString &labelRow, const QVector<QString> &labelsColumn) { - // Convert to QDataRow and add to QDataSet - QDataRow *row = new QDataRow(labelRow); - for (int i = 0; i < dataRow.size(); i++) - row->addItem(dataRow.at(i)); - row->d_ptr->verifySize(d_ptr->m_sampleCount.first); - d_ptr->m_dataSet->addRow(row); - d_ptr->handleLimitChange(); - d_ptr->m_dataSet->setLabels(d_ptr->m_axisLabelX, d_ptr->m_axisLabelZ, d_ptr->m_axisLabelY, - QVector<QString>(), labelsColumn); - d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); + d_ptr->m_shared->addDataRow(dataRow, labelRow, labelsColumn); } +/*! + * \a dataRow A QDataRow instance representing a single row of data. Sample space must be + * large enough to hold the row. Ownership of QDataRow is transferred to Q3DBars. + * + * Add a row of data. Each new row is added to the front of the sample space, moving previous + * rows back (if sample space is more than one row deep). + */ void Q3DBars::addDataRow(QDataRow *dataRow) { - QDataRow *row = dataRow; - // Check that the input data fits into sample space, and resize if it doesn't - row->d_ptr->verifySize(d_ptr->m_sampleCount.first); - // With each new row, the previous data row must be moved back - // ie. we need as many vectors as we have rows in the sample space - d_ptr->m_dataSet->addRow(row); - // if the added data pushed us over sample space, remove the oldest data set - d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); - d_ptr->handleLimitChange(); + d_ptr->m_shared->addDataRow(dataRow); } +/*! + * \a data A vector of vector of floats representing the whole data set. Sample space must be + * large enough to hold the set. + * + * \a labelsRow A vector of strings, one for each column in the row. + * + * \a labelsColumn A vector of strings, one for each row in the column. + * + * Adds a whole data set at once. If an old data set exists, it is deleted and replaced with the + * new one. + */ void Q3DBars::addDataSet(const QVector< QVector<float> > &data, const QVector<QString> &labelsRow, const QVector<QString> &labelsColumn) { - // Copy axis labels - QString xAxis; - QString zAxis; - QString yAxis; - d_ptr->m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis); - // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) - d_ptr->closeZoomMode(); - // Delete old data set - delete d_ptr->m_dataSet; - d_ptr->m_dataSet = new QDataSet(); - // Give drawer to data set - d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer); - // Convert to QDataRow and add to QDataSet - QDataRow *row; - for (int rowNr = 0; rowNr < data.size(); rowNr++) { - if (labelsRow.size() >= (rowNr + 1)) - row = new QDataRow(labelsRow.at(rowNr)); - else - row = new QDataRow(); - for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++) - row->addItem(new QDataItem(data.at(rowNr).at(colNr))); - row->d_ptr->verifySize(d_ptr->m_sampleCount.first); - d_ptr->m_dataSet->addRow(row); - row++; - } - d_ptr->handleLimitChange(); - d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); - d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); + d_ptr->m_shared->addDataSet(data, labelsRow, labelsColumn); } +/*! + * \a data A vector of vector of QDataItems representing the whole data set. Sample space must + * be large enough to hold the set. Ownership of QDataItems is transferred to Q3DBars. + * + * \a labelsRow A vector of strings, one for each column in the row. + * + * \a labelsColumn A vector of strings, one for each row in the column. + * + * Adds a whole data set at once. If an old data set exists, it is deleted and replaced with the + * new one. + */ void Q3DBars::addDataSet(const QVector< QVector<QDataItem*> > &data, const QVector<QString> &labelsRow, const QVector<QString> &labelsColumn) { - // Copy axis labels - QString xAxis; - QString zAxis; - QString yAxis; - d_ptr->m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis); - // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) - d_ptr->closeZoomMode(); - // Delete old data set - delete d_ptr->m_dataSet; - d_ptr->m_dataSet = new QDataSet(); - // Give drawer to data set - d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer); - // Convert to QDataRow and add to QDataSet - QDataRow *row; - for (int rowNr = 0; rowNr < data.size(); rowNr++) { - if (labelsRow.size() >= (rowNr + 1)) - row = new QDataRow(labelsRow.at(rowNr)); - else - row = new QDataRow(); - for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++) - row->addItem(data.at(rowNr).at(colNr)); - row->d_ptr->verifySize(d_ptr->m_sampleCount.first); - d_ptr->m_dataSet->addRow(row); - row++; - } - d_ptr->handleLimitChange(); - d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); - d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); + d_ptr->m_shared->addDataSet(data, labelsRow, labelsColumn); } -void Q3DBars::addDataSet(QDataSet* dataSet) +/*! + * \a dataSet A QDataSet instance holding the whole data set. Sample space must + * be large enough to hold the set. Ownership of QDataSet is transferred to Q3DBars. + * + * Adds a whole data set at once. If an old data set exists, it is deleted and replaced with the + * new one. + */ +void Q3DBars::addDataSet(QDataSet *dataSet) { - // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) - d_ptr->closeZoomMode(); - // Delete old data set - delete d_ptr->m_dataSet; - // Check sizes - dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second, d_ptr->m_sampleCount.first); - // Take ownership of given set - d_ptr->m_dataSet = dataSet; - d_ptr->handleLimitChange(); - // Give drawer to data set - d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer); + d_ptr->m_shared->addDataSet(dataSet); } -Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q) +Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q, QRect rect, GLuint fbohandle) : q_ptr(q), - m_paintDevice(0), - 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_sampleCount(0, 0), - m_objFile(QStringLiteral(":/defaultMeshes/bar")), - m_mousePressed(MouseNone), - m_mousePos(QPoint(0, 0)), - m_zoomLevel(100), - m_zoomAdjustment(1.0f), - m_horizontalRotation(-45.0f), - m_verticalRotation(15.0f), - m_barThickness(QSizeF(0.75f, 0.75f)), - m_barSpacing(m_barThickness * 3.0f), - m_heightNormalizer(0.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_theme(new Theme()), - m_isInitialized(false), - m_selectionMode(ModeBar), - m_selectedBar(0), - m_zoomSelection(0), - m_dataSet(new QDataSet()), - m_axisLabelX(QStringLiteral("X")), - m_axisLabelZ(QStringLiteral("Z")), - m_axisLabelY(QStringLiteral("Y")), - #ifdef USE_QML2_VERSION - m_sceneViewPort(0, 0, 800, 500), - #else - m_sceneViewPort(0, 0, q->width(), q->height()), - #endif - m_zoomViewPort(0, 0, q->width(), q->height()), - m_zoomActivated(false), - m_textureHelper(new TextureHelper()), - m_labelTransparency(TransparencyFromTheme), - m_font(QFont(QStringLiteral("Arial"))), - m_drawer(new Drawer(*m_theme, m_font, m_labelTransparency)), - m_xFlipped(false), - m_zFlipped(false), - m_yFlipped(false), - m_bgrTexture(0), - m_depthTexture(0), - m_selectionTexture(0), - m_depthFrameBuffer(0), - m_selectionFrameBuffer(0), - m_selectionDepthBuffer(0), - m_updateLabels(false), - m_gridEnabled(true), - m_bgrEnabled(true), - m_shadowQuality(ShadowLow), - m_shadowQualityToShader(33.3f), - m_tickCount(0), - m_tickStep(0), - m_negativeValues(false) + m_shared(new Bars3dShared(rect, fbohandle)) { - m_dataSet->d_ptr->setDrawer(m_drawer); - QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Q3DBarsPrivate::updateTextures); } Q3DBarsPrivate::~Q3DBarsPrivate() { qDebug() << "Destroying Q3DBarsPrivate"; -#ifndef USE_HAX0R_SELECTION - m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); - m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); - m_textureHelper->deleteTexture(&m_selectionTexture); -#endif - m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); - m_textureHelper->deleteTexture(&m_bgrTexture); - delete m_dataSet; - if (m_zoomSelection) { - m_zoomSelection->d_ptr->clear(); - delete m_zoomSelection; - } - delete m_barShader; - delete m_depthShader; - delete m_selectionShader; - delete m_backgroundShader; - delete m_barObj; - delete m_backgroundObj; - delete m_gridLineObj; - delete m_textureHelper; - delete m_drawer; -} - -void Q3DBarsPrivate::loadBarMesh() -{ - QString objectFileName = m_objFile; - if (m_barObj) - delete m_barObj; - // If background is disabled, load full version of bar mesh - if (!m_bgrEnabled) - objectFileName.append(QStringLiteral("Full")); - m_barObj = new ObjectHelper(objectFileName); - m_barObj->load(); -} - -void Q3DBarsPrivate::loadBackgroundMesh() -{ - if (m_backgroundObj) - delete m_backgroundObj; - if (m_negativeValues) - m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground")); - else - m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); - m_backgroundObj->load(); -} - -void Q3DBarsPrivate::loadGridLineMesh() -{ - if (m_gridLineObj) - delete m_gridLineObj; - m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar")); - m_gridLineObj->load(); -} - -void Q3DBarsPrivate::loadLabelMesh() -{ - if (m_labelObj) - delete m_labelObj; - m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); - m_labelObj->load(); -} - -void Q3DBarsPrivate::initShaders(const QString &vertexShader, const QString &fragmentShader) -{ - if (m_barShader) - delete m_barShader; - m_barShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader); - m_barShader->initialize(); -} - -void Q3DBarsPrivate::initSelectionShader() -{ - if (m_selectionShader) - delete m_selectionShader; - m_selectionShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexSelection"), - QStringLiteral(":/shaders/fragmentSelection")); - m_selectionShader->initialize(); -} - -void Q3DBarsPrivate::initSelectionBuffer() -{ -#ifndef USE_HAX0R_SELECTION - if (m_selectionTexture) { - m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); - m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); - m_textureHelper->deleteTexture(&m_selectionTexture); - } - m_selectionTexture = m_textureHelper->createSelectionTexture(q_ptr->size(), - m_selectionFrameBuffer, - m_selectionDepthBuffer); -#endif -} - -#if !defined(QT_OPENGL_ES_2) -void Q3DBarsPrivate::initDepthShader() -{ - if (m_depthShader) - delete m_depthShader; - m_depthShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexDepth"), - QStringLiteral(":/shaders/fragmentDepth")); - m_depthShader->initialize(); -} - -void Q3DBarsPrivate::initDepthBuffer() -{ - if (m_depthTexture) { - m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); - m_textureHelper->deleteTexture(&m_depthTexture); - } - m_depthTexture = m_textureHelper->createDepthTexture(q_ptr->size(), m_depthFrameBuffer, - m_shadowQuality); -} -#endif - -void Q3DBarsPrivate::initBackgroundShaders(const QString &vertexShader, - const QString &fragmentShader) -{ - if (m_backgroundShader) - delete m_backgroundShader; - m_backgroundShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader); - m_backgroundShader->initialize(); -} - -void Q3DBarsPrivate::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) -{ - if (m_labelShader) - delete m_labelShader; - m_labelShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader); - m_labelShader->initialize(); -} - -void Q3DBarsPrivate::updateTextures() -{ - // Drawer has changed; this flag needs to be checked when checking if we need to update labels - m_updateLabels = true; -} - -void Q3DBarsPrivate::calculateSceneScalingFactors() -{ - // Calculate scene scaling and translation factors - m_rowWidth = ((m_sampleCount.first + 1) * m_barSpacing.width()) / 2.0f; - m_columnDepth = ((m_sampleCount.second + 1) * m_barSpacing.height()) / 2.0f; - m_maxDimension = qMax(m_rowWidth, m_columnDepth); - m_scaleFactor = qMin((m_sampleCount.first * (m_maxDimension / m_maxSceneSize)), - (m_sampleCount.second * (m_maxDimension / m_maxSceneSize))); - m_scaleX = m_barThickness.width() / m_scaleFactor; - m_scaleZ = m_barThickness.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 Q3DBarsPrivate::calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits) -{ - // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer - m_yAdjustment = 2.0f - ((limits.second - limits.first) / m_heightNormalizer); - //qDebug() << m_yAdjustment; -} - -Q3DBarsPrivate::SelectionType Q3DBarsPrivate::isSelected(GLint row, GLint bar, - const QVector3D &selection) -{ - //static QVector3D prevSel = selection; // TODO: For debugging - SelectionType isSelectedType = SelectionNone; -#ifdef USE_HAX0R_SELECTION - if (selection == Utils::vectorFromColor(m_theme->m_windowColor)) -#else - if (selection == skipColor) -#endif - 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 == selection) - isSelectedType = SelectionBar; - else if (current.y() == selection.y() && (m_selectionMode == ModeBarAndColumn - || m_selectionMode == ModeBarRowAndColumn - || m_selectionMode == ModeZoomColumn)) - isSelectedType = SelectionColumn; - else if (current.x() == selection.x() && (m_selectionMode == ModeBarAndRow - || m_selectionMode == ModeBarRowAndColumn - || m_selectionMode == ModeZoomRow)) - isSelectedType = SelectionRow; - return isSelectedType; -} - -void Q3DBarsPrivate::handleLimitChange() -{ - // Get the limits - QPair<GLfloat, GLfloat> limits = m_dataSet->d_ptr->limitValues(); - - // TODO: What if we have only negative values? - - // Check if we have negative values - if (limits.first < 0 && !m_negativeValues) { - m_negativeValues = true; - // Reload background - loadBackgroundMesh(); - } else if (limits.first >= 0 && m_negativeValues) { - m_negativeValues = false; - // Reload background - loadBackgroundMesh(); - } - - // Don't auto-adjust height if tick count is set - if (m_tickCount == 0) { - m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); - calculateHeightAdjustment(limits); - } -} - -void Q3DBarsPrivate::closeZoomMode() -{ - m_zoomActivated = false; - m_sceneViewPort = QRect(0, 0, q_ptr->width(), q_ptr->height()); + delete m_shared; } QTENTERPRISE_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/q3dbars.h b/src/datavis3d/engine/q3dbars.h index 265df734..03635e4d 100644 --- a/src/datavis3d/engine/q3dbars.h +++ b/src/datavis3d/engine/q3dbars.h @@ -48,8 +48,6 @@ #include <QFont> -class QOpenGLShaderProgram; - QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE class Q3DBarsPrivate; @@ -68,15 +66,12 @@ class QTENTERPRISE_DATAVIS3D_EXPORT Q3DBars : public Q3DWindow Q_PROPERTY(bool background READ backgroundEnabled WRITE setBackgroundEnabled) public: - explicit Q3DBars(); + explicit Q3DBars(GLuint fbohandle = 0, const QSize &windowsize = QSize()); ~Q3DBars(); - void initialize(); - void render(); - // Add a row of data. Each new row is added to the front of the sample space, moving previous // rows back (if sample space is more than one row deep) - Q_INVOKABLE void addDataRow(const QVector<GLfloat> &dataRow, + Q_INVOKABLE void addDataRow(const QVector<float> &dataRow, const QString &labelRow = QString(), const QVector<QString> &labelsColumn = QVector<QString>()); // ownership of dataItems is transferred @@ -87,7 +82,7 @@ public: Q_INVOKABLE void addDataRow(QDataRow *dataRow); // Add complete data set at a time, as a vector of data rows - Q_INVOKABLE void addDataSet(const QVector< QVector<GLfloat> > &data, + Q_INVOKABLE void addDataSet(const QVector< QVector<float> > &data, const QVector<QString> &labelsRow = QVector<QString>(), const QVector<QString> &labelsColumn = QVector<QString>()); @@ -108,9 +103,6 @@ public: // bar type; bars (=cubes), pyramids, cones, cylinders, etc. Q_INVOKABLE void setBarType(BarStyle style, bool smooth = false); - // override bar type with own mesh - Q_INVOKABLE void setMeshFileName(const QString &objFileName); - // how many samples per row and column, and names for axes Q_INVOKABLE void setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow = QString(), @@ -139,6 +131,8 @@ public: // important to set if values can be negative. Q_INVOKABLE void setTickCount(GLint tickCount, GLfloat step, GLfloat minimum = 0.0f); + // override bar type with own mesh + Q_INVOKABLE void setMeshFileName(const QString &objFileName); // TODO: light placement API // Change selection mode; single bar, bar and row, bar and column, or all @@ -165,6 +159,11 @@ public: void setGridEnabled(bool enable); bool gridEnabled(); + // TODO: Do these need to be public? Where are they called from? + // Size + void setWidth(const int width); + void setHeight(const int height); + // Enable or disable background mesh void setBackgroundEnabled(bool enable); bool backgroundEnabled(); @@ -174,6 +173,9 @@ public: ShadowQuality shadowQuality(); protected: + void initialize(); + void render(); + #if defined(Q_OS_ANDROID) void mouseDoubleClickEvent(QMouseEvent *event); void touchEvent(QTouchEvent *event); diff --git a/src/datavis3d/engine/q3dbars_p.h b/src/datavis3d/engine/q3dbars_p.h index 33153b60..f5d0cf38 100644 --- a/src/datavis3d/engine/q3dbars_p.h +++ b/src/datavis3d/engine/q3dbars_p.h @@ -52,10 +52,8 @@ #ifndef Q3DBARS_p_H #define Q3DBARS_p_H -#include "qdatavis3dglobal.h" +#include "bars3dshared_p.h" #include "qdatavis3namespace.h" -#include <QOpenGLFunctions> -#include <QFont> class QOpenGLPaintDevice; @@ -65,122 +63,15 @@ class QSizeF; QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE class Q3DBars; -class QDataItem; -class QDataRow; -class QDataSet; -class ShaderHelper; -class ObjectHelper; -class TextureHelper; -class Theme; -class Drawer; class Q3DBarsPrivate : public QObject { public: - enum SelectionType { - SelectionNone = 0, - SelectionBar, - SelectionRow, - SelectionColumn - }; - - enum MousePressType { - MouseNone = 0, - MouseOnScene, - MouseOnOverview, - MouseOnZoom, - MouseRotating, - MouseOnPinch - }; - -public: - Q3DBarsPrivate(Q3DBars *q); + Q3DBarsPrivate(Q3DBars *q, QRect rect, GLuint fbohandle); ~Q3DBarsPrivate(); - void loadBarMesh(); - void loadBackgroundMesh(); - void loadGridLineMesh(); - void loadLabelMesh(); - void initShaders(const QString &vertexShader, const QString &fragmentShader); - 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 initDepthBuffer(); -#endif - void updateTextures(); - void calculateSceneScalingFactors(); - void calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits); - SelectionType isSelected(GLint row, GLint bar, const QVector3D &selection); - void handleLimitChange(); - void closeZoomMode(); - Q3DBars *q_ptr; - - QOpenGLPaintDevice *m_paintDevice; - 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; - QPair<int, int> m_sampleCount; - QString m_objFile; - MousePressType m_mousePressed; - QPoint m_mousePos; - GLint m_zoomLevel; - GLfloat m_zoomAdjustment; - GLfloat m_horizontalRotation; - GLfloat m_verticalRotation; - QSizeF m_barThickness; - QSizeF m_barSpacing; - 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; - Theme *m_theme; - bool m_isInitialized; - SelectionMode m_selectionMode; - QDataItem *m_selectedBar; - QDataRow *m_zoomSelection; - QDataSet *m_dataSet; - QString m_axisLabelX; - QString m_axisLabelZ; - QString m_axisLabelY; - QRect m_sceneViewPort; - QRect m_zoomViewPort; - bool m_zoomActivated; - TextureHelper *m_textureHelper; - LabelTransparency m_labelTransparency; - QFont m_font; - Drawer *m_drawer; - bool m_xFlipped; - bool m_zFlipped; - bool m_yFlipped; - GLuint m_bgrTexture; - GLuint m_depthTexture; - GLuint m_selectionTexture; - GLuint m_depthFrameBuffer; - GLuint m_selectionFrameBuffer; - GLuint m_selectionDepthBuffer; - bool m_updateLabels; - bool m_gridEnabled; - bool m_bgrEnabled; - ShadowQuality m_shadowQuality; - GLfloat m_shadowQualityToShader; - GLint m_tickCount; - GLfloat m_tickStep; - bool m_negativeValues; + Bars3dShared *m_shared; }; QTENTERPRISE_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/q3dmaps.cpp b/src/datavis3d/engine/q3dmaps.cpp index ad864042..0a1ca7ff 100644 --- a/src/datavis3d/engine/q3dmaps.cpp +++ b/src/datavis3d/engine/q3dmaps.cpp @@ -52,6 +52,7 @@ #include "utils_p.h" #include "drawer_p.h" +#include <QOpenGLFunctions> #include <QMatrix4x4> #include <QOpenGLPaintDevice> #include <QPainter> @@ -84,15 +85,39 @@ const GLfloat gridLineWidth = 0.005f; GLfloat distanceMod = 0.0f; static QVector3D skipColor = QVector3D(255, 255, 255); // Selection texture's background color +/*! + * \class Q3DMaps + * \inmodule QtDataVis3D + * \brief The Q3DMaps class provides methods for rendering 3D bars on maps or other planes. + * \since 1.0.0 + * + * This class enables developers to render bars or objects on maps or other planes in 3D and to + * view them by rotating the scene freely. Methods are provided for changing object types, themes + * and so on. + * + * See methods themselves for more complete description. + * + * \sa Q3DBars, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + * Constructs Q3DMaps. + */ Q3DMaps::Q3DMaps() : d_ptr(new Q3DMapsPrivate(this)) { } +/*! + * Destructs Q3DMaps. + */ Q3DMaps::~Q3DMaps() { } +/*! + * \internal + */ void Q3DMaps::initialize() { // Initialize shaders @@ -184,12 +209,17 @@ void Q3DMaps::initialize() // Set initialized -flag d_ptr->m_isInitialized = true; + d_ptr->m_drawer->initializeOpenGL(); + // Update default light position #ifndef USE_WIDER_SHADOWS distanceMod = 1.0f; #endif } +/*! + * \internal + */ void Q3DMaps::render() { if (!d_ptr->m_isInitialized) @@ -218,6 +248,9 @@ void Q3DMaps::render() drawScene(); } +/*! + * \internal + */ void Q3DMaps::drawScene() { // Set clear color @@ -922,6 +955,9 @@ void Q3DMaps::drawScene() } #if defined(Q_OS_ANDROID) +/*! + * \internal + */ void Q3DMaps::mouseDoubleClickEvent(QMouseEvent *event) { if (!d_ptr->m_zoomActivated) { @@ -931,6 +967,9 @@ void Q3DMaps::mouseDoubleClickEvent(QMouseEvent *event) } } +/*! + * \internal + */ void Q3DMaps::touchEvent(QTouchEvent *event) { static int prevDistance = 0; @@ -960,6 +999,9 @@ void Q3DMaps::touchEvent(QTouchEvent *event) } #endif +/*! + * \internal + */ void Q3DMaps::mousePressEvent(QMouseEvent *event) { if (Qt::LeftButton == event->button()) { @@ -998,6 +1040,9 @@ void Q3DMaps::mousePressEvent(QMouseEvent *event) CameraHelper::updateMousePos(d_ptr->m_mousePos); } +/*! + * \internal + */ void Q3DMaps::mouseReleaseEvent(QMouseEvent *event) { //qDebug() << "mouse button released" << event->button(); @@ -1009,6 +1054,9 @@ void Q3DMaps::mouseReleaseEvent(QMouseEvent *event) d_ptr->m_mousePressed = Q3DMapsPrivate::MouseNone; } +/*! + * \internal + */ void Q3DMaps::mouseMoveEvent(QMouseEvent *event) { if (Q3DMapsPrivate::MouseRotating == d_ptr->m_mousePressed) { @@ -1032,6 +1080,9 @@ void Q3DMaps::mouseMoveEvent(QMouseEvent *event) #endif } +/*! + * \internal + */ void Q3DMaps::wheelEvent(QWheelEvent *event) { if (d_ptr->m_zoomLevel > 100) @@ -1046,6 +1097,9 @@ void Q3DMaps::wheelEvent(QWheelEvent *event) d_ptr->m_zoomLevel = 10; } +/*! + * \internal + */ void Q3DMaps::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); @@ -1580,6 +1634,7 @@ void Q3DMapsPrivate::initSelectionShader() void Q3DMapsPrivate::initSelectionBuffer() { if (m_selectionTexture) { + m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); m_textureHelper->deleteTexture(&m_selectionTexture); diff --git a/src/datavis3d/engine/q3dmaps.h b/src/datavis3d/engine/q3dmaps.h index d9880d3a..67c8860b 100644 --- a/src/datavis3d/engine/q3dmaps.h +++ b/src/datavis3d/engine/q3dmaps.h @@ -80,10 +80,6 @@ public: explicit Q3DMaps(); ~Q3DMaps(); - void initialize(); - void render(); - void render(QPainter *painter); - // Add data item. New data item is appended to old data. // ownership of data is transferred Q_INVOKABLE bool addDataItem(QDataItem *dataItem); @@ -159,6 +155,9 @@ public: ShadowQuality shadowQuality(); protected: + void initialize(); + void render(); + #if defined(Q_OS_ANDROID) void mouseDoubleClickEvent(QMouseEvent *event); void touchEvent(QTouchEvent *event); diff --git a/src/datavis3d/engine/q3dwindow.cpp b/src/datavis3d/engine/q3dwindow.cpp index 869dc328..af975cb1 100644 --- a/src/datavis3d/engine/q3dwindow.cpp +++ b/src/datavis3d/engine/q3dwindow.cpp @@ -52,6 +52,24 @@ QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE +/*! + * \class Q3DWindow + * \inmodule QtDataVis3D + * \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, Q3DMaps, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + * \a parent A QWindow parent. + * + * Constructs Q3DWindow. 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)) @@ -70,26 +88,29 @@ Q3DWindow::Q3DWindow(QWindow *parent) create(); -#ifndef USE_QML2_VERSION d_ptr->m_context->setFormat(requestedFormat()); d_ptr->m_context->create(); d_ptr->m_context->makeCurrent(this); -#endif + qDebug() << "initializeOpenGLFunctions()"; initializeOpenGLFunctions(); -#ifndef USE_QML2_VERSION initialize(); -#endif } +/*! + * Destroys Q3DWindow. + */ Q3DWindow::~Q3DWindow() { } +/*! + * \internal + */ void Q3DWindow::initialize() { - const GLubyte* version = glGetString(GL_VERSION); + const GLubyte *version = glGetString(GL_VERSION); qDebug() << "OpenGL version:" << (const char *)version; version = glGetString(GL_SHADING_LANGUAGE_VERSION); qDebug() << "GLSL version:" << (const char *)version; @@ -102,10 +123,16 @@ void Q3DWindow::initialize() setAnimating(true); } +/*! + * \internal + */ void Q3DWindow::render() { } +/*! + * \internal + */ void Q3DWindow::renderLater() { if (!d_ptr->m_updatePending) { @@ -114,6 +141,9 @@ void Q3DWindow::renderLater() } } +/*! + * \internal + */ bool Q3DWindow::event(QEvent *event) { switch (event->type()) { @@ -125,6 +155,9 @@ bool Q3DWindow::event(QEvent *event) } } +/*! + * \internal + */ void Q3DWindow::exposeEvent(QExposeEvent *event) { Q_UNUSED(event); @@ -133,6 +166,9 @@ void Q3DWindow::exposeEvent(QExposeEvent *event) renderNow(); } +/*! + * \internal + */ void Q3DWindow::renderNow() { if (!isExposed()) @@ -157,6 +193,9 @@ void Q3DWindow::renderNow() renderLater(); } +/*! + * \internal + */ void Q3DWindow::setAnimating(bool animating) { d_ptr->m_animating = animating; diff --git a/src/datavis3d/engine/q3dwindow.h b/src/datavis3d/engine/q3dwindow.h index edabcf76..bf7d8f74 100644 --- a/src/datavis3d/engine/q3dwindow.h +++ b/src/datavis3d/engine/q3dwindow.h @@ -56,21 +56,20 @@ class Q3DWindowPrivate; class QTENTERPRISE_DATAVIS3D_EXPORT Q3DWindow : public QWindow, protected QOpenGLFunctions { Q_OBJECT + public: explicit Q3DWindow(QWindow *parent = 0); ~Q3DWindow(); - virtual void render(); - - virtual void initialize(); - - void setAnimating(bool animating); - -public slots: +private slots: void renderLater(); void renderNow(); protected: + virtual void render(); + virtual void initialize(); + + void setAnimating(bool animating); bool event(QEvent *event); void exposeEvent(QExposeEvent *event); diff --git a/src/datavis3d/engine/qdataitem.cpp b/src/datavis3d/engine/qdataitem.cpp index 8134fcb5..883c190c 100644 --- a/src/datavis3d/engine/qdataitem.cpp +++ b/src/datavis3d/engine/qdataitem.cpp @@ -47,15 +47,46 @@ QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE +/*! + * \class QDataItem + * \inmodule QtDataVis3D + * \brief The QDataItem class provides a container for data to be added to graphs. + * \since 1.0.0 + * + * A QDataItem holds data for a single bar in a Q3DMaps or Q3DBars graph. + * + * \sa QDataRow, QDataSet, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + * \a value A float value of the data item. + * + * \a label A QString label for the item. + * + * Constructs QDataItem. + */ QDataItem::QDataItem(float value, const QString &label) : d_ptr(new QDataItemPrivate(this, value, label)) { } +/*! + * Destroys QDataItem. + */ QDataItem::~QDataItem() { } +/*! + * \property QDataItem::label + * + * \a label A QString label for the data item. Unit, for example. + * + * \a prepend A flag to indicate if the label is to be prepended or appended to the value. + * \c false by default. + * + * Sets label for the data item. + */ void QDataItem::setLabel(const QString &label, bool prepend) { d_ptr->m_labelString = label; @@ -67,11 +98,25 @@ QString QDataItem::label() return d_ptr->m_labelString; } +/*! + * \property QDataItem::value + * + * \a value A float value for the data item. + * + * Sets value for the data item. + */ void QDataItem::setValue(float value) { d_ptr->m_value = value; } +/*! + * \overload QDataItem::value + * + * \a value An int value for the data item. + * + * Sets value for the data item. + */ void QDataItem::setValue(int value) { d_ptr->m_value = (float)value; @@ -82,11 +127,25 @@ float QDataItem::value() return d_ptr->m_value; } +/*! + * \property QDataItem::position + * + * \a position A QPointF position for the data item. + * + * Sets position for the data item. Has no effect in Q3DBars. + */ void QDataItem::setPosition(const QPointF &position) { d_ptr->m_position = position; } +/*! + * \overload QDataItem::position + * + * \a position A QPoint position for the data item. + * + * Sets position for the data item. Has no effect in Q3DBars. + */ void QDataItem::setPosition(const QPoint &position) { d_ptr->m_position = (QPointF)position; diff --git a/src/datavis3d/engine/qdataitem.h b/src/datavis3d/engine/qdataitem.h index 0106502f..7c8302f4 100644 --- a/src/datavis3d/engine/qdataitem.h +++ b/src/datavis3d/engine/qdataitem.h @@ -60,13 +60,13 @@ class QTENTERPRISE_DATAVIS3D_EXPORT QDataItem : public QObject Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(float value READ value WRITE setValue) Q_PROPERTY(int value READ value WRITE setValue) - Q_PROPERTY(int value READ value WRITE setValue) Q_PROPERTY(QPointF position READ position WRITE setPosition) public: explicit QDataItem(float value = 0.0f, const QString &label = QString()); ~QDataItem(); + // TODO: Provide a Q_INVOKABLE version of this, or move prepend to it's own property. void setLabel(const QString &label, bool prepend = false); // label for value, unit for example QString label(); void setValue(float value); @@ -79,8 +79,7 @@ public: private: QScopedPointer<QDataItemPrivate> d_ptr; - friend class Q3DBars; - friend class Q3DBarsPrivate; + friend class Bars3dShared; friend class Q3DMaps; friend class Q3DMapsPrivate; friend class QDataRowPrivate; diff --git a/src/datavis3d/engine/qdatarow.cpp b/src/datavis3d/engine/qdatarow.cpp index 79bc48e1..6bdd6d14 100644 --- a/src/datavis3d/engine/qdatarow.cpp +++ b/src/datavis3d/engine/qdatarow.cpp @@ -48,15 +48,44 @@ QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE +/*! + * \class QDataRow + * \inmodule QtDataVis3D + * \brief The QDataRow class provides a container for data items to be added to graphs. + * \since 1.0.0 + * + * A QDataRow is a container for all data to be added to a Q3DMaps instance, or a single row to + * be added to a QDataSet. It holds instances of QDataItem and has no knowledge of possible + * sample space sizes set for a Q3DBars instance. The ownership of QDataItem added is transferred + * to QDataRow. + * + * \sa QDataItem, QDataSet, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + * \a label A QString label for the row. + * + * Constructs QDataRow. + */ QDataRow::QDataRow(const QString &label) : d_ptr(new QDataRowPrivate(this, label)) { } +/*! + * Destroys QDataRow and all instances of QDataItem it may hold. + */ QDataRow::~QDataRow() { } +/*! + * \property QDataRow::label + * + * \a label A QString label for the row. + * + * Sets a label for the row. + */ void QDataRow::setLabel(const QString &label) { d_ptr->m_label = label; @@ -67,6 +96,11 @@ QString QDataRow::label() return d_ptr->m_label; } +/*! + * \a item A QDataItem instance. + * + * Adds a QDataItem to the QDataRow. Ownership of QDataItem is transferred to QDataRow. + */ void QDataRow::addItem(QDataItem *item) { d_ptr->m_row.prepend(item); diff --git a/src/datavis3d/engine/qdatarow.h b/src/datavis3d/engine/qdatarow.h index 2cdccfb5..72fa5f55 100644 --- a/src/datavis3d/engine/qdatarow.h +++ b/src/datavis3d/engine/qdatarow.h @@ -67,8 +67,7 @@ public: private: QScopedPointer<QDataRowPrivate> d_ptr; - friend class Q3DBars; - friend class Q3DBarsPrivate; + friend class Bars3dShared; friend class Q3DMaps; friend class Q3DMapsPrivate; friend class QDataSetPrivate; diff --git a/src/datavis3d/engine/qdataset.cpp b/src/datavis3d/engine/qdataset.cpp index ab892127..6fd59baf 100644 --- a/src/datavis3d/engine/qdataset.cpp +++ b/src/datavis3d/engine/qdataset.cpp @@ -53,17 +53,47 @@ QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE const QString empty; +/*! + * \class QDataSet + * \inmodule QtDataVis3D + * \brief The QDataSet class provides a container for data rows to be added to graphs. + * \since 1.0.0 + * + * A QDataSet is a container for data to be added into a Q3DBars instance. It holds instances of + * QDataRow and has no knowledge of sample space size set for Q3DBars. The ownership of QDataRow + * added is transferred to QDataSet. + * + * \sa QDataItem, QDataRow, {Qt Data Visualization 3D C++ Classes} + */ + +/*! + * Constructs QDataSet. + */ QDataSet::QDataSet() : d_ptr(new QDataSetPrivate(this)) { - //qDebug("QDataSet"); } +/*! + * Destroys QDataSet, including all QDataRow instances it may hold. + */ QDataSet::~QDataSet() { - //qDebug("~QDataSet"); } +/*! + * \a xAxis A QString label for x axis. + * + * \a zAxis A QString label for z axis. + * + * \a yAxis A QString label for y axis. + * + * \a labelsRow A QVector of QStrings, one for each row. + * + * \a labelsColumn A QVector of QStrings, one for each column. + * + * Sets labels for the QDataSet. + */ void QDataSet::setLabels(const QString &xAxis, const QString &zAxis, const QString &yAxis, @@ -106,6 +136,12 @@ void QDataSet::setLabels(const QString &xAxis, } } +/*! + * \a row A QDataRow instance. + * + * Adds a QDataRow instance to QDataSet. Ownership of the QDataRow instance is transferred to + * QDataSet. + */ void QDataSet::addRow(QDataRow *row) { d_ptr->m_set.prepend(row); diff --git a/src/datavis3d/engine/qdataset.h b/src/datavis3d/engine/qdataset.h index f0061ad8..e645bc16 100644 --- a/src/datavis3d/engine/qdataset.h +++ b/src/datavis3d/engine/qdataset.h @@ -71,8 +71,7 @@ public: private: QScopedPointer<QDataSetPrivate> d_ptr; - friend class Q3DBars; - friend class Q3DBarsPrivate; + friend class Bars3dShared; friend class Q3DMaps; friend class Q3DMapsPrivate; }; diff --git a/src/datavis3d/engine/theme_p.h b/src/datavis3d/engine/theme_p.h index 9ed97e6b..234d4709 100644 --- a/src/datavis3d/engine/theme_p.h +++ b/src/datavis3d/engine/theme_p.h @@ -69,8 +69,7 @@ public: void useTheme(ColorTheme theme); private: - friend class Q3DBars; - friend class Q3DBarsPrivate; + friend class Bars3dShared; friend class Q3DMaps; friend class Q3DMapsPrivate; friend class Drawer; diff --git a/src/datavis3d/global/qdatavis3dglobal.h b/src/datavis3d/global/qdatavis3dglobal.h index c57d5101..308e8607 100644 --- a/src/datavis3d/global/qdatavis3dglobal.h +++ b/src/datavis3d/global/qdatavis3dglobal.h @@ -18,8 +18,8 @@ ** ****************************************************************************/ -#ifndef QVIS3DGLOBAL_H -#define QVIS3DGLOBAL_H +#ifndef QDATAVIS3DGLOBAL_H +#define QDATAVIS3DGLOBAL_H #include <qglobal.h> diff --git a/src/datavis3d/utils/objecthelper.cpp b/src/datavis3d/utils/objecthelper.cpp index eaae52be..d280abf8 100644 --- a/src/datavis3d/utils/objecthelper.cpp +++ b/src/datavis3d/utils/objecthelper.cpp @@ -56,7 +56,6 @@ ObjectHelper::ObjectHelper(const QString &objectFile) m_indexCount(0), m_meshDataLoaded(false) { - initializeOpenGLFunctions(); } ObjectHelper::~ObjectHelper() @@ -74,6 +73,7 @@ void ObjectHelper::setObjectFile(const QString &objectFile) void ObjectHelper::load() { + initializeOpenGLFunctions(); if (m_meshDataLoaded) { // Delete old data glDeleteBuffers(1, &m_vertexbuffer); diff --git a/src/datavis3d/utils/texturehelper.cpp b/src/datavis3d/utils/texturehelper.cpp index cb08b17c..3d827c50 100644 --- a/src/datavis3d/utils/texturehelper.cpp +++ b/src/datavis3d/utils/texturehelper.cpp @@ -235,7 +235,6 @@ GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint &frameBuffer, 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); - // Use the following line if using shader's version 2 of shadowing, comment out if not 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); diff --git a/src/datavis3dqml2/datavis3dqml2.pro b/src/datavis3dqml2/datavis3dqml2.pro index 2f0c6300..59abef57 100644 --- a/src/datavis3dqml2/datavis3dqml2.pro +++ b/src/datavis3dqml2/datavis3dqml2.pro @@ -13,20 +13,17 @@ INCLUDEPATH += ../datavis3d/engine SOURCES += \ datavis3dqml2_plugin.cpp \ - datavisview.cpp \ - scenerenderernode.cpp \ declarativebars.cpp \ - declarativemaps.cpp #\ + declarativemaps.cpp #\ #declarativedataitem.cpp \ #declarativedatarow.cpp \ #declarativedataset.cpp HEADERS += \ datavis3dqml2_plugin.h \ - datavisview.h \ - scenerenderernode_p.h \ declarativebars.h \ - declarativemaps.h #\ + declarativemaps.h \ #\ + declarativebars_p.h #declarativedataitem.h \ #declarativedatarow.h \ #declarativedataset.h diff --git a/src/datavis3dqml2/datavis3dqml2_plugin.cpp b/src/datavis3dqml2/datavis3dqml2_plugin.cpp index 9ff0c6c1..86923cde 100644 --- a/src/datavis3dqml2/datavis3dqml2_plugin.cpp +++ b/src/datavis3dqml2/datavis3dqml2_plugin.cpp @@ -40,21 +40,21 @@ ****************************************************************************/ #include "datavis3dqml2_plugin.h" -#include "datavisview.h" #include <qqml.h> - +#include <QDebug> QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE void Datavis3dqml2Plugin::registerTypes(const char *uri) { + qDebug() << "Datavis3dqml2Plugin::registerTypes()"; + // @uri com.digia.QtDataVis3D - qmlRegisterType<DataVisView>(uri, 1, 0, "DataVisView"); - qmlRegisterType<DeclarativeBars>(uri, 1, 0, "Bars"); - qmlRegisterType<DeclarativeMaps>(uri, 1, 0, "Maps"); qmlRegisterType<QDataItem>(uri, 1, 0, "DataItem"); qmlRegisterType<QDataRow>(uri, 1, 0, "DataRow"); qmlRegisterType<QDataSet>(uri, 1, 0, "DataSet"); + + qmlRegisterType<DeclarativeBars>(uri, 1, 0, "Bars3D"); } //#include "moc_datavis3dqml2_plugin.cpp" diff --git a/src/datavis3dqml2/declarativebars.cpp b/src/datavis3dqml2/declarativebars.cpp index aac8b1d9..3194baa5 100644 --- a/src/datavis3dqml2/declarativebars.cpp +++ b/src/datavis3dqml2/declarativebars.cpp @@ -40,47 +40,341 @@ ****************************************************************************/ #include "declarativebars.h" +#include "bars3dshared_p.h" +#include <QtQuick/QQuickWindow> +#include <QtGui/QOpenGLFramebufferObject> +#include <QOpenGLContext> +#include <QGuiApplication> +#include <QThread> #include <QDebug> QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE -DeclarativeBars::DeclarativeBars() +DeclarativeBars::DeclarativeBars(QQuickItem *parent): QQuickItem(parent), m_cachedState(new DeclarativeBarsCachedStatePrivate()), m_shared(0) { + setFlags(QQuickItem::ItemHasContents); + + setRotation(180.0); + setAntialiasing(true); + setSmooth(true); } DeclarativeBars::~DeclarativeBars() { + delete m_shared; +} + +QSGNode *DeclarativeBars::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + qDebug() << "Enter DeclarativeBars::updatePaintNode"; + // Delete old node and recreate it. This function gets called when window geometry changes. + if (oldNode) + delete oldNode; + + if (!m_shared) + m_shared = new Bars3dShared(boundingRect().toRect()); + + // Lazy initialization of shared object on the SGRenderThread + m_shared->initializeOpenGL(); + + // We need to create a node class that does the rendering (ie. a node that "captures" the rendering we do) + qDebug() << "DeclarativeBars::updatePaintNode Creating new node"; + + // Create the new render node + DeclarativeBarsRenderer *node = new DeclarativeBarsRenderer(window(), m_shared); + node->setRect(boundingRect()); + m_shared->setBoundingRect(boundingRect().toRect()); + + if (m_cachedState->m_isSampleSpaceSet) { + m_shared->setupSampleSpace(m_cachedState->m_samplesRow, m_cachedState->m_samplesColumn, m_cachedState->m_labelRow, m_cachedState->m_labelColumn, m_cachedState->m_labelHeight); + m_cachedState->m_isSampleSpaceSet = false; + } + + if (m_cachedState->m_dataRow) { + m_shared->addDataRow(m_cachedState->m_dataRow); + m_cachedState->m_dataRow = 0; + } + + if (m_cachedState->m_isSelectionModeSet) { + m_shared->setSelectionMode(m_cachedState->m_selectionMode); + m_cachedState->m_isSelectionModeSet = false; + } + + if (m_cachedState->m_isLabelTransparencySet) { + m_shared->setLabelTransparency(m_cachedState->m_labelTransparency); + m_cachedState->m_isLabelTransparencySet = false; + } + + if (m_cachedState->m_isShadowQualitySet) { + m_shared->setShadowQuality(m_cachedState->m_shadowQuality); + m_cachedState->m_isShadowQualitySet = false; + } + + if (m_cachedState->m_isGridSet) { + m_shared->setGridEnabled(m_cachedState->m_isGridEnabled); + m_cachedState->m_isGridSet = false; + } + + qDebug() << "Exit DeclarativeBars::updatePaintNode"; + return node; +} + +void DeclarativeBars::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative) +{ + m_shared->setBarSpecs(thickness, spacing, relative); +} + +void DeclarativeBars::setBarType(BarStyle style, bool smooth) +{ + m_shared->setBarType(style, smooth); +} + +void DeclarativeBars::setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow, + const QString &labelColumn, const QString &labelHeight) +{ + m_cachedState->m_samplesRow = samplesRow; + m_cachedState->m_samplesColumn = samplesColumn; + m_cachedState->m_labelRow = labelRow; + m_cachedState->m_labelColumn = labelColumn; + m_cachedState->m_labelHeight = labelHeight; + m_cachedState->m_isSampleSpaceSet = true; +} + + +void DeclarativeBars::setCameraPreset(CameraPreset preset) +{ + m_shared->setCameraPreset(preset); +} + +void DeclarativeBars::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance) +{ + m_shared->setCameraPosition(horizontal, vertical, distance); +} + +void DeclarativeBars::setTheme(ColorTheme theme) +{ + m_shared->setTheme(theme); +} + +void DeclarativeBars::setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform) +{ + m_shared->setBarColor(baseColor, heightColor, depthColor, uniform); +} + + +void DeclarativeBars::setFontSize(float fontsize) +{ + m_shared->setFontSize(fontsize); +} + +float DeclarativeBars::fontSize() +{ + return m_shared->fontSize(); +} + +void DeclarativeBars::setFont(const QFont &font) +{ + m_shared->setFont(font); +} + +QFont DeclarativeBars::font() +{ + return m_shared->font(); +} + +void DeclarativeBars::setLabelTransparency(DeclarativeBars::LabelTransparency transparency) +{ + m_cachedState->m_labelTransparency = QtDataVis3D::LabelTransparency(transparency); + m_cachedState->m_isLabelTransparencySet = true; +} + +DeclarativeBars::LabelTransparency DeclarativeBars::labelTransparency() +{ + return DeclarativeBars::LabelTransparency(m_shared->labelTransparency()); +} + +void DeclarativeBars::setGridEnabled(bool enable) +{ + m_cachedState->m_isGridEnabled = enable; + m_cachedState->m_isGridSet = true; } -void DeclarativeBars::setSelMode(DeclarativeBars::SelectionMode mode) +bool DeclarativeBars::gridEnabled() { - setSelectionMode(QtDataVis3D::SelectionMode(mode)); + return m_shared->gridEnabled(); } -DeclarativeBars::SelectionMode DeclarativeBars::selMode() +void DeclarativeBars::setBackgroundEnabled(bool enable) { - return DeclarativeBars::SelectionMode(selectionMode()); + m_shared->setBackgroundEnabled(enable); } -void DeclarativeBars::setTransparency(DeclarativeBars::LabelTransparency transparency) +bool DeclarativeBars::backgroundEnabled() { - setLabelTransparency(QtDataVis3D::LabelTransparency(transparency)); + return m_shared->backgroundEnabled(); } -DeclarativeBars::LabelTransparency DeclarativeBars::transparency() +void DeclarativeBars::setTickCount(GLint tickCount, GLfloat step, GLfloat minimum) { - return DeclarativeBars::LabelTransparency(labelTransparency()); + m_shared->setTickCount(tickCount, step, minimum); +} + +void DeclarativeBars::addDataRow(const QVector<float> &dataRow, const QString &labelRow, + const QVector<QString> &labelsColumn) +{ + qDebug() << "Enter DeclarativeBars::addDataRow(const QVector<float> &dataRow...)"; + m_shared->addDataRow(dataRow, labelRow, labelsColumn); +} + +void DeclarativeBars::addDataRow(const QVector<QDataItem*> &dataRow, const QString &labelRow, + const QVector<QString> &labelsColumn) +{ + qDebug() << "Enter DeclarativeBars::addDataRow(const QVector<QDataItem*> &dataRow...)"; + m_shared->addDataRow(dataRow, labelRow, labelsColumn); +} + +void DeclarativeBars::addDataRow(QDataRow *dataRow) +{ + qDebug() << "Enter DeclarativeBars::addDataRow(QDataRow *dataRow)"; + m_cachedState->m_dataRow = dataRow; +} + +void DeclarativeBars::addDataSet(const QVector< QVector<float> > &data, const QVector<QString> &labelsRow, + const QVector<QString> &labelsColumn) +{ + m_shared->addDataSet(data, labelsRow,labelsColumn); +} + +void DeclarativeBars::addDataSet(const QVector< QVector<QDataItem*> > &data, + const QVector<QString> &labelsRow, + const QVector<QString> &labelsColumn) +{ + m_shared->addDataSet(data, labelsRow, labelsColumn); +} + +void DeclarativeBars::addDataSet(QDataSet* dataSet) +{ + m_shared->addDataSet(dataSet); +} + +void DeclarativeBars::setSelectionMode(DeclarativeBars::SelectionMode mode) +{ + m_cachedState->m_selectionMode = QtDataVis3D::SelectionMode(mode); + m_cachedState->m_isSelectionModeSet = true; +} + +DeclarativeBars::SelectionMode DeclarativeBars::selectionMode() +{ + return DeclarativeBars::SelectionMode(m_shared->selectionMode()); } void DeclarativeBars::setShadow(DeclarativeBars::ShadowQuality quality) { - setShadowQuality(QtDataVis3D::ShadowQuality(quality)); + m_cachedState->m_shadowQuality = QtDataVis3D::ShadowQuality(quality); + m_cachedState->m_isShadowQualitySet = true; } DeclarativeBars::ShadowQuality DeclarativeBars::shadow() { - return DeclarativeBars::ShadowQuality(shadowQuality()); + return DeclarativeBars::ShadowQuality(m_shared->shadowQuality()); +} + +void DeclarativeBars::setMeshFileName(const QString &objFileName) +{ + m_shared->setMeshFileName(objFileName); +} + + + + +DeclarativeBarsRenderer::DeclarativeBarsRenderer(QQuickWindow *window, Bars3dShared *renderer) + : m_fbo(0), + m_texture(0), + m_window(window), + m_barsRenderer(renderer) +{ + qDebug() << "DeclarativeBarsRenderer::DeclarativeBarsRenderer()"; + connect(m_window, SIGNAL(beforeRendering()), this, SLOT(render()), Qt::DirectConnection); + qDebug() << "QQuickWindow::openglContext()->thread()" << m_window->openglContext()->thread(); + qDebug() << "QGuiApplication::instance()->thread()" << QGuiApplication::instance()->thread(); } +DeclarativeBarsRenderer::~DeclarativeBarsRenderer() +{ + delete m_texture; + delete m_fbo; +} + +void DeclarativeBarsRenderer::render() +{ + static bool firstRender = true; + if (firstRender) qDebug() << "DeclarativeBarsRenderer::render() running on thread "<< QThread::currentThread(); + firstRender = false; + + QSize size = rect().size().toSize(); + + if (!m_fbo) { + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + m_fbo = new QOpenGLFramebufferObject(size, format); + m_texture = m_window->createTextureFromId(m_fbo->texture(), size); + + // TODO: If we create the vis3d this way, how do we connect it with QML? + // Should we create it at QML and give it to DataVisView using a property (setVisualizer or similar)? + // DataVisView can then give it here as an argument in constructor? + + // TODO: For testing. Add some data to scene. + QVector< QVector<float> > data; + QVector<float> row; + for (float j = 0.0f; j < 5.0f; j++) { + for (float i = 0.0f; i < 5.0f; i++) + row.append(j / 10.0f + i / 10.0f); + data.append(row); + row.clear(); + } + + setTexture(m_texture); + } + + m_fbo->bind(); + + // SGRendering State resets between calls... + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // Emulate mouse movement + // TODO: Remove this and implement properly + static int rot = 0; + rot += 5; + if (rot > 2870) rot = 0; + m_barsRenderer->m_mousePos.setX(rot); + m_barsRenderer->m_mousePos.setY(100); + + // Call the shared rendering function + m_barsRenderer->render(); + + m_fbo->bindDefault(); + + m_window->update(); +} + + +DeclarativeBarsCachedStatePrivate::DeclarativeBarsCachedStatePrivate() : + m_isSampleSpaceSet(false), + m_labelRow(QStringLiteral("")), + m_labelColumn(QStringLiteral("")), + m_labelHeight(QStringLiteral("")), + m_dataRow(0) +{ +} + +DeclarativeBarsCachedStatePrivate::~DeclarativeBarsCachedStatePrivate() +{ +} + + QTENTERPRISE_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3dqml2/declarativebars.h b/src/datavis3dqml2/declarativebars.h index 99c95e5c..8194cd7d 100644 --- a/src/datavis3dqml2/declarativebars.h +++ b/src/datavis3dqml2/declarativebars.h @@ -42,22 +42,38 @@ #ifndef DECLARATIVEBARS_H #define DECLARATIVEBARS_H -#include "QtDataVis3D/qdatavis3dglobal.h" -#include "QtDataVis3D/qdatavis3namespace.h" -#include "q3dbars.h" +#include "bars3dshared_p.h" +#include "qdatavis3dglobal.h" +#include "qdatavis3namespace.h" +#include "declarativebars_p.h" + +#include <qsgsimpletexturenode.h> +#include <QQuickItem> +#include <QObject> + +class QOpenGLFramebufferObject; +class QSGTexture; +class QQuickWindow; QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE -class DeclarativeBars : public Q3DBars +class DeclarativeBars : public QQuickItem { Q_OBJECT - Q_PROPERTY(SelectionMode selectionMode READ selMode WRITE setSelMode) - Q_PROPERTY(LabelTransparency labelTransparency READ transparency WRITE setTransparency) + Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(LabelTransparency labelTransparency READ labelTransparency WRITE setLabelTransparency) Q_PROPERTY(ShadowQuality shadowQuality READ shadow WRITE setShadow) + Q_PROPERTY(bool grid READ gridEnabled WRITE setGridEnabled) + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(int height READ height WRITE setHeight) Q_ENUMS(SelectionMode) Q_ENUMS(ShadowQuality) Q_ENUMS(LabelTransparency) +protected: + Bars3dShared *m_shared; + DeclarativeBarsCachedStatePrivate *m_cachedState; + public: // Duplicated here to be able to use the same enums enum SelectionMode { @@ -84,22 +100,134 @@ public: }; public: - explicit DeclarativeBars(); + explicit DeclarativeBars(QQuickItem *parent = 0); ~DeclarativeBars(); + // Add a row of data. Each new row is added to the front of the sample space, moving previous + // rows back (if sample space is more than one row deep) + Q_INVOKABLE void addDataRow(const QVector<GLfloat> &dataRow, + const QString &labelRow = QString(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataItems is transferred + Q_INVOKABLE void addDataRow(const QVector<QDataItem*> &dataRow, + const QString &labelRow = QString(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataRow is transferred + Q_INVOKABLE void addDataRow(QDataRow *dataRow); + + // Add complete data set at a time, as a vector of data rows + Q_INVOKABLE void addDataSet(const QVector< QVector<GLfloat> > &data, + const QVector<QString> &labelsRow = QVector<QString>(), + const QVector<QString> &labelsColumn = QVector<QString>()); + + // ownership of dataItems is transferred + Q_INVOKABLE void addDataSet(const QVector< QVector<QDataItem*> > &data, + const QVector<QString> &labelsRow = QVector<QString>(), + const QVector<QString> &labelsColumn = QVector<QString>()); + // ownership of dataSet is transferred + Q_INVOKABLE void addDataSet(QDataSet* dataSet); + + // 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 + Q_INVOKABLE void setBarSpecs(QSizeF thickness = QSizeF(1.0f, 1.0f), + QSizeF spacing = QSizeF(1.0f, 1.0f), + bool relative = true); + + // bar type; bars (=cubes), pyramids, cones, cylinders, etc. + Q_INVOKABLE void setBarType(BarStyle style, bool smooth = false); + + // override bar type with own mesh + Q_INVOKABLE void setMeshFileName(const QString &objFileName); + + // how many samples per row and column, and names for axes + Q_INVOKABLE void setupSampleSpace(int samplesRow, int samplesColumn, + const QString &labelRow = QString(), + const QString &labelColumn = QString(), + const QString &labelHeight = QString()); + + // Select preset camera placement + Q_INVOKABLE void setCameraPreset(CameraPreset preset); + + // Set camera rotation if you don't want to use the presets (in horizontal (-180...180) and + // vertical (0...90) (or (-90...90) if there are negative values) angles and distance in + // percentage (10...500)) + Q_INVOKABLE void setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance = 100); + + // Set theme (bar colors, shaders, window color, background colors, light intensity and text + // colors are affected) + Q_INVOKABLE void setTheme(ColorTheme theme); + + // Set color if you don't want to use themes. Set uniform to false if you want the (height) + // color to change from bottom to top + Q_INVOKABLE void setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, + bool uniform = true); + + // Set tick count and step. Note; tickCount * step should be the maximum possible value of data + // set. Minimum is the absolute minimum possible value a bar can have. This is especially + // important to set if values can be negative. + Q_INVOKABLE void setTickCount(GLint tickCount, GLfloat step, GLfloat minimum = 0.0f); + + // TODO: light placement API + // Change selection mode; single bar, bar and row, bar and column, or all - void setSelMode(DeclarativeBars::SelectionMode mode); - DeclarativeBars::SelectionMode selMode(); + void setSelectionMode(SelectionMode mode); + SelectionMode selectionMode(); + + // Font size adjustment + void setFontSize(float fontsize); + float fontSize(); + + // Set font + void setFont(const QFont &font); + QFont font(); // Label transparency adjustment - void setTransparency(DeclarativeBars::LabelTransparency transparency); - DeclarativeBars::LabelTransparency transparency(); + void setLabelTransparency(LabelTransparency transparency); + LabelTransparency labelTransparency(); + + // Enable or disable background grid + void setGridEnabled(bool enable); + bool gridEnabled(); + + // Enable or disable background mesh + void setBackgroundEnabled(bool enable); + bool backgroundEnabled(); + + // Adjust shadow quality + void setShadowQuality(ShadowQuality quality); + ShadowQuality shadowQuality(); // Adjust shadow quality void setShadow(DeclarativeBars::ShadowQuality quality); DeclarativeBars::ShadowQuality shadow(); + + protected: + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); + +}; + +// TODO: If we use texture node, our rendering is done into a texture that is then drawn to the +// qquickwindow -> selection will not work +class DeclarativeBarsRenderer : public QObject, public QSGSimpleTextureNode +{ + Q_OBJECT + +public: + DeclarativeBarsRenderer(QQuickWindow *window, Bars3dShared *shared); + ~DeclarativeBarsRenderer(); + +public slots: + void render(); + +private: + QOpenGLFramebufferObject *m_fbo; + QSGTexture *m_texture; + QQuickWindow *m_window; + Bars3dShared *m_barsRenderer; }; QTENTERPRISE_DATAVIS3D_END_NAMESPACE +QTENTERPRISE_DATAVIS3D_USE_NAMESPACE #endif diff --git a/src/datavis3dqml2/scenerenderernode_p.h b/src/datavis3dqml2/declarativebars_p.h index aa59b9c1..62dcc708 100644 --- a/src/datavis3dqml2/scenerenderernode_p.h +++ b/src/datavis3dqml2/declarativebars_p.h @@ -49,46 +49,48 @@ // // We mean it. -#ifndef SCENERENDERERNODE_P_H -#define SCENERENDERERNODE_P_H +#ifndef DECLARATIVEBARS_P_H +#define DECLARATIVEBARS_P_H #include "QtDataVis3D/qdatavis3dglobal.h" - -#include <QObject> -#include <qsgsimpletexturenode.h> - -class QOpenGLFramebufferObject; -class QSGTexture; -class QQuickWindow; +#include "QtDataVis3D/qdatavis3namespace.h" +#include <QString> QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE -class Q3DBars; -//class Q3DMaps; +class QDataRow; -// TODO: If we use texture node, our rendering is done into a texture that is then drawn to the -// qquickwindow -> selection will not work -// TODO: Check if better ones are available -class SceneRendererNode : public QObject, public QSGSimpleTextureNode +class DeclarativeBarsCachedStatePrivate { - Q_OBJECT - public: - SceneRendererNode(QQuickWindow *window); - ~SceneRendererNode(); + explicit DeclarativeBarsCachedStatePrivate(); + ~DeclarativeBarsCachedStatePrivate(); + + bool m_isSampleSpaceSet; + int m_cachedState; + int m_samplesRow; + int m_samplesColumn; + QString m_labelRow; + QString m_labelColumn; + QString m_labelHeight; + + QDataRow *m_dataRow; -public slots: - void render(); + bool m_isSelectionModeSet; + SelectionMode m_selectionMode; -private: - QOpenGLFramebufferObject *m_fbo; - QSGTexture *m_texture; - QQuickWindow *m_window; - Q3DBars *m_scene; - //Q3DMaps *m_scene; + bool m_isLabelTransparencySet; + LabelTransparency m_labelTransparency; + + bool m_isShadowQualitySet; + ShadowQuality m_shadowQuality; + + + bool m_isGridSet; + bool m_isGridEnabled; }; QTENTERPRISE_DATAVIS3D_END_NAMESPACE +QTENTERPRISE_DATAVIS3D_USE_NAMESPACE -#endif - +#endif // DECLARATIVEBARS_P_H diff --git a/src/datavis3dqml2/scenerenderernode.cpp b/src/datavis3dqml2/scenerenderernode.cpp deleted file mode 100644 index 778cedbe..00000000 --- a/src/datavis3dqml2/scenerenderernode.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtDataVis3D module. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "scenerenderernode_p.h" - -#include <QtQuick/QQuickWindow> -#include <QtGui/QOpenGLFramebufferObject> -#include "q3dbars.h" -//#include "q3dmaps.h" - -QTENTERPRISE_DATAVIS3D_BEGIN_NAMESPACE - -SceneRendererNode::SceneRendererNode(QQuickWindow *window) - : m_fbo(0), - m_texture(0), - m_window(window), - m_scene(0) -{ - connect(m_window, SIGNAL(beforeRendering()), this, SLOT(render())); -} - -SceneRendererNode::~SceneRendererNode() -{ - delete m_texture; - delete m_fbo; - delete m_scene; -} - -void SceneRendererNode::render() -{ - QSize size = rect().size().toSize(); - - if (!m_fbo) { - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - m_fbo = new QOpenGLFramebufferObject(size, format); - m_texture = m_window->createTextureFromId(m_fbo->texture(), size); - // TODO: If we create the vis3d this way, how do we connect it with QML? - // Should we create it at QML and give it to DataVisView using a property (setVisualizer or similar)? - // DataVisView can then give it here as an argument in constructor? - - m_scene = new Q3DBars(); - m_scene->setSelectionMode(ModeNone); - m_scene->setShadowQuality(ShadowNone); - m_scene->setTheme(ThemeSystem); - m_scene->initialize(); - - // TODO: For testing. Add some data to scene. - QVector< QVector<float> > data; - QVector<float> row; - for (float j = 0.0f; j < 5.0f; j++) { - for (float i = 0.0f; i < 5.0f; i++) - row.append(j / 10.0f + i / 10.0f); - data.append(row); - row.clear(); - } - // Set up sample space based on inserted data - m_scene->setupSampleSpace(5, 5); - // Add data to chart - m_scene->addDataSet(data); - m_scene->setBarType(Cones); - - //m_scene = new Q3DMaps(); - setTexture(m_texture); - } - - m_fbo->bind(); - - // TODO: Render here, or "capture" the rendering we do at Q3DBars/Q3DMaps - m_scene->render(); - - m_fbo->bindDefault(); - - m_window->update(); -} - -QTENTERPRISE_DATAVIS3D_END_NAMESPACE - - |