diff options
Diffstat (limited to 'src/engine/q3dbars.cpp')
-rw-r--r-- | src/engine/q3dbars.cpp | 1747 |
1 files changed, 1747 insertions, 0 deletions
diff --git a/src/engine/q3dbars.cpp b/src/engine/q3dbars.cpp new file mode 100644 index 00000000..dc20a8c6 --- /dev/null +++ b/src/engine/q3dbars.cpp @@ -0,0 +1,1747 @@ +/**************************************************************************** +** +** 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 "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 <QOpenGLPaintDevice> +#include <QPainter> +#include <QScreen> +#include <QMouseEvent> + +#include <qmath.h> + +#include <QDebug> + +//#define DISPLAY_RENDER_SPEED + +#ifdef DISPLAY_RENDER_SPEED +#include <QTime> +#endif + +QTCOMMERCIALDATAVIS3D_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; + +Q3DBars::Q3DBars() + : d_ptr(new Q3DBarsPrivate(this)) +{ +} + +Q3DBars::~Q3DBars() +{ +} + +void Q3DBars::initialize() +{ + // Initialize 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/vertexTexture"), + // QStringLiteral(":/shaders/fragmentTexture")); + d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); + d_ptr->initLabelShaders(QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + 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); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + + // 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 + d_ptr->m_isInitialized = true; +} + +void Q3DBars::render() +{ + 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; + + viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 5.0f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // Adjust scaling (zoom rate based on aspect ratio) + viewMatrix.scale(d_ptr->m_zoomAdjustment); + + // Set light position a bit above the camera (depends on do we have row or column zoom) + if (ModeZoomColumn == d_ptr->m_selectionMode) + lightPos = CameraHelper::calculateLightPosition(defaultLightPos, -85.0f); + else + lightPos = CameraHelper::calculateLightPosition(defaultLightPos, 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; + + 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)); + + 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(), + modelMatrix.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 = QVector3D(0, 0, 0); + + // 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 + 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()); + + // 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; + } + + // 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 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(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white + 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? + + // add +2 to avoid black + QVector3D barColor = QVector3D((GLdouble)(row + 2) + / (GLdouble)(d_ptr->m_sampleCount.second + 2), + (GLdouble)(bar + 2) + / (GLdouble)(d_ptr->m_sampleCount.first + 2), + 0.0); + + 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(); + + // 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 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; + + 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; + //if (d_ptr->m_mousePressed) { + // qDebug() << "selected object:" << barIndex << "( row:" << row + 1 << ", column:" << bar + 1 << ")"; + // qDebug() << "object position:" << modelMatrix.column(3).toVector3D(); + //} + // 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(), + modelMatrix.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(); + + // Bind background shader + d_ptr->m_backgroundShader->bind(); + + // TODO: If we want to use background texture, we should create it in initBackground instead of here and keep the texture id in d_ptr + // Create texture + //glEnable(GL_TEXTURE_2D); + //GLuint bgrTexture = d_ptr->m_textureHelper->create2DTexture( + // QImage(QStringLiteral(":/textures/background")), true, true); + + glCullFace(GL_BACK); + + // Draw background + if (d_ptr->m_backgroundObj) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + 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); + + MVPMatrix = projectionMatrix * viewMatrix * 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(), + modelMatrix.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->lightS(), + d_ptr->m_theme->m_lightStrength); + d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->ambientS(), + d_ptr->m_theme->m_ambientStrength); + + // Draw the object + d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj); + //d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj, true, + // bgrTexture); + } + + // Disable textures + //glBindTexture(GL_TEXTURE_2D, 0); + //glDeleteTextures(1, &bgrTexture); // TODO: If we want to use background texture, we should create it in initBackground and delete on exit + //glDisable(GL_TEXTURE_2D); + + // Release background shader + d_ptr->m_backgroundShader->release(); + + // Draw grid lines + if (d_ptr->m_gridEnabled) { + // Bind bar shader + d_ptr->m_barShader->bind(); + + // Set unchanging shader bindings + QVector3D barColor = Utils::vectorFromColor(Qt::black); + 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->lightS(), + d_ptr->m_theme->m_lightStrength); + 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; + + 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)); + + MVPMatrix = projectionMatrix * viewMatrix * 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(), + modelMatrix.inverted().transposed()); + d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); + + // 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; + + 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)); + + MVPMatrix = projectionMatrix * viewMatrix * 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(), + modelMatrix.inverted().transposed()); + d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); + + // 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 / 2.5; // TODO: Replace 2.5 with a dynamic number deduced from scene? + for (GLfloat barHeight = heightStep; barHeight <= d_ptr->m_heightNormalizer * 2.0f; + barHeight += heightStep) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + if (d_ptr->m_zFlipped) { + modelMatrix.translate(0.0f, + barHeight / d_ptr->m_heightNormalizer - d_ptr->m_yAdjustment, + d_ptr->m_columnDepth / d_ptr->m_scaleFactor + zComp); + } else { + modelMatrix.translate(0.0f, + barHeight / 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)); + + MVPMatrix = projectionMatrix * viewMatrix * 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(), + modelMatrix.inverted().transposed()); + d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); + + // Draw the object + d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj); + } + + // Wall lines: side wall + for (GLfloat barHeight = heightStep; barHeight <= d_ptr->m_heightNormalizer * 2.0f; + barHeight += heightStep) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + if (d_ptr->m_xFlipped) { + modelMatrix.translate(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, + barHeight / d_ptr->m_heightNormalizer - d_ptr->m_yAdjustment, + zComp); + } else { + modelMatrix.translate(-d_ptr->m_rowWidth / d_ptr->m_scaleFactor, + barHeight / d_ptr->m_heightNormalizer - d_ptr->m_yAdjustment, + zComp); + } + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + d_ptr->m_columnDepth / d_ptr->m_scaleFactor)); + + MVPMatrix = projectionMatrix * viewMatrix * 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(), + modelMatrix.inverted().transposed()); + d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix); + + // 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; + 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; + } + 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, 0.0f), 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; + 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; + } + 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, 0.0f), 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(); +} + +void Q3DBars::mousePressEvent(QMouseEvent *event) +{ + // TODO: for testing shaders + //static GLint shaderNo = 1; + //qDebug() << "mouse button pressed" << event->button(); + if (Qt::LeftButton == event->button()) { + if (d_ptr->m_zoomActivated) { + //qDebug() << event->pos().x() << event->pos().y() << d_ptr->m_sceneViewPort << d_ptr->m_zoomViewPort; + 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 { + d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnScene; + // 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()) { + d_ptr->m_mousePressed = Q3DBarsPrivate::MouseRotating; + // update mouse positions to prevent jumping when releasing or repressing a button + d_ptr->m_mousePos = event->pos(); + + // TODO: testing shaders + // if (++shaderNo > 3) + // shaderNo = 1; + // switch (shaderNo) { + // case 1: + // d_ptr->initShaders(QStringLiteral(":/shaders/vertex") + // , QStringLiteral(":/shaders/fragment")); + // break; + // case 2: + // d_ptr->initShaders(QStringLiteral(":/shaders/vertex") + // , QStringLiteral(":/shaders/fragmentColorOnY")); + // break; + // case 3: + // d_ptr->initShaders(QStringLiteral(":/shaders/vertex") + // , QStringLiteral(":/shaders/fragmentAmbient")); + // break; + // } + } + CameraHelper::updateMousePos(d_ptr->m_mousePos); +} + +void Q3DBars::mouseReleaseEvent(QMouseEvent *event) +{ + //qDebug() << "mouse button released" << event->button(); + 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; +} + +void Q3DBars::mouseMoveEvent(QMouseEvent *event) +{ + if (Q3DBarsPrivate::MouseRotating == d_ptr->m_mousePressed) { + //qDebug() << "mouse moved while pressed" << event->pos(); + d_ptr->m_mousePos = event->pos(); + } +#if 0 + // TODO: Testi - laske kursorin sijainti scenessä + QPointF mouse3D((2.0f * event->pos().x() - width()) / height(), + 1.0f - (2.0f * event->pos().y()) / height()); + //qDebug() << "mouse position in scene" << mouse3D; + + // TODO: Testi laske focal point + GLfloat focalPoint = tan(45.0f / 2.0f); + + // TODO: Testi - laske viewmatriisin kerroin + QVector3D worldRay = QVector3D(0.0f, 0.0f, 0.0f) + - QVector3D(mouse3D.x(), mouse3D.y(), -focalPoint); + //qDebug() << "worldRay" << worldRay; + // multiply viewmatrix with this to get something? +#endif +} + +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; +} + +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(); +} + +void Q3DBars::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative) +{ + 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(); +} + +void Q3DBars::setBarType(BarStyle style, bool smooth) +{ + 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"); + } + // Reload mesh data + if (d_ptr->m_isInitialized) + d_ptr->loadBarMesh(); +} + +void Q3DBars::setMeshFileName(const QString &objFileName) +{ + d_ptr->m_objFile = objFileName; +} + +void Q3DBars::setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow, + const QString &labelColumn, const QString &labelHeight) +{ + // 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; +} + +void Q3DBars::setCameraPreset(CameraPreset preset) +{ + CameraHelper::setCameraPreset(preset); +} + +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; +} + +void Q3DBars::setTheme(ColorTheme theme) +{ + d_ptr->m_theme->useTheme(theme); + d_ptr->m_drawer->setTheme(*d_ptr->m_theme); + // Re-initialize 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")); + } +} + +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) { + // Re-initialize 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->m_theme->m_uniformColor = uniform; +} + +void Q3DBars::setSelectionMode(SelectionMode mode) +{ + d_ptr->m_selectionMode = mode; + // Disable zoom if mode changes + d_ptr->m_zoomActivated = false; + d_ptr->m_sceneViewPort = QRect(0, 0, width(), height()); + // Create zoom selection if there isn't one + if (mode >= ModeZoomRow && !d_ptr->m_zoomSelection) + d_ptr->m_zoomSelection = new QDataRow(); +} + +void Q3DBars::setWindowTitle(const QString &title) +{ + setTitle(title); +} + +void Q3DBars::setFontSize(float fontsize) +{ + d_ptr->m_font.setPointSizeF(fontsize); + d_ptr->m_drawer->setFont(d_ptr->m_font); +} + +void Q3DBars::setFont(const QFont &font) +{ + d_ptr->m_font = font; + d_ptr->m_drawer->setFont(font); +} + +void Q3DBars::setLabelTransparency(LabelTransparency transparency) +{ + d_ptr->m_labelTransparency = transparency; + d_ptr->m_drawer->setTransparency(transparency); +} + +void Q3DBars::setGridEnabled(bool enable) +{ + d_ptr->m_gridEnabled = enable; +} + +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); + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); + 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); +} + +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); + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); + 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); +} + +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); + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); +} + +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); + // 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++; + } + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); + d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); + d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); +} + +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); + // 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++; + } + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); + d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn); + d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second); +} + +void Q3DBars::addDataSet(QDataSet* dataSet) +{ + 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; + // Find highest value + // Get the limits + QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues(); + d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first)); + d_ptr->calculateHeightAdjustment(limits); + // Give drawer to data set + d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer); +} + +Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q) + : q_ptr(q), + m_paintDevice(0), + m_barShader(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(0, 0, q->width(), q->height()), + m_zoomViewPort(0, 0, q->width(), q->height()), + m_zoomActivated(false), + m_textureHelper(new TextureHelper()), + m_labelTransparency(TransparencyNone), + m_font(QFont(QStringLiteral("Arial"))), + m_drawer(new Drawer(*m_theme, m_font, m_labelTransparency)), + m_xFlipped(false), + m_zFlipped(false), + m_selectionFrameBuffer(0), + m_selectionDepthBuffer(0), + m_selectionTexture(0), + m_updateLabels(false), + m_gridEnabled(true) +{ + 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); + //m_textureHelper->deleteTexture(&m_selectionDepthTexture); +#endif + delete m_dataSet; + if (m_zoomSelection) { + m_zoomSelection->d_ptr->clear(); + delete m_zoomSelection; + } + delete m_barShader; + delete m_selectionShader; + delete m_backgroundShader; + delete m_barObj; + delete m_backgroundObj; + delete m_gridLineObj; + delete m_textureHelper; + delete m_drawer; +} + +void Q3DBarsPrivate::loadBarMesh() +{ + if (m_barObj) + delete m_barObj; + m_barObj = new ObjectHelper(m_objFile); + m_barObj->load(); +} + +void Q3DBarsPrivate::loadBackgroundMesh() +{ + if (m_backgroundObj) + delete m_backgroundObj; + 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_textureHelper->deleteTexture(&m_selectionDepthTexture); + } + m_selectionTexture = m_textureHelper->createSelectionTexture(q_ptr->size(), + m_selectionFrameBuffer, + m_selectionDepthBuffer); +#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 == Utils::vectorFromColor(Qt::white)) +#endif + return isSelectedType; // skip window + QVector3D current = QVector3D((GLubyte)(((GLdouble)(row + 2) / (GLdouble)(m_sampleCount.second + 2)) + * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back) + (GLubyte)(((GLdouble)(bar + 2) / (GLdouble)(m_sampleCount.first + 2)) + * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back) + 0); + // TODO: For debugging + //if (selection != prevSel) { + // qDebug() << 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; +} + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE |