diff options
Diffstat (limited to 'src/datavisualization/engine')
107 files changed, 22690 insertions, 0 deletions
diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp new file mode 100644 index 00000000..bfdc375e --- /dev/null +++ b/src/datavisualization/engine/abstract3dcontroller.cpp @@ -0,0 +1,1056 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "abstract3dcontroller_p.h" +#include "camerahelper_p.h" +#include "q3dabstractaxis_p.h" +#include "q3dvalueaxis.h" +#include "q3dcategoryaxis.h" +#include "abstract3drenderer_p.h" +#include "q3dcamera.h" +#include "q3dlight.h" +#include "qabstractdataproxy_p.h" +#include "qabstract3dinputhandler_p.h" +#include "qtouch3dinputhandler.h" + +#include <QThread> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) : + QObject(parent), + m_boundingRect(boundRect.x(), boundRect.y(), boundRect.width(), boundRect.height()), + m_theme(), + m_font(QFont(QStringLiteral("Arial"))), + m_selectionMode(QDataVis::SelectionModeItem), + m_shadowQuality(QDataVis::ShadowQualityMedium), + m_labelStyle(QDataVis::LabelStyleTransparent), + m_isBackgroundEnabled(true), + m_isGridEnabled(true), + m_scene(new Q3DScene()), + m_activeInputHandler(0), + m_axisX(0), + m_axisY(0), + m_axisZ(0), + m_renderer(0), + m_isDataDirty(true), + m_data(0), + m_renderPending(false) +{ + m_theme.useTheme(QDataVis::ThemeQt); + + // Populate the scene + m_scene->activeLight()->setPosition(defaultLightPos); + + // Create initial default input handler + QAbstract3DInputHandler *inputHandler; + inputHandler = new QTouch3DInputHandler(); + inputHandler->d_ptr->m_isDefaultHandler = true; + setActiveInputHandler(inputHandler); + connect(inputHandler, &QAbstract3DInputHandler::inputStateChanged, this, + &Abstract3DController::emitNeedRender); + connect(m_scene, &Q3DScene::needRender, this, + &Abstract3DController::emitNeedRender); +} + +Abstract3DController::~Abstract3DController() +{ + // Renderer can be in another thread, don't delete it directly in that case + if (m_renderer && m_renderer->thread() != QThread::currentThread()) + m_renderer->deleteLater(); + else + delete m_renderer; + delete m_scene; +} + +void Abstract3DController::setRenderer(Abstract3DRenderer *renderer) +{ + m_renderer = renderer; +} + +void Abstract3DController::synchDataToRenderer() +{ + // If we don't have a renderer, don't do anything + if (!m_renderer) + return; + + if (m_changeTracker.boundingRectChanged || m_changeTracker.sizeChanged) { + m_renderer->updateBoundingRect(m_boundingRect); + m_changeTracker.boundingRectChanged = false; + m_changeTracker.sizeChanged = false; + } + + if (m_changeTracker.positionChanged) { + m_renderer->updatePosition(m_boundingRect); + m_changeTracker.positionChanged = false; + } + + m_renderer->updateScene(m_scene); + + if (m_changeTracker.themeChanged) { + m_renderer->updateTheme(m_theme); + m_changeTracker.themeChanged = false; + } + + if (m_changeTracker.fontChanged) { + m_renderer->updateFont(m_font); + m_changeTracker.fontChanged = false; + } + + if (m_changeTracker.labelStyleChanged) { + m_renderer->updateLabelStyle(m_labelStyle); + m_changeTracker.labelStyleChanged = false; + } + + if (m_changeTracker.shadowQualityChanged) { + m_renderer->updateShadowQuality(m_shadowQuality); + m_changeTracker.shadowQualityChanged = false; + } + + if (m_changeTracker.selectionModeChanged) { + m_renderer->updateSelectionMode(m_selectionMode); + m_changeTracker.selectionModeChanged = false; + } + + if (m_changeTracker.objFileChanged) { + m_renderer->updateMeshFileName(m_objFile); + m_changeTracker.objFileChanged = false; + } + + if (m_changeTracker.gridEnabledChanged) { + m_renderer->updateGridEnabled(m_isGridEnabled); + m_changeTracker.gridEnabledChanged = false; + } + + if (m_changeTracker.backgroundEnabledChanged) { + m_renderer->updateBackgroundEnabled(m_isBackgroundEnabled); + m_changeTracker.backgroundEnabledChanged = false; + } + + if (m_changeTracker.axisXTypeChanged) { + m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationX, m_axisX->type()); + m_changeTracker.axisXTypeChanged = false; + } + + if (m_changeTracker.axisYTypeChanged) { + m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationY, m_axisY->type()); + m_changeTracker.axisYTypeChanged = false; + } + + if (m_changeTracker.axisZTypeChanged) { + m_renderer->updateAxisType(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->type()); + m_changeTracker.axisZTypeChanged = false; + } + + if (m_changeTracker.axisXTitleChanged) { + m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationX, m_axisX->title()); + m_changeTracker.axisXTitleChanged = false; + } + + if (m_changeTracker.axisYTitleChanged) { + m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationY, m_axisY->title()); + m_changeTracker.axisYTitleChanged = false; + } + + if (m_changeTracker.axisZTitleChanged) { + m_renderer->updateAxisTitle(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->title()); + m_changeTracker.axisZTitleChanged = false; + } + + if (m_changeTracker.axisXLabelsChanged) { + m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationX, m_axisX->labels()); + m_changeTracker.axisXLabelsChanged = false; + } + + if (m_changeTracker.axisYLabelsChanged) { + m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationY, m_axisY->labels()); + m_changeTracker.axisYLabelsChanged = false; + } + if (m_changeTracker.axisZLabelsChanged) { + m_renderer->updateAxisLabels(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->labels()); + m_changeTracker.axisZLabelsChanged = false; + } + + if (m_changeTracker.axisXRangeChanged) { + m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationX, m_axisX->min(), + m_axisX->max()); + m_changeTracker.axisXRangeChanged = false; + } + + if (m_changeTracker.axisYRangeChanged) { + m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationY, m_axisY->min(), + m_axisY->max()); + m_changeTracker.axisYRangeChanged = false; + } + + if (m_changeTracker.axisZRangeChanged) { + m_renderer->updateAxisRange(Q3DAbstractAxis::AxisOrientationZ, m_axisZ->min(), + m_axisZ->max()); + m_changeTracker.axisZRangeChanged = false; + } + + if (m_changeTracker.axisXSegmentCountChanged) { + m_changeTracker.axisXSegmentCountChanged = false; + if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX); + m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationX, + valueAxisX->segmentCount()); + } + } + + if (m_changeTracker.axisYSegmentCountChanged) { + m_changeTracker.axisYSegmentCountChanged = false; + if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY); + m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationY, + valueAxisY->segmentCount()); + } + } + + if (m_changeTracker.axisZSegmentCountChanged) { + m_changeTracker.axisZSegmentCountChanged = false; + if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ); + m_renderer->updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientationZ, + valueAxisZ->segmentCount()); + } + } + + if (m_changeTracker.axisXSubSegmentCountChanged) { + m_changeTracker.axisXSubSegmentCountChanged = false; + if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX); + m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationX, + valueAxisX->subSegmentCount()); + } + } + + if (m_changeTracker.axisYSubSegmentCountChanged) { + m_changeTracker.axisYSubSegmentCountChanged = false; + if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY); + m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationY, + valueAxisY->subSegmentCount()); + } + } + + if (m_changeTracker.axisZSubSegmentCountChanged) { + m_changeTracker.axisZSubSegmentCountChanged = false; + if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ); + m_renderer->updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientationZ, + valueAxisZ->subSegmentCount()); + } + } + + if (m_changeTracker.axisXLabelFormatChanged) { + m_changeTracker.axisXLabelFormatChanged = false; + if (m_axisX->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisX = static_cast<Q3DValueAxis *>(m_axisX); + m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationX, + valueAxisX->labelFormat()); + } + } + + if (m_changeTracker.axisYLabelFormatChanged) { + m_changeTracker.axisYLabelFormatChanged = false; + if (m_axisY->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisY = static_cast<Q3DValueAxis *>(m_axisY); + m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationY, + valueAxisY->labelFormat()); + } + } + + if (m_changeTracker.axisZLabelFormatChanged) { + m_changeTracker.axisZLabelFormatChanged = false; + if (m_axisZ->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxisZ = static_cast<Q3DValueAxis *>(m_axisZ); + m_renderer->updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientationZ, + valueAxisZ->labelFormat()); + } + } +} + +void Abstract3DController::render(const GLuint defaultFboHandle) +{ + m_renderPending = false; + + // If not initialized, do nothing. + if (!m_renderer) + return; + + m_renderer->render(defaultFboHandle); + +#ifdef DISPLAY_RENDER_SPEED + // To get meaningful framerate, don't just do render on demand. + emitNeedRender(); +#endif +} + +void Abstract3DController::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (m_activeInputHandler) + m_activeInputHandler->mouseDoubleClickEvent(event); + + emitNeedRender(); +} + +void Abstract3DController::touchEvent(QTouchEvent *event) +{ + if (m_activeInputHandler) + m_activeInputHandler->touchEvent(event); + + emitNeedRender(); +} + +void Abstract3DController::mousePressEvent(QMouseEvent *event, const QPoint &mousePos) +{ + if (m_activeInputHandler) + m_activeInputHandler->mousePressEvent(event, mousePos); + + emitNeedRender(); +} + +void Abstract3DController::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos) +{ + if (m_activeInputHandler) + m_activeInputHandler->mouseReleaseEvent(event, mousePos); + + emitNeedRender(); +} + +void Abstract3DController::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos) +{ + if (m_activeInputHandler) + m_activeInputHandler->mouseMoveEvent(event, mousePos); + + emitNeedRender(); +} + +void Abstract3DController::wheelEvent(QWheelEvent *event) +{ + if (m_activeInputHandler) + m_activeInputHandler->wheelEvent(event); + + emitNeedRender(); +} + +void Abstract3DController::setSize(const int width, const int height) +{ + m_boundingRect.setWidth(width); + m_boundingRect.setHeight(height); + m_scene->setViewportSize(width, height); + + m_changeTracker.boundingRectChanged = true; + emitNeedRender(); +} + +const QSize Abstract3DController::size() +{ + return m_boundingRect.size(); +} + +const QRect Abstract3DController::boundingRect() +{ + return m_boundingRect; +} + +void Abstract3DController::setBoundingRect(const QRect boundingRect) +{ + m_boundingRect = boundingRect; + m_scene->setViewport(boundingRect); + + m_changeTracker.boundingRectChanged = true; + emitNeedRender(); +} + +void Abstract3DController::setWidth(const int width) +{ + m_boundingRect.setWidth(width); + m_scene->setViewportSize(width, m_scene->viewport().height()); + + m_changeTracker.sizeChanged = true; + emitNeedRender(); +} + +int Abstract3DController::width() +{ + return m_boundingRect.width(); +} + +void Abstract3DController::setHeight(const int height) +{ + m_boundingRect.setHeight(height); + m_scene->setViewportSize(m_scene->viewport().width(), height); + + m_changeTracker.sizeChanged = true; + emitNeedRender(); +} + +int Abstract3DController::height() +{ + return m_boundingRect.height(); +} + +void Abstract3DController::setX(const int x) +{ + m_boundingRect.setX(x); + + m_changeTracker.positionChanged = true; + emitNeedRender(); +} + +int Abstract3DController::x() +{ + return m_boundingRect.x(); +} + +void Abstract3DController::setY(const int y) +{ + m_boundingRect.setY(y); + + m_changeTracker.positionChanged = true; + emitNeedRender(); +} + +int Abstract3DController::y() +{ + return m_boundingRect.y(); +} + +QRect Abstract3DController::primarySubViewport() const +{ + return m_scene->primarySubViewport(); +} + +void Abstract3DController::setPrimarySubViewport(const QRect &primarySubViewport) +{ + m_scene->setPrimarySubViewport(primarySubViewport); +} + +QRect Abstract3DController::secondarySubViewport() const +{ + return m_scene->secondarySubViewport(); +} + +void Abstract3DController::setSecondarySubViewport(const QRect &secondarySubViewport) +{ + m_scene->setSecondarySubViewport(secondarySubViewport); +} + +void Abstract3DController::updateDevicePixelRatio(qreal ratio) +{ + m_scene->setDevicePixelRatio(ratio); +} + +void Abstract3DController::setAxisX(Q3DAbstractAxis *axis) +{ + setAxisHelper(Q3DAbstractAxis::AxisOrientationX, axis, &m_axisX); +} + +Q3DAbstractAxis *Abstract3DController::axisX() +{ + return m_axisX; +} + +void Abstract3DController::setAxisY(Q3DAbstractAxis *axis) +{ + setAxisHelper(Q3DAbstractAxis::AxisOrientationY, axis, &m_axisY); +} + +Q3DAbstractAxis *Abstract3DController::axisY() +{ + return m_axisY; +} + +void Abstract3DController::setAxisZ(Q3DAbstractAxis *axis) +{ + setAxisHelper(Q3DAbstractAxis::AxisOrientationZ, axis, &m_axisZ); +} + +Q3DAbstractAxis *Abstract3DController::axisZ() +{ + return m_axisZ; +} + +void Abstract3DController::addAxis(Q3DAbstractAxis *axis) +{ + Q_ASSERT(axis); + Abstract3DController *owner = qobject_cast<Abstract3DController *>(axis->parent()); + if (owner != this) { + Q_ASSERT_X(!owner, "addAxis", "Axis already attached to a graph."); + axis->setParent(this); + } + if (!m_axes.contains(axis)) + m_axes.append(axis); +} + +void Abstract3DController::releaseAxis(Q3DAbstractAxis *axis) +{ + if (axis && m_axes.contains(axis)) { + // Clear the default status from released default axes + if (axis->d_ptr->isDefaultAxis()) + axis->d_ptr->setDefaultAxis(false); + + // If the axis is in use, replace it with a temporary one + switch (axis->orientation()) { + case Q3DAbstractAxis::AxisOrientationX: + setAxisX(0); + break; + case Q3DAbstractAxis::AxisOrientationY: + setAxisY(0); + break; + case Q3DAbstractAxis::AxisOrientationZ: + setAxisZ(0); + break; + default: + break; + } + + m_axes.removeAll(axis); + axis->setParent(0); + } +} + +QList<Q3DAbstractAxis *> Abstract3DController::axes() const +{ + return m_axes; +} + +QAbstractDataProxy *Abstract3DController::activeDataProxy() const +{ + return m_data; +} + +void Abstract3DController::addDataProxy(QAbstractDataProxy *proxy) +{ + Q_ASSERT(proxy); + Abstract3DController *owner = qobject_cast<Abstract3DController *>(proxy->parent()); + if (owner != this) { + Q_ASSERT_X(!owner, "addDataProxy", "Proxy already attached to a graph."); + proxy->setParent(this); + } + if (!m_dataProxies.contains(proxy)) + m_dataProxies.append(proxy); +} + +void Abstract3DController::releaseDataProxy(QAbstractDataProxy *proxy) +{ + if (proxy && m_dataProxies.contains(proxy)) { + // Clear the default status from released default proxies + if (proxy->d_ptr->isDefaultProxy()) + proxy->d_ptr->setDefaultProxy(false); + + // If the proxy is in use, replace it with a temporary one + if (m_data == proxy) + setActiveDataProxy(0); + + m_dataProxies.removeAll(proxy); + proxy->setParent(0); + } +} + +QList<QAbstractDataProxy *> Abstract3DController::dataProxies() const +{ + return m_dataProxies; +} + +void Abstract3DController::setActiveDataProxy(QAbstractDataProxy *proxy) +{ + // If existing proxy is the default proxy, delete it + if (m_data) { + if (m_data->d_ptr->isDefaultProxy()) { + m_dataProxies.removeAll(m_data); + delete m_data; + } else { + // Disconnect the old proxy from use + QObject::disconnect(m_data, 0, this, 0); + } + } + + // Assume ownership and activate + addDataProxy(proxy); + m_data = proxy; + m_isDataDirty = true; + emitNeedRender(); +} + +void Abstract3DController::addInputHandler(QAbstract3DInputHandler *inputHandler) +{ + Q_ASSERT(inputHandler); + Abstract3DController *owner = qobject_cast<Abstract3DController *>(inputHandler->parent()); + if (owner != this) { + Q_ASSERT_X(!owner, "addInputHandler", "Input handler already attached to another component."); + inputHandler->setParent(this); + } + + if (!m_inputHandlers.contains(inputHandler)) + m_inputHandlers.append(inputHandler); +} + +void Abstract3DController::releaseInputHandler(QAbstract3DInputHandler *inputHandler) +{ + if (inputHandler && m_inputHandlers.contains(inputHandler)) { + // Clear the default status from released default input handler + if (inputHandler->d_ptr->m_isDefaultHandler) + inputHandler->d_ptr->m_isDefaultHandler = false; + + // If the input handler is in use, remove it + if (m_activeInputHandler == inputHandler) + setActiveInputHandler(0); + + m_inputHandlers.removeAll(inputHandler); + inputHandler->setParent(0); + } +} + +void Abstract3DController::setActiveInputHandler(QAbstract3DInputHandler *inputHandler) +{ + if (inputHandler == m_activeInputHandler) + return; + + // If existing input handler is the default input handler, delete it + if (m_activeInputHandler) { + if (m_activeInputHandler->d_ptr->m_isDefaultHandler) { + m_inputHandlers.removeAll(m_activeInputHandler); + delete m_activeInputHandler; + } else { + // Disconnect the old input handler from the scene + m_activeInputHandler->setScene(0); + } + } + + // Assume ownership and connect to this controller's scene + if (inputHandler) + addInputHandler(inputHandler); + + m_activeInputHandler = inputHandler; + if (m_activeInputHandler) + m_activeInputHandler->setScene(m_scene); + + // Notify change of input handler + emit activeInputHandlerChanged(m_activeInputHandler); +} + +QAbstract3DInputHandler* Abstract3DController::activeInputHandler() +{ + return m_activeInputHandler; +} + +int Abstract3DController::zoomLevel() +{ + return m_scene->activeCamera()->zoomLevel(); +} + +void Abstract3DController::setZoomLevel(int zoomLevel) +{ + m_scene->activeCamera()->setZoomLevel(zoomLevel); + + m_changeTracker.zoomLevelChanged = true; + emitNeedRender(); +} + +void Abstract3DController::setObjectColor(const QColor &baseColor, bool uniform) +{ + m_theme.m_baseColor = baseColor; + m_theme.m_uniformColor = uniform; + + m_changeTracker.themeChanged = true; + emitNeedRender(); +} + +QColor Abstract3DController::objectColor() const +{ + return m_theme.m_baseColor; +} + +void Abstract3DController::setTheme(QDataVis::Theme theme) +{ + m_theme.useTheme(theme); + + m_changeTracker.themeChanged = true; + emitNeedRender(); +} + +Theme Abstract3DController::theme() +{ + return m_theme; +} + +void Abstract3DController::setFont(const QFont &font) +{ + m_font = font; + + m_changeTracker.fontChanged = true; + emitNeedRender(); +} + +QFont Abstract3DController::font() +{ + return m_font; +} + +void Abstract3DController::setSelectionMode(QDataVis::SelectionMode mode) +{ + m_selectionMode = mode; + m_changeTracker.selectionModeChanged = true; + emitNeedRender(); +} + +QDataVis::SelectionMode Abstract3DController::selectionMode() +{ + return m_selectionMode; +} + +void Abstract3DController::setShadowQuality(QDataVis::ShadowQuality quality) +{ + m_shadowQuality = quality; + + m_changeTracker.shadowQualityChanged = true; + emit shadowQualityChanged(m_shadowQuality); + emitNeedRender(); +} + +QDataVis::ShadowQuality Abstract3DController::shadowQuality() +{ + return m_shadowQuality; +} + +void Abstract3DController::setLabelStyle(QDataVis::LabelStyle style) +{ + m_labelStyle = style; + + m_changeTracker.labelStyleChanged = true; + emitNeedRender(); +} + +QDataVis::LabelStyle Abstract3DController::labelStyle() +{ + return m_labelStyle; +} + +void Abstract3DController::setBackgroundEnabled(bool enable) +{ + m_isBackgroundEnabled = enable; + m_changeTracker.backgroundEnabledChanged = true; + emitNeedRender(); +} + +bool Abstract3DController::backgroundEnabled() +{ + return m_isBackgroundEnabled; +} + +void Abstract3DController::setGridEnabled(bool enable) +{ + m_isGridEnabled = enable; + m_changeTracker.gridEnabledChanged = true; + emitNeedRender(); +} + +bool Abstract3DController::gridEnabled() +{ + return m_isGridEnabled; +} + +bool Abstract3DController::isSlicingActive() +{ + return m_scene->isSlicingActive(); +} + +void Abstract3DController::setSlicingActive(bool isSlicing) +{ + m_scene->setSlicingActive(isSlicing); + emitNeedRender(); +} + +QDataVis::InputState Abstract3DController::inputState() +{ + if (m_activeInputHandler) + return m_activeInputHandler->inputState(); + else + return QDataVis::InputStateNone; +} + +QPoint Abstract3DController::inputPosition() +{ + if (m_activeInputHandler) + return m_activeInputHandler->inputPosition(); + else + return QPoint(0,0); +} + +void Abstract3DController::setMeshFileName(const QString &fileName) +{ + m_objFile = fileName; + m_changeTracker.objFileChanged = true; + emitNeedRender(); +} + +QString Abstract3DController::meshFileName() +{ + return m_objFile; +} + +Q3DScene *Abstract3DController::scene() +{ + return m_scene; +} + +void Abstract3DController::handleAxisTitleChanged(const QString &title) +{ + Q_UNUSED(title) + handleAxisTitleChangedBySender(sender()); +} + +void Abstract3DController::handleAxisTitleChangedBySender(QObject *sender) +{ + if (sender == m_axisX) + m_changeTracker.axisXTitleChanged = true; + else if (sender == m_axisY) + m_changeTracker.axisYTitleChanged = true; + else if (sender == m_axisZ) + m_changeTracker.axisZTitleChanged = true; + else + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + emitNeedRender(); +} + +void Abstract3DController::handleAxisLabelsChanged() +{ + handleAxisLabelsChangedBySender(sender()); +} + +void Abstract3DController::handleAxisLabelsChangedBySender(QObject *sender) +{ + if (sender == m_axisX) + m_changeTracker.axisXLabelsChanged = true; + else if (sender == m_axisY) + m_changeTracker.axisYLabelsChanged = true; + else if (sender == m_axisZ) + m_changeTracker.axisZLabelsChanged = true; + else + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + emitNeedRender(); +} + +void Abstract3DController::handleAxisRangeChanged(qreal min, qreal max) +{ + Q_UNUSED(min) + Q_UNUSED(max) + handleAxisRangeChangedBySender(sender()); +} + +void Abstract3DController::handleAxisRangeChangedBySender(QObject *sender) +{ + if (sender == m_axisX) { + m_isDataDirty = true; + m_changeTracker.axisXRangeChanged = true; + } else if (sender == m_axisY) { + m_isDataDirty = true; + m_changeTracker.axisYRangeChanged = true; + } else if (sender == m_axisZ) { + m_isDataDirty = true; + m_changeTracker.axisZRangeChanged = true; + } else { + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + } + emitNeedRender(); +} + +void Abstract3DController::handleAxisSegmentCountChanged(int count) +{ + Q_UNUSED(count) + handleAxisSegmentCountChangedBySender(sender()); +} + +void Abstract3DController::handleAxisSegmentCountChangedBySender(QObject *sender) +{ + if (sender == m_axisX) + m_changeTracker.axisXSegmentCountChanged = true; + else if (sender == m_axisY) + m_changeTracker.axisYSegmentCountChanged = true; + else if (sender == m_axisZ) + m_changeTracker.axisZSegmentCountChanged = true; + else + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + emitNeedRender(); +} + +void Abstract3DController::handleAxisSubSegmentCountChanged(int count) +{ + Q_UNUSED(count) + handleAxisSubSegmentCountChangedBySender(sender()); +} + +void Abstract3DController::handleAxisSubSegmentCountChangedBySender(QObject *sender) +{ + if (sender == m_axisX) + m_changeTracker.axisXSubSegmentCountChanged = true; + else if (sender == m_axisY) + m_changeTracker.axisYSubSegmentCountChanged = true; + else if (sender == m_axisZ) + m_changeTracker.axisZSubSegmentCountChanged = true; + else + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + emitNeedRender(); +} + +void Abstract3DController::handleAxisAutoAdjustRangeChanged(bool autoAdjust) +{ + QObject *sender = QObject::sender(); + if (sender != m_axisX && sender != m_axisY && sender != m_axisZ) + return; + + Q3DAbstractAxis *axis = static_cast<Q3DAbstractAxis*>(sender); + handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(), autoAdjust); +} + +void Abstract3DController::handleAxisLabelFormatChanged(const QString &format) +{ + Q_UNUSED(format) + handleAxisLabelFormatChangedBySender(sender()); +} + +void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) +{ + // Label format changing needs to dirty the data so that labels are reset. + if (sender == m_axisX) { + m_isDataDirty = true; + m_changeTracker.axisXLabelFormatChanged = true; + } else if (sender == m_axisY) { + m_isDataDirty = true; + m_changeTracker.axisYLabelFormatChanged = true; + } else if (sender == m_axisZ) { + m_isDataDirty = true; + m_changeTracker.axisZLabelFormatChanged = true; + } else { + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + } + emitNeedRender(); +} + +void Abstract3DController::setAxisHelper(Q3DAbstractAxis::AxisOrientation orientation, + Q3DAbstractAxis *axis, Q3DAbstractAxis **axisPtr) +{ + // Setting null axis indicates using default axis + if (!axis) + axis = createDefaultAxis(orientation); + + // If old axis is default axis, delete it + Q3DAbstractAxis *oldAxis = *axisPtr; + if (oldAxis) { + if (oldAxis->d_ptr->isDefaultAxis()) { + m_axes.removeAll(oldAxis); + delete oldAxis; + oldAxis = 0; + } else { + // Disconnect the old axis from use + QObject::disconnect(oldAxis, 0, this, 0); + oldAxis->d_ptr->setOrientation(Q3DAbstractAxis::AxisOrientationNone); + } + } + + // Assume ownership + addAxis(axis); + + // Connect the new axis + *axisPtr = axis; + + axis->d_ptr->setOrientation(orientation); + + QObject::connect(axis, &Q3DAbstractAxis::titleChanged, + this, &Abstract3DController::handleAxisTitleChanged); + QObject::connect(axis, &Q3DAbstractAxis::labelsChanged, + this, &Abstract3DController::handleAxisLabelsChanged); + QObject::connect(axis, &Q3DAbstractAxis::rangeChanged, + this, &Abstract3DController::handleAxisRangeChanged); + QObject::connect(axis, &Q3DAbstractAxis::autoAdjustRangeChanged, + this, &Abstract3DController::handleAxisAutoAdjustRangeChanged); + + if (orientation == Q3DAbstractAxis::AxisOrientationX) + m_changeTracker.axisXTypeChanged = true; + else if (orientation == Q3DAbstractAxis::AxisOrientationY) + m_changeTracker.axisYTypeChanged = true; + else if (orientation == Q3DAbstractAxis::AxisOrientationZ) + m_changeTracker.axisZTypeChanged = true; + + handleAxisTitleChangedBySender(axis); + handleAxisLabelsChangedBySender(axis); + handleAxisRangeChangedBySender(axis); + handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(), + axis->isAutoAdjustRange()); + + if (axis->type() & Q3DAbstractAxis::AxisTypeValue) { + Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(axis); + QObject::connect(valueAxis, &Q3DValueAxis::segmentCountChanged, + this, &Abstract3DController::handleAxisSegmentCountChanged); + QObject::connect(valueAxis, &Q3DValueAxis::subSegmentCountChanged, + this, &Abstract3DController::handleAxisSubSegmentCountChanged); + QObject::connect(valueAxis, &Q3DValueAxis::labelFormatChanged, + this, &Abstract3DController::handleAxisLabelFormatChanged); + + handleAxisSegmentCountChangedBySender(valueAxis); + handleAxisSubSegmentCountChangedBySender(valueAxis); + handleAxisLabelFormatChangedBySender(valueAxis); + } +} + +Q3DAbstractAxis *Abstract3DController::createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation) +{ + Q_UNUSED(orientation) + + // The default default axis is a value axis. If the graph type has a different default axis + // for some orientation, this function needs to be overridden. + Q3DAbstractAxis *defaultAxis = createDefaultValueAxis(); + return defaultAxis; +} + +Q3DValueAxis *Abstract3DController::createDefaultValueAxis() +{ + // Default value axis has single segment, empty label format, and auto scaling + // TODO: Grid should be also hidden, but that is not currently controlled by axis + Q3DValueAxis *defaultAxis = new Q3DValueAxis; + defaultAxis->setSegmentCount(1); + defaultAxis->setSubSegmentCount(1); + defaultAxis->setAutoAdjustRange(true); + defaultAxis->setLabelFormat(QString()); + defaultAxis->d_ptr->setDefaultAxis(true); + + return defaultAxis; +} + +Q3DCategoryAxis *Abstract3DController::createDefaultCategoryAxis() +{ + // Default category axis has no labels + // TODO: Grid should be also hidden, but that is not currently controlled by axis. + Q3DCategoryAxis *defaultAxis = new Q3DCategoryAxis; + defaultAxis->setAutoAdjustRange(true); + defaultAxis->d_ptr->setDefaultAxis(true); + return defaultAxis; +} + +void Abstract3DController::emitNeedRender() +{ + if (!m_renderPending) { + emit needRender(); + m_renderPending = true; + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h new file mode 100644 index 00000000..f17c6c4d --- /dev/null +++ b/src/datavisualization/engine/abstract3dcontroller_p.h @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CONTROLLER3DBASE_H +#define CONTROLLER3DBASE_H + +#include "datavisualizationglobal_p.h" +#include "theme_p.h" +#include "q3dabstractaxis.h" +#include "drawer_p.h" +#include "qabstract3dinputhandler.h" +#include "qabstractdataproxy.h" +#include "q3dscene.h" +#include "q3dbox.h" + +#include <QObject> + +class QFont; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class CameraHelper; +class Abstract3DRenderer; + +struct Abstract3DChangeBitField { + bool positionChanged : 1; + bool zoomLevelChanged : 1; + bool themeChanged : 1; + bool fontChanged : 1; + bool labelStyleChanged : 1; + bool boundingRectChanged : 1; + bool sizeChanged : 1; + bool shadowQualityChanged : 1; + bool selectionModeChanged : 1; + bool objFileChanged : 1; + bool gridEnabledChanged : 1; + bool backgroundEnabledChanged : 1; + bool axisXTypeChanged : 1; + bool axisYTypeChanged : 1; + bool axisZTypeChanged : 1; + bool axisXTitleChanged : 1; + bool axisYTitleChanged : 1; + bool axisZTitleChanged : 1; + bool axisXLabelsChanged : 1; + bool axisYLabelsChanged : 1; + bool axisZLabelsChanged : 1; + bool axisXRangeChanged : 1; + bool axisYRangeChanged : 1; + bool axisZRangeChanged : 1; + bool axisXSegmentCountChanged : 1; + bool axisYSegmentCountChanged : 1; + bool axisZSegmentCountChanged : 1; + bool axisXSubSegmentCountChanged : 1; + bool axisYSubSegmentCountChanged : 1; + bool axisZSubSegmentCountChanged : 1; + bool axisXLabelFormatChanged : 1; + bool axisYLabelFormatChanged : 1; + bool axisZLabelFormatChanged : 1; + + Abstract3DChangeBitField() : + positionChanged(true), + zoomLevelChanged(true), + themeChanged(true), + fontChanged(true), + labelStyleChanged(true), + boundingRectChanged(true), + sizeChanged(true), + shadowQualityChanged(true), + selectionModeChanged(true), + objFileChanged(true), + gridEnabledChanged(true), + backgroundEnabledChanged(true), + axisXTypeChanged(true), + axisYTypeChanged(true), + axisZTypeChanged(true), + axisXTitleChanged(true), + axisYTitleChanged(true), + axisZTitleChanged(true), + axisXLabelsChanged(true), + axisYLabelsChanged(true), + axisZLabelsChanged(true), + axisXRangeChanged(true), + axisYRangeChanged(true), + axisZRangeChanged(true), + axisXSegmentCountChanged(true), + axisYSegmentCountChanged(true), + axisZSegmentCountChanged(true), + axisXSubSegmentCountChanged(true), + axisYSubSegmentCountChanged(true), + axisZSubSegmentCountChanged(true), + axisXLabelFormatChanged(true), + axisYLabelFormatChanged(true), + axisZLabelFormatChanged(true) + { + } +}; + +class QT_DATAVISUALIZATION_EXPORT Abstract3DController : public QObject +{ + Q_OBJECT + +public: + enum SelectionType { + SelectionNone = 0, + SelectionItem, + SelectionRow, + SelectionColumn + }; + + enum MouseState { + MouseNone = 0, + MouseOnScene, + MouseOnOverview, + MouseOnZoom, + MouseRotating, + MouseOnPinch + }; + +private: + Abstract3DChangeBitField m_changeTracker; + QRect m_boundingRect; + GLfloat m_horizontalRotation; + GLfloat m_verticalRotation; + Theme m_theme; + QFont m_font; + QDataVis::SelectionMode m_selectionMode; + QDataVis::ShadowQuality m_shadowQuality; + QDataVis::LabelStyle m_labelStyle; + bool m_isBackgroundEnabled; + bool m_isGridEnabled; + QString m_objFile; + + Q3DScene *m_scene; + +protected: + QList<QAbstract3DInputHandler *> m_inputHandlers; // List of all added input handlers + QAbstract3DInputHandler *m_activeInputHandler; + CameraHelper *m_cameraHelper; + // Active axes + Q3DAbstractAxis *m_axisX; + Q3DAbstractAxis *m_axisY; + Q3DAbstractAxis *m_axisZ; + + QList<Q3DAbstractAxis *> m_axes; // List of all added axes + Abstract3DRenderer *m_renderer; + bool m_isDataDirty; + + QAbstractDataProxy *m_data; + QList<QAbstractDataProxy *> m_dataProxies; + + bool m_renderPending; + + explicit Abstract3DController(QRect boundRect, QObject *parent = 0); + virtual ~Abstract3DController(); + +public: + + inline bool isInitialized() { return (m_renderer != 0); } + + /** + * @brief synchDataToRenderer Called on the render thread while main GUI thread is blocked before rendering. + */ + virtual void synchDataToRenderer(); + + virtual void render(const GLuint defaultFboHandle = 0); + + /** + * @brief setRenderer Sets the renderer to be used. isInitialized returns true from this point onwards. + * @param renderer Renderer to be used. + */ + void setRenderer(Abstract3DRenderer *renderer); + + // Size + virtual void setSize(const int width, const int height); + virtual const QSize size(); + virtual const QRect boundingRect(); + virtual void setBoundingRect(const QRect boundingRect); + virtual void setWidth(const int width); + virtual int width(); + virtual void setHeight(const int height); + virtual int height(); + virtual void setX(const int x); + virtual int x(); + virtual void setY(const int y); + virtual int y(); + + virtual QRect primarySubViewport() const; + virtual void setPrimarySubViewport(const QRect &primarySubViewport); + + virtual QRect secondarySubViewport() const; + virtual void setSecondarySubViewport(const QRect &secondarySubViewport); + + virtual void setAxisX(Q3DAbstractAxis *axis); + virtual Q3DAbstractAxis *axisX(); + virtual void setAxisY(Q3DAbstractAxis *axis); + virtual Q3DAbstractAxis *axisY(); + virtual void setAxisZ(Q3DAbstractAxis *axis); + virtual Q3DAbstractAxis *axisZ(); + virtual void addAxis(Q3DAbstractAxis *axis); + virtual void releaseAxis(Q3DAbstractAxis *axis); + virtual QList<Q3DAbstractAxis *> axes() const; // Omits default axes + + virtual void addInputHandler(QAbstract3DInputHandler *inputHandler); + virtual void releaseInputHandler(QAbstract3DInputHandler *inputHandler); + virtual void setActiveInputHandler(QAbstract3DInputHandler *inputHandler); + virtual QAbstract3DInputHandler *activeInputHandler(); + + virtual QAbstractDataProxy *activeDataProxy() const; + virtual void addDataProxy(QAbstractDataProxy *proxy); + virtual void releaseDataProxy(QAbstractDataProxy *proxy); + virtual QList<QAbstractDataProxy *> dataProxies() const; + virtual void setActiveDataProxy(QAbstractDataProxy *proxy); + virtual void updateDevicePixelRatio(qreal ratio); + + virtual int zoomLevel(); + virtual void setZoomLevel(int zoomLevel); + + // Set color if you don't want to use themes. + virtual void setObjectColor(const QColor &baseColor, bool uniform = true); + virtual QColor objectColor() const; + + // Set theme (bar colors, shaders, window color, background colors, light intensity and text + // colors are affected) + virtual void setTheme(QDataVis::Theme theme); + virtual Theme theme(); + + // Set font + virtual void setFont(const QFont &font); + virtual QFont font(); + + // Selection mode + virtual void setSelectionMode(QDataVis::SelectionMode mode); + virtual QDataVis::SelectionMode selectionMode(); + + // Adjust shadow quality + virtual void setShadowQuality(QDataVis::ShadowQuality quality); + virtual QDataVis::ShadowQuality shadowQuality(); + + // Label style adjustment + virtual void setLabelStyle(QDataVis::LabelStyle style); + virtual QDataVis::LabelStyle labelStyle(); + + // Enable or disable background mesh + virtual void setBackgroundEnabled(bool enable); + virtual bool backgroundEnabled(); + + // Enable or disable background grid + virtual void setGridEnabled(bool enable); + virtual bool gridEnabled(); + + // Query input state and position + QDataVis::InputState inputState(); + QPoint inputPosition(); + + // Enable or disable slicing mode + bool isSlicingActive(); + void setSlicingActive(bool isSlicing); + + + // override bar type with own mesh + virtual void setMeshFileName(const QString &fileName); + virtual QString meshFileName(); + + Q3DScene *scene(); + + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void touchEvent(QTouchEvent *event); + virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos); + virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos); + virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos); + virtual void wheelEvent(QWheelEvent *event); + + virtual void handleAxisTitleChangedBySender(QObject *sender); + virtual void handleAxisLabelsChangedBySender(QObject *sender); + virtual void handleAxisRangeChangedBySender(QObject *sender); + virtual void handleAxisSegmentCountChangedBySender(QObject *sender); + virtual void handleAxisSubSegmentCountChangedBySender(QObject *sender); + virtual void handleAxisAutoAdjustRangeChangedInOrientation( + Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) = 0; + virtual void handleAxisLabelFormatChangedBySender(QObject *sender); + +public slots: + void handleAxisTitleChanged(const QString &title); + void handleAxisLabelsChanged(); + void handleAxisRangeChanged(qreal min, qreal max); + void handleAxisSegmentCountChanged(int count); + void handleAxisSubSegmentCountChanged(int count); + void handleAxisAutoAdjustRangeChanged(bool autoAdjust); + void handleAxisLabelFormatChanged(const QString &format); + +signals: + void shadowQualityChanged(QDataVis::ShadowQuality quality); + void activeInputHandlerChanged(QAbstract3DInputHandler *inputHandler); + void needRender(); + +protected: + virtual Q3DAbstractAxis *createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation); + Q3DValueAxis *createDefaultValueAxis(); + Q3DCategoryAxis *createDefaultCategoryAxis(); + void emitNeedRender(); + +private: + void setAxisHelper(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis *axis, + Q3DAbstractAxis **axisPtr); +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // CONTROLLER3DBASE_H diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp new file mode 100644 index 00000000..eef810df --- /dev/null +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "abstract3drenderer_p.h" +#include "q3dvalueaxis.h" +#include "texturehelper_p.h" +#include "utils_p.h" +#include "q3dscene_p.h" +#include "q3dcamera_p.h" +#include "q3dlight_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) + : QObject(0), + m_controller(controller), + m_hasNegativeValues(false), + m_cachedTheme(), + m_cachedFont(QFont(QStringLiteral("Arial"))), + m_cachedLabelStyle(QDataVis::LabelStyleFromTheme), + m_drawer(new Drawer(m_cachedTheme, m_cachedFont, m_cachedLabelStyle)), + m_cachedBoundingRect(QRect(0,0,0,0)), + m_cachedShadowQuality(QDataVis::ShadowQualityMedium), + m_autoScaleAdjustment(1.0f), + m_cachedSelectionMode(QDataVis::SelectionModeNone), + m_cachedIsGridEnabled(false), + m_cachedIsBackgroundEnabled(false), + m_cachedScene(new Q3DScene()) + #ifdef DISPLAY_RENDER_SPEED + , m_isFirstFrame(true), + m_numFrames(0) + #endif + +{ + QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Abstract3DRenderer::updateTextures); + QObject::connect(this, &Abstract3DRenderer::needRender, m_controller, + &Abstract3DController::needRender, Qt::QueuedConnection); +} + +Abstract3DRenderer::~Abstract3DRenderer() +{ + delete m_drawer; + delete m_textureHelper; + delete m_cachedScene; +} + +void Abstract3DRenderer::initializeOpenGL() +{ + // Set OpenGL features + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + +#if !defined(QT_OPENGL_ES_2) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); +#endif + + m_textureHelper = new TextureHelper(); + m_drawer->initializeOpenGL(); + + axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationX).setDrawer(m_drawer); + axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationY).setDrawer(m_drawer); + axisCacheForOrientation(Q3DAbstractAxis::AxisOrientationZ).setDrawer(m_drawer); +} + +void Abstract3DRenderer::render(const GLuint defaultFboHandle) +{ +#ifdef DISPLAY_RENDER_SPEED + // For speed computation + if (m_isFirstFrame) { + m_lastFrameTime.start(); + m_isFirstFrame = false; + } + + // Measure speed (as milliseconds per frame) + m_numFrames++; + if (m_lastFrameTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago + qDebug() << qreal(m_lastFrameTime.elapsed()) / qreal(m_numFrames) << "ms/frame (=" << qreal(m_numFrames) << "fps)"; + m_numFrames = 0; + m_lastFrameTime.restart(); + } +#endif + + if (defaultFboHandle) { + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glDisable(GL_BLEND); // For QtQuick2 blending is enabled by default, but we don't want it to be + } + + glViewport(m_cachedScene->viewport().x(), + m_cachedScene->viewport().y(), + m_cachedScene->viewport().width(), + m_cachedScene->viewport().height()); + + QVector3D clearColor = Utils::vectorFromColor(m_cachedTheme.m_windowColor); + glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +QString Abstract3DRenderer::generateValueLabel(const QString &format, qreal value) +{ + QString valueLabelFormat = format; + Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat); + QByteArray valueFormatArray = valueLabelFormat.toUtf8(); + return Utils::formatLabel(valueFormatArray, valueParamType, value); +} + +void Abstract3DRenderer::updateDataModel(QAbstractDataProxy *dataProxy) +{ + m_cachedItemLabelFormat = dataProxy->itemLabelFormat(); +} + +QString Abstract3DRenderer::itemLabelFormat() const +{ + return m_cachedItemLabelFormat; +} + +void Abstract3DRenderer::updateBoundingRect(const QRect &boundingRect) +{ + m_cachedBoundingRect = boundingRect; + handleResize(); +} + +void Abstract3DRenderer::updatePosition(const QRect &boundingRect) +{ + m_cachedBoundingRect = boundingRect; +} + +void Abstract3DRenderer::updateTheme(Theme theme) +{ + m_cachedTheme.setFromTheme(theme); + + m_drawer->setTheme(m_cachedTheme); + // Re-initialize shaders + handleShadowQualityChange(); +} + +void Abstract3DRenderer::updateScene(Q3DScene *scene) +{ + // Synchronize the controller scene to that of the renderer, and vice versa. + // Controller scene had priority if both have changed same values. + scene->d_ptr->sync(*m_cachedScene->d_ptr); + m_cachedScene->d_ptr->sync(*scene->d_ptr); +} + +void Abstract3DRenderer::handleShadowQualityChange() +{ +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + if (!m_cachedTheme.m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + } + initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadowNoTex")); + } else { + if (!m_cachedTheme.m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragmentColorOnY")); + } else { + initShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); + } + initBackgroundShaders(QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); + } +#else + if (!m_cachedTheme.m_uniformColor) { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentColorOnYES2")); + } else { + initShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentES2")); + } + initBackgroundShaders(QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentES2")); +#endif +} + +void Abstract3DRenderer::updateFont(const QFont &font) +{ + m_cachedFont = font; + m_drawer->setFont(font); +} + +void Abstract3DRenderer::updateLabelStyle(QDataVis::LabelStyle style) +{ + m_cachedLabelStyle = style; + m_drawer->setStyle(style); +} + +void Abstract3DRenderer::updateMeshFileName(const QString &objFileName) +{ + if (objFileName != m_cachedObjFile) { + m_cachedObjFile = objFileName; + loadMeshFile(); + } +} + +void Abstract3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) +{ + m_cachedSelectionMode = mode; +} + +void Abstract3DRenderer::updateGridEnabled(bool enable) +{ + m_cachedIsGridEnabled = enable; +} + +void Abstract3DRenderer::updateBackgroundEnabled(bool enable) +{ + m_cachedIsBackgroundEnabled = enable; +} + +void Abstract3DRenderer::handleResize() +{ + if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0) + return; + // Calculate zoom level based on aspect ratio + GLfloat div; + GLfloat zoomAdjustment; + div = qMin(m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + zoomAdjustment = defaultRatio * ((m_cachedBoundingRect.width() / div) + / (m_cachedBoundingRect.height() / div)); + m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f + + // Re-init selection buffer + initSelectionBuffer(); + +#if !defined(QT_OPENGL_ES_2) + // Re-init depth buffer + updateDepthBuffer(); +#endif +} + +void Abstract3DRenderer::updateAxisType(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis::AxisType type) +{ + axisCacheForOrientation(orientation).setType(type); +} + +void Abstract3DRenderer::updateAxisTitle(Q3DAbstractAxis::AxisOrientation orientation, const QString &title) +{ + axisCacheForOrientation(orientation).setTitle(title); +} + +void Abstract3DRenderer::updateAxisLabels(Q3DAbstractAxis::AxisOrientation orientation, const QStringList &labels) +{ + axisCacheForOrientation(orientation).setLabels(labels); +} + +void Abstract3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max) +{ + AxisRenderCache &cache = axisCacheForOrientation(orientation); + cache.setMin(min); + cache.setMax(max); +} + +void Abstract3DRenderer::updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count) +{ + axisCacheForOrientation(orientation).setSegmentCount(count); +} + +void Abstract3DRenderer::updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count) +{ + axisCacheForOrientation(orientation).setSubSegmentCount(count); +} + +void Abstract3DRenderer::updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientation orientation, const QString &format) +{ + axisCacheForOrientation(orientation).setLabelFormat(format); +} + +AxisRenderCache &Abstract3DRenderer::axisCacheForOrientation(Q3DAbstractAxis::AxisOrientation orientation) +{ + switch (orientation) { + case Q3DAbstractAxis::AxisOrientationX: + return m_axisCacheX; + case Q3DAbstractAxis::AxisOrientationY: + return m_axisCacheY; + case Q3DAbstractAxis::AxisOrientationZ: + return m_axisCacheZ; + default: + qFatal("Abstract3DRenderer::axisCacheForOrientation"); + return m_axisCacheX; + } +} + + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h new file mode 100644 index 00000000..1c61ac07 --- /dev/null +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef ABSTRACT3DRENDERER_P_H +#define ABSTRACT3DRENDERER_P_H + +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QFont> +#include <QTime> + +#include "datavisualizationglobal_p.h" +#include "abstract3dcontroller_p.h" +#include "axisrendercache_p.h" +#include "qabstractdataproxy.h" + +//#define DISPLAY_RENDER_SPEED + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class TextureHelper; +class Theme; +class Drawer; + +class Abstract3DRenderer : public QObject, protected QOpenGLFunctions +{ + Q_OBJECT + +private: + Abstract3DController *m_controller; + +protected: + bool m_hasNegativeValues; + Theme m_cachedTheme; + QFont m_cachedFont; + QDataVis::LabelStyle m_cachedLabelStyle; + Drawer *m_drawer; + QRect m_cachedBoundingRect; + QDataVis::ShadowQuality m_cachedShadowQuality; + GLfloat m_autoScaleAdjustment; + + QString m_cachedItemLabelFormat; + QString m_cachedObjFile; + QDataVis::SelectionMode m_cachedSelectionMode; + bool m_cachedIsGridEnabled; + bool m_cachedIsBackgroundEnabled; + + AxisRenderCache m_axisCacheX; + AxisRenderCache m_axisCacheY; + AxisRenderCache m_axisCacheZ; + TextureHelper *m_textureHelper; + Q3DBox m_boundingBox; + + Q3DScene *m_cachedScene; + +#ifdef DISPLAY_RENDER_SPEED + bool m_isFirstFrame; + QTime m_lastFrameTime; + GLint m_numFrames; +#endif + + QString generateValueLabel(const QString &format, qreal value); + +public: + virtual ~Abstract3DRenderer(); + + void updateDataModel(QAbstractDataProxy *dataProxy); + + virtual void render(GLuint defaultFboHandle); + + virtual void updateBoundingRect(const QRect &boundingRect); + virtual void updatePosition(const QRect &boundingRect); + + virtual void updateTheme(Theme theme); + virtual void updateFont(const QFont &font); + virtual void updateLabelStyle(QDataVis::LabelStyle style); + virtual void updateSelectionMode(QDataVis::SelectionMode newMode); + virtual void updateGridEnabled(bool enable); + virtual void updateBackgroundEnabled(bool enable); + virtual void updateMeshFileName(const QString &objFileName); + virtual void updateScene(Q3DScene *scene); + virtual QString itemLabelFormat() const; + virtual void updateTextures() = 0; + virtual void initSelectionBuffer() = 0; + +#if !defined(QT_OPENGL_ES_2) + virtual void updateDepthBuffer() = 0; +#endif + virtual void updateShadowQuality(QDataVis::ShadowQuality quality) = 0; + virtual void initShaders(const QString &vertexShader, const QString &fragmentShader) = 0; + virtual void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader) = 0; + virtual void updateAxisType(Q3DAbstractAxis::AxisOrientation orientation, Q3DAbstractAxis::AxisType type); + virtual void updateAxisTitle(Q3DAbstractAxis::AxisOrientation orientation, const QString &title); + virtual void updateAxisLabels(Q3DAbstractAxis::AxisOrientation orientation, const QStringList &labels); + virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max); + virtual void updateAxisSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count); + virtual void updateAxisSubSegmentCount(Q3DAbstractAxis::AxisOrientation orientation, int count); + virtual void updateAxisLabelFormat(Q3DAbstractAxis::AxisOrientation orientation, const QString &format); + +signals: + void needRender(); // Emit this if something in renderer causes need for another render pass. + +protected: + Abstract3DRenderer(Abstract3DController *controller); + + virtual void initializeOpenGL(); + + virtual void handleShadowQualityChange(); + virtual void handleResize(); + virtual void loadMeshFile() = 0; + + AxisRenderCache &axisCacheForOrientation(Q3DAbstractAxis::AxisOrientation orientation); +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // ABSTRACT3DRENDERER_P_H diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp new file mode 100644 index 00000000..55ac0765 --- /dev/null +++ b/src/datavisualization/engine/axisrendercache.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "axisrendercache_p.h" +#include "qmath.h" +#include <QFontMetrics> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +AxisRenderCache::AxisRenderCache() + : m_type(Q3DAbstractAxis::AxisTypeNone), + m_min(0.0), + m_max(10.0), + m_segmentCount(5), + m_subSegmentCount(1), + m_font(QFont(QStringLiteral("Arial"))), + m_drawer(0), + m_segmentStep(10.0f), + m_subSegmentStep(10.0f) +{ +} + +AxisRenderCache::~AxisRenderCache() +{ + foreach (LabelItem *label, m_labelItems) + delete label; +} + +void AxisRenderCache::setDrawer(Drawer *drawer) +{ + m_drawer = drawer; + m_font = m_drawer->font(); + if (m_drawer) { + QObject::connect(m_drawer, &Drawer::drawerChanged, this, &AxisRenderCache::updateTextures); + updateTextures(); + } +} + +void AxisRenderCache::setType(Q3DAbstractAxis::AxisType type) +{ + m_type = type; + + // If type is set, it means completely new axis instance, so clear all old data + m_labels.clear(); + m_title.clear(); + m_min = 0.0; + m_max = 10.0; + m_segmentCount = 5; + m_subSegmentCount = 1; + m_labelFormat.clear(); + + m_titleItem.clear(); + foreach (LabelItem *label, m_labelItems) + delete label; + m_labelItems.clear(); + m_segmentStep = 10.0f; + m_subSegmentStep = 10.0f; +} + +void AxisRenderCache::setTitle(const QString &title) +{ + if (m_title != title) { + m_title = title; + // Generate axis label texture + if (m_drawer) + m_drawer->generateLabelItem(m_titleItem, title); + } +} + +void AxisRenderCache::setLabels(const QStringList &labels) +{ + if (m_labels != labels) { + int newSize(labels.size()); + int oldSize(m_labels.size()); + + for (int i = newSize; i < oldSize; i++) + delete m_labelItems.takeLast(); + + m_labelItems.reserve(newSize); + + int widest = maxLabelWidth(labels); + + for (int i = 0; i < newSize; i++) { + if (i >= oldSize) + m_labelItems.append(new LabelItem); + if (m_drawer) { + if (labels.at(i).isEmpty()) + m_labelItems[i]->clear(); + else if (i >= oldSize || labels.at(i) != m_labels.at(i)) + m_drawer->generateLabelItem(*m_labelItems[i], labels.at(i), widest); + } + } + m_labels = labels; + } +} + +void AxisRenderCache::setMin(qreal min) +{ + m_min = min; + updateSegmentStep(); +} + +void AxisRenderCache::setMax(qreal max) +{ + m_max = max; + updateSegmentStep(); +} + +void AxisRenderCache::setSegmentCount(int count) +{ + m_segmentCount = count; + updateSegmentStep(); +} + +void AxisRenderCache::setSubSegmentCount(int count) +{ + m_subSegmentCount = count; + updateSubSegmentStep(); +} + +void AxisRenderCache::updateTextures() +{ + m_font = m_drawer->font(); + + if (m_title.isEmpty()) + m_titleItem.clear(); + else + m_drawer->generateLabelItem(m_titleItem, m_title); + + int widest = maxLabelWidth(m_labels); + + for (int i = 0; i < m_labels.size(); i++) { + if (m_labels.at(i).isEmpty()) + m_labelItems[i]->clear(); + else + m_drawer->generateLabelItem(*m_labelItems[i], m_labels.at(i), widest); + } +} + +void AxisRenderCache::updateSegmentStep() +{ + if (m_segmentCount > 0) + m_segmentStep = qFabs((m_max - m_min) / m_segmentCount); + else + m_segmentStep = 0.0f; // Irrelevant + updateSubSegmentStep(); +} + +void AxisRenderCache::updateSubSegmentStep() +{ + if (m_subSegmentCount > 1) + m_subSegmentStep = m_segmentStep / m_subSegmentCount; + else + m_subSegmentStep = m_segmentStep; +} + +int AxisRenderCache::maxLabelWidth(const QStringList &labels) const +{ + int labelWidth = 0; + QFont labelFont = m_font; + labelFont.setPointSize(textureFontSize); + QFontMetrics labelFM(labelFont); + for (int i = 0; i < labels.size(); i++) { + int newWidth = labelFM.width(labels.at(i)); + if (labelWidth < newWidth) + labelWidth = newWidth; + } + return labelWidth; +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h new file mode 100644 index 00000000..0bb1cf92 --- /dev/null +++ b/src/datavisualization/engine/axisrendercache_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef AXISRENDERCACHE_P_H +#define AXISRENDERCACHE_P_H + +#include "datavisualizationglobal_p.h" +#include "labelitem_p.h" +#include "q3dabstractaxis_p.h" +#include "drawer_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class AxisRenderCache : public QObject +{ + Q_OBJECT +public: + AxisRenderCache(); + virtual ~AxisRenderCache(); + + void setDrawer(Drawer *drawer); + + void setType(Q3DAbstractAxis::AxisType type); + inline Q3DAbstractAxis::AxisType type() const { return m_type; } + void setTitle(const QString &title); + inline const QString &title() { return m_title; } + void setLabels(const QStringList &labels); + inline const QStringList &labels() { return m_labels; } + void setMin(qreal min); + inline qreal min() { return m_min; } + void setMax(qreal max); + inline qreal max() { return m_max; } + void setSegmentCount(int count); + inline int segmentCount() const { return m_segmentCount; } + void setSubSegmentCount(int count); + inline int subSegmentCount() const { return m_subSegmentCount; } + inline void setLabelFormat(const QString &format) { m_labelFormat = format; } + inline const QString &labelFormat() { return m_labelFormat; } + + inline LabelItem &titleItem() { return m_titleItem; } + inline QList<LabelItem *> &labelItems() { return m_labelItems; } + inline GLfloat segmentStep() const { return m_segmentStep; } + inline GLfloat subSegmentStep() const { return m_subSegmentStep; } + +public slots: + void updateTextures(); + +private: + void updateSegmentStep(); + void updateSubSegmentStep(); + int maxLabelWidth(const QStringList &labels) const; + + // Cached axis values + Q3DAbstractAxis::AxisType m_type; + QString m_title; + QStringList m_labels; + qreal m_min; + qreal m_max; + int m_segmentCount; + int m_subSegmentCount; + QString m_labelFormat; + QFont m_font; + + // Renderer items + Drawer *m_drawer; // Not owned + LabelItem m_titleItem; + QList<LabelItem *> m_labelItems; + GLfloat m_segmentStep; + GLfloat m_subSegmentStep; + + Q_DISABLE_COPY(AxisRenderCache) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp new file mode 100644 index 00000000..50d8d030 --- /dev/null +++ b/src/datavisualization/engine/bars3dcontroller.cpp @@ -0,0 +1,428 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "bars3dcontroller_p.h" +#include "bars3drenderer_p.h" +#include "camerahelper_p.h" +#include "q3dabstractaxis_p.h" +#include "q3dvalueaxis_p.h" +#include "q3dcategoryaxis_p.h" +#include "qbardataproxy_p.h" + +#include <QMatrix4x4> +#include <qmath.h> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Bars3DController::Bars3DController(QRect boundRect) + : Abstract3DController(boundRect), + m_selectedBarPos(noSelectionPoint()), + m_isBarSpecRelative(true), + m_barThicknessRatio(1.0f), + m_barSpacing(QSizeF(1.0, 1.0)), + m_renderer(0) +{ + // Default bar type; specific to bars + setBarType(QDataVis::MeshStyleBevelBars, false); + + setActiveDataProxy(0); + + // Setting a null axis creates a new default axis according to orientation and graph type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); +} + +Bars3DController::~Bars3DController() +{ +} + +void Bars3DController::initializeOpenGL() +{ + // Initialization is called multiple times when Qt Quick components are used + if (isInitialized()) + return; + + m_renderer = new Bars3DRenderer(this); + + setRenderer(m_renderer); + synchDataToRenderer(); + + QObject::connect(m_renderer, &Bars3DRenderer::selectedBarPosChanged, this, + &Bars3DController::handleSelectedBarPosChanged, Qt::QueuedConnection); + emitNeedRender(); +} + +void Bars3DController::synchDataToRenderer() +{ + Abstract3DController::synchDataToRenderer(); + + if (!isInitialized()) + return; + + // Notify changes to renderer + if (m_changeTracker.barSpecsChanged) { + m_renderer->updateBarSpecs(m_barThicknessRatio, m_barSpacing, m_isBarSpecRelative); + m_changeTracker.barSpecsChanged = false; + } + + if (m_changeTracker.selectedBarPosChanged) { + m_renderer->updateSelectedBarPos(m_selectedBarPos); + m_changeTracker.selectedBarPosChanged = false; + } + + if (m_isDataDirty) { + m_renderer->updateDataModel(static_cast<QBarDataProxy *>(m_data)); + m_isDataDirty = false; + } +} + +void Bars3DController::setActiveDataProxy(QAbstractDataProxy *proxy) +{ + // Setting null proxy indicates default proxy + if (!proxy) { + proxy = new QBarDataProxy; + proxy->d_ptr->setDefaultProxy(true); + } + + Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeBar); + + Abstract3DController::setActiveDataProxy(proxy); + + QBarDataProxy *barDataProxy = static_cast<QBarDataProxy *>(m_data); + + QObject::connect(barDataProxy, &QBarDataProxy::arrayReset, this, + &Bars3DController::handleArrayReset); + QObject::connect(barDataProxy, &QBarDataProxy::rowsAdded, this, + &Bars3DController::handleRowsAdded); + QObject::connect(barDataProxy, &QBarDataProxy::rowsChanged, this, + &Bars3DController::handleRowsChanged); + QObject::connect(barDataProxy, &QBarDataProxy::rowsRemoved, this, + &Bars3DController::handleRowsRemoved); + QObject::connect(barDataProxy, &QBarDataProxy::rowsInserted, this, + &Bars3DController::handleRowsInserted); + QObject::connect(barDataProxy, &QBarDataProxy::itemChanged, this, + &Bars3DController::handleItemChanged); + QObject::connect(barDataProxy, &QBarDataProxy::rowLabelsChanged, this, + &Bars3DController::handleDataRowLabelsChanged); + QObject::connect(barDataProxy, &QBarDataProxy::columnLabelsChanged, this, + &Bars3DController::handleDataColumnLabelsChanged); + + scene()->setSlicingActive(false); + adjustAxisRanges(); + + // Always clear selection on proxy change + setSelectedBarPos(noSelectionPoint()); + + handleDataRowLabelsChanged(); + handleDataColumnLabelsChanged(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Bars3DController::handleArrayReset() +{ + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + // Clear selection unless still valid + setSelectedBarPos(m_selectedBarPos); + emitNeedRender(); +} + +void Bars3DController::handleRowsAdded(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should update slice instead of deactivating? + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Bars3DController::handleRowsChanged(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should update slice instead of deactivating? + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Bars3DController::handleRowsRemoved(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should update slice instead of deactivating? + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + + // Clear selection unless still valid + setSelectedBarPos(m_selectedBarPos); + + emitNeedRender(); +} + +void Bars3DController::handleRowsInserted(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should update slice instead of deactivating? + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Bars3DController::handleItemChanged(int rowIndex, int columnIndex) +{ + Q_UNUSED(rowIndex) + Q_UNUSED(columnIndex) + // TODO should update slice instead of deactivating? + scene()->setSlicingActive(false); + adjustAxisRanges(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Bars3DController::handleDataRowLabelsChanged() +{ + if (m_axisX && m_data) { + // Grab a sublist equal to data window (no need to have more labels in axis) + int min = int(m_axisX->min()); + int count = int(m_axisX->max()) - min + 1; + QStringList subList = static_cast<QBarDataProxy *>(m_data)->rowLabels().mid(min, count); + static_cast<Q3DCategoryAxis *>(m_axisX)->dptr()->setDataLabels(subList); + } +} + +void Bars3DController::handleDataColumnLabelsChanged() +{ + if (m_axisZ && m_data) { + // Grab a sublist equal to data window (no need to have more labels in axis) + int min = int(m_axisZ->min()); + int count = int(m_axisZ->max()) - min + 1; + QStringList subList = static_cast<QBarDataProxy *>(m_data)->columnLabels().mid(min, count); + static_cast<Q3DCategoryAxis *>(m_axisZ)->dptr()->setDataLabels(subList); + } +} + +void Bars3DController::handleSelectedBarPosChanged(const QPoint &position) +{ + QPoint pos = position; + if (pos == QPoint(255, 255)) + pos = noSelectionPoint(); + if (pos != m_selectedBarPos) { + m_selectedBarPos = pos; + emit selectedBarPosChanged(pos); + emitNeedRender(); + } +} + +void Bars3DController::handleAxisAutoAdjustRangeChangedInOrientation( + Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) +{ + Q_UNUSED(orientation) + Q_UNUSED(autoAdjust) + adjustAxisRanges(); +} + +QPoint Bars3DController::noSelectionPoint() +{ + static QPoint noSelectionPos(-1, -1); + return noSelectionPos; +} + +void Bars3DController::setAxisX(Q3DAbstractAxis *axis) +{ + Abstract3DController::setAxisX(axis); + handleDataRowLabelsChanged(); +} + +void Bars3DController::setAxisZ(Q3DAbstractAxis *axis) +{ + Abstract3DController::setAxisZ(axis); + handleDataColumnLabelsChanged(); +} + +void Bars3DController::handleAxisRangeChangedBySender(QObject *sender) +{ + // Data window changed + if (sender == m_axisX || sender == m_axisZ) { + // Disable zoom mode if we're in it (causes crash if not, as zoom selection is deleted) + scene()->setSlicingActive(false); + + // Clear selection unless still valid + setSelectedBarPos(m_selectedBarPos); + + if (sender == m_axisX) + handleDataRowLabelsChanged(); + if (sender == m_axisZ) + handleDataColumnLabelsChanged(); + } + + Abstract3DController::handleAxisRangeChangedBySender(sender); +} + +void Bars3DController::setBarSpecs(GLfloat thicknessRatio, const QSizeF &spacing, bool relative) +{ + m_barThicknessRatio = thicknessRatio; + m_barSpacing = spacing; + m_isBarSpecRelative = relative; + + m_changeTracker.barSpecsChanged = true; + emitNeedRender(); +} + +GLfloat Bars3DController::barThickness() +{ + return m_barThicknessRatio; +} + +QSizeF Bars3DController::barSpacing() +{ + return m_barSpacing; +} + +bool Bars3DController::isBarSpecRelative() +{ + return m_isBarSpecRelative; +} + +void Bars3DController::setBarType(QDataVis::MeshStyle style, bool smooth) +{ + QString objFile; + if (style == QDataVis::MeshStyleBars) + objFile = QStringLiteral(":/defaultMeshes/bar"); + else if (style == QDataVis::MeshStylePyramids) + objFile = QStringLiteral(":/defaultMeshes/pyramid"); + else if (style == QDataVis::MeshStyleCones) + objFile = QStringLiteral(":/defaultMeshes/cone"); + else if (style == QDataVis::MeshStyleCylinders) + objFile = QStringLiteral(":/defaultMeshes/cylinder"); + else if (style == QDataVis::MeshStyleBevelBars) + objFile = QStringLiteral(":/defaultMeshes/bevelbar"); + + if (smooth) + objFile += QStringLiteral("Smooth"); + + Abstract3DController::setMeshFileName(objFile); +} + +void Bars3DController::setSelectionMode(QDataVis::SelectionMode mode) +{ + // Disable zoom if selection mode changes + scene()->setSlicingActive(false); + Abstract3DController::setSelectionMode(mode); +} + +void Bars3DController::setSelectedBarPos(const QPoint &position) +{ + // If the selection is outside data window or targets non-existent + // bar, clear selection instead. + QPoint pos = position; + + if (pos != noSelectionPoint()) { + int minRow = int(m_axisX->min()); + int maxRow = int(m_axisX->max()); + int minCol = int(m_axisZ->min()); + int maxCol = int(m_axisZ->max()); + + if (pos.x() < minRow || pos.x() > maxRow || pos.y() < minCol || pos.y() > maxCol + || pos.x() + minRow >= static_cast<QBarDataProxy *>(m_data)->rowCount() + || pos.y() + minCol >= static_cast<QBarDataProxy *>(m_data)->rowAt(pos.x())->size()) { + pos = noSelectionPoint(); + } + } + + if (pos != m_selectedBarPos) { + m_selectedBarPos = pos; + m_changeTracker.selectedBarPosChanged = true; + emit selectedBarPosChanged(pos); + emitNeedRender(); + } +} + +QPoint Bars3DController::selectedBarPos() const +{ + return m_selectedBarPos; +} + +void Bars3DController::adjustAxisRanges() +{ + const QBarDataProxy *proxy = static_cast<QBarDataProxy *>(m_data); + const QBarDataArray *array = proxy->array(); + + Q3DCategoryAxis *categoryAxisX = static_cast<Q3DCategoryAxis *>(m_axisX); + if (categoryAxisX && categoryAxisX->isAutoAdjustRange() && proxy) { + int rowCount = proxy->rowCount(); + if (rowCount) + rowCount--; + categoryAxisX->dptr()->setRange(0.0, qreal(rowCount)); + } + + Q3DCategoryAxis *categoryAxisZ = static_cast<Q3DCategoryAxis *>(m_axisZ); + if (categoryAxisZ && categoryAxisZ->isAutoAdjustRange() && proxy) { + int columnCount = 0; + for (int i = 0; i < array->size(); i++) { + if (columnCount < array->at(i)->size()) + columnCount = array->at(i)->size(); + } + if (columnCount) + columnCount--; + categoryAxisZ->dptr()->setRange(0.0, qreal(columnCount)); + } + + Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisY); + if (valueAxis && categoryAxisX && categoryAxisZ && valueAxis->isAutoAdjustRange() && proxy) { + QPair<GLfloat, GLfloat> limits = proxy->dptrc()->limitValues(categoryAxisX->min(), + categoryAxisX->max(), + categoryAxisZ->min(), + categoryAxisZ->max()); + if (limits.first < 0) { + // TODO: Currently we only support symmetric y-axis for bar graph if there are negative values + qreal maxAbs = qMax(qFabs(limits.first), qFabs(limits.second)); + // Call private implementation to avoid unsetting auto adjust flag + valueAxis->dptr()->setRange(-maxAbs, maxAbs); + } else if (limits.second == 0.0) { + valueAxis->dptr()->setRange(0.0, 1.0); // Only zero value values in data set, set range to something. + } else { + valueAxis->dptr()->setRange(0.0, limits.second); + } + } +} + +Q3DAbstractAxis *Bars3DController::createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation) +{ + Q3DAbstractAxis *defaultAxis = 0; + + if (orientation == Q3DAbstractAxis::AxisOrientationY) + defaultAxis = createDefaultValueAxis(); + else + defaultAxis = createDefaultCategoryAxis(); + + return defaultAxis; +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/bars3dcontroller_p.h b/src/datavisualization/engine/bars3dcontroller_p.h new file mode 100644 index 00000000..8398dd81 --- /dev/null +++ b/src/datavisualization/engine/bars3dcontroller_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DBARSCONTROLLER_p_H +#define Q3DBARSCONTROLLER_p_H + +#include "datavisualizationglobal_p.h" +#include "abstract3dcontroller_p.h" + +//#define DISPLAY_RENDER_SPEED + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Bars3DRenderer; +class QBarDataProxy; + +struct Bars3DChangeBitField { + bool slicingActiveChanged : 1; + bool barSpecsChanged : 1; + bool selectedBarPosChanged : 1; + + Bars3DChangeBitField() : + slicingActiveChanged(true), + barSpecsChanged(true), + selectedBarPosChanged(true) + { + } +}; + +class QT_DATAVISUALIZATION_EXPORT Bars3DController : public Abstract3DController +{ + Q_OBJECT + +private: + Bars3DChangeBitField m_changeTracker; + + // Interaction + QPoint m_selectedBarPos; // Points to row & column in data window. + + // Look'n'feel + bool m_isBarSpecRelative; + GLfloat m_barThicknessRatio; + QSizeF m_barSpacing; + + // Rendering + Bars3DRenderer *m_renderer; + +public: + explicit Bars3DController(QRect rect); + ~Bars3DController(); + + void initializeOpenGL(); + virtual void synchDataToRenderer(); + + // bar thickness, spacing between bars, and is spacing relative to thickness or absolute + // y -component sets the thickness/spacing of z -direction + // With relative 0.0f means side-to-side, 1.0f = one thickness in between + void setBarSpecs(GLfloat thicknessRatio = 1.0f, + const QSizeF &spacing = QSizeF(1.0, 1.0), + bool relative = true); + GLfloat barThickness(); + QSizeF barSpacing(); + bool isBarSpecRelative(); + + // bar type; bars (=cubes), pyramids, cones, cylinders, etc. + void setBarType(QDataVis::MeshStyle style, bool smooth = false); + + // Change selection mode; single bar, bar and row, bar and column, or all + void setSelectionMode(QDataVis::SelectionMode mode); + + void setSelectedBarPos(const QPoint &position); + QPoint selectedBarPos() const; + + virtual void setActiveDataProxy(QAbstractDataProxy *proxy); + + virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); + + static QPoint noSelectionPoint(); + + virtual void setAxisX(Q3DAbstractAxis *axis); + virtual void setAxisZ(Q3DAbstractAxis *axis); + + virtual void handleAxisRangeChangedBySender(QObject *sender); + +public slots: + void handleArrayReset(); + void handleRowsAdded(int startIndex, int count); + void handleRowsChanged(int startIndex, int count); + void handleRowsRemoved(int startIndex, int count); + void handleRowsInserted(int startIndex, int count); + void handleItemChanged(int rowIndex, int columnIndex); + void handleDataRowLabelsChanged(); + void handleDataColumnLabelsChanged(); + + void handleSelectedBarPosChanged(const QPoint &position); + +signals: + void selectedBarPosChanged(QPoint position); + +protected: + virtual Q3DAbstractAxis *createDefaultAxis(Q3DAbstractAxis::AxisOrientation orientation); + +private: + void adjustAxisRanges(); + + Q_DISABLE_COPY(Bars3DController) + +}; + + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp new file mode 100644 index 00000000..74c1a99b --- /dev/null +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -0,0 +1,1880 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "bars3drenderer_p.h" +#include "bars3dcontroller_p.h" +#include "q3dcamera_p.h" +#include "shaderhelper_p.h" +#include "objecthelper_p.h" +#include "texturehelper_p.h" +#include "theme_p.h" +#include "utils_p.h" +#include "drawer_p.h" +#include "qbardataitem.h" +#include "q3dlight.h" + +#include <QMatrix4x4> +#include <QMouseEvent> +#include <QThread> +#include <qmath.h> +#include <QDebug> + +// You can verify that depth buffer drawing works correctly by uncommenting this. +// You should see the scene from where the light is +//#define SHOW_DEPTH_TEXTURE_SCENE + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +const GLfloat labelMargin = 0.05f; +const GLfloat gridLineWidth = 0.005f; +static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color + +Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) + : Abstract3DRenderer(controller), + m_controller(controller), + m_cachedIsSlicingActivated(false), + m_cachedRowCount(0), + m_cachedColumnCount(0), + m_selectedBar(0), + m_sliceSelection(0), + m_sliceCache(0), + m_sliceTitleItem(0), + m_xFlipped(false), + m_zFlipped(false), + m_yFlipped(false), + m_updateLabels(false), + m_barShader(0), + m_depthShader(0), + m_selectionShader(0), + m_backgroundShader(0), + m_labelShader(0), + m_barObj(0), + m_backgroundObj(0), + m_gridLineObj(0), + m_labelObj(0), + m_bgrTexture(0), + m_depthTexture(0), + m_selectionTexture(0), + m_depthFrameBuffer(0), + m_selectionFrameBuffer(0), + m_selectionDepthBuffer(0), + m_shadowQualityToShader(100.0f), + m_shadowQualityMultiplier(3), + m_heightNormalizer(1.0f), + m_yAdjustment(0.0f), + m_rowWidth(0), + m_columnDepth(0), + m_maxDimension(0), + m_scaleX(0), + m_scaleZ(0), + m_scaleFactor(0), + m_maxSceneSize(40.0), + m_selection(selectionSkipColor), + m_previousSelection(selectionSkipColor), + m_hasHeightAdjustmentChanged(true) +{ + initializeOpenGLFunctions(); + initializeOpenGL(); +} + +Bars3DRenderer::~Bars3DRenderer() +{ + m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); + m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); + m_textureHelper->deleteTexture(&m_selectionTexture); + m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); + m_textureHelper->deleteTexture(&m_bgrTexture); + if (m_sliceSelection) { + m_sliceSelection->clear(); // Slice doesn't own its items + delete m_sliceSelection; + } + delete m_barShader; + delete m_depthShader; + delete m_selectionShader; + delete m_backgroundShader; + delete m_barObj; + delete m_backgroundObj; + delete m_gridLineObj; + delete m_labelObj; + delete m_labelShader; +} + +void Bars3DRenderer::initializeOpenGL() +{ + Abstract3DRenderer::initializeOpenGL(); + + // Initialize shaders + handleShadowQualityChange(); + + initLabelShaders(QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + +#if !defined(QT_OPENGL_ES_2) + // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api. + initDepthShader(); +#endif + + // Init selection shader + initSelectionShader(); + + // Load grid line mesh + loadGridLineMesh(); + + // Load label mesh + loadLabelMesh(); + + // Set view port + glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(), + m_sliceViewPort.width(), m_sliceViewPort.height()); + + // Load background mesh (we need to be initialized first) + loadBackgroundMesh(); +} + +void Bars3DRenderer::updateDataModel(QBarDataProxy *dataProxy) +{ + int minRow = m_axisCacheX.min(); + int maxRow = m_axisCacheX.max(); + int minCol = m_axisCacheZ.min(); + int maxCol = m_axisCacheZ.max(); + int newRows = maxRow - minRow + 1; + int newColumns = maxCol - minCol + 1; + if (newRows != m_renderItemArray.size() || newColumns != m_renderItemArray.at(0).size()) { + // Destroy old render items and reallocate new array + m_renderItemArray.clear(); + m_renderItemArray.resize(newRows); + for (int i = 0; i < newRows; i++) + m_renderItemArray[i].resize(newColumns); + + // Force update for selection related items + m_sliceCache = 0; + m_sliceTitleItem = 0; + if (m_sliceSelection) + m_sliceSelection->clear(); + + m_cachedColumnCount = newColumns; + m_cachedRowCount = newRows; + // TODO: Invent foolproof max scene size formula + // This seems to work ok if spacing is not negative (and row/column or column/row ratio is not too high) + m_maxSceneSize = 2 * qSqrt(newColumns * newRows); + // Calculate here and at setting bar specs + calculateSceneScalingFactors(); + } + + // Update cached data window + int dataRowCount = dataProxy->rowCount(); + int dataRowIndex = minRow; + for (int i = 0; i < newRows; i++) { + int j = 0; + if (dataRowIndex < dataRowCount) { + const QBarDataRow *dataRow = dataProxy->rowAt(dataRowIndex); + int updateSize = qMin((dataRow->size() - minCol), m_renderItemArray[i].size()); + if (dataRow) { + int dataColIndex = minCol; + for (; j < updateSize ; j++) { + qreal value = dataRow->at(dataColIndex).value(); + m_renderItemArray[i][j].setValue(value); + m_renderItemArray[i][j].setHeight(GLfloat(value) / m_heightNormalizer); + dataColIndex++; + } + } + } + for (; j < m_renderItemArray[i].size(); j++) { + m_renderItemArray[i][j].setValue(0.0); + m_renderItemArray[i][j].setHeight(0.0f); + } + dataRowIndex++; + } + + Abstract3DRenderer::updateDataModel(dataProxy); +} + +void Bars3DRenderer::updateScene(Q3DScene *scene) +{ + // TODO: Move these to more suitable place e.g. controller should be controlling the viewports. + scene->setSecondarySubViewport(m_sliceViewPort); + scene->setPrimarySubViewport(m_mainViewPort); + + // TODO: See QTRD-2374 + if (m_hasNegativeValues) + scene->activeCamera()->setMinYRotation(-90.0); + else + scene->activeCamera()->setMinYRotation(0.0); + + if (m_hasHeightAdjustmentChanged) { + // Set initial camera position. Also update if height adjustment has changed. + scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp), + QVector3D(0.0f, -m_yAdjustment, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + m_hasHeightAdjustmentChanged = false; + } + + scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment); + // Set light position (rotate light with camera, a bit above it (as set in defaultLightPos)) + scene->setLightPositionRelativeToCamera(defaultLightPos); + + Abstract3DRenderer::updateScene(scene); + + updateSlicingActive(scene->isSlicingActive()); +} + +void Bars3DRenderer::render(GLuint defaultFboHandle) +{ + bool slicingChanged = m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive(); + + // Handle GL state setup for FBO buffers and clearing of the render surface + Abstract3DRenderer::render(defaultFboHandle); + + // If slice selection is on, draw the sliced scene + if (m_cachedIsSlicingActivated) + drawSlicedScene(m_axisCacheX.titleItem(), m_axisCacheY.titleItem(), m_axisCacheZ.titleItem()); + + // Draw bars scene + drawScene(defaultFboHandle); + + // If slicing has been activated by this render pass, we need another render + // Also trigger another render always when slicing changes in general to ensure + // final draw is correct. + if (m_cachedIsSlicingActivated != m_cachedScene->isSlicingActive() || slicingChanged) + emit needRender(); +} + +void Bars3DRenderer::drawSlicedScene(const LabelItem &xLabel, + const LabelItem &yLabel, + const LabelItem &zLabel) +{ + GLfloat barPosX = 0; + GLint startBar = 0; + GLint stopBar = m_sliceSelection->size(); + GLint stepBar = 1; + QVector3D lightPos; + GLfloat negativesComp = 1.0f; + + // Compensate bar scaling a bit to avoid drawing on axis titles when we have negative values + if (m_hasNegativeValues) + negativesComp = 0.67f; + + // Specify viewport + glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(), + m_sliceViewPort.width(), m_sliceViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_sliceViewPort.width() + / (GLfloat)m_sliceViewPort.height(), 0.1f, 100.0f); + + // Set view matrix + QMatrix4x4 viewMatrix; + + // Adjust scaling (zoom rate based on aspect ratio) + GLfloat camZPosSliced = 5.0f / m_autoScaleAdjustment + zComp; + + viewMatrix.lookAt(QVector3D(0.0f, 0.0f, camZPosSliced), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // Set light position + lightPos = QVector3D(0.0f, -m_yAdjustment, zComp); + + // Bind bar shader + m_barShader->bind(); + + // Draw bars + // Draw the selected row / column + for (int bar = startBar; bar != stopBar; bar += stepBar) { + BarRenderItem *item = m_sliceSelection->at(bar); + if (!item) + continue; + + if (item->height() < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + GLfloat barPosY = negativesComp * item->translation().y() - m_yAdjustment / 2.0f + 0.2f; // we need some room for labels underneath; add +0.2f + if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + barPosX = item->translation().x(); + else + barPosX = -(item->translation().z() - zComp); // flip z; frontmost bar to the left + modelMatrix.translate(barPosX, barPosY, zComp); + modelMatrix.scale(QVector3D(m_scaleX, negativesComp * item->height(), m_scaleZ)); + itModelMatrix.scale(QVector3D(m_scaleX, negativesComp * item->height(), m_scaleZ)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + +#if 0 + QVector3D baseColor; + if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y()) + baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); + else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor); + else + baseColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor); + + QVector3D heightColor = Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item->height(); + QVector3D barColor = baseColor + heightColor; +#else + QVector3D barColor; + if (m_selection.x() == item->position().x() && m_selection.y() == item->position().y()) + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); + else if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor); + else + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor); +#endif + + if (item->height() != 0) { + // Set shader bindings + m_barShader->setUniformValue(m_barShader->lightP(), lightPos); + m_barShader->setUniformValue(m_barShader->view(), viewMatrix); + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.inverted().transposed()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + m_barShader->setUniformValue(m_barShader->color(), barColor); + m_barShader->setUniformValue(m_barShader->lightS(), 0.5f); + m_barShader->setUniformValue(m_barShader->ambientS(), + m_cachedTheme.m_ambientStrength * 2.0f); + // Draw the object +#if defined (Q_OS_MAC) + // Mac slice issue hack fix. TODO: Fix correctly + m_drawer->drawObject(m_barShader, m_barObj, 0, -1); +#else + m_drawer->drawObject(m_barShader, m_barObj); +#endif + } + } + + // Release bar shader + m_barShader->release(); + + // Draw labels + m_labelShader->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + glCullFace(GL_BACK); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Draw labels for axes + BarRenderItem *dummyItem(0); + const LabelItem &sliceSelectionLabel = *m_sliceTitleItem; + if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) { + if (m_sliceTitleItem) { + m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelTop); + } + m_drawer->drawLabel(*dummyItem, zLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelBottom); + } else { + m_drawer->drawLabel(*dummyItem, xLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelBottom); + if (m_sliceTitleItem) { + m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelTop); + } + } + m_drawer->drawLabel(*dummyItem, yLabel, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, 90.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, Drawer::LabelLeft); + + // Draw labels for bars + for (int col = 0; col < m_sliceSelection->size(); col++) { + BarRenderItem *item = m_sliceSelection->at(col); + // Draw values + if (negativesComp == 1.0f) { + m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 90.0f), + item->height(), + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, + Drawer::LabelOver, Qt::AlignTop); + } else { + m_drawer->drawLabel(*item, item->sliceLabelItem(), viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), + negativesComp * negativesComp * item->height(), + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera()); + } + + // Draw labels + if (m_sliceCache->labelItems().size() > col) { + const LabelItem *labelItem(0); + labelItem = m_sliceCache->labelItems().at(col); + m_drawer->drawLabel(*item, *labelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_autoScaleAdjustment, zComp), + QVector3D(0.0f, 0.0f, -45.0f), item->height(), + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), false, false, + Drawer::LabelBelow); + } + } + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + + // Release label shader + m_labelShader->release(); +} + +void Bars3DRenderer::drawScene(GLuint defaultFboHandle) +{ + GLint startBar = 0; + GLint stopBar = 0; + GLint stepBar = 0; + + GLint startRow = 0; + GLint stopRow = 0; + GLint stepRow = 0; + + GLfloat backgroundRotation = 0; + + GLfloat colPos = 0; + GLfloat rowPos = 0; + + // Specify viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f); + + // Get the view matrix + QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix(); + + // Calculate drawing order + // Draw order is reversed to optimize amount of drawing (ie. draw front objects first, depth test handles not needing to draw objects behind them) + if (viewMatrix.row(0).x() > 0) { + startRow = 0; + stopRow = m_cachedRowCount; + stepRow = 1; + m_zFlipped = false; + } else { + startRow = m_cachedRowCount - 1; + stopRow = -1; + stepRow = -1; + m_zFlipped = true; + } + if (viewMatrix.row(0).z() <= 0) { + startBar = 0; + stopBar = m_cachedColumnCount; + stepBar = 1; + m_xFlipped = false; + } else { + startBar = m_cachedColumnCount - 1; + stopBar = -1; + stepBar = -1; + m_xFlipped = true; + } + + // Check if we're viewing the scene from below + if (viewMatrix.row(2).y() < 0) + m_yFlipped = true; + else + m_yFlipped = false; + + // calculate background rotation based on view matrix rotation + if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() <= 0) + backgroundRotation = 270.0f; + else if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() > 0) + backgroundRotation = 180.0f; + else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() > 0) + backgroundRotation = 90.0f; + else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() <= 0) + backgroundRotation = 0.0f; + + // Get light position from the scene + QVector3D lightPos = m_cachedScene->activeLight()->position(); + + // Skip depth rendering if we're in slice mode + // Introduce regardless of shadow quality to simplify logic + QMatrix4x4 depthViewMatrix; + QMatrix4x4 depthProjectionMatrix; + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone && !m_cachedIsSlicingActivated) { + // Render scene into a depth texture for using with shadow mapping + // Enable drawing to depth framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer); + glClear(GL_DEPTH_BUFFER_BIT); + + // Bind depth shader + m_depthShader->bind(); + + // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows. + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width() * m_shadowQualityMultiplier, + m_mainViewPort.height() * m_shadowQualityMultiplier); + + // Get the depth view matrix + // It may be possible to hack lightPos here if we want to make some tweaks to shadow + QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera( + QVector3D(0.0f, 0.0f, zComp), 0.0f, 1.5f / m_autoScaleAdjustment); + depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, -m_yAdjustment, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? + // That causes the scene to be not drawn from above -> must be fixed + // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3); + + // Set the depth projection matrix + depthProjectionMatrix.perspective(10.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f); + + // Draw bars to depth buffer + for (int row = startRow; row != stopRow; row += stepRow) { + for (int bar = startBar; bar != stopBar; bar += stepBar) { + const BarRenderItem &item = m_renderItemArray.at(row).at(bar); + if (!item.value()) + continue; + + GLfloat shadowOffset = 0.0f; + + // Set front face culling for negative valued bars and back face culling for + // positive valued bars to remove peter-panning issues + if (item.height() > 0) { + glCullFace(GL_BACK); + if (m_yFlipped) + shadowOffset = 0.015f; + } else { + glCullFace(GL_FRONT); + if (!m_yFlipped) + shadowOffset = -0.015f; + } + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + colPos = (bar + 0.5f) * (m_cachedBarSpacing.width()); + rowPos = (row + 0.5f) * (m_cachedBarSpacing.height()); + + // Draw shadows for bars "on the other side" a bit off ground to avoid seeing + // shadows through the ground + modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor, + item.height() - m_yAdjustment + shadowOffset, + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + // Scale the bars down in X and Z to reduce self-shadowing issues + modelMatrix.scale(QVector3D(m_scaleX * 0.9f, item.height(), m_scaleZ * 0.9f)); + + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_depthShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, m_barObj->vertexBuf()); + glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, + (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_barObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, m_barObj->indexCount(), GL_UNSIGNED_SHORT, + (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_depthShader->posAtt()); + } + } + + // Disable drawing to depth framebuffer (= enable drawing to screen) + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Release depth shader + m_depthShader->release(); + +#if 0 // Use this if you want to see what is being drawn to the framebuffer + // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it) + m_labelShader->bind(); + glCullFace(GL_BACK); + glEnable(GL_TEXTURE_2D); + QMatrix4x4 modelMatrix; + QMatrix4x4 viewmatrix; + viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + modelMatrix.translate(0.0, 0.0, zComp); + QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + m_drawer->drawObject(m_labelShader, m_labelObj, + m_depthTexture); + glDisable(GL_TEXTURE_2D); + m_labelShader->release(); +#endif + // Reset culling to normal + glCullFace(GL_BACK); + + // Revert to original viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + } +#endif + + // Skip selection mode drawing if we're slicing or have no selection mode + if (!m_cachedIsSlicingActivated && m_cachedSelectionMode > QDataVis::SelectionModeNone) { + // Bind selection shader + m_selectionShader->bind(); + + // Draw bars to selection buffer + glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); + glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used + glClearColor(selectionSkipColor.x() / 255, selectionSkipColor.y() / 255, + selectionSkipColor.z() / 255, 1.0f); // Set clear color to white (= selectionSkipColor) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer + glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled + for (int row = startRow; row != stopRow; row += stepRow) { + for (int bar = startBar; bar != stopBar; bar += stepBar) { + const BarRenderItem &item = m_renderItemArray.at(row).at(bar); + if (!item.value()) + continue; + + if (item.height() < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + colPos = (bar + 0.5f) * (m_cachedBarSpacing.width()); + rowPos = (row + 0.5f) * (m_cachedBarSpacing.height()); + + modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor, + item.height() - m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + modelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + + // TODO: Save position to qdataitem, so that we don't need to calculate it each time? + + //#if !defined(QT_OPENGL_ES_2) + // QVector3D barColor = QVector3D((GLdouble)row / 32767.0, + // (GLdouble)bar / 32767.0, + // 0.0); + //#else + QVector3D barColor = QVector3D((GLdouble)row / 255.0, + (GLdouble)bar / 255.0, + 0.0); + //#endif + + m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); + m_selectionShader->setUniformValue(m_selectionShader->color(), barColor); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_selectionShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, m_barObj->vertexBuf()); + glVertexAttribPointer(m_selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, + (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_barObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, m_barObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_selectionShader->posAtt()); + } + } + glEnable(GL_DITHER); + + // Read color under cursor + if (QDataVis::InputStateOnScene == m_controller->inputState()) { + m_selection = Utils::getSelection(m_controller->inputPosition(), + m_cachedBoundingRect.height()); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Release selection shader + m_selectionShader->release(); + +#if 0 // Use this if you want to see what is being drawn to the framebuffer + glCullFace(GL_BACK); + m_labelShader->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + QMatrix4x4 modelMatrix; + QMatrix4x4 viewmatrix; + viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + modelMatrix.translate(0.0, 0.0, zComp); + QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + m_drawer->drawObject(m_labelShader, m_labelObj, m_selectionTexture); + glDisable(GL_TEXTURE_2D); + m_labelShader->release(); +#endif + } + + // Enable texturing + glEnable(GL_TEXTURE_2D); + + // Bind bar shader + m_barShader->bind(); + + bool selectionDirty = (m_selection != m_previousSelection + || (m_selection != selectionSkipColor + && QDataVis::InputStateOnScene == m_controller->inputState() + && !m_cachedIsSlicingActivated)); + if (selectionDirty) { + m_previousSelection = m_selection; + if (m_sliceSelection) { + if (!m_cachedIsSlicingActivated) { + m_sliceCache = 0; + m_sliceTitleItem = 0; + } + if (m_sliceSelection->size()) { + // Slice doesn't own its items, no need to delete them - just clear + m_sliceSelection->clear(); + } + } + } + + // Draw bars + bool barSelectionFound = false; + BarRenderItem *selectedBar(0); + for (int row = startRow; row != stopRow; row += stepRow) { + for (int bar = startBar; bar != stopBar; bar += stepBar) { + BarRenderItem &item = m_renderItemArray[row][bar]; + + if (item.height() < 0) + glCullFace(GL_FRONT); + else + glCullFace(GL_BACK); + + QMatrix4x4 modelMatrix; + QMatrix4x4 itModelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + + colPos = (bar + 0.5f) * (m_cachedBarSpacing.width()); + rowPos = (row + 0.5f) * (m_cachedBarSpacing.height()); + + modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor, + item.height() - m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + modelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ)); + itModelMatrix.scale(QVector3D(m_scaleX, item.height(), m_scaleZ)); +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; +#else + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + +#if 0 + QVector3D baseColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor); + QVector3D heightColor = Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item.height(); + QVector3D depthColor = Utils::vectorFromColor(m_cachedTheme.m_depthColor) + * (float(row) / GLfloat(m_cachedRowCount)); + + QVector3D barColor = baseColor + heightColor + depthColor; +#else + QVector3D barColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor); +#endif + + GLfloat lightStrength = m_cachedTheme.m_lightStrength; + + if (m_cachedSelectionMode > QDataVis::SelectionModeNone) { + Bars3DController::SelectionType selectionType = isSelected(row, bar); + + switch (selectionType) { + case Bars3DController::SelectionItem: { + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); + lightStrength = m_cachedTheme.m_highlightLightStrength; + // Insert position data into render item. We have no ownership, don't delete the previous one + if (!m_cachedIsSlicingActivated) { + selectedBar = &item; + selectedBar->setPosition(QPoint(row, bar)); + item.setTranslation(modelMatrix.column(3).toVector3D()); + barSelectionFound = true; + } + if (selectionDirty && m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow) { + item.setTranslation(modelMatrix.column(3).toVector3D()); + item.setPosition(QPoint(row, bar)); + m_sliceSelection->append(&item); + barSelectionFound = true; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + if (m_axisCacheX.labelItems().size() > row) + m_sliceTitleItem = m_axisCacheX.labelItems().at(row); + if (!m_sliceCache) { + // m_sliceCache is the axis for labels, while title comes from different axis. + m_sliceCache = &m_axisCacheZ; + } + } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { + if (m_axisCacheZ.labelItems().size() > bar) + m_sliceTitleItem = m_axisCacheZ.labelItems().at(bar); + if (!m_sliceCache) { + // m_sliceCache is the axis for labels, while title comes from different axis. + m_sliceCache = &m_axisCacheX; + } + } + } + break; + } + case Bars3DController::SelectionRow: { + // Current bar is on the same row as the selected bar + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor); + lightStrength = m_cachedTheme.m_highlightLightStrength; + if (QDataVis::SelectionModeSliceRow == m_cachedSelectionMode) { + item.setTranslation(modelMatrix.column(3).toVector3D()); + item.setPosition(QPoint(row, bar)); + if (selectionDirty) + m_sliceSelection->append(&item); + } + break; + } + case Bars3DController::SelectionColumn: { + // Current bar is on the same column as the selected bar + barColor = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor); + lightStrength = m_cachedTheme.m_highlightLightStrength; + if (QDataVis::SelectionModeSliceColumn == m_cachedSelectionMode) { + item.setTranslation(modelMatrix.column(3).toVector3D()); + item.setPosition(QPoint(row, bar)); + if (selectionDirty) + m_sliceSelection->append(&item); + } + break; + } + case Bars3DController::SelectionNone: { + // Current bar is not selected, nor on a row or column + // do nothing + break; + } + } + } + + // Skip drawing of 0 -height bars + if (item.height() != 0) { + // Set shader bindings + m_barShader->setUniformValue(m_barShader->lightP(), lightPos); + m_barShader->setUniformValue(m_barShader->view(), viewMatrix); + m_barShader->setUniformValue(m_barShader->model(), modelMatrix); + m_barShader->setUniformValue(m_barShader->nModel(), + itModelMatrix.transposed().inverted()); + m_barShader->setUniformValue(m_barShader->MVP(), MVPMatrix); + m_barShader->setUniformValue(m_barShader->color(), barColor); + m_barShader->setUniformValue(m_barShader->ambientS(), m_cachedTheme.m_ambientStrength); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone + && !m_cachedIsSlicingActivated) { + // Set shadow shader bindings + m_barShader->setUniformValue(m_barShader->shadowQ(), m_shadowQualityToShader); + m_barShader->setUniformValue(m_barShader->depth(), depthMVPMatrix); + m_barShader->setUniformValue(m_barShader->lightS(), lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_barShader, m_barObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_barShader->setUniformValue(m_barShader->lightS(), lightStrength); + + // Draw the object +#if defined (Q_OS_MAC) + // Mac slice issue hack fix. TODO: Fix correctly + m_drawer->drawObject(m_barShader, m_barObj, 0, -1); +#else + m_drawer->drawObject(m_barShader, m_barObj); +#endif + } + } + } + } + + if (selectionDirty) + emit selectedBarPosChanged(QPoint(int(m_selection.x()), int(m_selection.y()))); + + // Release bar shader + m_barShader->release(); + + // Bind background shader + m_backgroundShader->bind(); + + if (m_hasNegativeValues) + glDisable(GL_CULL_FACE); + else + glCullFace(GL_BACK); + + // Draw background + if (m_cachedIsBackgroundEnabled && m_backgroundObj) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, 1.0f - m_yAdjustment, zComp); + modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, + 1.0f, + m_columnDepth / m_scaleFactor)); + modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); + itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, + 1.0f, + m_columnDepth / m_scaleFactor)); + +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; +#else + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor); + + // Set shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos); + m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->nModel(), + itModelMatrix.inverted().transposed()); + m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor); + m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(), + m_cachedTheme.m_ambientStrength * 2.0f); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(), + m_shadowQualityToShader); + m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj); + } + } + + // Release background shader + m_backgroundShader->release(); + + // Disable textures + glDisable(GL_TEXTURE_2D); + + // Reset culling + if (m_hasNegativeValues) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + // Draw grid lines + if (m_cachedIsGridEnabled && m_heightNormalizer) { + ShaderHelper *lineShader = m_backgroundShader; + // Bind bar shader + lineShader->bind(); + + // Set unchanging shader bindings + QVector3D barColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine); + lineShader->setUniformValue(lineShader->lightP(), lightPos); + lineShader->setUniformValue(lineShader->view(), viewMatrix); + lineShader->setUniformValue(lineShader->color(), barColor); + lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength); + + // Floor lines: rows + for (GLfloat row = 0.0f; row <= m_cachedRowCount; row++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + rowPos = row * m_cachedBarSpacing.height(); + modelMatrix.translate(0.0f, -m_yAdjustment, + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth, + gridLineWidth)); + itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth, + gridLineWidth)); + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } + + // Floor lines: columns + for (GLfloat bar = 0.0f; bar <= m_cachedColumnCount; bar++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + colPos = bar * m_cachedBarSpacing.width(); + modelMatrix.translate((m_rowWidth - colPos) / m_scaleFactor, + -m_yAdjustment, zComp); + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + m_columnDepth / m_scaleFactor)); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + m_columnDepth / m_scaleFactor)); + + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } + + if (m_axisCacheY.segmentCount() > 0) { + // Wall lines: back wall + GLfloat heightStep = m_axisCacheY.subSegmentStep(); + GLfloat startLine = 0.0f; + + if (m_hasNegativeValues) + startLine = -m_heightNormalizer; + + for (GLfloat lineHeight = startLine; lineHeight <= m_heightNormalizer; + lineHeight += heightStep) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_zFlipped) { + modelMatrix.translate(0.0f, + 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment, + m_columnDepth / m_scaleFactor + zComp); + } else { + modelMatrix.translate(0.0f, + 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment, + -m_columnDepth / m_scaleFactor + zComp); + } + modelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth, + gridLineWidth)); + itModelMatrix.scale(QVector3D(m_rowWidth / m_scaleFactor, gridLineWidth, + gridLineWidth)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } + + // Wall lines: side wall + for (GLfloat lineHeight = startLine; lineHeight <= m_heightNormalizer; + lineHeight += heightStep) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_xFlipped) { + modelMatrix.translate(m_rowWidth / m_scaleFactor, + 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment, + zComp); + } else { + modelMatrix.translate(-m_rowWidth / m_scaleFactor, + 2.0f * lineHeight / m_heightNormalizer - m_yAdjustment, + zComp); + } + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + m_columnDepth / m_scaleFactor)); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + m_columnDepth / m_scaleFactor)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + } + } + // Release bar shader + lineShader->release(); + } + + // TODO: Calculations done temporarily here. When optimizing, move to after data set addition? Keep drawing of the labels here. + // Bind label shader + m_labelShader->bind(); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Calculate the positions for row and column labels and store them + for (int row = 0; row != m_cachedRowCount; row++) { + if (m_axisCacheX.labelItems().size() > row) { + // Go through all rows and get position of max+1 or min-1 column, depending on x flip + // We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems + rowPos = (row + 0.5f) * m_cachedBarSpacing.height(); + colPos = (m_rowWidth / m_scaleFactor) + labelMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 0.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + if (m_xFlipped) { + colPos = -(m_rowWidth / m_scaleFactor) - labelMargin; + alignment = Qt::AlignLeft; + } + if (m_yFlipped) { + if (m_zFlipped) + rotLabelY = 0.0f; + else + rotLabelY = 180.0f; + rotLabelZ = 180.0f; + } + QVector3D labelPos = QVector3D(colPos, + -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" + (m_columnDepth - rowPos) / m_scaleFactor + zComp); + + m_dummyBarRenderItem.setTranslation(labelPos); + const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(row); + //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << m_axisCacheX.labels().at(row); + + m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + } + for (int column = 0; column != m_cachedColumnCount; column += 1) { + if (m_axisCacheZ.labelItems().size() > column) { + // Go through all columns and get position of max+1 or min-1 row, depending on z flip + // We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems + colPos = (column + 0.5f) * m_cachedBarSpacing.width(); + rowPos = (m_columnDepth / m_scaleFactor) + labelMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (m_xFlipped) + rotLabelY = -90.0f; + if (m_zFlipped) { + rowPos = -(m_columnDepth / m_scaleFactor) - labelMargin; + alignment = Qt::AlignRight; + } + if (m_yFlipped) { + if (m_xFlipped) + rotLabelY = -90.0f; + else + rotLabelY = 90.0f; + rotLabelZ = 180.0f; + } + QVector3D labelPos = QVector3D((colPos - m_rowWidth) / m_scaleFactor, + -m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering" + rowPos + zComp); + + m_dummyBarRenderItem.setTranslation(labelPos); + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(column); + + m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + } + + // Y Labels + int labelNbr = 0; + GLfloat heightStep = m_axisCacheY.segmentStep(); + GLfloat startLine = 0.0f; + int labelCount = m_axisCacheY.labels().size(); + if (m_hasNegativeValues) + startLine = -m_heightNormalizer; + GLfloat labelPos = startLine; + + for (int i = 0; i < labelCount; i++) { + if (m_axisCacheY.labelItems().size() > labelNbr) { + GLfloat labelMarginXTrans = labelMargin; + GLfloat labelMarginZTrans = labelMargin; + GLfloat labelXTrans = m_rowWidth / m_scaleFactor; + GLfloat labelZTrans = m_columnDepth / m_scaleFactor; + GLfloat labelYTrans = 2.0f * labelPos / m_heightNormalizer - m_yAdjustment; + GLfloat rotLabelX = 0.0f; + GLfloat rotLabelY = -90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (!m_xFlipped) { + labelXTrans = -labelXTrans; + labelMarginXTrans = -labelMargin; + rotLabelY = 90.0f; + } + if (m_zFlipped) { + labelZTrans = -labelZTrans; + labelMarginZTrans = -labelMargin; + alignment = Qt::AlignRight; + } + + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + + // Back wall + QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, + labelZTrans + labelMarginZTrans + zComp); + + //qDebug() << "labelPos, value:" << labelTrans; + + m_dummyBarRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + + // Side wall + if (m_xFlipped) + alignment = Qt::AlignLeft; + else + alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + else + rotLabelY = 0.0f; + + labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelYTrans, + -labelZTrans + zComp); + + m_dummyBarRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + labelNbr++; + labelPos += heightStep; + } + + // Handle slice activation and selection label drawing + if (!barSelectionFound) { + // We have no ownership, don't delete. Just NULL the pointer. + m_selectedBar = NULL; + if (m_cachedIsSlicingActivated + && (m_selection == selectionSkipColor + || QDataVis::InputStateOnOverview == m_controller->inputState())) { + m_cachedScene->setSlicingActive(false); + } + } else if (m_cachedSelectionMode >= QDataVis::SelectionModeSliceRow && selectionDirty) { + // Activate slice mode + m_cachedScene->setSlicingActive(true); + + // Create label textures + for (int col = 0; col < m_sliceSelection->size(); col++) { + BarRenderItem *item = m_sliceSelection->at(col); + if (item->sliceLabel().isNull()) + item->setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(), item->value())); + m_drawer->generateLabelItem(item->sliceLabelItem(), item->sliceLabel()); + } + } else { + // Print value of selected bar + glDisable(GL_DEPTH_TEST); + // Draw the selection label + LabelItem &labelItem = selectedBar->selectionLabelItem(); + if (m_selectedBar != selectedBar || m_updateLabels || !labelItem.textureId()) { + QString labelText = selectedBar->selectionLabel(); + if (labelText.isNull()) { + static const QString rowIndexTag(QStringLiteral("@rowIdx")); + static const QString rowLabelTag(QStringLiteral("@rowLabel")); + static const QString rowTitleTag(QStringLiteral("@rowTitle")); + static const QString colIndexTag(QStringLiteral("@colIdx")); + static const QString colLabelTag(QStringLiteral("@colLabel")); + static const QString colTitleTag(QStringLiteral("@colTitle")); + static const QString valueTitleTag(QStringLiteral("@valueTitle")); + static const QString valueLabelTag(QStringLiteral("@valueLabel")); + + // Custom format expects printf format specifier. There is no tag for it. + labelText = generateValueLabel(itemLabelFormat(), selectedBar->value()); + + int selBarPosX = selectedBar->position().x(); + int selBarPosY = selectedBar->position().y(); + labelText.replace(rowIndexTag, QString::number(selBarPosX)); + if (m_axisCacheX.labels().size() > selBarPosX) + labelText.replace(rowLabelTag, m_axisCacheX.labels().at(selBarPosX)); + else + labelText.replace(rowLabelTag, QString()); + labelText.replace(rowTitleTag, m_axisCacheX.title()); + labelText.replace(colIndexTag, QString::number(selBarPosY)); + if (m_axisCacheZ.labels().size() > selBarPosY) + labelText.replace(colLabelTag, m_axisCacheZ.labels().at(selBarPosY)); + else + labelText.replace(colLabelTag, QString()); + labelText.replace(colTitleTag, m_axisCacheZ.title()); + labelText.replace(valueTitleTag, m_axisCacheY.title()); + + if (labelText.contains(valueLabelTag)) { + QString labelFormat = m_axisCacheY.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, selectedBar->value()); + labelText.replace(valueLabelTag, valueLabelText); + } + + selectedBar->setSelectionLabel(labelText); + } + m_drawer->generateLabelItem(labelItem, labelText); + m_selectedBar = selectedBar; + } + + m_drawer->drawLabel(*selectedBar, labelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, 0.0f), selectedBar->height(), + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), true, false); + + // Reset label update flag; they should have been updated when we get here + m_updateLabels = false; + + glEnable(GL_DEPTH_TEST); + } + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // Release label shader + m_labelShader->release(); +} + +void Bars3DRenderer::handleResize() +{ + if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0) + return; + + // Set view port + if (m_cachedIsSlicingActivated) { + m_mainViewPort = QRect(0, + m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / 5, + m_cachedBoundingRect.width() / 5, + m_cachedBoundingRect.height() / 5); + m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + } else { + m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + m_sliceViewPort = QRect(0, 0, 0, 0); + } + + Abstract3DRenderer::handleResize(); +} + +void Bars3DRenderer::updateBarSpecs(GLfloat thicknessRatio, const QSizeF &spacing, bool relative) +{ + // Convert ratio to QSizeF, as we need it in that format for autoscaling calculations + m_cachedBarThickness.setWidth(1.0f); + m_cachedBarThickness.setHeight(1.0f / thicknessRatio); + + if (relative) { + m_cachedBarSpacing.setWidth((m_cachedBarThickness.width() * 2) * (spacing.width() + 1.0f)); + m_cachedBarSpacing.setHeight((m_cachedBarThickness.height() * 2) * (spacing.height() + 1.0f)); + } else { + m_cachedBarSpacing = m_cachedBarThickness * 2 + spacing * 2; + } + + // Calculate here and at setting sample space + calculateSceneScalingFactors(); +} + +void Bars3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max) +{ + Abstract3DRenderer::updateAxisRange(orientation, min, max); + + if (orientation == Q3DAbstractAxis::AxisOrientationY) { + calculateHeightAdjustment(); + // Check if we have negative values + if (min < 0 && !m_hasNegativeValues) { + m_hasNegativeValues = true; + // Reload background + loadBackgroundMesh(); + emit needRender(); + } else if (min >= 0 && m_hasNegativeValues) { + m_hasNegativeValues = false; + // Reload background + loadBackgroundMesh(); + emit needRender(); + } + + // TODO Currently bargraph only supports zero centered or zero minimum ranges + if (min > 0.0 || (min != 0.0 && (qFabs(min) != qFabs(max)))) { + qWarning() << __FUNCTION__ << "Bar graph currently properly supports only " + "zero-centered and zero minimum ranges for Y-axis."; + } + } +} + +void Bars3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) +{ + Abstract3DRenderer::updateSelectionMode(mode); + + // Create zoom selection if there isn't one + if (mode >= QDataVis::SelectionModeSliceRow && !m_sliceSelection) { + m_sliceSelection = new QList<BarRenderItem *>; + if (mode == QDataVis::SelectionModeSliceRow) + m_sliceSelection->reserve(m_cachedRowCount); + else + m_sliceSelection->reserve(m_cachedColumnCount); + } +} + +void Bars3DRenderer::updateBackgroundEnabled(bool enable) +{ + if (enable != m_cachedIsBackgroundEnabled) { + Abstract3DRenderer::updateBackgroundEnabled(enable); + loadMeshFile(); // Load changed bar type + } +} + +void Bars3DRenderer::updateSelectedBarPos(const QPoint &position) +{ + if (position == Bars3DController::noSelectionPoint()) + m_selection = selectionSkipColor; + else + m_selection = QVector3D(position.x(), position.y(), 0); + emit needRender(); +} + +void Bars3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality) +{ + m_cachedShadowQuality = quality; + switch (quality) { + case QDataVis::ShadowQualityLow: + m_shadowQualityToShader = 33.3f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualityMedium: + m_shadowQualityToShader = 100.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualityHigh: + m_shadowQualityToShader = 200.0f; + m_shadowQualityMultiplier = 5; + break; + case QDataVis::ShadowQualitySoftLow: + m_shadowQualityToShader = 7.5f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualitySoftMedium: + m_shadowQualityToShader = 10.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualitySoftHigh: + m_shadowQualityToShader = 15.0f; + m_shadowQualityMultiplier = 4; + break; + default: + m_shadowQualityToShader = 0.0f; + m_shadowQualityMultiplier = 1; + break; + } + + handleShadowQualityChange(); + +#if !defined(QT_OPENGL_ES_2) + // Re-init depth buffer + updateDepthBuffer(); +#endif +} + +void Bars3DRenderer::loadMeshFile() +{ + QString objectFileName = m_cachedObjFile; + if (m_barObj) + delete m_barObj; + // If background is disabled, load full version of bar mesh + if (!m_cachedIsBackgroundEnabled) + objectFileName.append(QStringLiteral("Full")); + m_barObj = new ObjectHelper(objectFileName); + m_barObj->load(); +} + +void Bars3DRenderer::loadBackgroundMesh() +{ + if (m_backgroundObj) + delete m_backgroundObj; + if (m_hasNegativeValues) + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground")); + else + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); + m_backgroundObj->load(); +} + +void Bars3DRenderer::loadGridLineMesh() +{ + if (m_gridLineObj) + delete m_gridLineObj; + m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar")); + m_gridLineObj->load(); +} + +void Bars3DRenderer::loadLabelMesh() +{ + if (m_labelObj) + delete m_labelObj; + m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); + m_labelObj->load(); +} + +void Bars3DRenderer::updateTextures() +{ + // Drawer has changed; this flag needs to be checked when checking if we need to update labels + m_updateLabels = true; +} + +void Bars3DRenderer::calculateSceneScalingFactors() +{ + // Calculate scene scaling and translation factors + m_rowWidth = (m_cachedColumnCount * m_cachedBarSpacing.width()) / 2.0f; + m_columnDepth = (m_cachedRowCount * m_cachedBarSpacing.height()) / 2.0f; + m_maxDimension = qMax(m_rowWidth, m_columnDepth); + m_scaleFactor = qMin((m_cachedColumnCount * (m_maxDimension / m_maxSceneSize)), + (m_cachedRowCount * (m_maxDimension / m_maxSceneSize))); + m_scaleX = m_cachedBarThickness.width() / m_scaleFactor; + m_scaleZ = m_cachedBarThickness.height() / m_scaleFactor; + //qDebug() << "m_scaleX" << m_scaleX << "m_scaleFactor" << m_scaleFactor; + //qDebug() << "m_scaleZ" << m_scaleZ << "m_scaleFactor" << m_scaleFactor; + //qDebug() << "m_rowWidth:" << m_rowWidth << "m_columnDepth:" << m_columnDepth << "m_maxDimension:" << m_maxDimension; +} + +void Bars3DRenderer::calculateHeightAdjustment() +{ + m_heightNormalizer = (GLfloat)qMax(qFabs(m_axisCacheY.min()), qFabs(m_axisCacheY.max())); + + // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer + GLfloat newAdjustment = 2.0f - ((m_heightNormalizer - m_axisCacheY.min()) / m_heightNormalizer); + if (newAdjustment != m_yAdjustment) { + m_hasHeightAdjustmentChanged = true; + m_yAdjustment = newAdjustment; + } + //qDebug() << m_yAdjustment; +} + +Bars3DController::SelectionType Bars3DRenderer::isSelected(GLint row, GLint bar) +{ + //static QVector3D prevSel = m_selection; // TODO: For debugging + Bars3DController::SelectionType isSelectedType = Bars3DController::SelectionNone; + if (m_selection == selectionSkipColor) + return isSelectedType; // skip window + + //#if !defined(QT_OPENGL_ES_2) + // QVector3D current = QVector3D((GLuint)row, (GLuint)bar, 0); + //#else + QVector3D current = QVector3D((GLubyte)row, (GLubyte)bar, 0); + //#endif + + // TODO: For debugging + //if (selection != prevSel) { + // qDebug() << "current" << current.x() << current .y() << current.z(); + // qDebug() << "selection" << selection.x() << selection .y() << selection.z(); + // prevSel = selection; + //} + if (current == m_selection) { + isSelectedType = Bars3DController::SelectionItem; + } + else if (current.y() == m_selection.y() && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndColumn + || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn + || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn)) { + isSelectedType = Bars3DController::SelectionColumn; + } + else if (current.x() == m_selection.x() && (m_cachedSelectionMode == QDataVis::SelectionModeItemAndRow + || m_cachedSelectionMode == QDataVis::SelectionModeItemRowAndColumn + || m_cachedSelectionMode == QDataVis::SelectionModeSliceRow)) { + isSelectedType = Bars3DController::SelectionRow; + } + return isSelectedType; +} + +void Bars3DRenderer::updateSlicingActive(bool isSlicing) +{ + if (isSlicing == m_cachedIsSlicingActivated) + return; + + m_cachedIsSlicingActivated = isSlicing; + if (isSlicing) { + m_mainViewPort = QRect(0, m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / 5, + m_cachedBoundingRect.width() / 5, m_cachedBoundingRect.height() / 5); + m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + if (m_depthTexture) { + m_textureHelper->deleteTexture(&m_depthTexture); + m_depthTexture = 0; + } + } else { + m_mainViewPort = QRect(0, 0, this->m_cachedBoundingRect.width(), + this->m_cachedBoundingRect.height()); + m_sliceViewPort = QRect(0, 0, 0, 0); + initSelectionBuffer(); // We need to re-init selection buffer in case there has been a resize +#if !defined(QT_OPENGL_ES_2) + updateDepthBuffer(); // Re-init depth buffer as well +#endif + } +} + +QRect Bars3DRenderer::mainViewPort() +{ + return m_mainViewPort; +} + +void Bars3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_barShader) + delete m_barShader; + m_barShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_barShader->initialize(); +} + +void Bars3DRenderer::initSelectionShader() +{ + if (m_selectionShader) + delete m_selectionShader; + m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSelection"), + QStringLiteral(":/shaders/fragmentSelection")); + m_selectionShader->initialize(); +} + +void Bars3DRenderer::initSelectionBuffer() +{ + if (m_cachedIsSlicingActivated) + return; + + if (m_selectionTexture) + m_textureHelper->deleteTexture(&m_selectionTexture); + + m_selectionTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(), + m_selectionFrameBuffer, + m_selectionDepthBuffer); +} + +#if !defined(QT_OPENGL_ES_2) +void Bars3DRenderer::initDepthShader() +{ + if (m_depthShader) + delete m_depthShader; + m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), + QStringLiteral(":/shaders/fragmentDepth")); + m_depthShader->initialize(); +} + +void Bars3DRenderer::updateDepthBuffer() +{ + if (m_cachedIsSlicingActivated) + return; + + if (m_depthTexture) { + m_textureHelper->deleteTexture(&m_depthTexture); + m_depthTexture = 0; + } + + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(), + m_depthFrameBuffer, + m_shadowQualityMultiplier); + if (!m_depthTexture) { + switch (m_cachedShadowQuality) { + case QDataVis::ShadowQualityHigh: + qWarning("Creating high quality shadows failed. Changing to medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium); + updateShadowQuality(QDataVis::ShadowQualityMedium); + break; + case QDataVis::ShadowQualityMedium: + qWarning("Creating medium quality shadows failed. Changing to low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow); + updateShadowQuality(QDataVis::ShadowQualityLow); + break; + case QDataVis::ShadowQualityLow: + qWarning("Creating low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + case QDataVis::ShadowQualitySoftHigh: + qWarning("Creating soft high quality shadows failed. Changing to soft medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium); + updateShadowQuality(QDataVis::ShadowQualitySoftMedium); + break; + case QDataVis::ShadowQualitySoftMedium: + qWarning("Creating soft medium quality shadows failed. Changing to soft low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow); + updateShadowQuality(QDataVis::ShadowQualitySoftLow); + break; + case QDataVis::ShadowQualitySoftLow: + qWarning("Creating soft low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + default: + // You'll never get here + break; + } + } + } +} +#endif + +void Bars3DRenderer::initBackgroundShaders(const QString &vertexShader, + const QString &fragmentShader) +{ + if (m_backgroundShader) + delete m_backgroundShader; + m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_backgroundShader->initialize(); +} + +void Bars3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_labelShader) + delete m_labelShader; + m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_labelShader->initialize(); +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h new file mode 100644 index 00000000..9b612474 --- /dev/null +++ b/src/datavisualization/engine/bars3drenderer_p.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DBARSRENDERER_p_H +#define Q3DBARSRENDERER_p_H + +#include "datavisualizationglobal_p.h" +#include "bars3dcontroller_p.h" +#include "abstract3drenderer_p.h" +#include "qbardataproxy.h" +#include "barrenderitem_p.h" + +class QPoint; +class QSizeF; +class QOpenGLShaderProgram; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class ShaderHelper; +class ObjectHelper; +class LabelItem; +class Q3DScene; + +class QT_DATAVISUALIZATION_EXPORT Bars3DRenderer : public Abstract3DRenderer +{ + Q_OBJECT + +private: + // TODO: Filter to the set of attributes to be moved to the model object. + Bars3DController *m_controller; + + // Cached state based on emitted signals from the controller + QSizeF m_cachedBarThickness; + QSizeF m_cachedBarSpacing; + bool m_cachedIsSlicingActivated; + int m_cachedRowCount; + int m_cachedColumnCount; + + // Internal state + BarRenderItem *m_selectedBar; // points to renderitem array + QList<BarRenderItem *> *m_sliceSelection; + AxisRenderCache *m_sliceCache; // not owned + const LabelItem *m_sliceTitleItem; // not owned + bool m_xFlipped; + bool m_zFlipped; + bool m_yFlipped; + QRect m_mainViewPort; + QRect m_sliceViewPort; + bool m_updateLabels; + ShaderHelper *m_barShader; + ShaderHelper *m_depthShader; + ShaderHelper *m_selectionShader; + ShaderHelper *m_backgroundShader; + ShaderHelper *m_labelShader; + ObjectHelper *m_barObj; + ObjectHelper *m_backgroundObj; + ObjectHelper *m_gridLineObj; + ObjectHelper *m_labelObj; + GLuint m_bgrTexture; + GLuint m_depthTexture; + GLuint m_selectionTexture; + GLuint m_depthFrameBuffer; + GLuint m_selectionFrameBuffer; + GLuint m_selectionDepthBuffer; + GLfloat m_shadowQualityToShader; + GLint m_shadowQualityMultiplier; + GLfloat m_heightNormalizer; + GLfloat m_yAdjustment; + GLfloat m_rowWidth; + GLfloat m_columnDepth; + GLfloat m_maxDimension; + GLfloat m_scaleX; + GLfloat m_scaleZ; + GLfloat m_scaleFactor; + GLfloat m_maxSceneSize; + QVector3D m_selection; + QVector3D m_previousSelection; + + bool m_hasHeightAdjustmentChanged; + BarRenderItem m_dummyBarRenderItem; + + BarRenderItemArray m_renderItemArray; + +public: + explicit Bars3DRenderer(Bars3DController *controller); + ~Bars3DRenderer(); + + void updateDataModel(QBarDataProxy *dataProxy); + void updateScene(Q3DScene *scene); + void render(GLuint defaultFboHandle = 0); + + QRect mainViewPort(); + +protected: + virtual void initializeOpenGL(); + virtual void loadMeshFile(); + +public slots: + void updateBarSpecs(GLfloat thicknessRatio = 1.0f, + const QSizeF &spacing = QSizeF(1.0, 1.0), + bool relative = true); + void updateSelectionMode(QDataVis::SelectionMode newMode); + void updateSlicingActive(bool isSlicing); + void updateBackgroundEnabled(bool enable); + void updateSelectedBarPos(const QPoint &position); + + // Overloaded from abstract renderer + virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max); + +signals: + void selectedBarPosChanged(QPoint position); + +private: + virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); + virtual void updateShadowQuality(QDataVis::ShadowQuality quality); + virtual void updateTextures(); + + void drawSlicedScene(const LabelItem &xLabel, const LabelItem &yLabel, const LabelItem &zLabel); + void drawScene(GLuint defaultFboHandle); + void handleResize(); + + void loadBackgroundMesh(); + void loadGridLineMesh(); + void loadLabelMesh(); + void initSelectionShader(); + void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader); + void initLabelShaders(const QString &vertexShader, const QString &fragmentShader); + void initSelectionBuffer(); +#if !defined(QT_OPENGL_ES_2) + void initDepthShader(); + void updateDepthBuffer(); +#endif + void calculateSceneScalingFactors(); + void calculateHeightAdjustment(); + Abstract3DController::SelectionType isSelected(GLint row, GLint bar); + + Q_DISABLE_COPY(Bars3DRenderer) + + friend class BarRenderItem; +}; + + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/drawer.cpp b/src/datavisualization/engine/drawer.cpp new file mode 100644 index 00000000..9d50186d --- /dev/null +++ b/src/datavisualization/engine/drawer.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "qdatavisualizationenums.h" +#include "drawer_p.h" +#include "shaderhelper_p.h" +#include "objecthelper_p.h" +#include "abstractobjecthelper_p.h" +#include "surfaceobject_p.h" +#include "q3dcamera.h" +#include "utils_p.h" +#include "texturehelper_p.h" +#include <QMatrix4x4> +#include <qmath.h> + +// Resources need to be explicitly initialized when building as static library +class StaticLibInitializer +{ +public: + StaticLibInitializer() + { + Q_INIT_RESOURCE(engine); + } +}; +StaticLibInitializer staticLibInitializer; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Drawer::Drawer(const Theme &theme, const QFont &font, QDataVis::LabelStyle style) + : m_theme(theme), + m_font(font), + m_style(style), + m_textureHelper(0) +{ +} + +Drawer::~Drawer() +{ + delete m_textureHelper; +} + +void Drawer::initializeOpenGL() +{ + if (!m_textureHelper) { + initializeOpenGLFunctions(); + m_textureHelper = new TextureHelper(); + } +} + +void Drawer::setTheme(const Theme &theme) +{ + m_theme = theme; + emit drawerChanged(); +} + +Theme Drawer::theme() const +{ + return m_theme; +} + +void Drawer::setFont(const QFont &font) +{ + m_font = font; + emit drawerChanged(); +} + +QFont Drawer::font() const +{ + return m_font; +} + +void Drawer::setStyle(QDataVis::LabelStyle style) +{ + m_style = style; + emit drawerChanged(); +} + +void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId, + GLuint depthTextureId) +{ + // Store the GL state before changing + GLint oldActiveTex[1]; + glGetIntegerv(GL_ACTIVE_TEXTURE, oldActiveTex); + GLint oldTexId[1]; + glGetIntegerv(GL_TEXTURE_BINDING_2D, oldTexId); + + if (textureId) { + // Activate texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureId); + shader->setUniformValue(shader->texture(), 0); + } + + if (depthTextureId) { + // Activate depth texture + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, depthTextureId); + shader->setUniformValue(shader->shadow(), 1); + } + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(shader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf()); + glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + // 2nd attribute buffer : normals + glEnableVertexAttribArray(shader->normalAtt()); + glBindBuffer(GL_ARRAY_BUFFER, object->normalBuf()); + glVertexAttribPointer(shader->normalAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + if (textureId || depthTextureId) { + // 3rd attribute buffer : UVs + glEnableVertexAttribArray(shader->uvAtt()); + glBindBuffer(GL_ARRAY_BUFFER, object->uvBuf()); + glVertexAttribPointer(shader->uvAtt(), 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + } + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, object->indexCount(), object->indicesType(), (void*)0); + + // Free buffers + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + if (textureId || depthTextureId) + glDisableVertexAttribArray(shader->uvAtt()); + + glDisableVertexAttribArray(shader->normalAtt()); + glDisableVertexAttribArray(shader->posAtt()); + + // Restore the GL state + glActiveTexture(*oldActiveTex); + glBindTexture(GL_TEXTURE_2D, *oldTexId); +} + +void Drawer::drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object) +{ + // Store the GL state before changing + GLint oldActiveTex[1]; + glGetIntegerv(GL_ACTIVE_TEXTURE, oldActiveTex); + GLint oldTexId[1]; + glGetIntegerv(GL_TEXTURE_BINDING_2D, oldTexId); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(shader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf()); + glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gridElementBuf()); + + // Draw the lines + glDrawElements(GL_LINES, object->gridIndexCount(), object->indicesType(), (void*)0); + + // Free buffers + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(shader->posAtt()); + + // Restore the GL state + glActiveTexture(*oldActiveTex); + glBindTexture(GL_TEXTURE_2D, *oldTexId); +} + +void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem, + const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix, + const QVector3D &positionComp, const QVector3D &rotation, + GLfloat itemHeight, QDataVis::SelectionMode mode, + ShaderHelper *shader, ObjectHelper *object, + const Q3DCamera *camera, + bool useDepth, bool rotateAlong, + LabelPosition position, Qt::AlignmentFlag alignment) +{ + // Draw label + if (!labelItem.textureId()) + return; // No texture, skip + + QSize textureSize = labelItem.size(); + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + GLfloat xPosition = 0.0f; + GLfloat yPosition = 0.0f; + GLfloat zPosition = positionComp.z(); + + switch (position) { + case LabelBelow: { + yPosition = -2.6f + positionComp.y(); // minus maximum negative height (+ some extra for axis title label) + break; + } + case LabelLow: { + yPosition = -positionComp.y(); + break; + } + case LabelMid: { + // Use this for positioning with absolute item y position value + yPosition = item.translation().y(); + break; + } + case LabelHigh: { + // TODO: Fix this. Can't seem to get it right (if ok with positive-only bars, doesn't look good on +- and vice versa) + yPosition = item.translation().y() + itemHeight / 2.0f; + break; + } + case LabelOver: { + float mod = 0.3f; + if (itemHeight < 0) + mod = 0.15f; + yPosition = item.translation().y() - (positionComp.y() / 2.0f) + itemHeight + mod; + break; + } + case LabelBottom: { + yPosition = -2.95f + positionComp.y(); + xPosition = 0.0f; + break; + } + case LabelTop: { + yPosition = 2.95f - positionComp.y(); + xPosition = 0.0f; + break; + } + case LabelLeft: { + yPosition = 0.0f; + xPosition = -2.95f; + break; + } + case LabelRight: { + yPosition = 0.0f; + xPosition = 2.95f; + break; + } + } + + // Calculate scale factor to get uniform font size + GLfloat scaledFontSize = 0.05f + m_font.pointSizeF() / 500.0f; + GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height(); + + // Apply alignment + GLfloat xAlignment = 0.0f; + GLfloat yAlignment = 0.0f; + GLfloat zAlignment = 0.0f; + switch (alignment) { + case Qt::AlignLeft: { + xAlignment = (-(GLfloat)textureSize.width() * scaleFactor) + * qFabs(qCos(qDegreesToRadians(rotation.y()))); + zAlignment = ((GLfloat)textureSize.width() * scaleFactor) + * qFabs(qSin(qDegreesToRadians(rotation.y()))); + break; + } + case Qt::AlignRight: { + xAlignment = ((GLfloat)textureSize.width() * scaleFactor) + * qFabs(qCos(qDegreesToRadians(rotation.y()))); + zAlignment = (-(GLfloat)textureSize.width() * scaleFactor) + * qFabs(qSin(qDegreesToRadians(rotation.y()))); + break; + } + case Qt::AlignTop: { + yAlignment = ((GLfloat)textureSize.width() * scaleFactor) + * qFabs(qCos(qDegreesToRadians(rotation.y()))); + if (itemHeight < 0) + yAlignment = -yAlignment; + break; + } + case Qt::AlignBottom: { + yAlignment = (-(GLfloat)textureSize.width() * scaleFactor) + * qFabs(qCos(qDegreesToRadians(rotation.y()))); + if (itemHeight < 0) + yAlignment = -yAlignment; + break; + } + default: { + break; + } + } + + if (position < LabelBottom) { + xPosition = item.translation().x(); + if (useDepth) + zPosition = item.translation().z(); + else if (QDataVis::SelectionModeSliceColumn == mode) + xPosition = -(item.translation().z()) + positionComp.z(); // flip first to left + } + + // Position label + modelMatrix.translate(xPosition + xAlignment, yPosition + yAlignment, zPosition + zAlignment); + + // Rotate + // TODO: We should convert rotations to use quaternions to avoid rotation order problems + //QQuaternion rotQuatX = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, rotation.x()); + //QQuaternion rotQuatY = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, rotation.y()); + //QQuaternion rotQuatZ = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, rotation.z()); + //QQuaternion rotQuaternion = rotQuatX + rotQuatY + rotQuatZ; + //modelMatrix.rotate(rotQuaternion); + modelMatrix.rotate(rotation.y(), 0.0f, 1.0f, 0.0f); + modelMatrix.rotate(rotation.z(), 0.0f, 0.0f, 1.0f); + modelMatrix.rotate(rotation.x(), 1.0f, 0.0f, 0.0f); + + if (useDepth && !rotateAlong) { + qreal yComp = qreal(qRadiansToDegrees(qTan(positionComp.y() / cameraDistance))); + // Apply negative camera rotations to keep labels facing camera + qreal camRotationX = camera->xRotation(); + qreal camRotationY = camera->yRotation(); + modelMatrix.rotate(-camRotationX, 0.0f, 1.0f, 0.0f); + modelMatrix.rotate(-camRotationY - yComp, 1.0f, 0.0f, 0.0f); + } + + // Scale label based on text size + modelMatrix.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor, + scaledFontSize, + 0.0f)); + + MVPMatrix = projectionmatrix * viewmatrix * modelMatrix; + + // Set shader bindings + shader->setUniformValue(shader->MVP(), MVPMatrix); + + // Draw the object + drawObject(shader, object, labelItem.textureId()); +} + +void Drawer::generateSelectionLabelTexture(AbstractRenderItem *item) +{ + LabelItem &labelItem = item->selectionLabelItem(); + generateLabelItem(labelItem, item->selectionLabel()); +} + +void Drawer::generateLabelItem(LabelItem &item, const QString &text, int widestLabel) +{ + initializeOpenGL(); + + item.clear(); + + if (!text.isEmpty()) { + // Create labels + // Print label into a QImage using QPainter + QImage label = Utils::printTextToImage(m_font, + text, + m_theme.m_textBackgroundColor, + m_theme.m_textColor, + m_style, + m_theme.m_labelBorders, + widestLabel); + + // Set label size + item.setSize(label.size()); + // Insert text texture into label (also deletes the old texture) + item.setTextureId(m_textureHelper->create2DTexture(label, true, true)); + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/drawer_p.h b/src/datavisualization/engine/drawer_p.h new file mode 100644 index 00000000..89a4ce8c --- /dev/null +++ b/src/datavisualization/engine/drawer_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef DRAWER_P_H +#define DRAWER_P_H + +#include "datavisualizationglobal_p.h" +#include "q3dbars.h" +#include "theme_p.h" +#include "labelitem_p.h" +#include "abstractrenderitem_p.h" +#include <QFont> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class ShaderHelper; +class ObjectHelper; +class AbstractObjectHelper; +class SurfaceObject; +class TextureHelper; +class Q3DCamera; + +class Drawer : public QObject, public QOpenGLFunctions +{ + Q_OBJECT + +public: + enum LabelPosition { + LabelBelow = 0, + LabelLow, + LabelMid, + LabelHigh, + LabelOver, + LabelBottom, // Absolute positions from here onward, used for axes (QDataItem is ignored) + LabelTop, + LabelLeft, + LabelRight + }; + +public: + explicit Drawer(const Theme &theme, const QFont &font, QDataVis::LabelStyle style); + ~Drawer(); + + void initializeOpenGL(); + + void setTheme(const Theme &theme); + Theme theme() const; + void setFont(const QFont &font); + QFont font() const; + void setStyle(QDataVis::LabelStyle style); + + void drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId = 0, + GLuint depthTextureId = 0); + void drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object); + void drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem, + const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix, + const QVector3D &positionComp, const QVector3D &rotation, GLfloat itemHeight, + QDataVis::SelectionMode mode, ShaderHelper *shader, ObjectHelper *object, + const Q3DCamera *camera, + bool useDepth = false, bool rotateAlong = false, + LabelPosition position = LabelOver, + Qt::AlignmentFlag alignment = Qt::AlignCenter); + + void generateSelectionLabelTexture(AbstractRenderItem *item); + void generateLabelItem(LabelItem &item, const QString &text, int widestLabel = 0); + +Q_SIGNALS: + void drawerChanged(); + +private: + Theme m_theme; + QFont m_font; + QDataVis::LabelStyle m_style; + TextureHelper *m_textureHelper; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/engine.pri b/src/datavisualization/engine/engine.pri new file mode 100644 index 00000000..4c905fe9 --- /dev/null +++ b/src/datavisualization/engine/engine.pri @@ -0,0 +1,53 @@ +HEADERS += $$PWD/q3dwindow_p.h \ + $$PWD/q3dwindow.h \ + $$PWD/q3dbars.h \ + $$PWD/q3dbars_p.h \ + $$PWD/theme_p.h \ + $$PWD/drawer_p.h \ + $$PWD/bars3dcontroller_p.h \ + $$PWD/bars3drenderer_p.h \ + $$PWD/q3dsurface.h \ + $$PWD/q3dsurface_p.h \ + $$PWD/surface3dcontroller_p.h \ + $$PWD/surface3drenderer_p.h \ + $$PWD/abstract3dcontroller_p.h \ + $$PWD/q3dscatter.h \ + $$PWD/q3dscatter_p.h \ + $$PWD/scatter3dcontroller_p.h \ + $$PWD/scatter3drenderer_p.h \ + $$PWD/axisrendercache_p.h \ + $$PWD/abstract3drenderer_p.h \ + $$PWD/selectionpointer_p.h \ + $$PWD/q3dcamera.h \ + $$PWD/q3dcamera_p.h \ + $$PWD/q3dscene.h \ + $$PWD/q3dlight.h \ + $$PWD/q3dlight_p.h \ + $$PWD/q3dbox.h \ + $$PWD/q3dobject.h \ + $$PWD/q3dobject_p.h \ + $$PWD/q3dscene_p.h + +SOURCES += $$PWD/q3dwindow.cpp \ + $$PWD/q3dbars.cpp \ + $$PWD/theme.cpp \ + $$PWD/drawer.cpp \ + $$PWD/bars3dcontroller.cpp \ + $$PWD/bars3drenderer.cpp \ + $$PWD/q3dsurface.cpp \ + $$PWD/surface3drenderer.cpp \ + $$PWD/surface3dcontroller.cpp \ + $$PWD/abstract3dcontroller.cpp \ + $$PWD/q3dscatter.cpp \ + $$PWD/scatter3dcontroller.cpp \ + $$PWD/scatter3drenderer.cpp \ + $$PWD/axisrendercache.cpp \ + $$PWD/abstract3drenderer.cpp \ + $$PWD/selectionpointer.cpp \ + $$PWD/q3dcamera.cpp \ + $$PWD/q3dlight.cpp \ + $$PWD/q3dbox.cpp \ + $$PWD/q3dobject.cpp \ + $$PWD/q3dscene.cpp + +RESOURCES += engine/engine.qrc diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc new file mode 100644 index 00000000..7420ae51 --- /dev/null +++ b/src/datavisualization/engine/engine.qrc @@ -0,0 +1,62 @@ +<RCC> + <qresource prefix="/defaultMeshes"> + <file alias="cone">meshes/coneFlat.obj</file> + <file alias="coneSmooth">meshes/coneSmooth.obj</file> + <file alias="pyramid">meshes/pyramidFlat.obj</file> + <file alias="pyramidSmooth">meshes/pyramidSmooth.obj</file> + <file alias="bar">meshes/cubeFlat.obj</file> + <file alias="barSmooth">meshes/cubeSmooth.obj</file> + <file alias="cylinder">meshes/cylinderFlat.obj</file> + <file alias="cylinderSmooth">meshes/cylinderSmooth.obj</file> + <file alias="background">meshes/backgroudFlat.obj</file> + <file alias="backgroundSmooth">meshes/backgroudSmooth.obj</file> + <file alias="label">meshes/plane.obj</file> + <file alias="sphere">meshes/sphere.obj</file> + <file alias="sphereSmooth">meshes/sphereSmooth.obj</file> + <file alias="bevelbar">meshes/barFlat.obj</file> + <file alias="bevelbarSmooth">meshes/barSmooth.obj</file> + <file alias="negativeBackground">meshes/backgroudNegatives.obj</file> + <file alias="coneFull">meshes/coneFilledFlat.obj</file> + <file alias="coneSmoothFull">meshes/coneFilledSmooth.obj</file> + <file alias="cylinderFull">meshes/cylinderFilledFlat.obj</file> + <file alias="cylinderSmoothFull">meshes/cylinderFilledSmooth.obj</file> + <file alias="pyramidFull">meshes/pyramidFilledFlat.obj</file> + <file alias="pyramidSmoothFull">meshes/pyramidFilledSmooth.obj</file> + <file alias="bevelbarFull">meshes/barFilledFlat.obj</file> + <file alias="bevelbarSmoothFull">meshes/barFilledSmooth.obj</file> + <file alias="barFull">meshes/cubeFilledFlat.obj</file> + <file alias="barSmoothFull">meshes/cubeFilledSmooth.obj</file> + <file alias="dotSmooth">meshes/scatterdot.obj</file> + <file alias="dot">meshes/scatterdotFlat.obj</file> + </qresource> + <qresource prefix="/shaders"> + <file alias="fragment">shaders/default.frag</file> + <file alias="vertex">shaders/default.vert</file> + <file alias="fragmentAmbient">shaders/ambient.frag</file> + <file alias="fragmentColorOnY">shaders/colorOnY.frag</file> + <file alias="fragmentSelection">shaders/selection.frag</file> + <file alias="vertexSelection">shaders/selection.vert</file> + <file alias="fragmentTexture">shaders/texture.frag</file> + <file alias="vertexTexture">shaders/texture.vert</file> + <file alias="fragmentLabel">shaders/label.frag</file> + <file alias="vertexLabel">shaders/label.vert</file> + <file alias="fragmentDepth">shaders/depth.frag</file> + <file alias="vertexDepth">shaders/depth.vert</file> + <file alias="fragmentShadow">shaders/shadow.frag</file> + <file alias="vertexShadow">shaders/shadow.vert</file> + <file alias="fragmentShadowNoTex">shaders/shadowNoTex.frag</file> + <file alias="fragmentShadowNoTexColorOnY">shaders/shadowNoTexColorOnY.frag</file> + <file alias="fragmentColorOnYES2">shaders/colorOnY_ES2.frag</file> + <file alias="fragmentES2">shaders/default_ES2.frag</file> + <file alias="vertexES2">shaders/default_ES2.vert</file> + <file alias="fragmentTextureES2">shaders/texture_ES2.frag</file> + <file alias="fragmentSurface">shaders/surface.frag</file> + <file alias="vertexSurface">shaders/surface.vert</file> + <file alias="fragmentSurfaceGrid">shaders/surfaceGrid.frag</file> + <file alias="vertexSurfaceGrid">shaders/surfaceGrid.vert</file> + <file alias="vertexSurfaceFlat">shaders/surfaceFlat.vert</file> + <file alias="fragmentSurfaceFlat">shaders/surfaceFlat.frag</file> + <file alias="fragmentSurfaceES2">shaders/surface_ES2.frag</file> + </qresource> + <qresource prefix="/textures"/> +</RCC> diff --git a/src/datavisualization/engine/meshes/backgroudFlat.obj b/src/datavisualization/engine/meshes/backgroudFlat.obj new file mode 100644 index 00000000..cf4d10a5 --- /dev/null +++ b/src/datavisualization/engine/meshes/backgroudFlat.obj @@ -0,0 +1,32 @@ +# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend' +# www.blender.org +o Cube +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 0.999999 1.000000 1.000001 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +vt 0.000000 0.501529 +vt 0.001529 1.000000 +vt 0.500000 0.998471 +vt 0.501529 0.500000 +vt 1.000000 0.498471 +vt 0.998471 0.000000 +vt 0.500000 0.498471 +vt 0.498471 0.000000 +vt 0.000000 0.001529 +vt 0.498471 0.500000 +vt 0.500000 0.001529 +vt 0.001529 0.500000 +vn -0.000000 1.000000 0.000000 +vn 0.000000 -0.000000 -1.000000 +vn 1.000000 0.000000 0.000000 +s off +f 1/1/1 4/2/1 3/3/1 +f 2/4/2 3/5/2 6/6/2 +f 3/7/3 4/8/3 7/9/3 +f 2/10/1 1/1/1 3/3/1 +f 5/11/2 2/4/2 6/6/2 +f 6/12/3 3/7/3 7/9/3 diff --git a/src/datavisualization/engine/meshes/backgroudNegatives.obj b/src/datavisualization/engine/meshes/backgroudNegatives.obj new file mode 100644 index 00000000..dd4d3f05 --- /dev/null +++ b/src/datavisualization/engine/meshes/backgroudNegatives.obj @@ -0,0 +1,37 @@ +# Blender v2.66 (sub 0) OBJ File: 'backgroudNegatives.blend' +# www.blender.org +o Cube +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 0.999999 1.000000 1.000001 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -3.000000 1.000000 +v -1.000000 -3.000000 1.000000 +v -1.000000 -3.000000 -1.000000 +vt 0.000100 0.666700 +vt 0.333300 0.666700 +vt 0.333300 0.999900 +vt 0.000100 0.000100 +vt 0.333300 0.000100 +vt 0.333300 0.666500 +vt 0.666500 0.000100 +vt 0.666500 0.666500 +vt 0.000100 0.999900 +vt 0.000100 0.666500 +vn 0.000000 0.999969 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.707083 0.000000 -0.707083 +vn 1.000000 0.000000 0.000000 +vn 0.999969 0.000000 0.000000 +vn 0.000000 0.000000 -0.999969 +s 1 +f 1/1/1 4/2/2 3/3/2 +f 8/4/3 9/5/4 6/6/4 +f 9/5/4 10/7/5 7/8/6 +f 2/9/2 1/1/1 3/3/2 +f 5/10/7 8/4/3 6/6/4 +f 6/6/4 9/5/4 7/8/6 diff --git a/src/datavisualization/engine/meshes/backgroudSmooth.obj b/src/datavisualization/engine/meshes/backgroudSmooth.obj new file mode 100644 index 00000000..ad16d904 --- /dev/null +++ b/src/datavisualization/engine/meshes/backgroudSmooth.obj @@ -0,0 +1,36 @@ +# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend' +# www.blender.org +o Cube +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 0.999999 1.000000 1.000001 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +vt 0.000000 0.501529 +vt 0.001529 1.000000 +vt 0.500000 0.998471 +vt 0.501529 0.500000 +vt 1.000000 0.498471 +vt 0.998471 0.000000 +vt 0.500000 0.498471 +vt 0.498471 0.000000 +vt 0.000000 0.001529 +vt 0.498471 0.500000 +vt 0.500000 0.001529 +vt 0.001529 0.500000 +vn 0.000000 0.999969 0.000000 +vn 0.707083 0.707083 0.000000 +vn 0.577349 0.577349 -0.577349 +vn 0.000000 0.707083 -0.707083 +vn 0.707083 0.000000 -0.707083 +vn 0.999969 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +s 1 +f 1/1/1 4/2/2 3/3/3 +f 2/4/4 3/5/3 6/6/5 +f 3/7/3 4/8/2 7/9/6 +f 2/10/4 1/1/1 3/3/3 +f 5/11/7 2/4/4 6/6/5 +f 6/12/5 3/7/3 7/9/6 diff --git a/src/datavisualization/engine/meshes/barFilledFlat.obj b/src/datavisualization/engine/meshes/barFilledFlat.obj new file mode 100644 index 00000000..5f627091 --- /dev/null +++ b/src/datavisualization/engine/meshes/barFilledFlat.obj @@ -0,0 +1,242 @@ +# Blender v2.66 (sub 0) OBJ File: 'smoothcube_filled.blend' +# www.blender.org +o Cube +v -0.980000 -1.000000 1.000000 +v -1.000000 -1.000000 0.980000 +v -0.994142 -1.000000 0.994142 +v -1.000000 -1.000000 -0.980000 +v -0.980000 -1.000000 -1.000000 +v -0.994142 -1.000000 -0.994142 +v 0.980000 -1.000000 -1.000000 +v 1.000000 -1.000000 -0.980000 +v 0.994142 -1.000000 -0.994142 +v 1.000000 -1.000000 0.980000 +v 0.980000 -1.000000 1.000000 +v 0.994142 -1.000000 0.994142 +v -0.980000 0.980000 1.000000 +v -0.980000 1.000000 0.980000 +v -1.000000 0.980000 0.980000 +v -0.980000 0.994142 0.994142 +v -0.994142 0.994142 0.980000 +v -0.994142 0.980000 0.994142 +v -0.992998 0.992998 0.992998 +v -1.000000 0.980000 -0.980000 +v -0.980000 1.000000 -0.980000 +v -0.980000 0.980000 -1.000000 +v -0.994142 0.994142 -0.980000 +v -0.980000 0.994142 -0.994142 +v -0.994142 0.980000 -0.994142 +v -0.992998 0.992998 -0.992998 +v 0.980000 0.980000 -1.000000 +v 0.980000 1.000000 -0.980000 +v 1.000000 0.980000 -0.980000 +v 0.980000 0.994142 -0.994142 +v 0.994142 0.994142 -0.980000 +v 0.994142 0.980000 -0.994142 +v 0.992998 0.992998 -0.992998 +v 1.000000 0.980000 0.980000 +v 0.980000 1.000000 0.980000 +v 0.980000 0.980000 1.000000 +v 0.994142 0.994142 0.980000 +v 0.980000 0.994142 0.994142 +v 0.994142 0.980000 0.994142 +v 0.992998 0.992998 0.992998 +vt 0.339018 0.659342 +vt 0.338105 0.335826 +vt 0.664825 0.343846 +vt 0.669233 0.664931 +vt 0.668227 0.337019 +vt 0.995472 0.336015 +vt 0.337976 0.003372 +vt 0.665888 0.002366 +vt 0.666894 0.330278 +vt 0.672755 0.331283 +vt 0.671749 0.003372 +vt 1.000000 0.330280 +vt 0.335610 0.335927 +vt 0.337937 0.333650 +vt 0.338982 0.331284 +vt 0.338989 0.333650 +vt 0.336616 0.331291 +vt 0.326720 0.346123 +vt 0.326875 0.343630 +vt 0.329215 0.346022 +vt 0.327633 0.669639 +vt 0.330128 0.669538 +vt 0.327801 0.671815 +vt 0.669260 0.330271 +vt 0.666901 0.332644 +vt 0.672610 0.333650 +vt 0.670266 0.331291 +vt 0.669260 0.003379 +vt 0.669412 0.001204 +vt 0.665880 0.000000 +vt 0.668056 0.000185 +vt 0.669089 0.667298 +vt 0.666910 0.667113 +vt 0.665738 0.337027 +vt 0.665891 0.334852 +vt 0.335610 0.003379 +vt 0.335795 0.001204 +vt 0.338863 0.661835 +vt 0.336686 0.661624 +vt 0.001081 0.663795 +vt 0.664657 0.341670 +vt 0.000155 0.335610 +vt 0.000000 0.338102 +vt 0.996478 0.663927 +vt 0.996334 0.666294 +vt 0.671590 0.001006 +vt 0.998835 0.000002 +vt 0.998994 0.002368 +vt 0.337969 0.001006 +vt 0.666744 0.664939 +vt 0.665738 0.667363 +vt 0.665583 0.669855 +vt 0.668068 0.334654 +vt 0.995313 0.333650 +vt 0.336523 0.659443 +vt 0.001006 0.332274 +vt 0.000000 0.004362 +vt 0.001993 0.334637 +vt 0.335761 0.333817 +vt 0.336814 0.333465 +vt 0.329052 0.343841 +vt 0.329977 0.671648 +vt 0.669075 0.332446 +vt 0.670432 0.333465 +vt 0.668254 0.002359 +vt 0.999855 0.332646 +vt 0.000913 0.661618 +vt 0.000973 0.001993 +vt 0.003336 0.001006 +vt 0.331248 0.000000 +vt 0.333617 0.000973 +vt 0.334604 0.003336 +vt 0.335610 0.331248 +vt 0.334637 0.333617 +vt 0.332274 0.334604 +vt 0.004362 0.335610 +vn 0.000000 0.000000 1.000000 +vn 1.000000 -0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn -0.357407 0.357407 0.862856 +vn -0.357409 0.862855 0.357407 +vn -0.862855 0.357409 0.357407 +vn -0.862855 0.357407 -0.357409 +vn -0.357407 0.862855 -0.357409 +vn -0.357408 0.357408 -0.862855 +vn 0.114222 0.380181 -0.917832 +vn 0.380181 0.917832 -0.114222 +vn 0.917832 0.114222 -0.380181 +vn 0.917832 0.380181 0.114222 +vn 0.114222 0.917832 0.380181 +vn 0.380181 0.114222 0.917832 +vn -0.382685 0.923879 0.000000 +vn -0.923879 0.382685 0.000000 +vn -0.382685 0.000000 -0.923879 +vn -0.923879 0.000000 -0.382685 +vn -0.382685 0.000000 0.923879 +vn -0.923879 0.000000 0.382685 +vn 0.000000 0.923879 -0.382685 +vn 0.000000 0.382685 -0.923879 +vn 0.923879 0.000000 -0.382685 +vn 0.382685 0.000000 -0.923879 +vn 0.382685 0.923879 0.000000 +vn 0.923879 0.382685 0.000000 +vn 0.382685 -0.000000 0.923879 +vn 0.923879 -0.000000 0.382685 +vn -0.000000 0.923879 0.382685 +vn -0.000000 0.382685 0.923879 +vn -1.000000 0.000000 0.000000 +vn -0.000000 -1.000000 -0.000000 +vn -0.095602 0.095602 0.990818 +vn -0.095602 0.990818 0.095602 +vn -0.990818 0.095602 0.095602 +vn -0.990818 0.095602 -0.095602 +vn -0.095602 0.990818 -0.095602 +vn -0.095602 0.095602 -0.990818 +vn 0.380181 0.114222 -0.917832 +vn 0.114222 0.917832 -0.380181 +vn 0.917832 0.380181 -0.114222 +vn 0.917832 0.114222 0.380181 +vn 0.380181 0.917832 0.114222 +vn 0.114222 0.380181 0.917832 +s off +f 36/1/1 13/2/1 1/3/1 +f 29/4/2 34/5/2 10/6/2 +f 35/7/3 28/8/3 21/9/3 +f 22/10/4 27/11/4 5/12/4 +f 13/2/5 16/13/5 18/14/5 +f 14/15/6 17/16/6 16/17/6 +f 15/18/7 18/19/7 17/20/7 +f 20/21/8 23/22/8 25/23/8 +f 21/9/9 24/24/9 23/25/9 +f 22/10/10 25/26/10 24/27/10 +f 27/11/11 30/28/11 33/29/11 +f 28/8/12 31/30/12 33/31/12 +f 29/4/13 32/32/13 33/33/13 +f 34/5/14 37/34/14 40/35/14 +f 35/7/15 38/36/15 40/37/15 +f 36/1/16 39/38/16 40/39/16 +f 14/15/17 21/9/17 17/16/17 +f 17/20/18 23/22/18 15/18/18 +f 22/10/19 5/12/19 25/26/19 +f 25/23/20 6/40/20 20/21/20 +f 1/3/21 13/2/21 3/41/21 +f 3/42/22 18/19/22 2/43/22 +f 21/9/23 28/8/23 24/24/23 +f 24/27/24 30/28/24 22/10/24 +f 29/4/25 8/44/25 9/45/25 +f 32/46/26 9/47/26 7/48/26 +f 28/8/27 35/7/27 37/49/27 +f 31/50/28 37/34/28 34/5/28 +f 36/1/29 11/51/29 12/52/29 +f 39/53/30 12/54/30 10/6/30 +f 35/7/31 14/15/31 16/17/31 +f 38/55/32 16/13/32 13/2/32 +f 15/18/33 20/21/33 2/43/33 +f 5/56/34 7/57/34 6/58/34 +f 11/51/1 36/1/1 1/3/1 +f 8/44/2 29/4/2 10/6/2 +f 14/15/3 35/7/3 21/9/3 +f 27/11/4 7/48/4 5/12/4 +f 16/13/35 19/59/35 18/14/35 +f 17/16/36 19/60/36 16/17/36 +f 18/19/37 19/61/37 17/20/37 +f 23/22/38 26/62/38 25/23/38 +f 24/24/39 26/63/39 23/25/39 +f 25/26/40 26/64/40 24/27/40 +f 32/46/41 27/11/41 33/29/41 +f 30/65/42 28/8/42 33/31/42 +f 31/50/43 29/4/43 33/33/43 +f 39/53/44 34/5/44 40/35/44 +f 37/49/45 35/7/45 40/37/45 +f 38/55/46 36/1/46 40/39/46 +f 21/9/17 23/25/17 17/16/17 +f 23/22/18 20/21/18 15/18/18 +f 5/12/19 6/66/19 25/26/19 +f 6/40/20 4/67/20 20/21/20 +f 13/2/21 18/14/21 3/41/21 +f 18/19/22 15/18/22 2/43/22 +f 28/8/23 30/65/23 24/24/23 +f 30/28/24 27/11/24 22/10/24 +f 32/32/25 29/4/25 9/45/25 +f 27/11/26 32/46/26 7/48/26 +f 31/30/27 28/8/27 37/49/27 +f 29/4/28 31/50/28 34/5/28 +f 39/38/29 36/1/29 12/52/29 +f 34/5/30 39/53/30 10/6/30 +f 38/36/31 35/7/31 16/17/31 +f 36/1/32 38/55/32 13/2/32 +f 20/21/33 4/67/33 2/43/33 +f 7/57/34 9/68/34 6/58/34 +f 9/68/34 8/69/34 6/58/34 +f 8/69/34 10/70/34 6/58/34 +f 10/70/34 12/71/34 6/58/34 +f 12/71/34 11/72/34 6/58/34 +f 11/72/34 1/73/34 6/58/34 +f 1/73/34 3/74/34 6/58/34 +f 3/74/34 2/75/34 4/76/34 +f 6/58/34 3/74/34 4/76/34 diff --git a/src/datavisualization/engine/meshes/barFilledSmooth.obj b/src/datavisualization/engine/meshes/barFilledSmooth.obj new file mode 100644 index 00000000..efc4317a --- /dev/null +++ b/src/datavisualization/engine/meshes/barFilledSmooth.obj @@ -0,0 +1,236 @@ +# Blender v2.66 (sub 0) OBJ File: 'smoothcube_filled.blend' +# www.blender.org +o Cube +v -0.980000 -1.000000 1.000000 +v -1.000000 -1.000000 0.980000 +v -0.994142 -1.000000 0.994142 +v -1.000000 -1.000000 -0.980000 +v -0.980000 -1.000000 -1.000000 +v -0.994142 -1.000000 -0.994142 +v 0.980000 -1.000000 -1.000000 +v 1.000000 -1.000000 -0.980000 +v 0.994142 -1.000000 -0.994142 +v 1.000000 -1.000000 0.980000 +v 0.980000 -1.000000 1.000000 +v 0.994142 -1.000000 0.994142 +v -0.980000 0.980000 1.000000 +v -0.980000 1.000000 0.980000 +v -1.000000 0.980000 0.980000 +v -0.980000 0.994142 0.994142 +v -0.994142 0.994142 0.980000 +v -0.994142 0.980000 0.994142 +v -0.992998 0.992998 0.992998 +v -1.000000 0.980000 -0.980000 +v -0.980000 1.000000 -0.980000 +v -0.980000 0.980000 -1.000000 +v -0.994142 0.994142 -0.980000 +v -0.980000 0.994142 -0.994142 +v -0.994142 0.980000 -0.994142 +v -0.992998 0.992998 -0.992998 +v 0.980000 0.980000 -1.000000 +v 0.980000 1.000000 -0.980000 +v 1.000000 0.980000 -0.980000 +v 0.980000 0.994142 -0.994142 +v 0.994142 0.994142 -0.980000 +v 0.994142 0.980000 -0.994142 +v 0.992998 0.992998 -0.992998 +v 1.000000 0.980000 0.980000 +v 0.980000 1.000000 0.980000 +v 0.980000 0.980000 1.000000 +v 0.994142 0.994142 0.980000 +v 0.980000 0.994142 0.994142 +v 0.994142 0.980000 0.994142 +v 0.992998 0.992998 0.992998 +vt 0.339018 0.659342 +vt 0.338105 0.335826 +vt 0.664825 0.343846 +vt 0.669233 0.664931 +vt 0.668227 0.337019 +vt 0.995472 0.336015 +vt 0.337976 0.003372 +vt 0.665888 0.002366 +vt 0.666894 0.330278 +vt 0.672755 0.331283 +vt 0.671749 0.003372 +vt 0.998994 0.002368 +vt 0.335610 0.335927 +vt 0.335761 0.333817 +vt 0.338982 0.331284 +vt 0.338989 0.333650 +vt 0.336814 0.333465 +vt 0.326720 0.346123 +vt 0.326875 0.343630 +vt 0.329052 0.343841 +vt 0.327633 0.669639 +vt 0.330128 0.669538 +vt 0.329977 0.671648 +vt 0.669260 0.330271 +vt 0.669075 0.332446 +vt 0.672610 0.333650 +vt 0.670432 0.333465 +vt 0.669260 0.003379 +vt 0.669412 0.001204 +vt 0.665880 0.000000 +vt 0.668056 0.000185 +vt 0.669089 0.667298 +vt 0.666910 0.667113 +vt 0.665738 0.337027 +vt 0.665891 0.334852 +vt 0.335610 0.003379 +vt 0.335795 0.001204 +vt 0.338863 0.661835 +vt 0.336686 0.661624 +vt 0.666901 0.332644 +vt 0.329215 0.346022 +vt 1.000000 0.330280 +vt 0.999855 0.332646 +vt 0.327801 0.671815 +vt 0.001081 0.663795 +vt 0.000913 0.661618 +vt 0.337937 0.333650 +vt 0.000155 0.335610 +vt 0.668254 0.002359 +vt 0.670266 0.331291 +vt 0.996478 0.663927 +vt 0.996334 0.666294 +vt 0.671590 0.001006 +vt 0.998835 0.000002 +vt 0.337969 0.001006 +vt 0.666744 0.664939 +vt 0.665738 0.667363 +vt 0.665583 0.669855 +vt 0.668068 0.334654 +vt 0.995313 0.333650 +vt 0.336616 0.331291 +vt 0.336523 0.659443 +vt 0.000000 0.004362 +vt 0.000973 0.001993 +vt 0.003336 0.001006 +vt 0.664657 0.341670 +vt 0.000000 0.338102 +vt 0.334604 0.003336 +vt 0.331248 0.000000 +vt 0.333617 0.000973 +vt 0.332274 0.334604 +vt 0.335610 0.331248 +vt 0.334637 0.333617 +vt 0.001993 0.334637 +vt 0.001006 0.332274 +vt 0.004362 0.335610 +vn 0.161046 0.161046 0.973693 +vn -0.161046 0.161046 0.973693 +vn -0.145573 -0.665700 0.731864 +vn 0.973693 0.161046 -0.161046 +vn 0.973693 0.161046 0.161046 +vn 0.731864 -0.665700 0.145573 +vn 0.161046 0.973693 0.161046 +vn 0.161046 0.973693 -0.161046 +vn -0.161046 0.973693 -0.161046 +vn -0.161046 0.161046 -0.973693 +vn 0.161046 0.161046 -0.973693 +vn 0.145573 -0.665700 -0.731864 +vn -0.060945 0.705771 0.705771 +vn -0.577349 0.577349 0.577349 +vn -0.161046 0.973693 0.161046 +vn -0.705771 0.705771 0.060945 +vn -0.973693 0.161046 0.161046 +vn -0.705771 0.060945 0.705771 +vn -0.973693 0.161046 -0.161046 +vn -0.705771 0.705771 -0.060945 +vn -0.577349 0.577349 -0.577349 +vn -0.060945 0.705771 -0.705771 +vn -0.705771 0.060945 -0.705771 +vn 0.060945 0.705771 -0.705771 +vn 0.577349 0.577349 -0.577349 +vn 0.705771 0.705771 -0.060945 +vn 0.705771 0.060945 -0.705771 +vn 0.705771 0.705771 0.060945 +vn 0.577349 0.577349 0.577349 +vn 0.060945 0.705771 0.705771 +vn 0.705771 0.060945 0.705771 +vn -0.145573 -0.665700 -0.731864 +vn -0.548967 -0.630238 -0.548967 +vn -0.731864 -0.665700 -0.145573 +vn -0.548967 -0.630238 0.548967 +vn 0.731864 -0.665700 -0.145573 +vn 0.548967 -0.630238 -0.548967 +vn 0.145573 -0.665700 0.731864 +vn 0.548967 -0.630238 0.548967 +vn -0.731864 -0.665700 0.145573 +s 1 +f 36/1/1 13/2/2 1/3/3 +f 29/4/4 34/5/5 10/6/6 +f 35/7/7 28/8/8 21/9/9 +f 22/10/10 27/11/11 7/12/12 +f 13/2/2 16/13/13 19/14/14 +f 14/15/15 17/16/16 19/17/14 +f 15/18/17 18/19/18 19/20/14 +f 20/21/19 23/22/20 26/23/21 +f 21/9/9 24/24/22 26/25/21 +f 22/10/10 25/26/23 26/27/21 +f 27/11/11 30/28/24 33/29/25 +f 28/8/8 31/30/26 33/31/25 +f 29/4/4 32/32/27 33/33/25 +f 34/5/5 37/34/28 40/35/29 +f 35/7/7 38/36/30 40/37/29 +f 36/1/1 39/38/31 40/39/29 +f 14/15/15 21/9/9 23/40/20 +f 17/41/16 23/22/20 20/21/19 +f 22/10/10 5/42/32 6/43/33 +f 25/44/23 6/45/33 4/46/34 +f 1/3/3 13/2/2 18/47/18 +f 3/48/35 18/19/18 15/18/17 +f 21/9/9 28/8/8 30/49/24 +f 24/50/22 30/28/24 27/11/11 +f 29/4/4 8/51/36 9/52/37 +f 32/53/27 9/54/37 7/12/12 +f 28/8/8 35/7/7 37/55/28 +f 31/56/26 37/34/28 34/5/5 +f 36/1/1 11/57/38 12/58/39 +f 39/59/31 12/60/39 10/6/6 +f 35/7/7 14/15/15 16/61/13 +f 38/62/30 16/13/13 13/2/2 +f 15/18/17 20/21/19 4/46/34 +f 7/63/12 9/64/37 8/65/36 +f 11/57/38 36/1/1 1/3/3 +f 8/51/36 29/4/4 10/6/6 +f 14/15/15 35/7/7 21/9/9 +f 5/42/32 22/10/10 7/12/12 +f 18/47/18 13/2/2 19/14/14 +f 16/61/13 14/15/15 19/17/14 +f 17/41/16 15/18/17 19/20/14 +f 25/44/23 20/21/19 26/23/21 +f 23/40/20 21/9/9 26/25/21 +f 24/50/22 22/10/10 26/27/21 +f 32/53/27 27/11/11 33/29/25 +f 30/49/24 28/8/8 33/31/25 +f 31/56/26 29/4/4 33/33/25 +f 39/59/31 34/5/5 40/35/29 +f 37/55/28 35/7/7 40/37/29 +f 38/62/30 36/1/1 40/39/29 +f 17/16/16 14/15/15 23/40/20 +f 15/18/17 17/41/16 20/21/19 +f 25/26/23 22/10/10 6/43/33 +f 20/21/19 25/44/23 4/46/34 +f 3/66/35 1/3/3 18/47/18 +f 2/67/40 3/48/35 15/18/17 +f 24/24/22 21/9/9 30/49/24 +f 22/10/10 24/50/22 27/11/11 +f 32/32/27 29/4/4 9/52/37 +f 27/11/11 32/53/27 7/12/12 +f 31/30/26 28/8/8 37/55/28 +f 29/4/4 31/56/26 34/5/5 +f 39/38/31 36/1/1 12/58/39 +f 34/5/5 39/59/31 10/6/6 +f 38/36/30 35/7/7 16/61/13 +f 36/1/1 38/62/30 13/2/2 +f 2/67/40 15/18/17 4/46/34 +f 11/68/38 10/69/6 12/70/39 +f 2/71/40 1/72/3 3/73/35 +f 6/74/33 5/75/32 4/76/34 +f 5/75/32 7/63/12 4/76/34 +f 2/71/40 4/76/34 8/65/36 +f 8/65/36 10/69/6 2/71/40 +f 10/69/6 11/68/38 1/72/3 +f 2/71/40 10/69/6 1/72/3 +f 4/76/34 7/63/12 8/65/36 diff --git a/src/datavisualization/engine/meshes/barFlat.obj b/src/datavisualization/engine/meshes/barFlat.obj new file mode 100644 index 00000000..b802feab --- /dev/null +++ b/src/datavisualization/engine/meshes/barFlat.obj @@ -0,0 +1,219 @@ +# Blender v2.66 (sub 0) OBJ File: 'smoothcube.blend' +# www.blender.org +o Cube +v -0.980000 -1.000000 1.000000 +v -1.000000 -1.000000 0.980000 +v -0.994142 -1.000000 0.994142 +v -1.000000 -1.000000 -0.980000 +v -0.980000 -1.000000 -1.000000 +v -0.994142 -1.000000 -0.994142 +v 0.980000 -1.000000 -1.000000 +v 1.000000 -1.000000 -0.980000 +v 0.994142 -1.000000 -0.994142 +v 1.000000 -1.000000 0.980000 +v 0.980000 -1.000000 1.000000 +v 0.994142 -1.000000 0.994142 +v -0.980000 0.980000 1.000000 +v -0.980000 1.000000 0.980000 +v -1.000000 0.980000 0.980000 +v -0.980000 0.994142 0.994142 +v -0.994142 0.994142 0.980000 +v -0.994142 0.980000 0.994142 +v -0.992998 0.992998 0.992998 +v -1.000000 0.980000 -0.980000 +v -0.980000 1.000000 -0.980000 +v -0.980000 0.980000 -1.000000 +v -0.994142 0.994142 -0.980000 +v -0.980000 0.994142 -0.994142 +v -0.994142 0.980000 -0.994142 +v -0.992998 0.992998 -0.992998 +v 0.980000 0.980000 -1.000000 +v 0.980000 1.000000 -0.980000 +v 1.000000 0.980000 -0.980000 +v 0.980000 0.994142 -0.994142 +v 0.994142 0.994142 -0.980000 +v 0.994142 0.980000 -0.994142 +v 0.992998 0.992998 -0.992998 +v 1.000000 0.980000 0.980000 +v 0.980000 1.000000 0.980000 +v 0.980000 0.980000 1.000000 +v 0.994142 0.994142 0.980000 +v 0.980000 0.994142 0.994142 +v 0.994142 0.980000 0.994142 +v 0.992998 0.992998 0.992998 +vt 0.338795 0.668183 +vt 0.337784 0.338666 +vt 0.666630 0.337658 +vt 0.003512 0.668185 +vt 0.002502 0.338668 +vt 0.331348 0.337660 +vt 0.002378 0.003388 +vt 0.331894 0.002378 +vt 0.332905 0.331894 +vt 0.671154 0.332902 +vt 0.670143 0.003386 +vt 1.000000 0.331893 +vt 0.335282 0.338674 +vt 0.337624 0.336289 +vt 0.003388 0.332905 +vt 0.003396 0.335282 +vt 0.001011 0.332912 +vt 0.338795 0.332902 +vt 0.338649 0.335280 +vt 0.336293 0.332910 +vt 0.337784 0.003386 +vt 0.335282 0.003394 +vt 0.337624 0.001009 +vt 0.335282 0.331887 +vt 0.332912 0.334272 +vt 0.671008 0.335280 +vt 0.668652 0.332910 +vt 0.667641 0.003394 +vt 0.667795 0.001208 +vt 0.331887 0.000000 +vt 0.334073 0.000186 +vt 0.003367 0.670563 +vt 0.001178 0.670377 +vt 0.000000 0.338676 +vt 0.000153 0.336490 +vt 0.000000 0.003396 +vt 0.000186 0.001210 +vt 0.338649 0.670561 +vt 0.336460 0.670375 +vt 0.666470 0.000000 +vt 0.666470 0.335280 +vt 0.667496 0.334272 +vt 0.667641 0.331894 +vt 0.332359 0.667176 +vt 0.332213 0.669554 +vt 0.669983 0.001009 +vt 0.998829 0.000000 +vt 0.998989 0.002377 +vt 0.002370 0.001011 +vt 0.001011 0.668192 +vt 0.667641 0.667174 +vt 0.667496 0.669552 +vt 0.002341 0.336291 +vt 0.331188 0.335282 +vt 0.336293 0.668191 +vt 0.335436 0.336488 +vt 0.001210 0.335097 +vt 0.336460 0.335095 +vt 0.335436 0.001208 +vt 0.335097 0.334073 +vt 0.668819 0.335095 +vt 0.334272 0.002370 +vt 0.999855 0.334272 +vt 0.666630 0.002377 +vn 0.000000 0.000000 1.000000 +vn 1.000000 -0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn -0.357407 0.357407 0.862856 +vn -0.357409 0.862855 0.357407 +vn -0.862855 0.357409 0.357407 +vn -0.862855 0.357407 -0.357409 +vn -0.357407 0.862855 -0.357409 +vn -0.357408 0.357408 -0.862855 +vn 0.114222 0.380181 -0.917832 +vn 0.380181 0.917832 -0.114222 +vn 0.917832 0.114222 -0.380181 +vn 0.917832 0.380181 0.114222 +vn 0.114222 0.917832 0.380181 +vn 0.380181 0.114222 0.917832 +vn -0.382685 0.923879 0.000000 +vn -0.923879 0.382685 0.000000 +vn -0.382685 0.000000 -0.923879 +vn -0.923879 0.000000 -0.382685 +vn -0.382685 0.000000 0.923879 +vn -0.923879 0.000000 0.382685 +vn 0.000000 0.923879 -0.382685 +vn 0.000000 0.382685 -0.923879 +vn 0.923879 0.000000 -0.382685 +vn 0.382685 0.000000 -0.923879 +vn 0.382685 0.923879 0.000000 +vn 0.923879 0.382685 0.000000 +vn 0.382685 -0.000000 0.923879 +vn 0.923879 -0.000000 0.382685 +vn -0.000000 0.923879 0.382685 +vn -0.000000 0.382685 0.923879 +vn -1.000000 0.000000 0.000000 +vn -0.095602 0.095602 0.990818 +vn -0.095602 0.990818 0.095602 +vn -0.990818 0.095602 0.095602 +vn -0.990818 0.095602 -0.095602 +vn -0.095602 0.990818 -0.095602 +vn -0.095602 0.095602 -0.990818 +vn 0.380181 0.114222 -0.917832 +vn 0.114222 0.917832 -0.380181 +vn 0.917832 0.380181 -0.114222 +vn 0.917832 0.114222 0.380181 +vn 0.380181 0.917832 0.114222 +vn 0.114222 0.380181 0.917832 +s off +f 36/1/1 13/2/1 1/3/1 +f 29/4/2 34/5/2 10/6/2 +f 35/7/3 28/8/3 21/9/3 +f 22/10/4 27/11/4 5/12/4 +f 13/2/5 16/13/5 18/14/5 +f 14/15/6 17/16/6 16/17/6 +f 15/18/7 18/19/7 17/20/7 +f 20/21/8 23/22/8 25/23/8 +f 21/9/9 24/24/9 23/25/9 +f 22/10/10 25/26/10 24/27/10 +f 27/11/11 30/28/11 33/29/11 +f 28/8/12 31/30/12 33/31/12 +f 29/4/13 32/32/13 33/33/13 +f 34/5/14 37/34/14 40/35/14 +f 35/7/15 38/36/15 40/37/15 +f 36/1/16 39/38/16 40/39/16 +f 14/15/17 21/9/17 17/16/17 +f 17/20/18 23/22/18 15/18/18 +f 22/10/19 5/12/19 25/26/19 +f 25/23/20 6/40/20 20/21/20 +f 1/3/21 13/2/21 3/41/21 +f 3/42/22 18/19/22 2/43/22 +f 21/9/23 28/8/23 24/24/23 +f 24/27/24 30/28/24 22/10/24 +f 29/4/25 8/44/25 9/45/25 +f 32/46/26 9/47/26 7/48/26 +f 28/8/27 35/7/27 37/49/27 +f 31/50/28 37/34/28 34/5/28 +f 36/1/29 11/51/29 12/52/29 +f 39/53/30 12/54/30 10/6/30 +f 35/7/31 14/15/31 16/17/31 +f 38/55/32 16/13/32 13/2/32 +f 15/18/33 20/21/33 2/43/33 +f 11/51/1 36/1/1 1/3/1 +f 8/44/2 29/4/2 10/6/2 +f 14/15/3 35/7/3 21/9/3 +f 27/11/4 7/48/4 5/12/4 +f 16/13/34 19/56/34 18/14/34 +f 17/16/35 19/57/35 16/17/35 +f 18/19/36 19/58/36 17/20/36 +f 23/22/37 26/59/37 25/23/37 +f 24/24/38 26/60/38 23/25/38 +f 25/26/39 26/61/39 24/27/39 +f 32/46/40 27/11/40 33/29/40 +f 30/62/41 28/8/41 33/31/41 +f 31/50/42 29/4/42 33/33/42 +f 39/53/43 34/5/43 40/35/43 +f 37/49/44 35/7/44 40/37/44 +f 38/55/45 36/1/45 40/39/45 +f 21/9/17 23/25/17 17/16/17 +f 23/22/18 20/21/18 15/18/18 +f 5/12/19 6/63/19 25/26/19 +f 6/40/20 4/64/20 20/21/20 +f 13/2/21 18/14/21 3/41/21 +f 18/19/22 15/18/22 2/43/22 +f 28/8/23 30/62/23 24/24/23 +f 30/28/24 27/11/24 22/10/24 +f 32/32/25 29/4/25 9/45/25 +f 27/11/26 32/46/26 7/48/26 +f 31/30/27 28/8/27 37/49/27 +f 29/4/28 31/50/28 34/5/28 +f 39/38/29 36/1/29 12/52/29 +f 34/5/30 39/53/30 10/6/30 +f 38/36/31 35/7/31 16/17/31 +f 36/1/32 38/55/32 13/2/32 +f 20/21/33 4/64/33 2/43/33 diff --git a/src/datavisualization/engine/meshes/barSmooth.obj b/src/datavisualization/engine/meshes/barSmooth.obj new file mode 100644 index 00000000..aa4fdd92 --- /dev/null +++ b/src/datavisualization/engine/meshes/barSmooth.obj @@ -0,0 +1,214 @@ +# Blender v2.66 (sub 0) OBJ File: 'smoothcube.blend' +# www.blender.org +o Cube +v -0.980000 -1.000000 1.000000 +v -1.000000 -1.000000 0.980000 +v -0.994142 -1.000000 0.994142 +v -1.000000 -1.000000 -0.980000 +v -0.980000 -1.000000 -1.000000 +v -0.994142 -1.000000 -0.994142 +v 0.980000 -1.000000 -1.000000 +v 1.000000 -1.000000 -0.980000 +v 0.994142 -1.000000 -0.994142 +v 1.000000 -1.000000 0.980000 +v 0.980000 -1.000000 1.000000 +v 0.994142 -1.000000 0.994142 +v -0.980000 0.980000 1.000000 +v -0.980000 1.000000 0.980000 +v -1.000000 0.980000 0.980000 +v -0.980000 0.994142 0.994142 +v -0.994142 0.994142 0.980000 +v -0.994142 0.980000 0.994142 +v -0.992998 0.992998 0.992998 +v -1.000000 0.980000 -0.980000 +v -0.980000 1.000000 -0.980000 +v -0.980000 0.980000 -1.000000 +v -0.994142 0.994142 -0.980000 +v -0.980000 0.994142 -0.994142 +v -0.994142 0.980000 -0.994142 +v -0.992998 0.992998 -0.992998 +v 0.980000 0.980000 -1.000000 +v 0.980000 1.000000 -0.980000 +v 1.000000 0.980000 -0.980000 +v 0.980000 0.994142 -0.994142 +v 0.994142 0.994142 -0.980000 +v 0.994142 0.980000 -0.994142 +v 0.992998 0.992998 -0.992998 +v 1.000000 0.980000 0.980000 +v 0.980000 1.000000 0.980000 +v 0.980000 0.980000 1.000000 +v 0.994142 0.994142 0.980000 +v 0.980000 0.994142 0.994142 +v 0.994142 0.980000 0.994142 +v 0.992998 0.992998 0.992998 +vt 0.338795 0.668183 +vt 0.337784 0.338666 +vt 0.666630 0.337658 +vt 0.003512 0.668185 +vt 0.002502 0.338668 +vt 0.331348 0.337660 +vt 0.002378 0.003388 +vt 0.331894 0.002378 +vt 0.332905 0.331894 +vt 0.671154 0.332902 +vt 0.670143 0.003386 +vt 1.000000 0.331893 +vt 0.335282 0.338674 +vt 0.337624 0.336289 +vt 0.003388 0.332905 +vt 0.003396 0.335282 +vt 0.001011 0.332912 +vt 0.338795 0.332902 +vt 0.338649 0.335280 +vt 0.336293 0.332910 +vt 0.337784 0.003386 +vt 0.335282 0.003394 +vt 0.337624 0.001009 +vt 0.335282 0.331887 +vt 0.332912 0.334272 +vt 0.671008 0.335280 +vt 0.668652 0.332910 +vt 0.667641 0.003394 +vt 0.667795 0.001208 +vt 0.331887 0.000000 +vt 0.334073 0.000186 +vt 0.003367 0.670563 +vt 0.001178 0.670377 +vt 0.000000 0.338676 +vt 0.000153 0.336490 +vt 0.000000 0.003396 +vt 0.000186 0.001210 +vt 0.338649 0.670561 +vt 0.336460 0.670375 +vt 0.666470 0.000000 +vt 0.666470 0.335280 +vt 0.667496 0.334272 +vt 0.667641 0.331894 +vt 0.332359 0.667176 +vt 0.332213 0.669554 +vt 0.669983 0.001009 +vt 0.998829 0.000000 +vt 0.998989 0.002377 +vt 0.002370 0.001011 +vt 0.001011 0.668192 +vt 0.667641 0.667174 +vt 0.667496 0.669552 +vt 0.002341 0.336291 +vt 0.331188 0.335282 +vt 0.336293 0.668191 +vt 0.335436 0.336488 +vt 0.001210 0.335097 +vt 0.336460 0.335095 +vt 0.335436 0.001208 +vt 0.335097 0.334073 +vt 0.668819 0.335095 +vt 0.334272 0.002370 +vt 0.999855 0.334272 +vt 0.666630 0.002377 +vn 0.161046 0.161046 0.973693 +vn -0.187689 0.187689 0.964110 +vn -0.195074 0.000000 0.980773 +vn 0.973693 0.161046 -0.161046 +vn 0.973693 0.161046 0.161046 +vn 0.980773 0.000000 0.195074 +vn 0.161046 0.973693 0.161046 +vn 0.161046 0.973693 -0.161046 +vn -0.187689 0.964110 -0.187689 +vn -0.187689 0.187689 -0.964110 +vn 0.161046 0.161046 -0.973693 +vn -0.195074 0.000000 -0.980773 +vn -0.135655 0.700552 0.700552 +vn -0.700552 0.135655 0.700552 +vn -0.187689 0.964110 0.187689 +vn -0.700552 0.700552 0.135655 +vn -0.964110 0.187689 0.187689 +vn -0.964110 0.187689 -0.187689 +vn -0.700552 0.700552 -0.135655 +vn -0.700552 0.135655 -0.700552 +vn -0.135655 0.700552 -0.700552 +vn 0.060945 0.705771 -0.705771 +vn 0.577349 0.577349 -0.577349 +vn 0.705771 0.705771 -0.060945 +vn 0.705771 0.060945 -0.705771 +vn 0.705771 0.705771 0.060945 +vn 0.577349 0.577349 0.577349 +vn 0.060945 0.705771 0.705771 +vn 0.705771 0.060945 0.705771 +vn -0.707083 0.000000 -0.707083 +vn -0.707083 0.000000 0.707083 +vn -0.980773 0.000000 0.195074 +vn 0.980773 0.000000 -0.195074 +vn 0.707083 0.000000 -0.707083 +vn 0.195074 0.000000 -0.980773 +vn 0.195074 0.000000 0.980773 +vn 0.707083 0.000000 0.707083 +vn -0.577349 0.577349 0.577349 +vn -0.577349 0.577349 -0.577349 +vn -0.980773 0.000000 -0.195074 +s 1 +f 36/1/1 13/2/2 1/3/3 +f 29/4/4 34/5/5 10/6/6 +f 35/7/7 28/8/8 21/9/9 +f 22/10/10 27/11/11 5/12/12 +f 13/2/2 16/13/13 18/14/14 +f 14/15/15 17/16/16 16/17/13 +f 15/18/17 18/19/14 17/20/16 +f 20/21/18 23/22/19 25/23/20 +f 21/9/9 24/24/21 23/25/19 +f 22/10/10 25/26/20 24/27/21 +f 27/11/11 30/28/22 33/29/23 +f 28/8/8 31/30/24 33/31/23 +f 29/4/4 32/32/25 33/33/23 +f 34/5/5 37/34/26 40/35/27 +f 35/7/7 38/36/28 40/37/27 +f 36/1/1 39/38/29 40/39/27 +f 14/15/15 21/9/9 17/16/16 +f 17/20/16 23/22/19 15/18/17 +f 22/10/10 5/12/12 25/26/20 +f 25/23/20 6/40/30 20/21/18 +f 1/3/3 13/2/2 3/41/31 +f 3/42/31 18/19/14 2/43/32 +f 21/9/9 28/8/8 24/24/21 +f 24/27/21 30/28/22 22/10/10 +f 29/4/4 8/44/33 9/45/34 +f 32/46/25 9/47/34 7/48/35 +f 28/8/8 35/7/7 37/49/26 +f 31/50/24 37/34/26 34/5/5 +f 36/1/1 11/51/36 12/52/37 +f 39/53/29 12/54/37 10/6/6 +f 35/7/7 14/15/15 16/17/13 +f 38/55/28 16/13/13 13/2/2 +f 15/18/17 20/21/18 2/43/32 +f 11/51/36 36/1/1 1/3/3 +f 8/44/33 29/4/4 10/6/6 +f 14/15/15 35/7/7 21/9/9 +f 27/11/11 7/48/35 5/12/12 +f 16/13/13 19/56/38 18/14/14 +f 17/16/16 19/57/38 16/17/13 +f 18/19/14 19/58/38 17/20/16 +f 23/22/19 26/59/39 25/23/20 +f 24/24/21 26/60/39 23/25/19 +f 25/26/20 26/61/39 24/27/21 +f 32/46/25 27/11/11 33/29/23 +f 30/62/22 28/8/8 33/31/23 +f 31/50/24 29/4/4 33/33/23 +f 39/53/29 34/5/5 40/35/27 +f 37/49/26 35/7/7 40/37/27 +f 38/55/28 36/1/1 40/39/27 +f 21/9/9 23/25/19 17/16/16 +f 23/22/19 20/21/18 15/18/17 +f 5/12/12 6/63/30 25/26/20 +f 6/40/30 4/64/40 20/21/18 +f 13/2/2 18/14/14 3/41/31 +f 18/19/14 15/18/17 2/43/32 +f 28/8/8 30/62/22 24/24/21 +f 30/28/22 27/11/11 22/10/10 +f 32/32/25 29/4/4 9/45/34 +f 27/11/11 32/46/25 7/48/35 +f 31/30/24 28/8/8 37/49/26 +f 29/4/4 31/50/24 34/5/5 +f 39/38/29 36/1/1 12/52/37 +f 34/5/5 39/53/29 10/6/6 +f 38/36/28 35/7/7 16/17/13 +f 36/1/1 38/55/28 13/2/2 +f 20/21/18 4/64/40 2/43/32 diff --git a/src/datavisualization/engine/meshes/coneFilledFlat.obj b/src/datavisualization/engine/meshes/coneFilledFlat.obj new file mode 100644 index 00000000..cbbffaff --- /dev/null +++ b/src/datavisualization/engine/meshes/coneFilledFlat.obj @@ -0,0 +1,128 @@ +# Blender v2.66 (sub 0) OBJ File: 'cone_filled.blend' +# www.blender.org +o Cone_Cone.001 +v 0.000000 -1.000000 -1.000000 +v 0.309017 -1.000000 -0.951057 +v 0.587785 -1.000000 -0.809017 +v 0.809017 -1.000000 -0.587785 +v 0.951057 -1.000000 -0.309017 +v 1.000000 -1.000000 0.000000 +v 0.951056 -1.000000 0.309017 +v 0.809017 -1.000000 0.587785 +v 0.000000 1.000000 0.000000 +v 0.587785 -1.000000 0.809017 +v 0.309017 -1.000000 0.951057 +v -0.000000 -1.000000 1.000000 +v -0.309017 -1.000000 0.951056 +v -0.587786 -1.000000 0.809017 +v -0.809017 -1.000000 0.587785 +v -0.951057 -1.000000 0.309016 +v -1.000000 -1.000000 -0.000001 +v -0.951056 -1.000000 -0.309018 +v -0.809016 -1.000000 -0.587786 +v -0.587784 -1.000000 -0.809018 +v -0.309016 -1.000000 -0.951057 +vt 0.636534 0.537407 +vt 0.609784 0.926283 +vt 0.571680 0.562142 +vt 0.911640 0.504376 +vt 0.571680 0.368442 +vt 0.953118 0.448721 +vt 0.853526 0.537297 +vt 0.973901 0.375780 +vt 0.712378 0.537297 +vt 0.791787 0.561822 +vt 0.866987 0.608581 +vt 0.930618 0.672998 +vt 0.976451 0.748767 +vt 1.000000 0.828470 +vt 0.998959 0.904307 +vt 0.973430 0.968853 +vt 0.629860 0.006965 +vt 0.571746 0.039886 +vt 0.698921 0.000000 +vt 0.772169 0.019673 +vt 0.842434 0.064059 +vt 0.902837 0.128812 +vt 0.947467 0.207594 +vt 0.971954 0.292693 +vt 0.154453 0.543699 +vt 0.081201 0.490478 +vt 0.240567 0.571679 +vt 0.027980 0.417226 +vt 0.000000 0.331112 +vt 0.000000 0.240567 +vt 0.027980 0.154454 +vt 0.081201 0.081201 +vt 0.154454 0.027980 +vt 0.240567 0.000000 +vt 0.331112 0.000000 +vt 0.417226 0.027980 +vt 0.490479 0.081201 +vt 0.543700 0.154454 +vt 0.571680 0.240567 +vt 0.571680 0.331113 +vt 0.543699 0.417226 +vt 0.490478 0.490479 +vt 0.417226 0.543700 +vt 0.331112 0.571680 +vn -0.407058 0.442793 -0.798898 +vn 0.140263 0.442793 -0.885585 +vn -0.140262 0.442793 -0.885585 +vn 0.407059 0.442793 -0.798898 +vn -0.634008 0.442793 -0.634010 +vn -0.798897 0.442793 -0.407060 +vn -0.885585 0.442793 -0.140264 +vn -0.885585 0.442793 0.140262 +vn -0.798898 0.442793 0.407058 +vn -0.634009 0.442793 0.634009 +vn -0.407059 0.442793 0.798898 +vn -0.140263 0.442793 0.885585 +vn 0.140263 0.442793 0.885585 +vn 0.407059 0.442793 0.798898 +vn 0.634009 0.442793 0.634009 +vn 0.798898 0.442793 0.407059 +vn 0.885585 0.442793 0.140263 +vn 0.885585 0.442793 -0.140263 +vn 0.798898 0.442793 -0.407059 +vn 0.634009 0.442793 -0.634009 +vn -0.000000 -1.000000 -0.000000 +s off +f 20/1/1 9/2/1 21/3/1 +f 1/4/2 9/5/2 2/6/2 +f 21/7/3 9/5/3 1/4/3 +f 2/6/4 9/5/4 3/8/4 +f 19/9/5 9/2/5 20/1/5 +f 18/10/6 9/2/6 19/9/6 +f 17/11/7 9/2/7 18/10/7 +f 16/12/8 9/2/8 17/11/8 +f 15/13/9 9/2/9 16/12/9 +f 14/14/10 9/2/10 15/13/10 +f 13/15/11 9/2/11 14/14/11 +f 12/16/12 9/2/12 13/15/12 +f 11/17/13 9/5/13 12/18/13 +f 10/19/14 9/5/14 11/17/14 +f 8/20/15 9/5/15 10/19/15 +f 7/21/16 9/5/16 8/20/16 +f 6/22/17 9/5/17 7/21/17 +f 5/23/18 9/5/18 6/22/18 +f 4/24/19 9/5/19 5/23/19 +f 3/8/20 9/5/20 4/24/20 +f 21/25/21 1/26/21 20/27/21 +f 1/26/21 2/28/21 20/27/21 +f 2/28/21 3/29/21 20/27/21 +f 3/29/21 4/30/21 20/27/21 +f 4/30/21 5/31/21 20/27/21 +f 5/31/21 6/32/21 20/27/21 +f 6/32/21 7/33/21 20/27/21 +f 7/33/21 8/34/21 20/27/21 +f 8/34/21 10/35/21 20/27/21 +f 10/35/21 11/36/21 20/27/21 +f 11/36/21 12/37/21 20/27/21 +f 12/37/21 13/38/21 20/27/21 +f 13/38/21 14/39/21 20/27/21 +f 14/39/21 15/40/21 20/27/21 +f 15/40/21 16/41/21 20/27/21 +f 16/41/21 17/42/21 20/27/21 +f 17/42/21 18/43/21 19/44/21 +f 20/27/21 17/42/21 19/44/21 diff --git a/src/datavisualization/engine/meshes/coneFilledSmooth.obj b/src/datavisualization/engine/meshes/coneFilledSmooth.obj new file mode 100644 index 00000000..ea3a8702 --- /dev/null +++ b/src/datavisualization/engine/meshes/coneFilledSmooth.obj @@ -0,0 +1,128 @@ +# Blender v2.66 (sub 0) OBJ File: 'cone_filled.blend' +# www.blender.org +o Cone_Cone.001 +v 0.000000 -1.000000 -1.000000 +v 0.309017 -1.000000 -0.951057 +v 0.587785 -1.000000 -0.809017 +v 0.809017 -1.000000 -0.587785 +v 0.951057 -1.000000 -0.309017 +v 1.000000 -1.000000 0.000000 +v 0.951056 -1.000000 0.309017 +v 0.809017 -1.000000 0.587785 +v 0.000000 1.000000 0.000000 +v 0.587785 -1.000000 0.809017 +v 0.309017 -1.000000 0.951057 +v -0.000000 -1.000000 1.000000 +v -0.309017 -1.000000 0.951056 +v -0.587786 -1.000000 0.809017 +v -0.809017 -1.000000 0.587785 +v -0.951057 -1.000000 0.309016 +v -1.000000 -1.000000 -0.000001 +v -0.951056 -1.000000 -0.309018 +v -0.809016 -1.000000 -0.587786 +v -0.587784 -1.000000 -0.809018 +v -0.309016 -1.000000 -0.951057 +vt 0.636534 0.537407 +vt 0.609784 0.926283 +vt 0.571680 0.562142 +vt 0.911640 0.504376 +vt 0.571680 0.368442 +vt 0.953118 0.448721 +vt 0.853526 0.537297 +vt 0.973901 0.375780 +vt 0.712378 0.537297 +vt 0.791787 0.561822 +vt 0.866987 0.608581 +vt 0.930618 0.672998 +vt 0.976451 0.748767 +vt 1.000000 0.828470 +vt 0.998959 0.904307 +vt 0.973430 0.968853 +vt 0.629860 0.006965 +vt 0.571746 0.039886 +vt 0.698921 0.000000 +vt 0.772169 0.019673 +vt 0.842434 0.064059 +vt 0.902837 0.128812 +vt 0.947467 0.207594 +vt 0.971954 0.292693 +vt 0.154453 0.543699 +vt 0.081201 0.490478 +vt 0.240567 0.571679 +vt 0.027980 0.417226 +vt 0.000000 0.331112 +vt 0.000000 0.240567 +vt 0.027980 0.154454 +vt 0.081201 0.081201 +vt 0.154454 0.027980 +vt 0.240567 0.000000 +vt 0.331112 0.000000 +vt 0.417226 0.027980 +vt 0.490479 0.081201 +vt 0.543700 0.154454 +vt 0.571680 0.240567 +vt 0.571680 0.331113 +vt 0.543699 0.417226 +vt 0.490478 0.490479 +vt 0.417226 0.543700 +vt 0.331112 0.571680 +vn -0.512009 -0.491043 -0.704733 +vn 0.000000 1.000000 0.000000 +vn -0.269173 -0.491043 -0.828486 +vn 0.000000 -0.491043 -0.871120 +vn 0.269173 -0.491043 -0.828486 +vn 0.512009 -0.491043 -0.704733 +vn -0.704733 -0.491043 -0.512040 +vn -0.828486 -0.491043 -0.269173 +vn -0.871120 -0.491043 0.000000 +vn -0.828486 -0.491043 0.269173 +vn -0.704733 -0.491043 0.512009 +vn -0.512009 -0.491043 0.704733 +vn -0.269173 -0.491043 0.828486 +vn 0.000000 -0.491043 0.871120 +vn 0.269173 -0.491043 0.828486 +vn 0.512009 -0.491043 0.704733 +vn 0.704733 -0.491043 0.512009 +vn 0.828486 -0.491043 0.269173 +vn 0.871120 -0.491043 0.000000 +vn 0.828486 -0.491043 -0.269173 +vn 0.704733 -0.491043 -0.512009 +s 1 +f 20/1/1 9/2/2 21/3/3 +f 1/4/4 9/5/2 2/6/5 +f 21/7/3 9/5/2 1/4/4 +f 2/6/5 9/5/2 3/8/6 +f 19/9/7 9/2/2 20/1/1 +f 18/10/8 9/2/2 19/9/7 +f 17/11/9 9/2/2 18/10/8 +f 16/12/10 9/2/2 17/11/9 +f 15/13/11 9/2/2 16/12/10 +f 14/14/12 9/2/2 15/13/11 +f 13/15/13 9/2/2 14/14/12 +f 12/16/14 9/2/2 13/15/13 +f 11/17/15 9/5/2 12/18/14 +f 10/19/16 9/5/2 11/17/15 +f 8/20/17 9/5/2 10/19/16 +f 7/21/18 9/5/2 8/20/17 +f 6/22/19 9/5/2 7/21/18 +f 5/23/20 9/5/2 6/22/19 +f 4/24/21 9/5/2 5/23/20 +f 3/8/6 9/5/2 4/24/21 +f 21/25/3 1/26/4 20/27/1 +f 1/26/4 2/28/5 20/27/1 +f 2/28/5 3/29/6 20/27/1 +f 3/29/6 4/30/21 20/27/1 +f 4/30/21 5/31/20 20/27/1 +f 5/31/20 6/32/19 20/27/1 +f 6/32/19 7/33/18 20/27/1 +f 7/33/18 8/34/17 20/27/1 +f 8/34/17 10/35/16 20/27/1 +f 10/35/16 11/36/15 20/27/1 +f 11/36/15 12/37/14 20/27/1 +f 12/37/14 13/38/13 20/27/1 +f 13/38/13 14/39/12 20/27/1 +f 14/39/12 15/40/11 20/27/1 +f 15/40/11 16/41/10 20/27/1 +f 16/41/10 17/42/9 20/27/1 +f 17/42/9 18/43/8 19/44/7 +f 20/27/1 17/42/9 19/44/7 diff --git a/src/datavisualization/engine/meshes/coneFlat.obj b/src/datavisualization/engine/meshes/coneFlat.obj new file mode 100644 index 00000000..51c3821e --- /dev/null +++ b/src/datavisualization/engine/meshes/coneFlat.obj @@ -0,0 +1,89 @@ +# Blender v2.66 (sub 0) OBJ File: 'cone.blend' +# www.blender.org +o Cone_Cone.001 +v 0.000000 -1.000000 -1.000000 +v 0.309017 -1.000000 -0.951057 +v 0.587785 -1.000000 -0.809017 +v 0.809017 -1.000000 -0.587785 +v 0.951057 -1.000000 -0.309017 +v 1.000000 -1.000000 0.000000 +v 0.951056 -1.000000 0.309017 +v 0.809017 -1.000000 0.587785 +v 0.000000 1.000000 0.000000 +v 0.587785 -1.000000 0.809017 +v 0.309017 -1.000000 0.951057 +v -0.000000 -1.000000 1.000000 +v -0.309017 -1.000000 0.951056 +v -0.587786 -1.000000 0.809017 +v -0.809017 -1.000000 0.587785 +v -0.951057 -1.000000 0.309016 +v -1.000000 -1.000000 -0.000001 +v -0.951056 -1.000000 -0.309018 +v -0.809016 -1.000000 -0.587786 +v -0.587784 -1.000000 -0.809018 +v -0.309016 -1.000000 -0.951057 +vt 0.018984 0.308330 +vt 0.500000 0.482045 +vt 0.000000 0.410924 +vt 0.011213 0.505476 +vt 0.051524 0.582730 +vt 0.116989 0.635124 +vt 0.066306 0.207736 +vt 0.137334 0.118990 +vt 0.225115 0.050777 +vt 0.321057 0.009776 +vt 0.415768 0.000000 +vt 0.499978 0.022406 +vt 0.551525 0.582730 +vt 1.000000 0.482045 +vt 0.616989 0.635125 +vt 0.511213 0.505476 +vt 0.500000 0.410924 +vt 0.518984 0.308330 +vt 0.566306 0.207736 +vt 0.637334 0.118990 +vt 0.725115 0.050777 +vt 0.821057 0.009776 +vt 0.915768 0.000000 +vt 0.999978 0.022406 +vn -0.407058 0.442793 -0.798898 +vn 0.140263 0.442793 -0.885585 +vn -0.140262 0.442793 -0.885585 +vn 0.407059 0.442793 -0.798898 +vn -0.634008 0.442793 -0.634010 +vn -0.798897 0.442793 -0.407060 +vn -0.885585 0.442793 -0.140264 +vn -0.885585 0.442793 0.140262 +vn -0.798898 0.442793 0.407058 +vn -0.634009 0.442793 0.634009 +vn -0.407059 0.442793 0.798898 +vn -0.140263 0.442793 0.885585 +vn 0.140263 0.442793 0.885585 +vn 0.407059 0.442793 0.798898 +vn 0.634009 0.442793 0.634009 +vn 0.798898 0.442793 0.407059 +vn 0.885585 0.442793 0.140263 +vn 0.885585 0.442793 -0.140263 +vn 0.798898 0.442793 -0.407059 +vn 0.634009 0.442793 -0.634009 +s off +f 20/1/1 9/2/1 21/3/1 +f 1/4/2 9/2/2 2/5/2 +f 21/3/3 9/2/3 1/4/3 +f 2/5/4 9/2/4 3/6/4 +f 19/7/5 9/2/5 20/1/5 +f 18/8/6 9/2/6 19/7/6 +f 17/9/7 9/2/7 18/8/7 +f 16/10/8 9/2/8 17/9/8 +f 15/11/9 9/2/9 16/10/9 +f 14/12/10 9/2/10 15/11/10 +f 13/13/11 9/14/11 14/15/11 +f 12/16/12 9/14/12 13/13/12 +f 11/17/13 9/14/13 12/16/13 +f 10/18/14 9/14/14 11/17/14 +f 8/19/15 9/14/15 10/18/15 +f 7/20/16 9/14/16 8/19/16 +f 6/21/17 9/14/17 7/20/17 +f 5/22/18 9/14/18 6/21/18 +f 4/23/19 9/14/19 5/22/19 +f 3/24/20 9/14/20 4/23/20 diff --git a/src/datavisualization/engine/meshes/coneSmooth.obj b/src/datavisualization/engine/meshes/coneSmooth.obj new file mode 100644 index 00000000..48c48ba8 --- /dev/null +++ b/src/datavisualization/engine/meshes/coneSmooth.obj @@ -0,0 +1,90 @@ +# Blender v2.66 (sub 0) OBJ File: 'cone.blend' +# www.blender.org +o Cone_Cone.001 +v 0.000000 -1.000000 -1.000000 +v 0.309017 -1.000000 -0.951057 +v 0.587785 -1.000000 -0.809017 +v 0.809017 -1.000000 -0.587785 +v 0.951057 -1.000000 -0.309017 +v 1.000000 -1.000000 0.000000 +v 0.951056 -1.000000 0.309017 +v 0.809017 -1.000000 0.587785 +v 0.000000 1.000000 0.000000 +v 0.587785 -1.000000 0.809017 +v 0.309017 -1.000000 0.951057 +v -0.000000 -1.000000 1.000000 +v -0.309017 -1.000000 0.951056 +v -0.587786 -1.000000 0.809017 +v -0.809017 -1.000000 0.587785 +v -0.951057 -1.000000 0.309016 +v -1.000000 -1.000000 -0.000001 +v -0.951056 -1.000000 -0.309018 +v -0.809016 -1.000000 -0.587786 +v -0.587784 -1.000000 -0.809018 +v -0.309016 -1.000000 -0.951057 +vt 0.018984 0.308330 +vt 0.500000 0.482045 +vt 0.000000 0.410924 +vt 0.011213 0.505476 +vt 0.051524 0.582730 +vt 0.116989 0.635124 +vt 0.066306 0.207736 +vt 0.137334 0.118990 +vt 0.225115 0.050777 +vt 0.321057 0.009776 +vt 0.415768 0.000000 +vt 0.499978 0.022406 +vt 0.551525 0.582730 +vt 1.000000 0.482045 +vt 0.616989 0.635125 +vt 0.511213 0.505476 +vt 0.500000 0.410924 +vt 0.518984 0.308330 +vt 0.566306 0.207736 +vt 0.637334 0.118990 +vt 0.725115 0.050777 +vt 0.821057 0.009776 +vt 0.915768 0.000000 +vt 0.999978 0.022406 +vn -0.525712 0.447188 -0.723594 +vn 0.000000 1.000000 0.000000 +vn -0.276376 0.447188 -0.850642 +vn 0.000000 0.447188 -0.894406 +vn 0.276376 0.447188 -0.850642 +vn 0.525712 0.447188 -0.723594 +vn -0.723594 0.447188 -0.525712 +vn -0.850642 0.447188 -0.276376 +vn -0.894406 0.447188 0.000000 +vn -0.850642 0.447188 0.276376 +vn -0.723594 0.447188 0.525712 +vn -0.525712 0.447188 0.723594 +vn -0.276376 0.447188 0.850642 +vn 0.000000 0.447188 0.894406 +vn 0.276376 0.447188 0.850642 +vn 0.525712 0.447188 0.723594 +vn 0.723594 0.447188 0.525712 +vn 0.850642 0.447188 0.276376 +vn 0.894406 0.447188 0.000000 +vn 0.850642 0.447188 -0.276376 +vn 0.723594 0.447188 -0.525712 +s 1 +f 20/1/1 9/2/2 21/3/3 +f 1/4/4 9/2/2 2/5/5 +f 21/3/3 9/2/2 1/4/4 +f 2/5/5 9/2/2 3/6/6 +f 19/7/7 9/2/2 20/1/1 +f 18/8/8 9/2/2 19/7/7 +f 17/9/9 9/2/2 18/8/8 +f 16/10/10 9/2/2 17/9/9 +f 15/11/11 9/2/2 16/10/10 +f 14/12/12 9/2/2 15/11/11 +f 13/13/13 9/14/2 14/15/12 +f 12/16/14 9/14/2 13/13/13 +f 11/17/15 9/14/2 12/16/14 +f 10/18/16 9/14/2 11/17/15 +f 8/19/17 9/14/2 10/18/16 +f 7/20/18 9/14/2 8/19/17 +f 6/21/19 9/14/2 7/20/18 +f 5/22/20 9/14/2 6/21/19 +f 4/23/21 9/14/2 5/22/20 +f 3/24/6 9/14/2 4/23/21 diff --git a/src/datavisualization/engine/meshes/cubeFilledFlat.obj b/src/datavisualization/engine/meshes/cubeFilledFlat.obj new file mode 100644 index 00000000..108cf7ac --- /dev/null +++ b/src/datavisualization/engine/meshes/cubeFilledFlat.obj @@ -0,0 +1,54 @@ +# Blender v2.66 (sub 0) OBJ File: 'cube_filled.blend' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +vt 0.666667 0.332314 +vt 0.334353 0.333333 +vt 0.665647 0.000000 +vt 0.001020 0.333333 +vt 0.000000 0.001020 +vt 0.333333 0.332314 +vt 0.333333 0.665647 +vt 0.001019 0.666667 +vt 0.000000 0.334353 +vt 0.334353 0.666667 +vt 0.333333 0.334353 +vt 0.665647 0.333333 +vt 0.333333 0.667686 +vt 0.665647 0.666667 +vt 0.666667 0.998980 +vt 0.667686 0.333333 +vt 0.666667 0.001019 +vt 0.998980 0.000000 +vt 0.333333 0.001019 +vt 0.332314 0.000000 +vt 0.332314 0.333333 +vt 0.666667 0.665647 +vt 0.334353 1.000000 +vt 1.000000 0.332314 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 1.000000 -0.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 1.000000 0.000000 +vn -0.000000 -1.000000 -0.000000 +s off +f 5/1/1 6/2/1 1/3/1 +f 6/4/2 7/5/2 2/6/2 +f 7/7/3 8/8/3 4/9/3 +f 8/10/4 5/11/4 1/12/4 +f 8/13/5 7/14/5 6/15/5 +f 2/16/6 3/17/6 4/18/6 +f 6/2/1 2/19/1 1/3/1 +f 7/5/2 3/20/2 2/6/2 +f 3/21/3 7/7/3 4/9/3 +f 4/22/4 8/10/4 1/12/4 +f 5/23/5 8/13/5 6/15/5 +f 1/24/6 2/16/6 4/18/6 diff --git a/src/datavisualization/engine/meshes/cubeFilledSmooth.obj b/src/datavisualization/engine/meshes/cubeFilledSmooth.obj new file mode 100644 index 00000000..07350f03 --- /dev/null +++ b/src/datavisualization/engine/meshes/cubeFilledSmooth.obj @@ -0,0 +1,56 @@ +# Blender v2.66 (sub 0) OBJ File: 'cube_filled.blend' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +vt 0.666667 0.332314 +vt 0.334353 0.333333 +vt 0.665647 0.000000 +vt 0.001020 0.333333 +vt 0.000000 0.001020 +vt 0.333333 0.332314 +vt 0.333333 0.665647 +vt 0.001019 0.666667 +vt 0.000000 0.334353 +vt 0.334353 0.666667 +vt 0.333333 0.334353 +vt 0.665647 0.333333 +vt 0.333333 0.667686 +vt 0.665647 0.666667 +vt 0.666667 0.998980 +vt 0.667686 0.333333 +vt 0.666667 0.001019 +vt 0.998980 0.000000 +vt 0.333333 0.001019 +vt 0.332314 0.000000 +vt 0.332314 0.333333 +vt 0.666667 0.665647 +vt 0.334353 1.000000 +vt 1.000000 0.332314 +vn -0.577349 0.577349 0.577349 +vn -0.577349 0.577349 -0.577349 +vn -0.577349 -0.577349 0.577349 +vn 0.577349 0.577349 -0.577349 +vn -0.577349 -0.577349 -0.577349 +vn 0.577349 0.577349 0.577349 +vn 0.577349 -0.577349 0.577349 +vn 0.577349 -0.577349 -0.577349 +s 1 +f 5/1/1 6/2/2 1/3/3 +f 6/4/2 7/5/4 2/6/5 +f 7/7/4 8/8/6 4/9/7 +f 8/10/6 5/11/1 1/12/3 +f 8/13/6 7/14/4 6/15/2 +f 2/16/5 3/17/8 4/18/7 +f 6/2/2 2/19/5 1/3/3 +f 7/5/4 3/20/8 2/6/5 +f 3/21/8 7/7/4 4/9/7 +f 4/22/7 8/10/6 1/12/3 +f 5/23/1 8/13/6 6/15/2 +f 1/24/3 2/16/5 4/18/7 diff --git a/src/datavisualization/engine/meshes/cubeFlat.obj b/src/datavisualization/engine/meshes/cubeFlat.obj new file mode 100644 index 00000000..3c8d6d0a --- /dev/null +++ b/src/datavisualization/engine/meshes/cubeFlat.obj @@ -0,0 +1,47 @@ +# Blender v2.66 (sub 0) OBJ File: 'cube.blend' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +vt 0.998999 0.334334 +vt 0.667668 0.334334 +vt 0.998999 0.665666 +vt 0.332332 0.001001 +vt 0.001001 0.001001 +vt 0.332332 0.332332 +vt 0.332332 0.334334 +vt 0.001001 0.334334 +vt 0.001001 0.665666 +vt 0.665666 0.001001 +vt 0.334334 0.001001 +vt 0.334334 0.332332 +vt 0.665666 0.334334 +vt 0.334334 0.334334 +vt 0.334334 0.665666 +vt 0.667668 0.665666 +vt 0.001001 0.332332 +vt 0.332332 0.665666 +vt 0.665666 0.332332 +vt 0.665666 0.665666 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 1.000000 -0.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 1.000000 0.000000 +s off +f 5/1/1 6/2/1 1/3/1 +f 6/4/2 7/5/2 2/6/2 +f 7/7/3 8/8/3 4/9/3 +f 8/10/4 5/11/4 1/12/4 +f 8/13/5 7/14/5 6/15/5 +f 6/2/1 2/16/1 1/3/1 +f 7/5/2 3/17/2 2/6/2 +f 3/18/3 7/7/3 4/9/3 +f 4/19/4 8/10/4 1/12/4 +f 5/20/5 8/13/5 6/15/5 diff --git a/src/datavisualization/engine/meshes/cubeSmooth.obj b/src/datavisualization/engine/meshes/cubeSmooth.obj new file mode 100644 index 00000000..9d147bfd --- /dev/null +++ b/src/datavisualization/engine/meshes/cubeSmooth.obj @@ -0,0 +1,50 @@ +# Blender v2.66 (sub 0) OBJ File: 'cube.blend' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +vt 0.998999 0.334334 +vt 0.667668 0.334334 +vt 0.998999 0.665666 +vt 0.332332 0.001001 +vt 0.001001 0.001001 +vt 0.332332 0.332332 +vt 0.332332 0.334334 +vt 0.001001 0.334334 +vt 0.001001 0.665666 +vt 0.665666 0.001001 +vt 0.334334 0.001001 +vt 0.334334 0.332332 +vt 0.665666 0.334334 +vt 0.334334 0.334334 +vt 0.334334 0.665666 +vt 0.667668 0.665666 +vt 0.001001 0.332332 +vt 0.332332 0.665666 +vt 0.665666 0.332332 +vt 0.665666 0.665666 +vn -0.577349 0.577349 0.577349 +vn -0.577349 0.577349 -0.577349 +vn -0.707083 0.000000 0.707083 +vn 0.577349 0.577349 -0.577349 +vn -0.707083 0.000000 -0.707083 +vn 0.577349 0.577349 0.577349 +vn 0.707083 0.000000 0.707083 +vn 0.707083 0.000000 -0.707083 +s 1 +f 5/1/1 6/2/2 1/3/3 +f 6/4/2 7/5/4 2/6/5 +f 7/7/4 8/8/6 4/9/7 +f 8/10/6 5/11/1 1/12/3 +f 8/13/6 7/14/4 6/15/2 +f 6/2/2 2/16/5 1/3/3 +f 7/5/4 3/17/8 2/6/5 +f 3/18/8 7/7/4 4/9/7 +f 4/19/7 8/10/6 1/12/3 +f 5/20/1 8/13/6 6/15/2 diff --git a/src/datavisualization/engine/meshes/cylinderFilledFlat.obj b/src/datavisualization/engine/meshes/cylinderFilledFlat.obj new file mode 100644 index 00000000..16c2ef36 --- /dev/null +++ b/src/datavisualization/engine/meshes/cylinderFilledFlat.obj @@ -0,0 +1,361 @@ +# Blender v2.66 (sub 0) OBJ File: 'cylinder_filled.blend' +# www.blender.org +o Cylinder +v 0.000000 -1.000000 -1.000000 +v 0.000000 1.000000 -1.000000 +v 0.195090 -1.000000 -0.980785 +v 0.195090 1.000000 -0.980785 +v 0.382683 -1.000000 -0.923880 +v 0.382683 1.000000 -0.923880 +v 0.555570 -1.000000 -0.831470 +v 0.555570 1.000000 -0.831470 +v 0.707107 -1.000000 -0.707107 +v 0.707107 1.000000 -0.707107 +v 0.831470 -1.000000 -0.555570 +v 0.831470 1.000000 -0.555570 +v 0.923880 -1.000000 -0.382683 +v 0.923880 1.000000 -0.382683 +v 0.980785 -1.000000 -0.195090 +v 0.980785 1.000000 -0.195090 +v 1.000000 -1.000000 -0.000000 +v 1.000000 1.000000 -0.000000 +v 0.980785 -1.000000 0.195090 +v 0.980785 1.000000 0.195090 +v 0.923880 -1.000000 0.382683 +v 0.923880 1.000000 0.382683 +v 0.831470 -1.000000 0.555570 +v 0.831470 1.000000 0.555570 +v 0.707107 -1.000000 0.707107 +v 0.707107 1.000000 0.707107 +v 0.555570 -1.000000 0.831470 +v 0.555570 1.000000 0.831470 +v 0.382683 -1.000000 0.923880 +v 0.382683 1.000000 0.923880 +v 0.195090 -1.000000 0.980785 +v 0.195090 1.000000 0.980785 +v -0.000000 -1.000000 1.000000 +v -0.000000 1.000000 1.000000 +v -0.195091 -1.000000 0.980785 +v -0.195091 1.000000 0.980785 +v -0.382684 -1.000000 0.923879 +v -0.382684 1.000000 0.923879 +v -0.555571 -1.000000 0.831469 +v -0.555571 1.000000 0.831469 +v -0.707107 -1.000000 0.707106 +v -0.707107 1.000000 0.707106 +v -0.831470 -1.000000 0.555570 +v -0.831470 1.000000 0.555570 +v -0.923880 -1.000000 0.382683 +v -0.923880 1.000000 0.382683 +v -0.980785 -1.000000 0.195089 +v -0.980785 1.000000 0.195089 +v -1.000000 -1.000000 -0.000001 +v -1.000000 1.000000 -0.000001 +v -0.980785 -1.000000 -0.195091 +v -0.980785 1.000000 -0.195091 +v -0.923879 -1.000000 -0.382684 +v -0.923879 1.000000 -0.382684 +v -0.831469 -1.000000 -0.555571 +v -0.831469 1.000000 -0.555571 +v -0.707106 -1.000000 -0.707108 +v -0.707106 1.000000 -0.707108 +v -0.555569 -1.000000 -0.831470 +v -0.555569 1.000000 -0.831470 +v -0.382682 -1.000000 -0.923880 +v -0.382682 1.000000 -0.923880 +v -0.195089 -1.000000 -0.980786 +v -0.195089 1.000000 -0.980786 +vt 0.059001 0.355439 +vt 0.057906 0.712417 +vt 0.027048 0.712322 +vt 0.028143 0.355344 +vt 0.000000 0.712239 +vt 0.998905 0.355261 +vt 1.000000 0.712239 +vt 0.972952 0.712322 +vt 0.971857 0.355344 +vt 0.942094 0.712417 +vt 0.940999 0.355439 +vt 0.908611 0.712520 +vt 0.907515 0.355541 +vt 0.873789 0.712627 +vt 0.872694 0.355648 +vt 0.838968 0.712733 +vt 0.837872 0.355755 +vt 0.805484 0.712836 +vt 0.777341 0.713350 +vt 0.776246 1.070328 +vt 0.742763 1.070225 +vt 0.743858 0.713247 +vt 0.707941 1.070119 +vt 0.709036 0.713140 +vt 0.673120 1.070012 +vt 0.674215 0.713033 +vt 0.639636 1.069909 +vt 0.640732 0.712931 +vt 0.608778 1.069814 +vt 0.609873 0.712836 +vt 0.608778 0.355858 +vt 0.642261 0.355755 +vt 0.643357 0.712733 +vt 0.677083 0.355648 +vt 0.678178 0.712627 +vt 0.711904 0.355541 +vt 0.713000 0.712520 +vt 0.746483 0.712417 +vt 0.745388 0.355439 +vt 0.777341 0.712322 +vt 0.776246 0.355344 +vt 0.804389 0.712239 +vt 0.607683 0.355261 +vt 0.608778 0.712239 +vt 0.580635 0.355344 +vt 0.581730 0.712322 +vt 0.549777 0.355439 +vt 0.550872 0.712417 +vt 0.516293 0.355541 +vt 0.517389 0.712520 +vt 0.481472 0.355648 +vt 0.482567 0.712627 +vt 0.446650 0.355755 +vt 0.447746 0.712733 +vt 0.413167 0.355858 +vt 0.414262 0.712836 +vt 0.382309 0.355952 +vt 0.383404 0.712931 +vt 0.355261 0.356035 +vt 0.226469 0.355952 +vt 0.225374 0.712931 +vt 0.195611 0.355858 +vt 0.194516 0.712836 +vt 0.162127 0.355755 +vt 0.161032 0.712733 +vt 0.127306 0.355648 +vt 0.000000 0.160135 +vt 0.006826 0.125818 +vt 0.000000 0.195126 +vt 0.092484 0.355541 +vt 0.091389 0.712520 +vt 0.126211 0.712627 +vt 0.394917 0.290863 +vt 0.375477 0.261770 +vt 0.419658 0.315605 +vt 0.001095 0.355261 +vt 0.804389 0.355858 +vt 0.803294 0.355261 +vt 0.356356 0.713014 +vt 0.020216 0.093491 +vt 0.039656 0.064398 +vt 0.064397 0.039656 +vt 0.093491 0.020217 +vt 0.125817 0.006826 +vt 0.160135 0.000000 +vt 0.195125 0.000000 +vt 0.229443 0.006826 +vt 0.261770 0.020216 +vt 0.290863 0.039656 +vt 0.315605 0.064398 +vt 0.335045 0.093491 +vt 0.348435 0.125818 +vt 0.355261 0.160135 +vt 0.355261 0.195126 +vt 0.348435 0.229443 +vt 0.335045 0.261770 +vt 0.315605 0.290863 +vt 0.290863 0.315605 +vt 0.261770 0.335045 +vt 0.229443 0.348435 +vt 0.195126 0.355261 +vt 0.160135 0.355261 +vt 0.125818 0.348435 +vt 0.093491 0.335045 +vt 0.064398 0.315605 +vt 0.039656 0.290863 +vt 0.020216 0.261770 +vt 0.006826 0.229443 +vt 0.362087 0.229443 +vt 0.362087 0.125818 +vt 0.375477 0.093491 +vt 0.394917 0.064398 +vt 0.419659 0.039656 +vt 0.448752 0.020216 +vt 0.481079 0.006826 +vt 0.515396 0.000000 +vt 0.550387 0.000000 +vt 0.584704 0.006826 +vt 0.617031 0.020216 +vt 0.646124 0.039656 +vt 0.670866 0.064398 +vt 0.690306 0.093491 +vt 0.703696 0.125818 +vt 0.710522 0.160136 +vt 0.710522 0.195126 +vt 0.703696 0.229444 +vt 0.690306 0.261770 +vt 0.670866 0.290864 +vt 0.646124 0.315605 +vt 0.617031 0.335045 +vt 0.584704 0.348435 +vt 0.550386 0.355261 +vt 0.515396 0.355261 +vt 0.481078 0.348435 +vt 0.448752 0.335045 +vn 0.098017 0.000000 -0.995185 +vn 0.290285 0.000000 -0.956940 +vn 0.471397 0.000000 -0.881921 +vn 0.634393 0.000000 -0.773010 +vn 0.773010 0.000000 -0.634393 +vn 0.881921 0.000000 -0.471397 +vn 0.956940 0.000000 -0.290285 +vn 0.995185 0.000000 -0.098017 +vn 0.995185 0.000000 0.098017 +vn 0.956940 0.000000 0.290285 +vn 0.881921 0.000000 0.471396 +vn 0.773010 0.000000 0.634393 +vn 0.634393 0.000000 0.773010 +vn 0.471397 0.000000 0.881921 +vn 0.290284 0.000000 0.956940 +vn 0.098017 0.000000 0.995185 +vn -0.098018 0.000000 0.995185 +vn -0.290285 0.000000 0.956940 +vn -0.471397 0.000000 0.881921 +vn -0.634394 0.000000 0.773010 +vn -0.773011 0.000000 0.634393 +vn -0.881922 0.000000 0.471396 +vn -0.956941 0.000000 0.290284 +vn -0.995185 0.000000 0.098016 +vn -0.995185 -0.000000 -0.098018 +vn -0.956940 -0.000000 -0.290286 +vn -0.881921 -0.000000 -0.471398 +vn -0.773010 -0.000000 -0.634394 +vn -0.634392 -0.000000 -0.773011 +vn -0.471395 -0.000000 -0.881922 +vn -0.000000 1.000000 0.000000 +vn -0.098017 -0.000000 -0.995185 +vn -0.290283 -0.000000 -0.956941 +vn -0.000000 -1.000000 -0.000000 +s off +f 1/1/1 2/2/1 4/3/1 +f 3/4/2 4/3/2 6/5/2 +f 5/6/3 6/7/3 8/8/3 +f 7/9/4 8/8/4 10/10/4 +f 9/11/5 10/10/5 12/12/5 +f 11/13/6 12/12/6 14/14/6 +f 13/15/7 14/14/7 16/16/7 +f 15/17/8 16/16/8 18/18/8 +f 17/19/9 18/20/9 20/21/9 +f 19/22/10 20/21/10 22/23/10 +f 21/24/11 22/23/11 24/25/11 +f 23/26/12 24/25/12 26/27/12 +f 25/28/13 26/27/13 28/29/13 +f 27/30/14 28/31/14 30/32/14 +f 29/33/15 30/32/15 32/34/15 +f 31/35/16 32/34/16 34/36/16 +f 33/37/17 34/36/17 35/38/17 +f 35/38/18 36/39/18 37/40/18 +f 37/40/19 38/41/19 39/42/19 +f 39/43/20 40/44/20 41/45/20 +f 41/45/21 42/46/21 43/47/21 +f 43/47/22 44/48/22 45/49/22 +f 45/49/23 46/50/23 47/51/23 +f 47/51/24 48/52/24 49/53/24 +f 49/53/25 50/54/25 51/55/25 +f 51/55/26 52/56/26 53/57/26 +f 53/57/27 54/58/27 55/59/27 +f 55/60/28 56/61/28 57/62/28 +f 57/62/29 58/63/29 59/64/29 +f 59/64/30 60/65/30 61/66/30 +f 4/67/31 2/68/31 6/69/31 +f 63/70/32 64/71/32 1/1/32 +f 61/66/33 62/72/33 63/70/33 +f 63/73/34 1/74/34 61/75/34 +f 3/4/1 1/1/1 4/3/1 +f 5/76/2 3/4/2 6/5/2 +f 7/9/3 5/6/3 8/8/3 +f 9/11/4 7/9/4 10/10/4 +f 11/13/5 9/11/5 12/12/5 +f 13/15/6 11/13/6 14/14/6 +f 15/17/7 13/15/7 16/16/7 +f 17/77/8 15/17/8 18/18/8 +f 19/22/9 17/19/9 20/21/9 +f 21/24/10 19/22/10 22/23/10 +f 23/26/11 21/24/11 24/25/11 +f 25/28/12 23/26/12 26/27/12 +f 27/30/13 25/28/13 28/29/13 +f 29/33/14 27/30/14 30/32/14 +f 31/35/15 29/33/15 32/34/15 +f 33/37/16 31/35/16 34/36/16 +f 34/36/17 36/39/17 35/38/17 +f 36/39/18 38/41/18 37/40/18 +f 38/41/19 40/78/19 39/42/19 +f 40/44/20 42/46/20 41/45/20 +f 42/46/21 44/48/21 43/47/21 +f 44/48/22 46/50/22 45/49/22 +f 46/50/23 48/52/23 47/51/23 +f 48/52/24 50/54/24 49/53/24 +f 50/54/25 52/56/25 51/55/25 +f 52/56/26 54/58/26 53/57/26 +f 54/58/27 56/79/27 55/59/27 +f 56/61/28 58/63/28 57/62/28 +f 58/63/29 60/65/29 59/64/29 +f 60/65/30 62/72/30 61/66/30 +f 2/68/31 64/80/31 6/69/31 +f 64/80/31 62/81/31 6/69/31 +f 62/81/31 60/82/31 6/69/31 +f 60/82/31 58/83/31 6/69/31 +f 58/83/31 56/84/31 6/69/31 +f 56/84/31 54/85/31 6/69/31 +f 54/85/31 52/86/31 6/69/31 +f 52/86/31 50/87/31 6/69/31 +f 50/87/31 48/88/31 6/69/31 +f 48/88/31 46/89/31 6/69/31 +f 46/89/31 44/90/31 6/69/31 +f 44/90/31 42/91/31 6/69/31 +f 42/91/31 40/92/31 6/69/31 +f 40/92/31 38/93/31 6/69/31 +f 38/93/31 36/94/31 6/69/31 +f 36/94/31 34/95/31 6/69/31 +f 34/95/31 32/96/31 6/69/31 +f 32/96/31 30/97/31 6/69/31 +f 30/97/31 28/98/31 6/69/31 +f 28/98/31 26/99/31 6/69/31 +f 26/99/31 24/100/31 6/69/31 +f 24/100/31 22/101/31 6/69/31 +f 22/101/31 20/102/31 6/69/31 +f 20/102/31 18/103/31 6/69/31 +f 18/103/31 16/104/31 6/69/31 +f 16/104/31 14/105/31 6/69/31 +f 14/105/31 12/106/31 6/69/31 +f 12/106/31 10/107/31 8/108/31 +f 6/69/31 12/106/31 8/108/31 +f 64/71/32 2/2/32 1/1/32 +f 62/72/33 64/71/33 63/70/33 +f 1/74/34 3/109/34 61/75/34 +f 3/109/34 5/94/34 61/75/34 +f 5/94/34 7/93/34 61/75/34 +f 7/93/34 9/110/34 61/75/34 +f 9/110/34 11/111/34 61/75/34 +f 11/111/34 13/112/34 61/75/34 +f 13/112/34 15/113/34 61/75/34 +f 15/113/34 17/114/34 61/75/34 +f 17/114/34 19/115/34 61/75/34 +f 19/115/34 21/116/34 61/75/34 +f 21/116/34 23/117/34 61/75/34 +f 23/117/34 25/118/34 61/75/34 +f 25/118/34 27/119/34 61/75/34 +f 27/119/34 29/120/34 61/75/34 +f 29/120/34 31/121/34 61/75/34 +f 31/121/34 33/122/34 61/75/34 +f 33/122/34 35/123/34 61/75/34 +f 35/123/34 37/124/34 61/75/34 +f 37/124/34 39/125/34 61/75/34 +f 39/125/34 41/126/34 61/75/34 +f 41/126/34 43/127/34 61/75/34 +f 43/127/34 45/128/34 61/75/34 +f 45/128/34 47/129/34 61/75/34 +f 47/129/34 49/130/34 61/75/34 +f 49/130/34 51/131/34 61/75/34 +f 51/131/34 53/132/34 61/75/34 +f 53/132/34 55/133/34 61/75/34 +f 55/133/34 57/134/34 59/135/34 +f 61/75/34 55/133/34 59/135/34 diff --git a/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj b/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj new file mode 100644 index 00000000..90db7d63 --- /dev/null +++ b/src/datavisualization/engine/meshes/cylinderFilledSmooth.obj @@ -0,0 +1,391 @@ +# Blender v2.66 (sub 0) OBJ File: 'cylinder_filled.blend' +# www.blender.org +o Cylinder +v 0.000000 -1.000000 -1.000000 +v 0.000000 1.000000 -1.000000 +v 0.195090 -1.000000 -0.980785 +v 0.195090 1.000000 -0.980785 +v 0.382683 -1.000000 -0.923880 +v 0.382683 1.000000 -0.923880 +v 0.555570 -1.000000 -0.831470 +v 0.555570 1.000000 -0.831470 +v 0.707107 -1.000000 -0.707107 +v 0.707107 1.000000 -0.707107 +v 0.831470 -1.000000 -0.555570 +v 0.831470 1.000000 -0.555570 +v 0.923880 -1.000000 -0.382683 +v 0.923880 1.000000 -0.382683 +v 0.980785 -1.000000 -0.195090 +v 0.980785 1.000000 -0.195090 +v 1.000000 -1.000000 -0.000000 +v 1.000000 1.000000 -0.000000 +v 0.980785 -1.000000 0.195090 +v 0.980785 1.000000 0.195090 +v 0.923880 -1.000000 0.382683 +v 0.923880 1.000000 0.382683 +v 0.831470 -1.000000 0.555570 +v 0.831470 1.000000 0.555570 +v 0.707107 -1.000000 0.707107 +v 0.707107 1.000000 0.707107 +v 0.555570 -1.000000 0.831470 +v 0.555570 1.000000 0.831470 +v 0.382683 -1.000000 0.923880 +v 0.382683 1.000000 0.923880 +v 0.195090 -1.000000 0.980785 +v 0.195090 1.000000 0.980785 +v -0.000000 -1.000000 1.000000 +v -0.000000 1.000000 1.000000 +v -0.195091 -1.000000 0.980785 +v -0.195091 1.000000 0.980785 +v -0.382684 -1.000000 0.923879 +v -0.382684 1.000000 0.923879 +v -0.555571 -1.000000 0.831469 +v -0.555571 1.000000 0.831469 +v -0.707107 -1.000000 0.707106 +v -0.707107 1.000000 0.707106 +v -0.831470 -1.000000 0.555570 +v -0.831470 1.000000 0.555570 +v -0.923880 -1.000000 0.382683 +v -0.923880 1.000000 0.382683 +v -0.980785 -1.000000 0.195089 +v -0.980785 1.000000 0.195089 +v -1.000000 -1.000000 -0.000001 +v -1.000000 1.000000 -0.000001 +v -0.980785 -1.000000 -0.195091 +v -0.980785 1.000000 -0.195091 +v -0.923879 -1.000000 -0.382684 +v -0.923879 1.000000 -0.382684 +v -0.831469 -1.000000 -0.555571 +v -0.831469 1.000000 -0.555571 +v -0.707106 -1.000000 -0.707108 +v -0.707106 1.000000 -0.707108 +v -0.555569 -1.000000 -0.831470 +v -0.555569 1.000000 -0.831470 +v -0.382682 -1.000000 -0.923880 +v -0.382682 1.000000 -0.923880 +v -0.195089 -1.000000 -0.980786 +v -0.195089 1.000000 -0.980786 +vt 0.059001 0.355439 +vt 0.057906 0.712417 +vt 0.027048 0.712322 +vt 0.028143 0.355344 +vt 0.000000 0.712239 +vt 0.998905 0.355261 +vt 1.000000 0.712239 +vt 0.972952 0.712322 +vt 0.971857 0.355344 +vt 0.942094 0.712417 +vt 0.940999 0.355439 +vt 0.908611 0.712520 +vt 0.907515 0.355541 +vt 0.873789 0.712627 +vt 0.872694 0.355648 +vt 0.838968 0.712733 +vt 0.837872 0.355755 +vt 0.805484 0.712836 +vt 0.777341 0.713350 +vt 0.776246 1.070328 +vt 0.742763 1.070225 +vt 0.743858 0.713247 +vt 0.707941 1.070119 +vt 0.709036 0.713140 +vt 0.673120 1.070012 +vt 0.674215 0.713033 +vt 0.639636 1.069909 +vt 0.640732 0.712931 +vt 0.608778 1.069814 +vt 0.609873 0.712836 +vt 0.608778 0.355858 +vt 0.642261 0.355755 +vt 0.643357 0.712733 +vt 0.677083 0.355648 +vt 0.678178 0.712627 +vt 0.711904 0.355541 +vt 0.713000 0.712520 +vt 0.746483 0.712417 +vt 0.745388 0.355439 +vt 0.777341 0.712322 +vt 0.776246 0.355344 +vt 0.804389 0.712239 +vt 0.607683 0.355261 +vt 0.608778 0.712239 +vt 0.580635 0.355344 +vt 0.581730 0.712322 +vt 0.549777 0.355439 +vt 0.550872 0.712417 +vt 0.516293 0.355541 +vt 0.517389 0.712520 +vt 0.481472 0.355648 +vt 0.482567 0.712627 +vt 0.446650 0.355755 +vt 0.447746 0.712733 +vt 0.413167 0.355858 +vt 0.414262 0.712836 +vt 0.382309 0.355952 +vt 0.383404 0.712931 +vt 0.355261 0.356035 +vt 0.226469 0.355952 +vt 0.225374 0.712931 +vt 0.195611 0.355858 +vt 0.194516 0.712836 +vt 0.162127 0.355755 +vt 0.161032 0.712733 +vt 0.127306 0.355648 +vt 0.000000 0.160135 +vt 0.006826 0.125818 +vt 0.000000 0.195126 +vt 0.092484 0.355541 +vt 0.091389 0.712520 +vt 0.126211 0.712627 +vt 0.394917 0.290863 +vt 0.375477 0.261770 +vt 0.419658 0.315605 +vt 0.001095 0.355261 +vt 0.804389 0.355858 +vt 0.803294 0.355261 +vt 0.356356 0.713014 +vt 0.020216 0.093491 +vt 0.039656 0.064398 +vt 0.064397 0.039656 +vt 0.093491 0.020217 +vt 0.125817 0.006826 +vt 0.160135 0.000000 +vt 0.195125 0.000000 +vt 0.229443 0.006826 +vt 0.261770 0.020216 +vt 0.290863 0.039656 +vt 0.315605 0.064398 +vt 0.335045 0.093491 +vt 0.348435 0.125818 +vt 0.355261 0.160135 +vt 0.355261 0.195126 +vt 0.348435 0.229443 +vt 0.335045 0.261770 +vt 0.315605 0.290863 +vt 0.290863 0.315605 +vt 0.261770 0.335045 +vt 0.229443 0.348435 +vt 0.195126 0.355261 +vt 0.160135 0.355261 +vt 0.125818 0.348435 +vt 0.093491 0.335045 +vt 0.064398 0.315605 +vt 0.039656 0.290863 +vt 0.020216 0.261770 +vt 0.006826 0.229443 +vt 0.362087 0.229443 +vt 0.362087 0.125818 +vt 0.375477 0.093491 +vt 0.394917 0.064398 +vt 0.419659 0.039656 +vt 0.448752 0.020216 +vt 0.481079 0.006826 +vt 0.515396 0.000000 +vt 0.550387 0.000000 +vt 0.584704 0.006826 +vt 0.617031 0.020216 +vt 0.646124 0.039656 +vt 0.670866 0.064398 +vt 0.690306 0.093491 +vt 0.703696 0.125818 +vt 0.710522 0.160136 +vt 0.710522 0.195126 +vt 0.703696 0.229444 +vt 0.690306 0.261770 +vt 0.670866 0.290864 +vt 0.646124 0.315605 +vt 0.617031 0.335045 +vt 0.584704 0.348435 +vt 0.550386 0.355261 +vt 0.515396 0.355261 +vt 0.481078 0.348435 +vt 0.448752 0.335045 +vn 0.000000 -0.685690 -0.727866 +vn 0.000000 0.685690 -0.727866 +vn 0.142003 0.685690 -0.713889 +vn 0.142003 -0.685690 -0.713889 +vn 0.278542 0.685690 -0.672475 +vn 0.278542 -0.685690 -0.672475 +vn 0.404370 0.685690 -0.605213 +vn 0.404370 -0.685690 -0.605213 +vn 0.514664 0.685690 -0.514664 +vn 0.514664 -0.685690 -0.514664 +vn 0.605213 0.685690 -0.404370 +vn 0.605213 -0.685690 -0.404370 +vn 0.672475 0.685690 -0.278542 +vn 0.672475 -0.685690 -0.278542 +vn 0.713889 0.685690 -0.142003 +vn 0.713889 -0.685690 -0.142003 +vn 0.727866 0.685690 0.000000 +vn 0.727866 -0.685690 0.000000 +vn 0.713889 0.685690 0.142003 +vn 0.713889 -0.685690 0.142003 +vn 0.672475 0.685690 0.278542 +vn 0.672475 -0.685690 0.278542 +vn 0.605213 0.685690 0.404370 +vn 0.605213 -0.685690 0.404370 +vn 0.514664 0.685690 0.514664 +vn 0.514664 -0.685690 0.514664 +vn 0.404370 0.685690 0.605213 +vn 0.404370 -0.685690 0.605213 +vn 0.278542 0.685690 0.672475 +vn 0.278542 -0.685690 0.672475 +vn 0.142003 0.685690 0.713889 +vn 0.142003 -0.685690 0.713889 +vn 0.000000 0.685690 0.727866 +vn 0.000000 -0.685690 0.727866 +vn -0.142003 -0.685690 0.713889 +vn -0.142003 0.685690 0.713889 +vn -0.278542 -0.685690 0.672475 +vn -0.278542 0.685690 0.672475 +vn -0.404370 -0.685690 0.605213 +vn -0.404370 0.685690 0.605213 +vn -0.514695 -0.685690 0.514664 +vn -0.514664 0.685690 0.514664 +vn -0.605213 -0.685690 0.404370 +vn -0.605213 0.685690 0.404370 +vn -0.672475 -0.685690 0.278542 +vn -0.672475 0.685690 0.278542 +vn -0.713889 -0.685690 0.142003 +vn -0.713889 0.685690 0.142003 +vn -0.727866 -0.685690 0.000000 +vn -0.727866 0.685690 0.000000 +vn -0.713889 -0.685690 -0.142003 +vn -0.713889 0.685690 -0.142003 +vn -0.672475 -0.685690 -0.278542 +vn -0.672475 0.685690 -0.278542 +vn -0.605213 -0.685690 -0.404370 +vn -0.605213 0.685690 -0.404370 +vn -0.514664 -0.685690 -0.514695 +vn -0.514664 0.685690 -0.514695 +vn -0.404370 -0.685690 -0.605213 +vn -0.404370 0.685690 -0.605213 +vn -0.278542 -0.685690 -0.672475 +vn -0.142003 -0.685690 -0.713889 +vn -0.142003 0.685690 -0.713889 +vn -0.278542 0.685690 -0.672475 +s 1 +f 1/1/1 2/2/2 4/3/3 +f 3/4/4 4/3/3 6/5/5 +f 5/6/6 6/7/5 8/8/7 +f 7/9/8 8/8/7 10/10/9 +f 9/11/10 10/10/9 12/12/11 +f 11/13/12 12/12/11 14/14/13 +f 13/15/14 14/14/13 16/16/15 +f 15/17/16 16/16/15 18/18/17 +f 17/19/18 18/20/17 20/21/19 +f 19/22/20 20/21/19 22/23/21 +f 21/24/22 22/23/21 24/25/23 +f 23/26/24 24/25/23 26/27/25 +f 25/28/26 26/27/25 28/29/27 +f 27/30/28 28/31/27 30/32/29 +f 29/33/30 30/32/29 32/34/31 +f 31/35/32 32/34/31 34/36/33 +f 33/37/34 34/36/33 35/38/35 +f 35/38/35 36/39/36 37/40/37 +f 37/40/37 38/41/38 39/42/39 +f 39/43/39 40/44/40 41/45/41 +f 41/45/41 42/46/42 43/47/43 +f 43/47/43 44/48/44 45/49/45 +f 45/49/45 46/50/46 47/51/47 +f 47/51/47 48/52/48 49/53/49 +f 49/53/49 50/54/50 51/55/51 +f 51/55/51 52/56/52 53/57/53 +f 53/57/53 54/58/54 55/59/55 +f 55/60/55 56/61/56 57/62/57 +f 57/62/57 58/63/58 59/64/59 +f 59/64/59 60/65/60 61/66/61 +f 4/67/3 2/68/2 6/69/5 +f 63/70/62 64/71/63 1/1/1 +f 61/66/61 62/72/64 63/70/62 +f 63/73/62 1/74/1 61/75/61 +f 3/4/4 1/1/1 4/3/3 +f 5/76/6 3/4/4 6/5/5 +f 7/9/8 5/6/6 8/8/7 +f 9/11/10 7/9/8 10/10/9 +f 11/13/12 9/11/10 12/12/11 +f 13/15/14 11/13/12 14/14/13 +f 15/17/16 13/15/14 16/16/15 +f 17/77/18 15/17/16 18/18/17 +f 19/22/20 17/19/18 20/21/19 +f 21/24/22 19/22/20 22/23/21 +f 23/26/24 21/24/22 24/25/23 +f 25/28/26 23/26/24 26/27/25 +f 27/30/28 25/28/26 28/29/27 +f 29/33/30 27/30/28 30/32/29 +f 31/35/32 29/33/30 32/34/31 +f 33/37/34 31/35/32 34/36/33 +f 34/36/33 36/39/36 35/38/35 +f 36/39/36 38/41/38 37/40/37 +f 38/41/38 40/78/40 39/42/39 +f 40/44/40 42/46/42 41/45/41 +f 42/46/42 44/48/44 43/47/43 +f 44/48/44 46/50/46 45/49/45 +f 46/50/46 48/52/48 47/51/47 +f 48/52/48 50/54/50 49/53/49 +f 50/54/50 52/56/52 51/55/51 +f 52/56/52 54/58/54 53/57/53 +f 54/58/54 56/79/56 55/59/55 +f 56/61/56 58/63/58 57/62/57 +f 58/63/58 60/65/60 59/64/59 +f 60/65/60 62/72/64 61/66/61 +f 2/68/2 64/80/63 6/69/5 +f 64/80/63 62/81/64 6/69/5 +f 62/81/64 60/82/60 6/69/5 +f 60/82/60 58/83/58 6/69/5 +f 58/83/58 56/84/56 6/69/5 +f 56/84/56 54/85/54 6/69/5 +f 54/85/54 52/86/52 6/69/5 +f 52/86/52 50/87/50 6/69/5 +f 50/87/50 48/88/48 6/69/5 +f 48/88/48 46/89/46 6/69/5 +f 46/89/46 44/90/44 6/69/5 +f 44/90/44 42/91/42 6/69/5 +f 42/91/42 40/92/40 6/69/5 +f 40/92/40 38/93/38 6/69/5 +f 38/93/38 36/94/36 6/69/5 +f 36/94/36 34/95/33 6/69/5 +f 34/95/33 32/96/31 6/69/5 +f 32/96/31 30/97/29 6/69/5 +f 30/97/29 28/98/27 6/69/5 +f 28/98/27 26/99/25 6/69/5 +f 26/99/25 24/100/23 6/69/5 +f 24/100/23 22/101/21 6/69/5 +f 22/101/21 20/102/19 6/69/5 +f 20/102/19 18/103/17 6/69/5 +f 18/103/17 16/104/15 6/69/5 +f 16/104/15 14/105/13 6/69/5 +f 14/105/13 12/106/11 6/69/5 +f 12/106/11 10/107/9 8/108/7 +f 6/69/5 12/106/11 8/108/7 +f 64/71/63 2/2/2 1/1/1 +f 62/72/64 64/71/63 63/70/62 +f 1/74/1 3/109/4 61/75/61 +f 3/109/4 5/94/6 61/75/61 +f 5/94/6 7/93/8 61/75/61 +f 7/93/8 9/110/10 61/75/61 +f 9/110/10 11/111/12 61/75/61 +f 11/111/12 13/112/14 61/75/61 +f 13/112/14 15/113/16 61/75/61 +f 15/113/16 17/114/18 61/75/61 +f 17/114/18 19/115/20 61/75/61 +f 19/115/20 21/116/22 61/75/61 +f 21/116/22 23/117/24 61/75/61 +f 23/117/24 25/118/26 61/75/61 +f 25/118/26 27/119/28 61/75/61 +f 27/119/28 29/120/30 61/75/61 +f 29/120/30 31/121/32 61/75/61 +f 31/121/32 33/122/34 61/75/61 +f 33/122/34 35/123/35 61/75/61 +f 35/123/35 37/124/37 61/75/61 +f 37/124/37 39/125/39 61/75/61 +f 39/125/39 41/126/41 61/75/61 +f 41/126/41 43/127/43 61/75/61 +f 43/127/43 45/128/45 61/75/61 +f 45/128/45 47/129/47 61/75/61 +f 47/129/47 49/130/49 61/75/61 +f 49/130/49 51/131/51 61/75/61 +f 51/131/51 53/132/53 61/75/61 +f 53/132/53 55/133/55 61/75/61 +f 55/133/55 57/134/57 59/135/59 +f 61/75/61 55/133/55 59/135/59 diff --git a/src/datavisualization/engine/meshes/cylinderFlat.obj b/src/datavisualization/engine/meshes/cylinderFlat.obj new file mode 100644 index 00000000..2b7e3e5e --- /dev/null +++ b/src/datavisualization/engine/meshes/cylinderFlat.obj @@ -0,0 +1,299 @@ +# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend' +# www.blender.org +o Cylinder +v 0.000000 -1.000000 -1.000000 +v 0.000000 1.000000 -1.000000 +v 0.195090 -1.000000 -0.980785 +v 0.195090 1.000000 -0.980785 +v 0.382683 -1.000000 -0.923880 +v 0.382683 1.000000 -0.923880 +v 0.555570 -1.000000 -0.831470 +v 0.555570 1.000000 -0.831470 +v 0.707107 -1.000000 -0.707107 +v 0.707107 1.000000 -0.707107 +v 0.831470 -1.000000 -0.555570 +v 0.831470 1.000000 -0.555570 +v 0.923880 -1.000000 -0.382683 +v 0.923880 1.000000 -0.382683 +v 0.980785 -1.000000 -0.195090 +v 0.980785 1.000000 -0.195090 +v 1.000000 -1.000000 -0.000000 +v 1.000000 1.000000 -0.000000 +v 0.980785 -1.000000 0.195090 +v 0.980785 1.000000 0.195090 +v 0.923880 -1.000000 0.382683 +v 0.923880 1.000000 0.382683 +v 0.831470 -1.000000 0.555570 +v 0.831470 1.000000 0.555570 +v 0.707107 -1.000000 0.707107 +v 0.707107 1.000000 0.707107 +v 0.555570 -1.000000 0.831470 +v 0.555570 1.000000 0.831470 +v 0.382683 -1.000000 0.923880 +v 0.382683 1.000000 0.923880 +v 0.195090 -1.000000 0.980785 +v 0.195090 1.000000 0.980785 +v -0.000000 -1.000000 1.000000 +v -0.000000 1.000000 1.000000 +v -0.195091 -1.000000 0.980785 +v -0.195091 1.000000 0.980785 +v -0.382684 -1.000000 0.923879 +v -0.382684 1.000000 0.923879 +v -0.555571 -1.000000 0.831469 +v -0.555571 1.000000 0.831469 +v -0.707107 -1.000000 0.707106 +v -0.707107 1.000000 0.707106 +v -0.831470 -1.000000 0.555570 +v -0.831470 1.000000 0.555570 +v -0.923880 -1.000000 0.382683 +v -0.923880 1.000000 0.382683 +v -0.980785 -1.000000 0.195089 +v -0.980785 1.000000 0.195089 +v -1.000000 -1.000000 -0.000001 +v -1.000000 1.000000 -0.000001 +v -0.980785 -1.000000 -0.195091 +v -0.980785 1.000000 -0.195091 +v -0.923879 -1.000000 -0.382684 +v -0.923879 1.000000 -0.382684 +v -0.831469 -1.000000 -0.555571 +v -0.831469 1.000000 -0.555571 +v -0.707106 -1.000000 -0.707108 +v -0.707106 1.000000 -0.707108 +v -0.555569 -1.000000 -0.831470 +v -0.555569 1.000000 -0.831470 +v -0.382682 -1.000000 -0.923880 +v -0.382682 1.000000 -0.923880 +v -0.195089 -1.000000 -0.980786 +v -0.195089 1.000000 -0.980786 +vt 0.289718 0.879351 +vt 0.288367 0.438844 +vt 0.330714 0.438714 +vt 0.332066 0.879221 +vt 0.370605 0.438592 +vt 0.371956 0.879099 +vt 0.406505 0.438482 +vt 0.407857 0.878988 +vt 0.437036 0.438388 +vt 0.778904 0.000000 +vt 0.780256 0.440507 +vt 0.749725 0.440601 +vt 0.748373 0.000094 +vt 0.713824 0.440711 +vt 0.712473 0.000204 +vt 0.673934 0.440833 +vt 0.672582 0.000326 +vt 0.631586 0.440963 +vt 0.630235 0.000456 +vt 0.588409 0.441095 +vt 0.587057 0.000588 +vt 0.546061 0.441225 +vt 0.544710 0.000718 +vt 0.506171 0.441348 +vt 0.504819 0.000841 +vt 0.470270 0.441458 +vt 0.468919 0.000951 +vt 0.439739 0.441552 +vt 0.720545 0.882916 +vt 0.719194 0.442409 +vt 0.755094 0.442299 +vt 0.756446 0.882806 +vt 0.794985 0.442176 +vt 0.796336 0.882683 +vt 0.837333 0.442046 +vt 0.838684 0.882553 +vt 0.881861 0.882421 +vt 0.880510 0.441914 +vt 0.924209 0.882291 +vt 0.922857 0.441784 +vt 0.964099 0.882168 +vt 0.962748 0.441662 +vt 1.000000 0.882058 +vt 0.717842 0.441552 +vt 0.719194 0.882058 +vt 0.681942 0.441662 +vt 0.683293 0.882169 +vt 0.642051 0.441784 +vt 0.643403 0.882291 +vt 0.599704 0.441914 +vt 0.601055 0.882421 +vt 0.556526 0.442046 +vt 0.557878 0.882553 +vt 0.514179 0.442176 +vt 0.515530 0.882683 +vt 0.474288 0.442299 +vt 0.475640 0.882806 +vt 0.438388 0.442409 +vt 0.097872 0.879939 +vt 0.096520 0.439433 +vt 0.128403 0.879846 +vt 0.127051 0.439339 +vt 0.164303 0.879735 +vt 0.162952 0.439229 +vt 0.204194 0.879613 +vt 0.000000 0.197605 +vt 0.008423 0.155257 +vt 0.000000 0.240783 +vt 0.246541 0.879483 +vt 0.245190 0.438976 +vt 0.202842 0.439106 +vt 0.438388 0.878895 +vt 0.438388 0.001045 +vt 0.998649 0.441552 +vt 0.439739 0.882916 +vt 0.024947 0.115367 +vt 0.048935 0.079466 +vt 0.079466 0.048935 +vt 0.115366 0.024947 +vt 0.155257 0.008424 +vt 0.197605 0.000000 +vt 0.240782 0.000000 +vt 0.283130 0.008423 +vt 0.323021 0.024947 +vt 0.358922 0.048935 +vt 0.389453 0.079466 +vt 0.413441 0.115367 +vt 0.429964 0.155257 +vt 0.438388 0.197605 +vt 0.438388 0.240783 +vt 0.429964 0.283130 +vt 0.413441 0.323021 +vt 0.389453 0.358922 +vt 0.358922 0.389453 +vt 0.323021 0.413441 +vt 0.283130 0.429964 +vt 0.240783 0.438388 +vt 0.197605 0.438388 +vt 0.155257 0.429964 +vt 0.115367 0.413441 +vt 0.079466 0.389453 +vt 0.048935 0.358922 +vt 0.024947 0.323021 +vt 0.008423 0.283130 +vn 0.098017 0.000000 -0.995185 +vn 0.290285 0.000000 -0.956940 +vn 0.471397 0.000000 -0.881921 +vn 0.634393 0.000000 -0.773010 +vn 0.773010 0.000000 -0.634393 +vn 0.881921 0.000000 -0.471397 +vn 0.956940 0.000000 -0.290285 +vn 0.995185 0.000000 -0.098017 +vn 0.995185 0.000000 0.098017 +vn 0.956940 0.000000 0.290285 +vn 0.881921 0.000000 0.471396 +vn 0.773010 0.000000 0.634393 +vn 0.634393 0.000000 0.773010 +vn 0.471397 0.000000 0.881921 +vn 0.290284 0.000000 0.956940 +vn 0.098017 0.000000 0.995185 +vn -0.098018 0.000000 0.995185 +vn -0.290285 0.000000 0.956940 +vn -0.471397 0.000000 0.881921 +vn -0.634394 0.000000 0.773010 +vn -0.773011 0.000000 0.634393 +vn -0.881922 0.000000 0.471396 +vn -0.956941 0.000000 0.290284 +vn -0.995185 0.000000 0.098016 +vn -0.995185 -0.000000 -0.098018 +vn -0.956940 -0.000000 -0.290286 +vn -0.881921 -0.000000 -0.471398 +vn -0.773010 -0.000000 -0.634394 +vn -0.634392 -0.000000 -0.773011 +vn -0.471395 -0.000000 -0.881922 +vn -0.000000 1.000000 0.000000 +vn -0.098017 -0.000000 -0.995185 +vn -0.290283 -0.000000 -0.956941 +s off +f 1/1/1 2/2/1 4/3/1 +f 3/4/2 4/3/2 6/5/2 +f 5/6/3 6/5/3 8/7/3 +f 7/8/4 8/7/4 10/9/4 +f 9/10/5 10/11/5 12/12/5 +f 11/13/6 12/12/6 14/14/6 +f 13/15/7 14/14/7 16/16/7 +f 15/17/8 16/16/8 18/18/8 +f 17/19/9 18/18/9 20/20/9 +f 19/21/10 20/20/10 22/22/10 +f 21/23/11 22/22/11 24/24/11 +f 23/25/12 24/24/12 26/26/12 +f 25/27/13 26/26/13 28/28/13 +f 27/29/14 28/30/14 30/31/14 +f 29/32/15 30/31/15 32/33/15 +f 31/34/16 32/33/16 34/35/16 +f 33/36/17 34/35/17 35/37/17 +f 35/37/18 36/38/18 37/39/18 +f 37/39/19 38/40/19 39/41/19 +f 39/41/20 40/42/20 41/43/20 +f 41/44/21 42/45/21 43/46/21 +f 43/46/22 44/47/22 45/48/22 +f 45/48/23 46/49/23 47/50/23 +f 47/50/24 48/51/24 49/52/24 +f 49/52/25 50/53/25 51/54/25 +f 51/54/26 52/55/26 53/56/26 +f 53/56/27 54/57/27 55/58/27 +f 55/59/28 56/60/28 57/61/28 +f 57/61/29 58/62/29 59/63/29 +f 59/63/30 60/64/30 61/65/30 +f 4/66/31 2/67/31 6/68/31 +f 63/69/32 64/70/32 1/1/32 +f 61/65/33 62/71/33 63/69/33 +f 3/4/1 1/1/1 4/3/1 +f 5/6/2 3/4/2 6/5/2 +f 7/8/3 5/6/3 8/7/3 +f 9/72/4 7/8/4 10/9/4 +f 11/13/5 9/10/5 12/12/5 +f 13/15/6 11/13/6 14/14/6 +f 15/17/7 13/15/7 16/16/7 +f 17/19/8 15/17/8 18/18/8 +f 19/21/9 17/19/9 20/20/9 +f 21/23/10 19/21/10 22/22/10 +f 23/25/11 21/23/11 24/24/11 +f 25/27/12 23/25/12 26/26/12 +f 27/73/13 25/27/13 28/28/13 +f 29/32/14 27/29/14 30/31/14 +f 31/34/15 29/32/15 32/33/15 +f 33/36/16 31/34/16 34/35/16 +f 34/35/17 36/38/17 35/37/17 +f 36/38/18 38/40/18 37/39/18 +f 38/40/19 40/42/19 39/41/19 +f 40/42/20 42/74/20 41/43/20 +f 42/45/21 44/47/21 43/46/21 +f 44/47/22 46/49/22 45/48/22 +f 46/49/23 48/51/23 47/50/23 +f 48/51/24 50/53/24 49/52/24 +f 50/53/25 52/55/25 51/54/25 +f 52/55/26 54/57/26 53/56/26 +f 54/57/27 56/75/27 55/58/27 +f 56/60/28 58/62/28 57/61/28 +f 58/62/29 60/64/29 59/63/29 +f 60/64/30 62/71/30 61/65/30 +f 2/67/31 64/76/31 6/68/31 +f 64/76/31 62/77/31 6/68/31 +f 62/77/31 60/78/31 6/68/31 +f 60/78/31 58/79/31 6/68/31 +f 58/79/31 56/80/31 6/68/31 +f 56/80/31 54/81/31 6/68/31 +f 54/81/31 52/82/31 6/68/31 +f 52/82/31 50/83/31 6/68/31 +f 50/83/31 48/84/31 6/68/31 +f 48/84/31 46/85/31 6/68/31 +f 46/85/31 44/86/31 6/68/31 +f 44/86/31 42/87/31 6/68/31 +f 42/87/31 40/88/31 6/68/31 +f 40/88/31 38/89/31 6/68/31 +f 38/89/31 36/90/31 6/68/31 +f 36/90/31 34/91/31 6/68/31 +f 34/91/31 32/92/31 6/68/31 +f 32/92/31 30/93/31 6/68/31 +f 30/93/31 28/94/31 6/68/31 +f 28/94/31 26/95/31 6/68/31 +f 26/95/31 24/96/31 6/68/31 +f 24/96/31 22/97/31 6/68/31 +f 22/97/31 20/98/31 6/68/31 +f 20/98/31 18/99/31 6/68/31 +f 18/99/31 16/100/31 6/68/31 +f 16/100/31 14/101/31 6/68/31 +f 14/101/31 12/102/31 6/68/31 +f 12/102/31 10/103/31 8/104/31 +f 6/68/31 12/102/31 8/104/31 +f 64/70/32 2/2/32 1/1/32 +f 62/71/33 64/70/33 63/69/33 diff --git a/src/datavisualization/engine/meshes/cylinderSmooth.obj b/src/datavisualization/engine/meshes/cylinderSmooth.obj new file mode 100644 index 00000000..6ccbb286 --- /dev/null +++ b/src/datavisualization/engine/meshes/cylinderSmooth.obj @@ -0,0 +1,330 @@ +# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend' +# www.blender.org +o Cylinder +v 0.000000 -1.000000 -1.000000 +v 0.000000 1.000000 -1.000000 +v 0.195090 -1.000000 -0.980785 +v 0.195090 1.000000 -0.980785 +v 0.382683 -1.000000 -0.923880 +v 0.382683 1.000000 -0.923880 +v 0.555570 -1.000000 -0.831470 +v 0.555570 1.000000 -0.831470 +v 0.707107 -1.000000 -0.707107 +v 0.707107 1.000000 -0.707107 +v 0.831470 -1.000000 -0.555570 +v 0.831470 1.000000 -0.555570 +v 0.923880 -1.000000 -0.382683 +v 0.923880 1.000000 -0.382683 +v 0.980785 -1.000000 -0.195090 +v 0.980785 1.000000 -0.195090 +v 1.000000 -1.000000 -0.000000 +v 1.000000 1.000000 -0.000000 +v 0.980785 -1.000000 0.195090 +v 0.980785 1.000000 0.195090 +v 0.923880 -1.000000 0.382683 +v 0.923880 1.000000 0.382683 +v 0.831470 -1.000000 0.555570 +v 0.831470 1.000000 0.555570 +v 0.707107 -1.000000 0.707107 +v 0.707107 1.000000 0.707107 +v 0.555570 -1.000000 0.831470 +v 0.555570 1.000000 0.831470 +v 0.382683 -1.000000 0.923880 +v 0.382683 1.000000 0.923880 +v 0.195090 -1.000000 0.980785 +v 0.195090 1.000000 0.980785 +v -0.000000 -1.000000 1.000000 +v -0.000000 1.000000 1.000000 +v -0.195091 -1.000000 0.980785 +v -0.195091 1.000000 0.980785 +v -0.382684 -1.000000 0.923879 +v -0.382684 1.000000 0.923879 +v -0.555571 -1.000000 0.831469 +v -0.555571 1.000000 0.831469 +v -0.707107 -1.000000 0.707106 +v -0.707107 1.000000 0.707106 +v -0.831470 -1.000000 0.555570 +v -0.831470 1.000000 0.555570 +v -0.923880 -1.000000 0.382683 +v -0.923880 1.000000 0.382683 +v -0.980785 -1.000000 0.195089 +v -0.980785 1.000000 0.195089 +v -1.000000 -1.000000 -0.000001 +v -1.000000 1.000000 -0.000001 +v -0.980785 -1.000000 -0.195091 +v -0.980785 1.000000 -0.195091 +v -0.923879 -1.000000 -0.382684 +v -0.923879 1.000000 -0.382684 +v -0.831469 -1.000000 -0.555571 +v -0.831469 1.000000 -0.555571 +v -0.707106 -1.000000 -0.707108 +v -0.707106 1.000000 -0.707108 +v -0.555569 -1.000000 -0.831470 +v -0.555569 1.000000 -0.831470 +v -0.382682 -1.000000 -0.923880 +v -0.382682 1.000000 -0.923880 +v -0.195089 -1.000000 -0.980786 +v -0.195089 1.000000 -0.980786 +vt 0.289718 0.879351 +vt 0.288367 0.438844 +vt 0.330714 0.438714 +vt 0.332066 0.879221 +vt 0.370605 0.438592 +vt 0.371956 0.879099 +vt 0.406505 0.438482 +vt 0.407857 0.878988 +vt 0.437036 0.438388 +vt 0.778904 0.000000 +vt 0.780256 0.440507 +vt 0.749725 0.440601 +vt 0.748373 0.000094 +vt 0.713824 0.440711 +vt 0.712473 0.000204 +vt 0.673934 0.440833 +vt 0.672582 0.000326 +vt 0.631586 0.440963 +vt 0.630235 0.000456 +vt 0.588409 0.441095 +vt 0.587057 0.000588 +vt 0.546061 0.441225 +vt 0.544710 0.000718 +vt 0.506171 0.441348 +vt 0.504819 0.000841 +vt 0.470270 0.441458 +vt 0.468919 0.000951 +vt 0.439739 0.441552 +vt 0.720545 0.882916 +vt 0.719194 0.442409 +vt 0.755094 0.442299 +vt 0.756446 0.882806 +vt 0.794985 0.442176 +vt 0.796336 0.882683 +vt 0.837333 0.442046 +vt 0.838684 0.882553 +vt 0.881861 0.882421 +vt 0.880510 0.441914 +vt 0.924209 0.882291 +vt 0.922857 0.441784 +vt 0.964099 0.882168 +vt 0.962748 0.441662 +vt 1.000000 0.882058 +vt 0.717842 0.441552 +vt 0.719194 0.882058 +vt 0.681942 0.441662 +vt 0.683293 0.882169 +vt 0.642051 0.441784 +vt 0.643403 0.882291 +vt 0.599704 0.441914 +vt 0.601055 0.882421 +vt 0.556526 0.442046 +vt 0.557878 0.882553 +vt 0.514179 0.442176 +vt 0.515530 0.882683 +vt 0.474288 0.442299 +vt 0.475640 0.882806 +vt 0.438388 0.442409 +vt 0.097872 0.879939 +vt 0.096520 0.439433 +vt 0.128403 0.879846 +vt 0.127051 0.439339 +vt 0.164303 0.879735 +vt 0.162952 0.439229 +vt 0.204194 0.879613 +vt 0.000000 0.197605 +vt 0.008423 0.155257 +vt 0.000000 0.240783 +vt 0.246541 0.879483 +vt 0.245190 0.438976 +vt 0.202842 0.439106 +vt 0.438388 0.878895 +vt 0.438388 0.001045 +vt 0.998649 0.441552 +vt 0.439739 0.882916 +vt 0.024947 0.115367 +vt 0.048935 0.079466 +vt 0.079466 0.048935 +vt 0.115366 0.024947 +vt 0.155257 0.008424 +vt 0.197605 0.000000 +vt 0.240782 0.000000 +vt 0.283130 0.008423 +vt 0.323021 0.024947 +vt 0.358922 0.048935 +vt 0.389453 0.079466 +vt 0.413441 0.115367 +vt 0.429964 0.155257 +vt 0.438388 0.197605 +vt 0.438388 0.240783 +vt 0.429964 0.283130 +vt 0.413441 0.323021 +vt 0.389453 0.358922 +vt 0.358922 0.389453 +vt 0.323021 0.413441 +vt 0.283130 0.429964 +vt 0.240783 0.438388 +vt 0.197605 0.438388 +vt 0.155257 0.429964 +vt 0.115367 0.413441 +vt 0.079466 0.389453 +vt 0.048935 0.358922 +vt 0.024947 0.323021 +vt 0.008423 0.283130 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.685690 -0.727866 +vn 0.142003 0.685690 -0.713889 +vn 0.195074 0.000000 -0.980773 +vn 0.278542 0.685690 -0.672475 +vn 0.382672 0.000000 -0.923856 +vn 0.404370 0.685690 -0.605213 +vn 0.555559 0.000000 -0.831446 +vn 0.514664 0.685690 -0.514664 +vn 0.707083 0.000000 -0.707083 +vn 0.605213 0.685690 -0.404370 +vn 0.831446 0.000000 -0.555559 +vn 0.672475 0.685690 -0.278542 +vn 0.923856 0.000000 -0.382672 +vn 0.713889 0.685690 -0.142003 +vn 0.980773 0.000000 -0.195074 +vn 0.727866 0.685690 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.713889 0.685690 0.142003 +vn 0.980773 0.000000 0.195074 +vn 0.672475 0.685690 0.278542 +vn 0.923856 0.000000 0.382672 +vn 0.605213 0.685690 0.404370 +vn 0.831446 0.000000 0.555559 +vn 0.514664 0.685690 0.514664 +vn 0.707083 0.000000 0.707083 +vn 0.404370 0.685690 0.605213 +vn 0.555559 0.000000 0.831446 +vn 0.278542 0.685690 0.672475 +vn 0.382672 0.000000 0.923856 +vn 0.142003 0.685690 0.713889 +vn 0.195074 0.000000 0.980773 +vn 0.000000 0.685690 0.727866 +vn 0.000000 0.000000 0.999969 +vn -0.195074 0.000000 0.980773 +vn -0.142003 0.685690 0.713889 +vn -0.382672 0.000000 0.923856 +vn -0.278542 0.685690 0.672475 +vn -0.555559 0.000000 0.831446 +vn -0.404370 0.685690 0.605213 +vn -0.707083 0.000000 0.707083 +vn -0.514664 0.685690 0.514664 +vn -0.831446 0.000000 0.555559 +vn -0.605213 0.685690 0.404370 +vn -0.923856 0.000000 0.382672 +vn -0.672475 0.685690 0.278542 +vn -0.980773 0.000000 0.195074 +vn -0.713889 0.685690 0.142003 +vn -1.000000 0.000000 0.000000 +vn -0.727866 0.685690 0.000000 +vn -0.980773 0.000000 -0.195074 +vn -0.713889 0.685690 -0.142003 +vn -0.923856 0.000000 -0.382672 +vn -0.672475 0.685690 -0.278542 +vn -0.831446 0.000000 -0.555559 +vn -0.605213 0.685690 -0.404370 +vn -0.707083 0.000000 -0.707083 +vn -0.514664 0.685690 -0.514695 +vn -0.555559 0.000000 -0.831446 +vn -0.404370 0.685690 -0.605213 +vn -0.382672 0.000000 -0.923856 +vn -0.195074 0.000000 -0.980773 +vn -0.142003 0.685690 -0.713889 +vn -0.278542 0.685690 -0.672475 +s 1 +f 1/1/1 2/2/2 4/3/3 +f 3/4/4 4/3/3 6/5/5 +f 5/6/6 6/5/5 8/7/7 +f 7/8/8 8/7/7 10/9/9 +f 9/10/10 10/11/9 12/12/11 +f 11/13/12 12/12/11 14/14/13 +f 13/15/14 14/14/13 16/16/15 +f 15/17/16 16/16/15 18/18/17 +f 17/19/18 18/18/17 20/20/19 +f 19/21/20 20/20/19 22/22/21 +f 21/23/22 22/22/21 24/24/23 +f 23/25/24 24/24/23 26/26/25 +f 25/27/26 26/26/25 28/28/27 +f 27/29/28 28/30/27 30/31/29 +f 29/32/30 30/31/29 32/33/31 +f 31/34/32 32/33/31 34/35/33 +f 33/36/34 34/35/33 35/37/35 +f 35/37/35 36/38/36 37/39/37 +f 37/39/37 38/40/38 39/41/39 +f 39/41/39 40/42/40 41/43/41 +f 41/44/41 42/45/42 43/46/43 +f 43/46/43 44/47/44 45/48/45 +f 45/48/45 46/49/46 47/50/47 +f 47/50/47 48/51/48 49/52/49 +f 49/52/49 50/53/50 51/54/51 +f 51/54/51 52/55/52 53/56/53 +f 53/56/53 54/57/54 55/58/55 +f 55/59/55 56/60/56 57/61/57 +f 57/61/57 58/62/58 59/63/59 +f 59/63/59 60/64/60 61/65/61 +f 4/66/3 2/67/2 6/68/5 +f 63/69/62 64/70/63 1/1/1 +f 61/65/61 62/71/64 63/69/62 +f 3/4/4 1/1/1 4/3/3 +f 5/6/6 3/4/4 6/5/5 +f 7/8/8 5/6/6 8/7/7 +f 9/72/10 7/8/8 10/9/9 +f 11/13/12 9/10/10 12/12/11 +f 13/15/14 11/13/12 14/14/13 +f 15/17/16 13/15/14 16/16/15 +f 17/19/18 15/17/16 18/18/17 +f 19/21/20 17/19/18 20/20/19 +f 21/23/22 19/21/20 22/22/21 +f 23/25/24 21/23/22 24/24/23 +f 25/27/26 23/25/24 26/26/25 +f 27/73/28 25/27/26 28/28/27 +f 29/32/30 27/29/28 30/31/29 +f 31/34/32 29/32/30 32/33/31 +f 33/36/34 31/34/32 34/35/33 +f 34/35/33 36/38/36 35/37/35 +f 36/38/36 38/40/38 37/39/37 +f 38/40/38 40/42/40 39/41/39 +f 40/42/40 42/74/42 41/43/41 +f 42/45/42 44/47/44 43/46/43 +f 44/47/44 46/49/46 45/48/45 +f 46/49/46 48/51/48 47/50/47 +f 48/51/48 50/53/50 49/52/49 +f 50/53/50 52/55/52 51/54/51 +f 52/55/52 54/57/54 53/56/53 +f 54/57/54 56/75/56 55/58/55 +f 56/60/56 58/62/58 57/61/57 +f 58/62/58 60/64/60 59/63/59 +f 60/64/60 62/71/64 61/65/61 +f 2/67/2 64/76/63 6/68/5 +f 64/76/63 62/77/64 6/68/5 +f 62/77/64 60/78/60 6/68/5 +f 60/78/60 58/79/58 6/68/5 +f 58/79/58 56/80/56 6/68/5 +f 56/80/56 54/81/54 6/68/5 +f 54/81/54 52/82/52 6/68/5 +f 52/82/52 50/83/50 6/68/5 +f 50/83/50 48/84/48 6/68/5 +f 48/84/48 46/85/46 6/68/5 +f 46/85/46 44/86/44 6/68/5 +f 44/86/44 42/87/42 6/68/5 +f 42/87/42 40/88/40 6/68/5 +f 40/88/40 38/89/38 6/68/5 +f 38/89/38 36/90/36 6/68/5 +f 36/90/36 34/91/33 6/68/5 +f 34/91/33 32/92/31 6/68/5 +f 32/92/31 30/93/29 6/68/5 +f 30/93/29 28/94/27 6/68/5 +f 28/94/27 26/95/25 6/68/5 +f 26/95/25 24/96/23 6/68/5 +f 24/96/23 22/97/21 6/68/5 +f 22/97/21 20/98/19 6/68/5 +f 20/98/19 18/99/17 6/68/5 +f 18/99/17 16/100/15 6/68/5 +f 16/100/15 14/101/13 6/68/5 +f 14/101/13 12/102/11 6/68/5 +f 12/102/11 10/103/9 8/104/7 +f 6/68/5 12/102/11 8/104/7 +f 64/70/63 2/2/2 1/1/1 +f 62/71/64 64/70/63 63/69/62 diff --git a/src/datavisualization/engine/meshes/plane.obj b/src/datavisualization/engine/meshes/plane.obj new file mode 100644 index 00000000..96ac0dd7 --- /dev/null +++ b/src/datavisualization/engine/meshes/plane.obj @@ -0,0 +1,15 @@ +# Blender v2.66 (sub 0) OBJ File: 'plane.blend' +# www.blender.org +o Plane +v -1.000000 -1.000000 -0.000001 +v -1.000000 1.000000 -0.000000 +v 1.000000 -1.000000 0.000000 +v 1.000000 1.000000 0.000001 +vt 0.003058 1.000000 +vt 0.000000 0.003058 +vt 1.000000 0.996942 +vt 0.996942 0.000000 +vn -0.000001 -0.000001 1.000000 +s off +f 2/1/1 1/2/1 4/3/1 +f 1/2/1 3/4/1 4/3/1 diff --git a/src/datavisualization/engine/meshes/pyramidFilledFlat.obj b/src/datavisualization/engine/meshes/pyramidFilledFlat.obj new file mode 100644 index 00000000..0cf73bbe --- /dev/null +++ b/src/datavisualization/engine/meshes/pyramidFilledFlat.obj @@ -0,0 +1,36 @@ +# Blender v2.66 (sub 0) OBJ File: 'pyramid_filled.blend' +# www.blender.org +o Cone_Cone.001 +v 1.000000 -1.000000 -0.999999 +v 0.999999 -1.000000 1.000000 +v -1.000000 -1.000000 0.999999 +v 0.000000 1.000000 0.000000 +v -0.999999 -1.000000 -1.000000 +vt 0.323067 0.577790 +vt 0.000097 0.866793 +vt 0.000000 0.433396 +vt 0.646133 0.144393 +vt 0.323164 0.433396 +vt 0.323067 0.000000 +vt 0.646133 0.577790 +vt 0.323163 0.866793 +vt 0.323067 0.433396 +vt 0.323067 0.144393 +vt 0.000097 0.433396 +vt 0.000000 0.000000 +vt 0.646133 0.787263 +vt 0.646133 0.433396 +vt 1.000000 0.433396 +vt 1.000000 0.787263 +vn -0.894427 0.447214 -0.000000 +vn 0.894427 0.447213 0.000000 +vn 0.000000 0.447214 -0.894427 +vn -0.000000 0.447214 0.894427 +vn 0.000000 -1.000000 -0.000000 +s off +f 3/1/1 4/2/1 5/3/1 +f 1/4/2 4/5/2 2/6/2 +f 5/7/3 4/8/3 1/9/3 +f 2/10/4 4/11/4 3/12/4 +f 5/13/5 1/14/5 2/15/5 +f 3/16/5 5/13/5 2/15/5 diff --git a/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj b/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj new file mode 100644 index 00000000..306bda58 --- /dev/null +++ b/src/datavisualization/engine/meshes/pyramidFilledSmooth.obj @@ -0,0 +1,36 @@ +# Blender v2.66 (sub 0) OBJ File: 'pyramid_filled.blend' +# www.blender.org +o Cone_Cone.001 +v 1.000000 -1.000000 -0.999999 +v 0.999999 -1.000000 1.000000 +v -1.000000 -1.000000 0.999999 +v 0.000000 1.000000 0.000000 +v -0.999999 -1.000000 -1.000000 +vt 0.323067 0.577790 +vt 0.000097 0.866793 +vt 0.000000 0.433396 +vt 0.646133 0.144393 +vt 0.323164 0.433396 +vt 0.323067 0.000000 +vt 0.646133 0.577790 +vt 0.323163 0.866793 +vt 0.323067 0.433396 +vt 0.323067 0.144393 +vt 0.000097 0.433396 +vt 0.000000 0.000000 +vt 0.646133 0.787263 +vt 0.646133 0.433396 +vt 1.000000 0.433396 +vt 1.000000 0.787263 +vn -0.662618 -0.349040 0.662618 +vn 0.000000 1.000000 0.000000 +vn -0.662618 -0.349040 -0.662618 +vn 0.662618 -0.349040 -0.662618 +vn 0.662618 -0.349040 0.662618 +s 1 +f 3/1/1 4/2/2 5/3/3 +f 1/4/4 4/5/2 2/6/5 +f 5/7/3 4/8/2 1/9/4 +f 2/10/5 4/11/2 3/12/1 +f 5/13/3 1/14/4 2/15/5 +f 3/16/1 5/13/3 2/15/5 diff --git a/src/datavisualization/engine/meshes/pyramidFlat.obj b/src/datavisualization/engine/meshes/pyramidFlat.obj new file mode 100644 index 00000000..35edb477 --- /dev/null +++ b/src/datavisualization/engine/meshes/pyramidFlat.obj @@ -0,0 +1,22 @@ +# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend' +# www.blender.org +o Cone_Cone.001 +v 1.000000 -1.000000 -0.999999 +v 0.999999 -1.000000 1.000000 +v -1.000000 -1.000000 0.999999 +v 0.000000 1.000000 0.000000 +v -0.999999 -1.000000 -1.000000 +vt 0.999900 0.000100 +vt 0.500000 0.500000 +vt 0.000100 0.000100 +vt 0.000100 0.999900 +vt 0.999900 0.999900 +vn -0.894427 0.447214 -0.000000 +vn 0.894427 0.447213 0.000000 +vn 0.000000 0.447214 -0.894427 +vn -0.000000 0.447214 0.894427 +s off +f 3/1/1 4/2/1 5/3/1 +f 1/4/2 4/2/2 2/5/2 +f 5/3/3 4/2/3 1/4/3 +f 2/5/4 4/2/4 3/1/4 diff --git a/src/datavisualization/engine/meshes/pyramidSmooth.obj b/src/datavisualization/engine/meshes/pyramidSmooth.obj new file mode 100644 index 00000000..b11c8750 --- /dev/null +++ b/src/datavisualization/engine/meshes/pyramidSmooth.obj @@ -0,0 +1,23 @@ +# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend' +# www.blender.org +o Cone_Cone.001 +v 1.000000 -1.000000 -0.999999 +v 0.999999 -1.000000 1.000000 +v -1.000000 -1.000000 0.999999 +v 0.000000 1.000000 0.000000 +v -0.999999 -1.000000 -1.000000 +vt 0.999900 0.000100 +vt 0.500000 0.500000 +vt 0.000100 0.000100 +vt 0.000100 0.999900 +vt 0.999900 0.999900 +vn -0.577349 0.577349 0.577349 +vn 0.000000 1.000000 0.000000 +vn -0.577349 0.577349 -0.577349 +vn 0.577349 0.577349 -0.577349 +vn 0.577349 0.577349 0.577349 +s 1 +f 3/1/1 4/2/2 5/3/3 +f 1/4/4 4/2/2 2/5/5 +f 5/3/3 4/2/2 1/4/4 +f 2/5/5 4/2/2 3/1/1 diff --git a/src/datavisualization/engine/meshes/scatterdot.obj b/src/datavisualization/engine/meshes/scatterdot.obj new file mode 100644 index 00000000..d994a80f --- /dev/null +++ b/src/datavisualization/engine/meshes/scatterdot.obj @@ -0,0 +1,28 @@ +# Blender v2.66 (sub 0) OBJ File: 'scatterdot.blend' +# www.blender.org +o Cone +v 0.000000 -0.500000 -1.000000 +v 0.866025 -0.500000 0.500000 +v 0.000000 0.500000 0.000000 +v -0.866025 -0.500000 0.500000 +vt 0.999727 0.000000 +vt 1.000000 0.492691 +vt 0.522886 0.369782 +vt 0.477114 0.973202 +vt 0.000000 1.096111 +vt 0.000273 0.603420 +vt 0.523159 0.985382 +vt 0.522886 0.492691 +vt 1.000000 0.615600 +vt 0.000000 0.603420 +vt 0.000617 0.000000 +vt 0.522886 0.302245 +vn -0.833033 -0.273293 0.480941 +vn 0.000000 0.999969 0.000000 +vn 0.000000 -0.273293 -0.961913 +vn 0.833033 -0.273293 0.480941 +s 1 +f 4/1/1 3/2/2 1/3/3 +f 1/4/3 3/5/2 2/6/4 +f 2/7/4 3/8/2 4/9/1 +f 1/10/3 2/11/4 4/12/1 diff --git a/src/datavisualization/engine/meshes/scatterdotFlat.obj b/src/datavisualization/engine/meshes/scatterdotFlat.obj new file mode 100644 index 00000000..4052738d --- /dev/null +++ b/src/datavisualization/engine/meshes/scatterdotFlat.obj @@ -0,0 +1,28 @@ +# Blender v2.66 (sub 0) OBJ File: 'scatterdot.blend' +# www.blender.org +o Cone +v 0.000000 -0.500000 -1.000000 +v 0.866025 -0.500000 0.500000 +v 0.000000 0.500000 0.000000 +v -0.866025 -0.500000 0.500000 +vt 0.999727 0.000000 +vt 1.000000 0.492691 +vt 0.522886 0.369782 +vt 0.477114 0.973202 +vt 0.000000 1.096111 +vt 0.000273 0.603420 +vt 0.523159 0.985382 +vt 0.522886 0.492691 +vt 1.000000 0.615600 +vt 0.000000 0.603420 +vt 0.000617 0.000000 +vt 0.522886 0.302245 +vn -0.774597 0.447214 -0.447214 +vn 0.774597 0.447214 -0.447214 +vn -0.000000 0.447214 0.894427 +vn 0.000000 -1.000000 -0.000000 +s off +f 4/1/1 3/2/1 1/3/1 +f 1/4/2 3/5/2 2/6/2 +f 2/7/3 3/8/3 4/9/3 +f 1/10/4 2/11/4 4/12/4 diff --git a/src/datavisualization/engine/meshes/sphere.obj b/src/datavisualization/engine/meshes/sphere.obj new file mode 100644 index 00000000..671a7bcc --- /dev/null +++ b/src/datavisualization/engine/meshes/sphere.obj @@ -0,0 +1,1301 @@ +# Blender v2.66 (sub 0) OBJ File: 'sphere.blend' +# www.blender.org +o Sphere +v -0.195090 0.980785 0.000000 +v -0.382683 0.923880 0.000000 +v -0.555570 0.831470 0.000000 +v -0.707107 0.707107 0.000000 +v -0.831470 0.555570 0.000000 +v -0.923880 0.382683 0.000000 +v -0.980785 0.195090 0.000000 +v -1.000000 0.000000 0.000000 +v -0.980785 -0.195090 0.000000 +v -0.923880 -0.382683 0.000000 +v -0.831470 -0.555570 0.000000 +v -0.707107 -0.707107 0.000000 +v -0.555570 -0.831470 0.000000 +v -0.382683 -0.923880 0.000000 +v -0.195090 -0.980785 0.000000 +v -0.180240 0.980785 -0.074658 +v -0.353553 0.923880 -0.146447 +v -0.513280 0.831470 -0.212608 +v -0.653281 0.707107 -0.270598 +v -0.768178 0.555570 -0.318190 +v -0.853553 0.382683 -0.353553 +v -0.906127 0.195090 -0.375330 +v -0.923880 0.000000 -0.382684 +v -0.906127 -0.195090 -0.375330 +v -0.853553 -0.382683 -0.353554 +v -0.768178 -0.555570 -0.318190 +v -0.653281 -0.707107 -0.270598 +v -0.513280 -0.831470 -0.212608 +v -0.353553 -0.923880 -0.146447 +v -0.180240 -0.980785 -0.074658 +v 0.000000 -1.000000 0.000000 +v -0.137950 0.980785 -0.137950 +v -0.270598 0.923880 -0.270598 +v -0.392847 0.831470 -0.392848 +v -0.500000 0.707107 -0.500000 +v -0.587938 0.555570 -0.587938 +v -0.653281 0.382683 -0.653282 +v -0.693520 0.195090 -0.693520 +v -0.707107 0.000000 -0.707107 +v -0.693520 -0.195090 -0.693520 +v -0.653281 -0.382683 -0.653282 +v -0.587938 -0.555570 -0.587938 +v -0.500000 -0.707107 -0.500000 +v -0.392847 -0.831470 -0.392848 +v -0.270598 -0.923880 -0.270598 +v -0.137949 -0.980785 -0.137950 +v -0.074658 0.980785 -0.180240 +v -0.146446 0.923880 -0.353554 +v -0.212607 0.831470 -0.513280 +v -0.270598 0.707107 -0.653282 +v -0.318189 0.555570 -0.768178 +v -0.353553 0.382683 -0.853554 +v -0.375330 0.195090 -0.906128 +v -0.382683 0.000000 -0.923880 +v -0.375330 -0.195090 -0.906128 +v -0.353553 -0.382683 -0.853554 +v -0.318189 -0.555570 -0.768178 +v -0.270598 -0.707107 -0.653282 +v -0.212607 -0.831470 -0.513280 +v -0.146446 -0.923880 -0.353554 +v -0.074658 -0.980785 -0.180240 +v 0.000000 0.980785 -0.195091 +v 0.000000 0.923880 -0.382684 +v 0.000000 0.831470 -0.555570 +v 0.000000 0.707107 -0.707107 +v 0.000000 0.555570 -0.831470 +v 0.000000 0.382683 -0.923880 +v 0.000000 0.195090 -0.980785 +v 0.000000 0.000000 -1.000000 +v 0.000000 -0.195090 -0.980785 +v 0.000000 -0.382683 -0.923880 +v 0.000000 -0.555570 -0.831470 +v 0.000000 -0.707107 -0.707107 +v 0.000000 -0.831470 -0.555570 +v 0.000000 -0.923880 -0.382684 +v 0.000000 -0.980785 -0.195090 +v 0.074658 0.980785 -0.180240 +v 0.146447 0.923880 -0.353554 +v 0.212608 0.831470 -0.513280 +v 0.270598 0.707107 -0.653282 +v 0.318190 0.555570 -0.768178 +v 0.353554 0.382683 -0.853553 +v 0.375331 0.195090 -0.906128 +v 0.382684 0.000000 -0.923880 +v 0.375331 -0.195090 -0.906128 +v 0.353554 -0.382683 -0.853553 +v 0.318190 -0.555570 -0.768178 +v 0.270598 -0.707107 -0.653282 +v 0.212608 -0.831470 -0.513280 +v 0.146447 -0.923880 -0.353554 +v 0.074658 -0.980785 -0.180240 +v 0.137950 0.980785 -0.137950 +v 0.270599 0.923880 -0.270598 +v 0.392848 0.831470 -0.392848 +v 0.500000 0.707107 -0.500000 +v 0.587938 0.555570 -0.587938 +v 0.653282 0.382683 -0.653282 +v 0.693520 0.195090 -0.693520 +v 0.707107 0.000000 -0.707107 +v 0.693520 -0.195090 -0.693520 +v 0.653282 -0.382683 -0.653281 +v 0.587938 -0.555570 -0.587938 +v 0.500000 -0.707107 -0.500000 +v 0.392848 -0.831470 -0.392848 +v 0.270599 -0.923880 -0.270598 +v 0.137950 -0.980785 -0.137950 +v 0.180241 0.980785 -0.074658 +v 0.353554 0.923880 -0.146447 +v 0.513280 0.831470 -0.212608 +v 0.653282 0.707107 -0.270598 +v 0.768178 0.555570 -0.318190 +v 0.853554 0.382683 -0.353553 +v 0.906128 0.195090 -0.375330 +v 0.923880 0.000000 -0.382683 +v 0.906128 -0.195090 -0.375330 +v 0.853554 -0.382683 -0.353553 +v 0.768178 -0.555570 -0.318190 +v 0.653282 -0.707107 -0.270598 +v 0.513280 -0.831470 -0.212608 +v 0.353554 -0.923880 -0.146447 +v 0.180240 -0.980785 -0.074658 +v 0.195091 0.980785 0.000000 +v 0.382684 0.923880 0.000000 +v 0.555571 0.831470 0.000000 +v 0.707107 0.707107 0.000000 +v 0.831470 0.555570 0.000000 +v 0.923880 0.382683 0.000000 +v 0.980786 0.195090 0.000000 +v 1.000000 0.000000 0.000000 +v 0.980786 -0.195090 0.000000 +v 0.923880 -0.382683 0.000000 +v 0.831470 -0.555570 0.000000 +v 0.707107 -0.707107 0.000000 +v 0.555571 -0.831470 0.000000 +v 0.382684 -0.923880 0.000000 +v 0.195091 -0.980785 0.000000 +v 0.180241 0.980785 0.074658 +v 0.353554 0.923880 0.146447 +v 0.513280 0.831470 0.212608 +v 0.653282 0.707107 0.270598 +v 0.768178 0.555570 0.318190 +v 0.853554 0.382683 0.353553 +v 0.906128 0.195090 0.375330 +v 0.923880 0.000000 0.382684 +v 0.906128 -0.195090 0.375330 +v 0.853554 -0.382683 0.353553 +v 0.768178 -0.555570 0.318190 +v 0.653282 -0.707107 0.270598 +v 0.513280 -0.831470 0.212608 +v 0.353554 -0.923880 0.146447 +v 0.180240 -0.980785 0.074658 +v 0.137950 0.980785 0.137950 +v 0.270599 0.923880 0.270598 +v 0.392848 0.831470 0.392848 +v 0.500000 0.707107 0.500000 +v 0.587938 0.555570 0.587938 +v 0.653282 0.382683 0.653282 +v 0.693520 0.195090 0.693520 +v 0.707107 0.000000 0.707107 +v 0.693520 -0.195090 0.693520 +v 0.653282 -0.382683 0.653282 +v 0.587938 -0.555570 0.587938 +v 0.500000 -0.707107 0.500000 +v 0.392848 -0.831470 0.392848 +v 0.270599 -0.923880 0.270598 +v 0.137950 -0.980785 0.137950 +v 0.074658 0.980785 0.180240 +v 0.146447 0.923880 0.353554 +v 0.212608 0.831470 0.513280 +v 0.270598 0.707107 0.653282 +v 0.318190 0.555570 0.768178 +v 0.353554 0.382683 0.853553 +v 0.375331 0.195090 0.906128 +v 0.382684 0.000000 0.923880 +v 0.375331 -0.195090 0.906128 +v 0.353554 -0.382683 0.853553 +v 0.318190 -0.555570 0.768178 +v 0.270598 -0.707107 0.653282 +v 0.212608 -0.831470 0.513280 +v 0.146447 -0.923880 0.353554 +v 0.074658 -0.980785 0.180240 +v 0.000000 0.980785 0.195091 +v 0.000000 0.923880 0.382684 +v 0.000000 0.831470 0.555570 +v 0.000000 0.707107 0.707107 +v 0.000000 0.555570 0.831470 +v 0.000000 0.382683 0.923880 +v 0.000000 0.195090 0.980785 +v 0.000000 0.000000 1.000000 +v 0.000000 -0.195090 0.980785 +v 0.000000 -0.382683 0.923879 +v 0.000000 -0.555570 0.831470 +v 0.000000 -0.707107 0.707107 +v 0.000000 -0.831470 0.555570 +v 0.000000 -0.923880 0.382684 +v 0.000000 -0.980785 0.195090 +v -0.074658 0.980785 0.180240 +v -0.146446 0.923880 0.353554 +v -0.212607 0.831470 0.513280 +v -0.270598 0.707107 0.653282 +v -0.318189 0.555570 0.768178 +v -0.353553 0.382683 0.853553 +v -0.375330 0.195090 0.906128 +v -0.382683 0.000000 0.923880 +v -0.375330 -0.195090 0.906128 +v -0.353553 -0.382683 0.853553 +v -0.318189 -0.555570 0.768178 +v -0.270598 -0.707107 0.653282 +v -0.212607 -0.831470 0.513280 +v -0.146446 -0.923880 0.353554 +v -0.074658 -0.980785 0.180240 +v 0.000000 1.000000 0.000000 +v -0.137950 0.980785 0.137950 +v -0.270598 0.923880 0.270598 +v -0.392847 0.831470 0.392848 +v -0.500000 0.707107 0.500000 +v -0.587938 0.555570 0.587938 +v -0.653281 0.382683 0.653281 +v -0.693520 0.195090 0.693520 +v -0.707107 0.000000 0.707107 +v -0.693520 -0.195090 0.693520 +v -0.653281 -0.382683 0.653281 +v -0.587938 -0.555570 0.587938 +v -0.500000 -0.707107 0.500000 +v -0.392847 -0.831470 0.392848 +v -0.270598 -0.923880 0.270598 +v -0.137949 -0.980785 0.137950 +v -0.180240 0.980785 0.074658 +v -0.353553 0.923880 0.146447 +v -0.513280 0.831470 0.212608 +v -0.653281 0.707107 0.270598 +v -0.768177 0.555570 0.318190 +v -0.853553 0.382683 0.353553 +v -0.906127 0.195090 0.375330 +v -0.923879 0.000000 0.382683 +v -0.906127 -0.195090 0.375330 +v -0.853553 -0.382683 0.353553 +v -0.768177 -0.555570 0.318190 +v -0.653281 -0.707107 0.270598 +v -0.513280 -0.831470 0.212608 +v -0.353553 -0.923880 0.146447 +v -0.180240 -0.980785 0.074658 +vt 0.040867 0.325557 +vt 0.048386 0.386583 +vt 0.001015 0.334499 +vt 0.081872 0.692529 +vt 0.092315 0.752973 +vt 0.006404 0.709363 +vt 1.031336 0.264931 +vt 1.040867 0.325557 +vt 0.999822 0.272029 +vt 0.073887 0.631595 +vt 0.005301 0.646891 +vt 0.333915 0.937286 +vt 0.448527 0.905466 +vt 0.447682 0.976645 +vt 1.017784 0.205113 +vt 0.998129 0.209571 +vt 0.067156 0.570413 +vt 0.004397 0.584414 +vt 0.196016 0.918498 +vt 0.034176 0.958662 +vt 0.060989 0.509119 +vt 0.003585 0.521934 +vt 0.135028 0.869370 +vt 0.015221 0.896641 +vt 0.054891 0.447811 +vt 0.002796 0.459454 +vt 0.107782 0.812401 +vt 0.010297 0.834265 +vt 0.001965 0.396975 +vt 0.007907 0.771825 +vt 0.978319 0.207096 +vt 1.004397 0.584414 +vt 1.005301 0.646891 +vt 0.941200 0.576589 +vt 1.034176 0.958662 +vt 0.823807 0.933258 +vt 1.003585 0.521934 +vt 0.945911 0.514786 +vt 1.015221 0.896641 +vt 0.885287 0.880701 +vt 1.002796 0.459454 +vt 0.950535 0.452971 +vt 1.010297 0.834265 +vt 0.908873 0.821779 +vt 1.001965 0.396975 +vt 0.955439 0.391196 +vt 1.007907 0.771825 +vt 0.921503 0.761167 +vt 1.001015 0.334499 +vt 0.961079 0.329532 +vt 1.006404 0.709363 +vt 0.929787 0.699898 +vt 0.968202 0.268089 +vt 0.936013 0.638321 +vt 0.488610 0.915189 +vt 0.647808 0.950687 +vt 0.921611 0.311033 +vt 0.859136 0.666985 +vt 0.937209 0.253354 +vt 0.870446 0.607941 +vt 0.532175 0.909643 +vt 0.657607 0.903302 +vt 0.959449 0.197860 +vt 0.880347 0.548455 +vt 0.745300 0.879338 +vt 0.889690 0.488794 +vt 0.796385 0.834663 +vt 0.899158 0.429173 +vt 0.825891 0.781668 +vt 0.909472 0.369816 +vt 0.845097 0.725165 +vt 0.848920 0.390841 +vt 0.761226 0.728711 +vt 0.864196 0.334814 +vt 0.780693 0.674598 +vt 0.882867 0.280332 +vt 0.796418 0.618773 +vt 0.907539 0.228698 +vt 0.810089 0.562031 +vt 0.558962 0.891763 +vt 0.641452 0.857179 +vt 0.942759 0.182515 +vt 0.822818 0.504873 +vt 0.697492 0.824480 +vt 0.835477 0.447684 +vt 0.735147 0.779653 +vt 0.879896 0.195479 +vt 0.753309 0.508011 +vt 0.618082 0.815427 +vt 0.767315 0.452094 +vt 0.657173 0.773912 +vt 0.782092 0.396562 +vt 0.685241 0.725518 +vt 0.798714 0.341964 +vt 0.706593 0.673391 +vt 0.818709 0.289116 +vt 0.723996 0.619193 +vt 0.844487 0.239416 +vt 0.739178 0.563865 +vt 0.567268 0.868303 +vt 0.563300 0.844314 +vt 0.770454 0.236269 +vt 0.670392 0.566231 +vt 0.805029 0.190637 +vt 0.683774 0.509644 +vt 0.551952 0.822879 +vt 0.929896 0.162212 +vt 0.855308 0.155368 +vt 0.697011 0.452991 +vt 0.591182 0.780044 +vt 0.710973 0.396675 +vt 0.618699 0.730484 +vt 0.726705 0.341193 +vt 0.639317 0.677374 +vt 0.745717 0.287291 +vt 0.655961 0.622327 +vt 0.665037 0.288362 +vt 0.594131 0.638967 +vt 0.684737 0.232805 +vt 0.605914 0.580518 +vt 0.713639 0.180821 +vt 0.616615 0.521685 +vt 0.760428 0.136665 +vt 0.627046 0.462757 +vt 0.536166 0.805967 +vt 0.923407 0.138703 +vt 0.836350 0.110271 +vt 0.637946 0.403995 +vt 0.562017 0.752770 +vt 0.650183 0.345708 +vt 0.580132 0.696622 +vt 0.517784 0.794886 +vt 0.927547 0.114679 +vt 0.833915 0.062714 +vt 0.573887 0.368405 +vt 0.531336 0.735069 +vt 0.581872 0.307471 +vt 0.540867 0.674443 +vt 0.592315 0.247027 +vt 0.548386 0.613417 +vt 0.607782 0.187599 +vt 0.554891 0.552189 +vt 0.635028 0.130630 +vt 0.560989 0.490881 +vt 0.696016 0.081502 +vt 0.567156 0.429587 +vt 0.502796 0.540546 +vt 0.515221 0.103359 +vt 0.503585 0.478066 +vt 0.534176 0.041338 +vt 0.504397 0.415586 +vt 0.498129 0.790428 +vt 0.948527 0.094534 +vt 0.947682 0.023355 +vt 0.505301 0.353109 +vt 0.499822 0.727971 +vt 0.506404 0.290637 +vt 0.501015 0.665501 +vt 0.507907 0.228175 +vt 0.501965 0.603025 +vt 0.510297 0.165735 +vt 0.429787 0.300102 +vt 0.461079 0.670468 +vt 0.421503 0.238833 +vt 0.455439 0.608804 +vt 0.408873 0.178221 +vt 0.445911 0.485214 +vt 0.385287 0.119299 +vt 1.323807 0.066742 +vt 0.441200 0.423411 +vt 0.478319 0.792904 +vt 0.988610 0.084811 +vt 1.147808 0.049313 +vt 0.436013 0.361679 +vt 0.468202 0.731911 +vt 0.147808 0.049313 +vt 0.323807 0.066742 +vt 0.245300 0.120661 +vt 0.380347 0.451545 +vt 0.459449 0.802140 +vt 0.032175 0.090357 +vt 0.157607 0.096698 +vt 0.370446 0.392059 +vt 0.437209 0.746646 +vt 0.359136 0.333015 +vt 0.421611 0.688967 +vt 0.345097 0.274835 +vt 0.450536 0.547029 +vt 0.409472 0.630184 +vt 0.325892 0.218332 +vt 0.399158 0.570827 +vt 0.296385 0.165337 +vt 0.389690 0.511206 +vt 0.261226 0.271289 +vt 0.348920 0.609159 +vt 0.235147 0.220347 +vt 0.335478 0.552316 +vt 0.197492 0.175520 +vt 0.322818 0.495127 +vt 0.442759 0.817485 +vt 0.058962 0.108237 +vt 0.141452 0.142821 +vt 0.310089 0.437969 +vt 0.407539 0.771302 +vt 0.296418 0.381227 +vt 0.382867 0.719668 +vt 0.280693 0.325402 +vt 0.364196 0.665186 +vt 0.223996 0.380807 +vt 0.318709 0.710884 +vt 0.206593 0.326609 +vt 0.298714 0.658036 +vt 0.185241 0.274482 +vt 0.282092 0.603438 +vt 0.157173 0.226088 +vt 0.267315 0.547906 +vt 0.118082 0.184573 +vt 0.253309 0.491989 +vt 0.379896 0.804521 +vt 0.067268 0.131697 +vt 0.063300 0.155685 +vt 0.239178 0.436135 +vt 0.344487 0.760584 +vt 0.091182 0.219955 +vt 0.197011 0.547009 +vt 0.429896 0.837788 +vt 0.355308 0.844632 +vt 0.051952 0.177121 +vt 0.183774 0.490356 +vt 0.305029 0.809363 +vt 0.170392 0.433769 +vt 0.270454 0.763731 +vt 0.155961 0.377673 +vt 0.245717 0.712709 +vt 0.226706 0.658807 +vt 0.118699 0.269516 +vt 0.210973 0.603325 +vt 0.139317 0.322626 +vt 0.094131 0.361033 +vt 0.165037 0.711638 +vt 0.080132 0.303378 +vt 0.150183 0.654292 +vt 0.062017 0.247229 +vt 0.137946 0.596005 +vt 0.423407 0.861296 +vt 0.336350 0.889729 +vt 0.036166 0.194032 +vt 0.127046 0.537243 +vt 0.260428 0.863335 +vt 0.116615 0.478315 +vt 0.213639 0.819179 +vt 0.105914 0.419482 +vt 0.184737 0.767195 +vt 0.495265 0.852856 +vt 0.995265 0.147143 +vt 1.032175 0.090357 +vt 1.058962 0.108237 +vt 1.067268 0.131697 +vt 1.063300 0.155685 +vt 1.051952 0.177121 +vt 0.427547 0.885321 +vt 1.036166 0.194032 +vt 0.031336 0.264931 +vt 0.017784 0.205113 +vn -0.629402 -0.766928 -0.125196 +vn -0.940062 0.285165 -0.186990 +vn -0.469338 -0.878070 -0.093357 +vn -0.976241 0.096152 -0.194186 +vn -0.289802 0.955349 -0.057645 +vn -0.289802 -0.955349 -0.057645 +vn -0.976241 -0.096151 -0.194186 +vn -0.469338 0.878070 -0.093357 +vn -0.940062 -0.285165 -0.186990 +vn -0.629402 0.766928 -0.125196 +vn -0.868657 -0.464306 -0.172787 +vn -0.764031 0.627024 -0.151975 +vn -0.764031 -0.627024 -0.151975 +vn -0.868657 0.464306 -0.172787 +vn -0.245682 -0.955349 -0.164159 +vn -0.827617 -0.096152 -0.552996 +vn -0.397886 0.878069 -0.265859 +vn -0.796946 -0.285165 -0.532502 +vn -0.533581 0.766929 -0.356527 +vn -0.736412 -0.464306 -0.492055 +vn -0.647715 0.627024 -0.432789 +vn -0.647714 -0.627024 -0.432789 +vn -0.736412 0.464306 -0.492055 +vn -0.533581 -0.766928 -0.356528 +vn -0.796946 0.285165 -0.532502 +vn -0.397886 -0.878070 -0.265859 +vn -0.827617 0.096152 -0.552996 +vn -0.245682 0.955349 -0.164160 +vn -0.356527 -0.766928 -0.533581 +vn -0.532502 0.285165 -0.796946 +vn -0.265859 -0.878070 -0.397886 +vn -0.552996 0.096152 -0.827617 +vn -0.164160 0.955349 -0.245682 +vn -0.164159 -0.955349 -0.245682 +vn -0.552996 -0.096152 -0.827617 +vn -0.265859 0.878069 -0.397886 +vn -0.532502 -0.285165 -0.796946 +vn -0.356527 0.766929 -0.533581 +vn -0.492054 -0.464306 -0.736412 +vn -0.432789 0.627024 -0.647715 +vn -0.432789 -0.627024 -0.647715 +vn -0.492054 0.464306 -0.736412 +vn -0.172786 -0.464306 -0.868657 +vn -0.151975 0.627024 -0.764032 +vn -0.151975 -0.627024 -0.764032 +vn -0.172786 0.464306 -0.868657 +vn -0.125196 -0.766928 -0.629402 +vn -0.186990 0.285165 -0.940062 +vn -0.093357 -0.878070 -0.469338 +vn -0.194186 0.096152 -0.976241 +vn -0.057645 0.955349 -0.289802 +vn -0.057645 -0.955349 -0.289801 +vn -0.194186 -0.096152 -0.976241 +vn -0.093357 0.878069 -0.469338 +vn -0.186990 -0.285165 -0.940062 +vn -0.125196 0.766929 -0.629402 +vn 0.057645 -0.955349 -0.289801 +vn 0.194186 -0.096152 -0.976241 +vn 0.093357 0.878069 -0.469338 +vn 0.186990 -0.285165 -0.940062 +vn 0.125196 0.766929 -0.629402 +vn 0.172787 -0.464306 -0.868657 +vn 0.151975 0.627024 -0.764031 +vn 0.151975 -0.627024 -0.764031 +vn 0.172787 0.464306 -0.868657 +vn 0.125196 -0.766928 -0.629402 +vn 0.186990 0.285165 -0.940062 +vn 0.093357 -0.878070 -0.469338 +vn 0.194186 0.096152 -0.976241 +vn 0.057645 0.955349 -0.289802 +vn 0.356528 -0.766928 -0.533581 +vn 0.532502 0.285165 -0.796946 +vn 0.265859 -0.878070 -0.397886 +vn 0.552996 0.096152 -0.827617 +vn 0.164160 0.955349 -0.245682 +vn 0.164159 -0.955349 -0.245682 +vn 0.552996 -0.096152 -0.827617 +vn 0.265859 0.878069 -0.397886 +vn 0.532502 -0.285165 -0.796946 +vn 0.356527 0.766929 -0.533581 +vn 0.492055 -0.464306 -0.736412 +vn 0.432789 0.627024 -0.647715 +vn 0.432789 -0.627024 -0.647714 +vn 0.492055 0.464306 -0.736412 +vn 0.736412 -0.464306 -0.492055 +vn 0.647715 0.627024 -0.432789 +vn 0.647715 -0.627024 -0.432789 +vn 0.736412 0.464306 -0.492054 +vn 0.533581 -0.766928 -0.356528 +vn 0.796946 0.285165 -0.532502 +vn 0.397886 -0.878070 -0.265859 +vn 0.827617 0.096152 -0.552996 +vn 0.245682 0.955349 -0.164160 +vn 0.245682 -0.955349 -0.164159 +vn 0.827617 -0.096152 -0.552996 +vn 0.397886 0.878069 -0.265859 +vn 0.796946 -0.285165 -0.532502 +vn 0.533581 0.766929 -0.356527 +vn 0.289802 0.955349 -0.057645 +vn 0.289801 -0.955349 -0.057645 +vn 0.976241 -0.096152 -0.194186 +vn 0.469338 0.878069 -0.093357 +vn 0.940062 -0.285165 -0.186990 +vn 0.629402 0.766929 -0.125196 +vn 0.868657 -0.464306 -0.172786 +vn 0.764032 0.627024 -0.151975 +vn 0.764032 -0.627024 -0.151975 +vn 0.868657 0.464307 -0.172786 +vn 0.629402 -0.766928 -0.125196 +vn 0.940062 0.285165 -0.186990 +vn 0.469338 -0.878069 -0.093357 +vn 0.976241 0.096152 -0.194186 +vn 0.868657 0.464306 0.172787 +vn 0.629402 -0.766928 0.125196 +vn 0.940062 0.285165 0.186990 +vn 0.469338 -0.878069 0.093357 +vn 0.976241 0.096152 0.194186 +vn 0.289802 0.955349 0.057645 +vn 0.289801 -0.955349 0.057645 +vn 0.976241 -0.096152 0.194187 +vn 0.469338 0.878069 0.093357 +vn 0.940061 -0.285165 0.186990 +vn 0.629402 0.766929 0.125196 +vn 0.868657 -0.464306 0.172787 +vn 0.764032 0.627024 0.151975 +vn 0.764032 -0.627024 0.151976 +vn 0.796946 -0.285165 0.532502 +vn 0.533581 0.766929 0.356527 +vn 0.736412 -0.464306 0.492055 +vn 0.647715 0.627024 0.432789 +vn 0.647715 -0.627024 0.432789 +vn 0.736411 0.464307 0.492054 +vn 0.533581 -0.766928 0.356528 +vn 0.796946 0.285165 0.532502 +vn 0.397886 -0.878070 0.265859 +vn 0.827617 0.096151 0.552996 +vn 0.245682 0.955349 0.164160 +vn 0.245682 -0.955349 0.164159 +vn 0.827617 -0.096151 0.552996 +vn 0.397886 0.878070 0.265859 +vn 0.265859 -0.878070 0.397886 +vn 0.552996 0.096151 0.827617 +vn 0.164160 0.955349 0.245682 +vn 0.164159 -0.955349 0.245682 +vn 0.552996 -0.096151 0.827617 +vn 0.265859 0.878070 0.397886 +vn 0.532502 -0.285165 0.796946 +vn 0.356527 0.766929 0.533581 +vn 0.492054 -0.464306 0.736412 +vn 0.432789 0.627024 0.647715 +vn 0.432789 -0.627024 0.647715 +vn 0.492054 0.464307 0.736412 +vn 0.356528 -0.766928 0.533581 +vn 0.532502 0.285165 0.796946 +vn 0.151975 -0.627024 0.764032 +vn 0.172786 0.464307 0.868656 +vn 0.125196 -0.766928 0.629402 +vn 0.186990 0.285165 0.940062 +vn 0.093357 -0.878070 0.469338 +vn 0.194186 0.096151 0.976241 +vn 0.057645 0.955349 0.289802 +vn 0.057645 -0.955349 0.289801 +vn 0.194186 -0.096151 0.976241 +vn 0.093357 0.878070 0.469338 +vn 0.186990 -0.285166 0.940061 +vn 0.125196 0.766929 0.629402 +vn 0.172786 -0.464306 0.868657 +vn 0.151975 0.627023 0.764032 +vn -0.186990 -0.285166 0.940061 +vn -0.125196 0.766929 0.629402 +vn -0.172787 -0.464306 0.868657 +vn -0.151976 0.627023 0.764032 +vn -0.151975 -0.627024 0.764032 +vn -0.172787 0.464307 0.868656 +vn -0.125196 -0.766928 0.629402 +vn -0.186990 0.285165 0.940062 +vn -0.093357 -0.878069 0.469338 +vn -0.194186 0.096151 0.976241 +vn -0.057645 0.955349 0.289802 +vn -0.057645 -0.955349 0.289801 +vn -0.194186 -0.096151 0.976241 +vn -0.093357 0.878069 0.469338 +vn -0.265859 -0.878070 0.397886 +vn -0.552996 0.096151 0.827617 +vn -0.164160 0.955349 0.245682 +vn -0.164159 -0.955349 0.245682 +vn -0.552996 -0.096151 0.827617 +vn -0.265859 0.878070 0.397886 +vn -0.532502 -0.285166 0.796945 +vn -0.356527 0.766929 0.533581 +vn -0.492054 -0.464306 0.736412 +vn -0.432790 0.627023 0.647715 +vn -0.432789 -0.627024 0.647715 +vn -0.492054 0.464307 0.736411 +vn -0.356528 -0.766928 0.533581 +vn -0.532502 0.285165 0.796946 +vn -0.647715 -0.627024 0.432789 +vn -0.736411 0.464307 0.492054 +vn -0.533581 -0.766928 0.356528 +vn -0.796946 0.285165 0.532502 +vn -0.397886 -0.878070 0.265859 +vn -0.827617 0.096151 0.552996 +vn -0.245682 0.955349 0.164160 +vn -0.245682 -0.955349 0.164159 +vn -0.827617 -0.096151 0.552996 +vn -0.397886 0.878070 0.265859 +vn -0.796946 -0.285166 0.532502 +vn -0.533581 0.766929 0.356527 +vn -0.736412 -0.464306 0.492054 +vn -0.647715 0.627023 0.432789 +vn -0.097999 0.994996 -0.019493 +vn -0.097998 -0.994996 -0.019493 +vn -0.083079 -0.994996 -0.055512 +vn -0.083079 0.994996 -0.055512 +vn -0.055512 0.994996 -0.083079 +vn -0.055512 -0.994996 -0.083079 +vn -0.019493 0.994996 -0.097998 +vn -0.019493 -0.994996 -0.097998 +vn 0.019493 -0.994996 -0.097998 +vn 0.019493 0.994996 -0.097998 +vn 0.055512 0.994996 -0.083079 +vn 0.055512 -0.994996 -0.083079 +vn 0.083079 0.994996 -0.055512 +vn 0.083079 -0.994996 -0.055512 +vn 0.097998 -0.994996 -0.019493 +vn 0.097998 0.994996 -0.019493 +vn 0.097998 0.994996 0.019493 +vn 0.097998 -0.994996 0.019493 +vn 0.083079 0.994996 0.055512 +vn 0.083079 -0.994996 0.055512 +vn 0.055512 -0.994996 0.083079 +vn 0.055512 0.994996 0.083079 +vn 0.019493 0.994996 0.097999 +vn 0.019493 -0.994996 0.097998 +vn -0.019493 -0.994996 0.097998 +vn -0.019493 0.994996 0.097999 +vn -0.055512 -0.994996 0.083079 +vn -0.055512 0.994996 0.083079 +vn -0.083079 0.994996 0.055512 +vn -0.083079 -0.994996 0.055512 +vn -0.097998 -0.994996 0.019493 +vn -0.940061 -0.285166 0.186991 +vn -0.629402 0.766929 0.125196 +vn -0.868656 -0.464306 0.172788 +vn -0.764032 0.627023 0.151977 +vn -0.764032 -0.627024 0.151976 +vn -0.868656 0.464307 0.172787 +vn -0.629402 -0.766928 0.125196 +vn -0.940061 0.285165 0.186990 +vn -0.097999 0.994996 0.019493 +vn -0.469338 -0.878070 0.093357 +vn -0.976241 0.096151 0.194187 +vn -0.289802 0.955349 0.057646 +vn -0.289801 -0.955349 0.057645 +vn -0.976241 -0.096151 0.194187 +vn -0.469338 0.878070 0.093358 +vn -0.976241 -0.096152 -0.194186 +vn -0.469338 0.878069 -0.093357 +vn -0.629401 0.766929 -0.125196 +vn -0.764032 0.627024 -0.151975 +vn -0.736411 -0.464306 -0.492055 +vn -0.736411 0.464306 -0.492055 +vn -0.356528 -0.766928 -0.533581 +vn -0.151975 -0.627024 -0.764031 +vn -0.194186 -0.096151 -0.976241 +vn 0.186990 -0.285165 -0.940061 +vn 0.151975 0.627024 -0.764032 +vn 0.432789 -0.627024 -0.647715 +vn 0.492055 0.464306 -0.736411 +vn 0.736412 -0.464306 -0.492054 +vn 0.736411 0.464307 -0.492054 +vn 0.976241 -0.096151 -0.194186 +vn 0.940062 -0.285166 -0.186990 +vn 0.868657 -0.464306 -0.172787 +vn 0.868657 0.464306 -0.172786 +vn 0.940061 0.285165 -0.186990 +vn 0.868656 0.464307 0.172787 +vn 0.976241 0.096151 0.194187 +vn 0.976241 -0.096151 0.194186 +vn 0.469338 0.878070 0.093357 +vn 0.940061 -0.285166 0.186990 +vn 0.764032 0.627024 0.151976 +vn 0.764032 -0.627024 0.151975 +vn 0.796945 -0.285166 0.532502 +vn 0.647715 0.627023 0.432790 +vn 0.736411 0.464307 0.492055 +vn 0.532502 -0.285166 0.796946 +vn 0.432789 0.627023 0.647715 +vn 0.492054 0.464307 0.736411 +vn 0.151975 -0.627023 0.764032 +vn 0.186990 0.285165 0.940061 +vn 0.093357 0.878069 0.469338 +vn -0.151975 0.627023 0.764032 +vn -0.151976 -0.627023 0.764032 +vn -0.186990 0.285165 0.940061 +vn -0.093357 -0.878070 0.469338 +vn -0.093357 0.878070 0.469338 +vn -0.532502 -0.285166 0.796946 +vn -0.492055 -0.464306 0.736412 +vn -0.432789 -0.627023 0.647715 +vn -0.647715 -0.627023 0.432789 +vn -0.796945 -0.285166 0.532502 +vn -0.647715 0.627023 0.432790 +vn -0.940062 -0.285165 0.186990 +vn -0.629402 0.766928 0.125196 +vn -0.764031 0.627024 0.151975 +vn -0.764031 -0.627024 0.151976 +vn -0.868657 0.464306 0.172788 +vn -0.940062 0.285165 0.186991 +vn -0.976241 0.096152 0.194187 +vn -0.289802 -0.955349 0.057645 +s off +f 13/1/1 12/2/1 28/3/1 +f 7/4/2 6/5/2 22/6/2 +f 14/7/3 13/8/3 29/9/3 +f 8/10/4 7/4/4 23/11/4 +f 2/12/5 1/13/5 17/14/5 +f 15/15/6 14/7/6 30/16/6 +f 9/17/7 8/10/7 24/18/7 +f 3/19/8 2/12/8 18/20/8 +f 10/21/9 9/17/9 25/22/9 +f 4/23/10 3/19/10 19/24/10 +f 11/25/11 10/21/11 26/26/11 +f 5/27/12 4/23/12 20/28/12 +f 12/2/13 11/25/13 27/29/13 +f 6/5/14 5/27/14 21/30/14 +f 30/16/15 29/9/15 46/31/15 +f 24/32/16 23/33/16 40/34/16 +f 18/35/17 17/14/17 34/36/17 +f 25/37/18 24/32/18 41/38/18 +f 19/39/19 18/35/19 35/40/19 +f 26/41/20 25/37/20 42/42/20 +f 20/43/21 19/39/21 36/44/21 +f 27/45/22 26/41/22 43/46/22 +f 21/47/23 20/43/23 37/48/23 +f 28/49/24 27/45/24 44/50/24 +f 22/51/25 21/47/25 38/52/25 +f 29/9/26 28/49/26 45/53/26 +f 23/33/27 22/51/27 39/54/27 +f 17/14/28 16/55/28 33/56/28 +f 44/50/29 43/46/29 59/57/29 +f 38/52/30 37/48/30 53/58/30 +f 45/53/31 44/50/31 60/59/31 +f 39/54/32 38/52/32 54/60/32 +f 33/56/33 32/61/33 48/62/33 +f 46/31/34 45/53/34 61/63/34 +f 40/34/35 39/54/35 55/64/35 +f 34/36/36 33/56/36 49/65/36 +f 41/38/37 40/34/37 56/66/37 +f 35/40/38 34/36/38 50/67/38 +f 42/42/39 41/38/39 57/68/39 +f 36/44/40 35/40/40 51/69/40 +f 43/46/41 42/42/41 58/70/41 +f 37/48/42 36/44/42 52/71/42 +f 57/68/43 56/66/43 72/72/43 +f 51/69/44 50/67/44 66/73/44 +f 58/70/45 57/68/45 73/74/45 +f 52/71/46 51/69/46 67/75/46 +f 59/57/47 58/70/47 74/76/47 +f 53/58/48 52/71/48 68/77/48 +f 60/59/49 59/57/49 75/78/49 +f 54/60/50 53/58/50 69/79/50 +f 48/62/51 47/80/51 63/81/51 +f 61/63/52 60/59/52 76/82/52 +f 55/64/53 54/60/53 70/83/53 +f 49/65/54 48/62/54 64/84/54 +f 56/66/55 55/64/55 71/85/55 +f 50/67/56 49/65/56 65/86/56 +f 76/82/57 75/78/57 90/87/57 +f 70/83/58 69/79/58 84/88/58 +f 64/84/59 63/81/59 78/89/59 +f 71/85/60 70/83/60 85/90/60 +f 65/86/61 64/84/61 79/91/61 +f 72/72/62 71/85/62 86/92/62 +f 66/73/63 65/86/63 80/93/63 +f 73/74/64 72/72/64 87/94/64 +f 67/75/65 66/73/65 81/95/65 +f 74/76/66 73/74/66 88/96/66 +f 68/77/67 67/75/67 82/97/67 +f 75/78/68 74/76/68 89/98/68 +f 69/79/69 68/77/69 83/99/69 +f 63/81/70 62/100/70 77/101/70 +f 89/98/71 88/96/71 103/102/71 +f 83/99/72 82/97/72 97/103/72 +f 90/87/73 89/98/73 104/104/73 +f 84/88/74 83/99/74 98/105/74 +f 78/89/75 77/101/75 92/106/75 +f 91/107/76 90/87/76 105/108/76 +f 85/90/77 84/88/77 99/109/77 +f 79/91/78 78/89/78 93/110/78 +f 86/92/79 85/90/79 100/111/79 +f 80/93/80 79/91/80 94/112/80 +f 87/94/81 86/92/81 101/113/81 +f 81/95/82 80/93/82 95/114/82 +f 88/96/83 87/94/83 102/115/83 +f 82/97/84 81/95/84 96/116/84 +f 102/115/85 101/113/85 116/117/85 +f 96/116/86 95/114/86 110/118/86 +f 103/102/87 102/115/87 117/119/87 +f 97/103/88 96/116/88 111/120/88 +f 104/104/89 103/102/89 118/121/89 +f 98/105/90 97/103/90 112/122/90 +f 105/108/91 104/104/91 119/123/91 +f 99/109/92 98/105/92 113/124/92 +f 93/110/93 92/106/93 107/125/93 +f 106/126/94 105/108/94 120/127/94 +f 100/111/95 99/109/95 114/128/95 +f 94/112/96 93/110/96 108/129/96 +f 101/113/97 100/111/97 115/130/97 +f 95/114/98 94/112/98 109/131/98 +f 108/129/99 107/125/99 122/132/99 +f 121/133/100 120/127/100 135/134/100 +f 115/130/101 114/128/101 129/135/101 +f 109/131/102 108/129/102 123/136/102 +f 116/117/103 115/130/103 130/137/103 +f 110/118/104 109/131/104 124/138/104 +f 117/119/105 116/117/105 131/139/105 +f 111/120/106 110/118/106 125/140/106 +f 118/121/107 117/119/107 132/141/107 +f 112/122/108 111/120/108 126/142/108 +f 119/123/109 118/121/109 133/143/109 +f 113/124/110 112/122/110 127/144/110 +f 120/127/111 119/123/111 134/145/111 +f 114/128/112 113/124/112 128/146/112 +f 127/144/113 126/142/113 141/147/113 +f 134/145/114 133/143/114 148/148/114 +f 128/146/115 127/144/115 142/149/115 +f 135/134/116 134/145/116 149/150/116 +f 129/135/117 128/146/117 143/151/117 +f 123/136/118 122/132/118 137/152/118 +f 136/153/119 135/134/119 150/154/119 +f 130/137/120 129/135/120 144/155/120 +f 124/138/121 123/136/121 138/156/121 +f 131/139/122 130/137/122 145/157/122 +f 125/140/123 124/138/123 139/158/123 +f 132/141/124 131/139/124 146/159/124 +f 126/142/125 125/140/125 140/160/125 +f 133/143/126 132/141/126 147/161/126 +f 146/159/127 145/157/127 160/162/127 +f 140/160/128 139/158/128 154/163/128 +f 147/161/129 146/159/129 161/164/129 +f 141/147/130 140/160/130 155/165/130 +f 148/148/131 147/161/131 162/166/131 +f 142/149/132 141/147/132 157/167/132 +f 149/150/133 148/148/133 163/168/133 +f 143/151/134 142/149/134 157/167/134 +f 150/154/135 149/150/135 164/169/135 +f 144/155/136 143/151/136 158/170/136 +f 138/156/137 137/152/137 152/171/137 +f 151/172/138 150/154/138 165/173/138 +f 145/157/139 144/155/139 159/174/139 +f 139/158/140 138/156/140 153/175/140 +f 165/176/141 164/177/141 179/178/141 +f 159/174/142 158/170/142 173/179/142 +f 153/175/143 152/171/143 167/180/143 +f 166/181/144 165/176/144 180/182/144 +f 160/162/145 159/174/145 174/183/145 +f 154/163/146 153/175/146 168/184/146 +f 161/164/147 160/162/147 175/185/147 +f 155/165/148 154/163/148 169/186/148 +f 162/166/149 161/164/149 176/187/149 +f 156/188/150 155/165/150 170/189/150 +f 163/168/151 162/166/151 177/190/151 +f 157/167/152 156/188/152 171/191/152 +f 164/177/153 163/168/153 178/192/153 +f 158/170/154 157/167/154 172/193/154 +f 178/192/155 177/190/155 192/194/155 +f 172/193/156 171/191/156 186/195/156 +f 179/178/157 178/192/157 193/196/157 +f 173/179/158 172/193/158 187/197/158 +f 180/182/159 179/178/159 194/198/159 +f 174/183/160 173/179/160 188/199/160 +f 168/184/161 167/180/161 182/200/161 +f 181/201/162 180/182/162 195/202/162 +f 175/185/163 174/183/163 189/203/163 +f 169/186/164 168/184/164 183/204/164 +f 176/187/165 175/185/165 190/205/165 +f 170/189/166 169/186/166 184/206/166 +f 177/190/167 176/187/167 191/207/167 +f 171/191/168 170/189/168 185/208/168 +f 191/207/169 190/205/169 206/209/169 +f 185/208/170 184/206/170 200/210/170 +f 192/194/171 191/207/171 207/211/171 +f 186/195/172 185/208/172 201/212/172 +f 193/196/173 192/194/173 208/213/173 +f 187/197/174 186/195/174 202/214/174 +f 194/198/175 193/196/175 209/215/175 +f 188/199/176 187/197/176 203/216/176 +f 195/202/177 194/198/177 210/217/177 +f 189/203/178 188/199/178 204/218/178 +f 183/204/179 182/200/179 198/219/179 +f 196/220/180 195/202/180 211/221/180 +f 190/205/181 189/203/181 205/222/181 +f 184/206/182 183/204/182 199/223/182 +f 210/217/183 209/215/183 226/224/183 +f 204/218/184 203/216/184 220/225/184 +f 198/219/185 197/226/185 214/227/185 +f 211/221/186 210/217/186 227/228/186 +f 205/222/187 204/218/187 221/229/187 +f 199/223/188 198/219/188 215/230/188 +f 206/209/189 205/222/189 222/231/189 +f 200/210/190 199/223/190 216/232/190 +f 207/211/191 206/209/191 223/233/191 +f 201/212/192 200/210/192 217/234/192 +f 208/213/193 207/211/193 223/233/193 +f 202/214/194 201/212/194 218/235/194 +f 209/215/195 208/213/195 225/236/195 +f 203/216/196 202/214/196 219/237/196 +f 224/238/197 223/233/197 239/239/197 +f 218/235/198 217/234/198 233/240/198 +f 225/236/199 224/238/199 240/241/199 +f 219/237/200 218/235/200 234/242/200 +f 226/224/201 225/236/201 241/243/201 +f 220/225/202 219/237/202 235/244/202 +f 214/227/203 213/245/203 229/246/203 +f 227/228/204 226/224/204 242/247/204 +f 221/229/205 220/225/205 236/248/205 +f 215/230/206 214/227/206 230/249/206 +f 222/231/207 221/229/207 237/250/207 +f 216/232/208 215/230/208 231/251/208 +f 223/233/209 222/231/209 238/252/209 +f 217/234/210 216/232/210 232/253/210 +f 1/13/211 212/254/211 16/55/211 +f 31/255/212 15/15/212 30/16/212 +f 31/255/213 30/16/213 46/31/213 +f 16/55/214 212/254/214 32/61/214 +f 32/61/215 212/254/215 47/80/215 +f 31/255/216 46/31/216 61/63/216 +f 47/80/217 212/254/217 62/100/217 +f 31/255/218 61/63/218 76/82/218 +f 31/255/219 76/82/219 91/107/219 +f 62/100/220 212/254/220 77/101/220 +f 77/101/221 212/254/221 92/106/221 +f 31/255/222 91/107/222 106/126/222 +f 92/106/223 212/254/223 107/125/223 +f 31/255/224 106/126/224 121/133/224 +f 31/255/225 121/133/225 136/153/225 +f 107/125/226 212/254/226 122/132/226 +f 122/132/227 212/254/227 137/152/227 +f 31/255/228 136/153/228 151/172/228 +f 137/152/229 212/254/229 152/171/229 +f 31/255/230 151/172/230 166/256/230 +f 31/255/231 166/256/231 181/257/231 +f 152/171/232 212/254/232 167/180/232 +f 167/180/233 212/254/233 182/200/233 +f 31/255/234 181/257/234 196/258/234 +f 31/255/235 196/258/235 211/259/235 +f 182/200/236 212/254/236 197/226/236 +f 31/255/237 211/259/237 227/260/237 +f 197/226/238 212/254/238 213/245/238 +f 213/245/239 212/254/239 228/261/239 +f 31/255/240 227/260/240 242/262/240 +f 31/255/241 242/262/241 15/15/241 +f 237/250/242 236/248/242 10/21/242 +f 231/251/243 230/249/243 4/23/243 +f 238/252/244 237/250/244 10/21/244 +f 232/253/245 231/251/245 5/27/245 +f 239/239/246 238/252/246 11/25/246 +f 233/240/247 232/253/247 6/5/247 +f 240/241/248 239/239/248 13/1/248 +f 234/242/249 233/240/249 7/4/249 +f 228/261/250 212/254/250 1/13/250 +f 241/243/251 240/241/251 14/263/251 +f 235/244/252 234/242/252 8/10/252 +f 229/246/253 228/261/253 2/12/253 +f 242/247/254 241/243/254 15/264/254 +f 236/248/255 235/244/255 9/17/255 +f 230/249/256 229/246/256 3/19/256 +f 12/2/1 27/29/1 28/3/1 +f 6/5/2 21/30/2 22/6/2 +f 13/8/3 28/49/3 29/9/3 +f 7/4/4 22/6/4 23/11/4 +f 1/13/5 16/55/5 17/14/5 +f 14/7/6 29/9/6 30/16/6 +f 8/10/257 23/11/257 24/18/257 +f 2/12/258 17/14/258 18/20/258 +f 9/17/9 24/18/9 25/22/9 +f 3/19/259 18/20/259 19/24/259 +f 10/21/11 25/22/11 26/26/11 +f 4/23/260 19/24/260 20/28/260 +f 11/25/13 26/26/13 27/29/13 +f 5/27/14 20/28/14 21/30/14 +f 29/9/15 45/53/15 46/31/15 +f 23/33/16 39/54/16 40/34/16 +f 17/14/17 33/56/17 34/36/17 +f 24/32/18 40/34/18 41/38/18 +f 18/35/19 34/36/19 35/40/19 +f 25/37/261 41/38/261 42/42/261 +f 19/39/21 35/40/21 36/44/21 +f 26/41/22 42/42/22 43/46/22 +f 20/43/262 36/44/262 37/48/262 +f 27/45/24 43/46/24 44/50/24 +f 21/47/25 37/48/25 38/52/25 +f 28/49/26 44/50/26 45/53/26 +f 22/51/27 38/52/27 39/54/27 +f 16/55/28 32/61/28 33/56/28 +f 43/46/263 58/70/263 59/57/263 +f 37/48/30 52/71/30 53/58/30 +f 44/50/31 59/57/31 60/59/31 +f 38/52/32 53/58/32 54/60/32 +f 32/61/33 47/80/33 48/62/33 +f 45/53/34 60/59/34 61/63/34 +f 39/54/35 54/60/35 55/64/35 +f 33/56/36 48/62/36 49/65/36 +f 40/34/37 55/64/37 56/66/37 +f 34/36/38 49/65/38 50/67/38 +f 41/38/39 56/66/39 57/68/39 +f 35/40/40 50/67/40 51/69/40 +f 42/42/41 57/68/41 58/70/41 +f 36/44/42 51/69/42 52/71/42 +f 56/66/43 71/85/43 72/72/43 +f 50/67/44 65/86/44 66/73/44 +f 57/68/264 72/72/264 73/74/264 +f 51/69/46 66/73/46 67/75/46 +f 58/70/47 73/74/47 74/76/47 +f 52/71/48 67/75/48 68/77/48 +f 59/57/49 74/76/49 75/78/49 +f 53/58/50 68/77/50 69/79/50 +f 47/80/51 62/100/51 63/81/51 +f 60/59/52 75/78/52 76/82/52 +f 54/60/265 69/79/265 70/83/265 +f 48/62/54 63/81/54 64/84/54 +f 55/64/55 70/83/55 71/85/55 +f 49/65/56 64/84/56 65/86/56 +f 91/107/57 76/82/57 90/87/57 +f 85/90/58 70/83/58 84/88/58 +f 79/91/59 64/84/59 78/89/59 +f 86/92/266 71/85/266 85/90/266 +f 80/93/61 65/86/61 79/91/61 +f 87/94/62 72/72/62 86/92/62 +f 81/95/267 66/73/267 80/93/267 +f 88/96/64 73/74/64 87/94/64 +f 82/97/65 67/75/65 81/95/65 +f 89/98/66 74/76/66 88/96/66 +f 83/99/67 68/77/67 82/97/67 +f 90/87/68 75/78/68 89/98/68 +f 84/88/69 69/79/69 83/99/69 +f 78/89/70 63/81/70 77/101/70 +f 104/104/71 89/98/71 103/102/71 +f 98/105/72 83/99/72 97/103/72 +f 105/108/73 90/87/73 104/104/73 +f 99/109/74 84/88/74 98/105/74 +f 93/110/75 78/89/75 92/106/75 +f 106/126/76 91/107/76 105/108/76 +f 100/111/77 85/90/77 99/109/77 +f 94/112/78 79/91/78 93/110/78 +f 101/113/79 86/92/79 100/111/79 +f 95/114/80 80/93/80 94/112/80 +f 102/115/81 87/94/81 101/113/81 +f 96/116/82 81/95/82 95/114/82 +f 103/102/268 88/96/268 102/115/268 +f 97/103/269 82/97/269 96/116/269 +f 117/119/270 102/115/270 116/117/270 +f 111/120/86 96/116/86 110/118/86 +f 118/121/87 103/102/87 117/119/87 +f 112/122/271 97/103/271 111/120/271 +f 119/123/89 104/104/89 118/121/89 +f 113/124/90 98/105/90 112/122/90 +f 120/127/91 105/108/91 119/123/91 +f 114/128/92 99/109/92 113/124/92 +f 108/129/93 93/110/93 107/125/93 +f 121/133/94 106/126/94 120/127/94 +f 115/130/95 100/111/95 114/128/95 +f 109/131/96 94/112/96 108/129/96 +f 116/117/97 101/113/97 115/130/97 +f 110/118/98 95/114/98 109/131/98 +f 123/136/99 108/129/99 122/132/99 +f 136/153/100 121/133/100 135/134/100 +f 130/137/272 115/130/272 129/135/272 +f 124/138/102 109/131/102 123/136/102 +f 131/139/273 116/117/273 130/137/273 +f 125/140/104 110/118/104 124/138/104 +f 132/141/274 117/119/274 131/139/274 +f 126/142/106 111/120/106 125/140/106 +f 133/143/107 118/121/107 132/141/107 +f 127/144/275 112/122/275 126/142/275 +f 134/145/109 119/123/109 133/143/109 +f 128/146/276 113/124/276 127/144/276 +f 135/134/111 120/127/111 134/145/111 +f 129/135/112 114/128/112 128/146/112 +f 142/149/277 127/144/277 141/147/277 +f 149/150/114 134/145/114 148/148/114 +f 143/151/115 128/146/115 142/149/115 +f 150/154/116 135/134/116 149/150/116 +f 144/155/278 129/135/278 143/151/278 +f 138/156/118 123/136/118 137/152/118 +f 151/172/119 136/153/119 150/154/119 +f 145/157/279 130/137/279 144/155/279 +f 139/158/280 124/138/280 138/156/280 +f 146/159/281 131/139/281 145/157/281 +f 140/160/123 125/140/123 139/158/123 +f 147/161/124 132/141/124 146/159/124 +f 141/147/282 126/142/282 140/160/282 +f 148/148/283 133/143/283 147/161/283 +f 161/164/284 146/159/284 160/162/284 +f 155/165/128 140/160/128 154/163/128 +f 162/166/129 147/161/129 161/164/129 +f 156/188/285 141/147/285 155/165/285 +f 163/168/131 148/148/131 162/166/131 +f 141/147/286 156/188/286 157/167/286 +f 164/177/133 149/150/133 163/168/133 +f 158/170/134 143/151/134 157/167/134 +f 165/173/135 150/154/135 164/169/135 +f 159/174/136 144/155/136 158/170/136 +f 153/175/137 138/156/137 152/171/137 +f 166/256/138 151/172/138 165/173/138 +f 160/162/139 145/157/139 159/174/139 +f 154/163/140 139/158/140 153/175/140 +f 180/182/141 165/176/141 179/178/141 +f 174/183/142 159/174/142 173/179/142 +f 168/184/143 153/175/143 167/180/143 +f 181/201/144 166/181/144 180/182/144 +f 175/185/145 160/162/145 174/183/145 +f 169/186/146 154/163/146 168/184/146 +f 176/187/287 161/164/287 175/185/287 +f 170/189/148 155/165/148 169/186/148 +f 177/190/149 162/166/149 176/187/149 +f 171/191/288 156/188/288 170/189/288 +f 178/192/151 163/168/151 177/190/151 +f 172/193/289 157/167/289 171/191/289 +f 179/178/153 164/177/153 178/192/153 +f 173/179/154 158/170/154 172/193/154 +f 193/196/290 178/192/290 192/194/290 +f 187/197/156 172/193/156 186/195/156 +f 194/198/157 179/178/157 193/196/157 +f 188/199/291 173/179/291 187/197/291 +f 195/202/159 180/182/159 194/198/159 +f 189/203/160 174/183/160 188/199/160 +f 183/204/161 168/184/161 182/200/161 +f 196/220/162 181/201/162 195/202/162 +f 190/205/163 175/185/163 189/203/163 +f 184/206/292 169/186/292 183/204/292 +f 191/207/165 176/187/165 190/205/165 +f 185/208/166 170/189/166 184/206/166 +f 192/194/167 177/190/167 191/207/167 +f 186/195/168 171/191/168 185/208/168 +f 190/205/169 205/222/169 206/209/169 +f 184/206/170 199/223/170 200/210/170 +f 191/207/171 206/209/171 207/211/171 +f 185/208/293 200/210/293 201/212/293 +f 192/194/294 207/211/294 208/213/294 +f 186/195/174 201/212/174 202/214/174 +f 193/196/175 208/213/175 209/215/175 +f 187/197/295 202/214/295 203/216/295 +f 194/198/296 209/215/296 210/217/296 +f 188/199/178 203/216/178 204/218/178 +f 182/200/179 197/226/179 198/219/179 +f 195/202/180 210/217/180 211/221/180 +f 189/203/181 204/218/181 205/222/181 +f 183/204/297 198/219/297 199/223/297 +f 209/215/183 225/236/183 226/224/183 +f 203/216/184 219/237/184 220/225/184 +f 197/226/185 213/245/185 214/227/185 +f 210/217/186 226/224/186 227/228/186 +f 204/218/187 220/225/187 221/229/187 +f 198/219/188 214/227/188 215/230/188 +f 205/222/298 221/229/298 222/231/298 +f 199/223/190 215/230/190 216/232/190 +f 206/209/299 222/231/299 223/233/299 +f 200/210/192 216/232/192 217/234/192 +f 224/238/300 208/213/300 223/233/300 +f 201/212/194 217/234/194 218/235/194 +f 208/213/195 224/238/195 225/236/195 +f 202/214/196 218/235/196 219/237/196 +f 223/233/301 238/252/301 239/239/301 +f 217/234/198 232/253/198 233/240/198 +f 224/238/199 239/239/199 240/241/199 +f 218/235/200 233/240/200 234/242/200 +f 225/236/201 240/241/201 241/243/201 +f 219/237/202 234/242/202 235/244/202 +f 213/245/203 228/261/203 229/246/203 +f 226/224/204 241/243/204 242/247/204 +f 220/225/205 235/244/205 236/248/205 +f 214/227/206 229/246/206 230/249/206 +f 221/229/302 236/248/302 237/250/302 +f 215/230/208 230/249/208 231/251/208 +f 222/231/209 237/250/209 238/252/209 +f 216/232/303 231/251/303 232/253/303 +f 236/248/304 9/17/304 10/21/304 +f 230/249/305 3/19/305 4/23/305 +f 11/25/244 238/252/244 10/21/244 +f 231/251/306 4/23/306 5/27/306 +f 12/2/307 239/239/307 11/25/307 +f 232/253/308 5/27/308 6/5/308 +f 239/239/248 12/2/248 13/1/248 +f 233/240/309 6/5/309 7/4/309 +f 240/241/251 13/1/251 14/263/251 +f 234/242/310 7/4/310 8/10/310 +f 228/261/253 1/13/253 2/12/253 +f 241/243/311 14/263/311 15/264/311 +f 235/244/255 8/10/255 9/17/255 +f 229/246/256 2/12/256 3/19/256 diff --git a/src/datavisualization/engine/meshes/sphereSmooth.obj b/src/datavisualization/engine/meshes/sphereSmooth.obj new file mode 100644 index 00000000..3c5b1299 --- /dev/null +++ b/src/datavisualization/engine/meshes/sphereSmooth.obj @@ -0,0 +1,1232 @@ +# Blender v2.66 (sub 0) OBJ File: 'sphere.blend' +# www.blender.org +o Sphere +v -0.195090 0.980785 0.000000 +v -0.382683 0.923880 0.000000 +v -0.555570 0.831470 0.000000 +v -0.707107 0.707107 0.000000 +v -0.831470 0.555570 0.000000 +v -0.923880 0.382683 0.000000 +v -0.980785 0.195090 0.000000 +v -1.000000 0.000000 0.000000 +v -0.980785 -0.195090 0.000000 +v -0.923880 -0.382683 0.000000 +v -0.831470 -0.555570 0.000000 +v -0.707107 -0.707107 0.000000 +v -0.555570 -0.831470 0.000000 +v -0.382683 -0.923880 0.000000 +v -0.195090 -0.980785 0.000000 +v -0.180240 0.980785 -0.074658 +v -0.353553 0.923880 -0.146447 +v -0.513280 0.831470 -0.212608 +v -0.653281 0.707107 -0.270598 +v -0.768178 0.555570 -0.318190 +v -0.853553 0.382683 -0.353553 +v -0.906127 0.195090 -0.375330 +v -0.923880 0.000000 -0.382684 +v -0.906127 -0.195090 -0.375330 +v -0.853553 -0.382683 -0.353554 +v -0.768178 -0.555570 -0.318190 +v -0.653281 -0.707107 -0.270598 +v -0.513280 -0.831470 -0.212608 +v -0.353553 -0.923880 -0.146447 +v -0.180240 -0.980785 -0.074658 +v 0.000000 -1.000000 0.000000 +v -0.137950 0.980785 -0.137950 +v -0.270598 0.923880 -0.270598 +v -0.392847 0.831470 -0.392848 +v -0.500000 0.707107 -0.500000 +v -0.587938 0.555570 -0.587938 +v -0.653281 0.382683 -0.653282 +v -0.693520 0.195090 -0.693520 +v -0.707107 0.000000 -0.707107 +v -0.693520 -0.195090 -0.693520 +v -0.653281 -0.382683 -0.653282 +v -0.587938 -0.555570 -0.587938 +v -0.500000 -0.707107 -0.500000 +v -0.392847 -0.831470 -0.392848 +v -0.270598 -0.923880 -0.270598 +v -0.137949 -0.980785 -0.137950 +v -0.074658 0.980785 -0.180240 +v -0.146446 0.923880 -0.353554 +v -0.212607 0.831470 -0.513280 +v -0.270598 0.707107 -0.653282 +v -0.318189 0.555570 -0.768178 +v -0.353553 0.382683 -0.853554 +v -0.375330 0.195090 -0.906128 +v -0.382683 0.000000 -0.923880 +v -0.375330 -0.195090 -0.906128 +v -0.353553 -0.382683 -0.853554 +v -0.318189 -0.555570 -0.768178 +v -0.270598 -0.707107 -0.653282 +v -0.212607 -0.831470 -0.513280 +v -0.146446 -0.923880 -0.353554 +v -0.074658 -0.980785 -0.180240 +v 0.000000 0.980785 -0.195091 +v 0.000000 0.923880 -0.382684 +v 0.000000 0.831470 -0.555570 +v 0.000000 0.707107 -0.707107 +v 0.000000 0.555570 -0.831470 +v 0.000000 0.382683 -0.923880 +v 0.000000 0.195090 -0.980785 +v 0.000000 0.000000 -1.000000 +v 0.000000 -0.195090 -0.980785 +v 0.000000 -0.382683 -0.923880 +v 0.000000 -0.555570 -0.831470 +v 0.000000 -0.707107 -0.707107 +v 0.000000 -0.831470 -0.555570 +v 0.000000 -0.923880 -0.382684 +v 0.000000 -0.980785 -0.195090 +v 0.074658 0.980785 -0.180240 +v 0.146447 0.923880 -0.353554 +v 0.212608 0.831470 -0.513280 +v 0.270598 0.707107 -0.653282 +v 0.318190 0.555570 -0.768178 +v 0.353554 0.382683 -0.853553 +v 0.375331 0.195090 -0.906128 +v 0.382684 0.000000 -0.923880 +v 0.375331 -0.195090 -0.906128 +v 0.353554 -0.382683 -0.853553 +v 0.318190 -0.555570 -0.768178 +v 0.270598 -0.707107 -0.653282 +v 0.212608 -0.831470 -0.513280 +v 0.146447 -0.923880 -0.353554 +v 0.074658 -0.980785 -0.180240 +v 0.137950 0.980785 -0.137950 +v 0.270599 0.923880 -0.270598 +v 0.392848 0.831470 -0.392848 +v 0.500000 0.707107 -0.500000 +v 0.587938 0.555570 -0.587938 +v 0.653282 0.382683 -0.653282 +v 0.693520 0.195090 -0.693520 +v 0.707107 0.000000 -0.707107 +v 0.693520 -0.195090 -0.693520 +v 0.653282 -0.382683 -0.653281 +v 0.587938 -0.555570 -0.587938 +v 0.500000 -0.707107 -0.500000 +v 0.392848 -0.831470 -0.392848 +v 0.270599 -0.923880 -0.270598 +v 0.137950 -0.980785 -0.137950 +v 0.180241 0.980785 -0.074658 +v 0.353554 0.923880 -0.146447 +v 0.513280 0.831470 -0.212608 +v 0.653282 0.707107 -0.270598 +v 0.768178 0.555570 -0.318190 +v 0.853554 0.382683 -0.353553 +v 0.906128 0.195090 -0.375330 +v 0.923880 0.000000 -0.382683 +v 0.906128 -0.195090 -0.375330 +v 0.853554 -0.382683 -0.353553 +v 0.768178 -0.555570 -0.318190 +v 0.653282 -0.707107 -0.270598 +v 0.513280 -0.831470 -0.212608 +v 0.353554 -0.923880 -0.146447 +v 0.180240 -0.980785 -0.074658 +v 0.195091 0.980785 0.000000 +v 0.382684 0.923880 0.000000 +v 0.555571 0.831470 0.000000 +v 0.707107 0.707107 0.000000 +v 0.831470 0.555570 0.000000 +v 0.923880 0.382683 0.000000 +v 0.980786 0.195090 0.000000 +v 1.000000 0.000000 0.000000 +v 0.980786 -0.195090 0.000000 +v 0.923880 -0.382683 0.000000 +v 0.831470 -0.555570 0.000000 +v 0.707107 -0.707107 0.000000 +v 0.555571 -0.831470 0.000000 +v 0.382684 -0.923880 0.000000 +v 0.195091 -0.980785 0.000000 +v 0.180241 0.980785 0.074658 +v 0.353554 0.923880 0.146447 +v 0.513280 0.831470 0.212608 +v 0.653282 0.707107 0.270598 +v 0.768178 0.555570 0.318190 +v 0.853554 0.382683 0.353553 +v 0.906128 0.195090 0.375330 +v 0.923880 0.000000 0.382684 +v 0.906128 -0.195090 0.375330 +v 0.853554 -0.382683 0.353553 +v 0.768178 -0.555570 0.318190 +v 0.653282 -0.707107 0.270598 +v 0.513280 -0.831470 0.212608 +v 0.353554 -0.923880 0.146447 +v 0.180240 -0.980785 0.074658 +v 0.137950 0.980785 0.137950 +v 0.270599 0.923880 0.270598 +v 0.392848 0.831470 0.392848 +v 0.500000 0.707107 0.500000 +v 0.587938 0.555570 0.587938 +v 0.653282 0.382683 0.653282 +v 0.693520 0.195090 0.693520 +v 0.707107 0.000000 0.707107 +v 0.693520 -0.195090 0.693520 +v 0.653282 -0.382683 0.653282 +v 0.587938 -0.555570 0.587938 +v 0.500000 -0.707107 0.500000 +v 0.392848 -0.831470 0.392848 +v 0.270599 -0.923880 0.270598 +v 0.137950 -0.980785 0.137950 +v 0.074658 0.980785 0.180240 +v 0.146447 0.923880 0.353554 +v 0.212608 0.831470 0.513280 +v 0.270598 0.707107 0.653282 +v 0.318190 0.555570 0.768178 +v 0.353554 0.382683 0.853553 +v 0.375331 0.195090 0.906128 +v 0.382684 0.000000 0.923880 +v 0.375331 -0.195090 0.906128 +v 0.353554 -0.382683 0.853553 +v 0.318190 -0.555570 0.768178 +v 0.270598 -0.707107 0.653282 +v 0.212608 -0.831470 0.513280 +v 0.146447 -0.923880 0.353554 +v 0.074658 -0.980785 0.180240 +v 0.000000 0.980785 0.195091 +v 0.000000 0.923880 0.382684 +v 0.000000 0.831470 0.555570 +v 0.000000 0.707107 0.707107 +v 0.000000 0.555570 0.831470 +v 0.000000 0.382683 0.923880 +v 0.000000 0.195090 0.980785 +v 0.000000 0.000000 1.000000 +v 0.000000 -0.195090 0.980785 +v 0.000000 -0.382683 0.923879 +v 0.000000 -0.555570 0.831470 +v 0.000000 -0.707107 0.707107 +v 0.000000 -0.831470 0.555570 +v 0.000000 -0.923880 0.382684 +v 0.000000 -0.980785 0.195090 +v -0.074658 0.980785 0.180240 +v -0.146446 0.923880 0.353554 +v -0.212607 0.831470 0.513280 +v -0.270598 0.707107 0.653282 +v -0.318189 0.555570 0.768178 +v -0.353553 0.382683 0.853553 +v -0.375330 0.195090 0.906128 +v -0.382683 0.000000 0.923880 +v -0.375330 -0.195090 0.906128 +v -0.353553 -0.382683 0.853553 +v -0.318189 -0.555570 0.768178 +v -0.270598 -0.707107 0.653282 +v -0.212607 -0.831470 0.513280 +v -0.146446 -0.923880 0.353554 +v -0.074658 -0.980785 0.180240 +v 0.000000 1.000000 0.000000 +v -0.137950 0.980785 0.137950 +v -0.270598 0.923880 0.270598 +v -0.392847 0.831470 0.392848 +v -0.500000 0.707107 0.500000 +v -0.587938 0.555570 0.587938 +v -0.653281 0.382683 0.653281 +v -0.693520 0.195090 0.693520 +v -0.707107 0.000000 0.707107 +v -0.693520 -0.195090 0.693520 +v -0.653281 -0.382683 0.653281 +v -0.587938 -0.555570 0.587938 +v -0.500000 -0.707107 0.500000 +v -0.392847 -0.831470 0.392848 +v -0.270598 -0.923880 0.270598 +v -0.137949 -0.980785 0.137950 +v -0.180240 0.980785 0.074658 +v -0.353553 0.923880 0.146447 +v -0.513280 0.831470 0.212608 +v -0.653281 0.707107 0.270598 +v -0.768177 0.555570 0.318190 +v -0.853553 0.382683 0.353553 +v -0.906127 0.195090 0.375330 +v -0.923879 0.000000 0.382683 +v -0.906127 -0.195090 0.375330 +v -0.853553 -0.382683 0.353553 +v -0.768177 -0.555570 0.318190 +v -0.653281 -0.707107 0.270598 +v -0.513280 -0.831470 0.212608 +v -0.353553 -0.923880 0.146447 +v -0.180240 -0.980785 0.074658 +vt 0.040867 0.325557 +vt 0.048386 0.386583 +vt 0.001015 0.334499 +vt 0.081872 0.692529 +vt 0.092315 0.752973 +vt 0.006404 0.709363 +vt 1.031336 0.264931 +vt 1.040867 0.325557 +vt 0.999822 0.272029 +vt 0.073887 0.631595 +vt 0.005301 0.646891 +vt 0.333915 0.937286 +vt 0.448527 0.905466 +vt 0.447682 0.976645 +vt 1.017784 0.205113 +vt 0.998129 0.209571 +vt 0.067156 0.570413 +vt 0.004397 0.584414 +vt 0.196016 0.918498 +vt 0.034176 0.958662 +vt 0.060989 0.509119 +vt 0.003585 0.521934 +vt 0.135028 0.869370 +vt 0.015221 0.896641 +vt 0.054891 0.447811 +vt 0.002796 0.459454 +vt 0.107782 0.812401 +vt 0.010297 0.834265 +vt 0.001965 0.396975 +vt 0.007907 0.771825 +vt 0.978319 0.207096 +vt 1.004397 0.584414 +vt 1.005301 0.646891 +vt 0.941200 0.576589 +vt 1.034176 0.958662 +vt 0.823807 0.933258 +vt 1.003585 0.521934 +vt 0.945911 0.514786 +vt 1.015221 0.896641 +vt 0.885287 0.880701 +vt 1.002796 0.459454 +vt 0.950535 0.452971 +vt 1.010297 0.834265 +vt 0.908873 0.821779 +vt 1.001965 0.396975 +vt 0.955439 0.391196 +vt 1.007907 0.771825 +vt 0.921503 0.761167 +vt 1.001015 0.334499 +vt 0.961079 0.329532 +vt 1.006404 0.709363 +vt 0.929787 0.699898 +vt 0.968202 0.268089 +vt 0.936013 0.638321 +vt 0.488610 0.915189 +vt 0.647808 0.950687 +vt 0.921611 0.311033 +vt 0.859136 0.666985 +vt 0.937209 0.253354 +vt 0.870446 0.607941 +vt 0.532175 0.909643 +vt 0.657607 0.903302 +vt 0.959449 0.197860 +vt 0.880347 0.548455 +vt 0.745300 0.879338 +vt 0.889690 0.488794 +vt 0.796385 0.834663 +vt 0.899158 0.429173 +vt 0.825891 0.781668 +vt 0.909472 0.369816 +vt 0.845097 0.725165 +vt 0.848920 0.390841 +vt 0.761226 0.728711 +vt 0.864196 0.334814 +vt 0.780693 0.674598 +vt 0.882867 0.280332 +vt 0.796418 0.618773 +vt 0.907539 0.228698 +vt 0.810089 0.562031 +vt 0.558962 0.891763 +vt 0.641452 0.857179 +vt 0.942759 0.182515 +vt 0.822818 0.504873 +vt 0.697492 0.824480 +vt 0.835477 0.447684 +vt 0.735147 0.779653 +vt 0.879896 0.195479 +vt 0.753309 0.508011 +vt 0.618082 0.815427 +vt 0.767315 0.452094 +vt 0.657173 0.773912 +vt 0.782092 0.396562 +vt 0.685241 0.725518 +vt 0.798714 0.341964 +vt 0.706593 0.673391 +vt 0.818709 0.289116 +vt 0.723996 0.619193 +vt 0.844487 0.239416 +vt 0.739178 0.563865 +vt 0.567268 0.868303 +vt 0.563300 0.844314 +vt 0.770454 0.236269 +vt 0.670392 0.566231 +vt 0.805029 0.190637 +vt 0.683774 0.509644 +vt 0.551952 0.822879 +vt 0.929896 0.162212 +vt 0.855308 0.155368 +vt 0.697011 0.452991 +vt 0.591182 0.780044 +vt 0.710973 0.396675 +vt 0.618699 0.730484 +vt 0.726705 0.341193 +vt 0.639317 0.677374 +vt 0.745717 0.287291 +vt 0.655961 0.622327 +vt 0.665037 0.288362 +vt 0.594131 0.638967 +vt 0.684737 0.232805 +vt 0.605914 0.580518 +vt 0.713639 0.180821 +vt 0.616615 0.521685 +vt 0.760428 0.136665 +vt 0.627046 0.462757 +vt 0.536166 0.805967 +vt 0.923407 0.138703 +vt 0.836350 0.110271 +vt 0.637946 0.403995 +vt 0.562017 0.752770 +vt 0.650183 0.345708 +vt 0.580132 0.696622 +vt 0.517784 0.794886 +vt 0.927547 0.114679 +vt 0.833915 0.062714 +vt 0.573887 0.368405 +vt 0.531336 0.735069 +vt 0.581872 0.307471 +vt 0.540867 0.674443 +vt 0.592315 0.247027 +vt 0.548386 0.613417 +vt 0.607782 0.187599 +vt 0.554891 0.552189 +vt 0.635028 0.130630 +vt 0.560989 0.490881 +vt 0.696016 0.081502 +vt 0.567156 0.429587 +vt 0.502796 0.540546 +vt 0.515221 0.103359 +vt 0.503585 0.478066 +vt 0.534176 0.041338 +vt 0.504397 0.415586 +vt 0.498129 0.790428 +vt 0.948527 0.094534 +vt 0.947682 0.023355 +vt 0.505301 0.353109 +vt 0.499822 0.727971 +vt 0.506404 0.290637 +vt 0.501015 0.665501 +vt 0.507907 0.228175 +vt 0.501965 0.603025 +vt 0.510297 0.165735 +vt 0.429787 0.300102 +vt 0.461079 0.670468 +vt 0.421503 0.238833 +vt 0.455439 0.608804 +vt 0.408873 0.178221 +vt 0.445911 0.485214 +vt 0.385287 0.119299 +vt 1.323807 0.066742 +vt 0.441200 0.423411 +vt 0.478319 0.792904 +vt 0.988610 0.084811 +vt 1.147808 0.049313 +vt 0.436013 0.361679 +vt 0.468202 0.731911 +vt 0.147808 0.049313 +vt 0.323807 0.066742 +vt 0.245300 0.120661 +vt 0.380347 0.451545 +vt 0.459449 0.802140 +vt 0.032175 0.090357 +vt 0.157607 0.096698 +vt 0.370446 0.392059 +vt 0.437209 0.746646 +vt 0.359136 0.333015 +vt 0.421611 0.688967 +vt 0.345097 0.274835 +vt 0.450536 0.547029 +vt 0.409472 0.630184 +vt 0.325892 0.218332 +vt 0.399158 0.570827 +vt 0.296385 0.165337 +vt 0.389690 0.511206 +vt 0.261226 0.271289 +vt 0.348920 0.609159 +vt 0.235147 0.220347 +vt 0.335478 0.552316 +vt 0.197492 0.175520 +vt 0.322818 0.495127 +vt 0.442759 0.817485 +vt 0.058962 0.108237 +vt 0.141452 0.142821 +vt 0.310089 0.437969 +vt 0.407539 0.771302 +vt 0.296418 0.381227 +vt 0.382867 0.719668 +vt 0.280693 0.325402 +vt 0.364196 0.665186 +vt 0.223996 0.380807 +vt 0.318709 0.710884 +vt 0.206593 0.326609 +vt 0.298714 0.658036 +vt 0.185241 0.274482 +vt 0.282092 0.603438 +vt 0.157173 0.226088 +vt 0.267315 0.547906 +vt 0.118082 0.184573 +vt 0.253309 0.491989 +vt 0.379896 0.804521 +vt 0.067268 0.131697 +vt 0.063300 0.155685 +vt 0.239178 0.436135 +vt 0.344487 0.760584 +vt 0.091182 0.219955 +vt 0.197011 0.547009 +vt 0.429896 0.837788 +vt 0.355308 0.844632 +vt 0.051952 0.177121 +vt 0.183774 0.490356 +vt 0.305029 0.809363 +vt 0.170392 0.433769 +vt 0.270454 0.763731 +vt 0.155961 0.377673 +vt 0.245717 0.712709 +vt 0.226706 0.658807 +vt 0.118699 0.269516 +vt 0.210973 0.603325 +vt 0.139317 0.322626 +vt 0.094131 0.361033 +vt 0.165037 0.711638 +vt 0.080132 0.303378 +vt 0.150183 0.654292 +vt 0.062017 0.247229 +vt 0.137946 0.596005 +vt 0.423407 0.861296 +vt 0.336350 0.889729 +vt 0.036166 0.194032 +vt 0.127046 0.537243 +vt 0.260428 0.863335 +vt 0.116615 0.478315 +vt 0.213639 0.819179 +vt 0.105914 0.419482 +vt 0.184737 0.767195 +vt 0.495265 0.852856 +vt 0.995265 0.147143 +vt 1.032175 0.090357 +vt 1.058962 0.108237 +vt 1.067268 0.131697 +vt 1.063300 0.155685 +vt 1.051952 0.177121 +vt 0.427547 0.885321 +vt 1.036166 0.194032 +vt 0.031336 0.264931 +vt 0.017784 0.205113 +vn -0.563891 -0.825831 0.000000 +vn -0.713095 -0.701041 0.000000 +vn -0.520981 -0.825831 -0.215796 +vn -0.981231 0.192785 0.000000 +vn -0.925596 0.378430 0.000000 +vn -0.906522 0.192785 -0.375500 +vn -0.393017 -0.919523 0.000000 +vn -0.363109 -0.919523 -0.150395 +vn -1.000000 0.000000 0.000000 +vn -0.923856 0.000000 -0.382672 +vn -0.393017 0.919523 0.000000 +vn -0.206793 0.978362 0.000000 +vn -0.363109 0.919523 -0.150395 +vn -0.206793 -0.978362 0.000000 +vn -0.191046 -0.978362 -0.079134 +vn -0.981231 -0.192785 0.000000 +vn -0.906522 -0.192785 -0.375500 +vn -0.563891 0.825831 0.000000 +vn -0.520981 0.825831 -0.215796 +vn -0.925596 -0.378430 0.000000 +vn -0.855159 -0.378430 -0.354198 +vn -0.713095 0.701041 0.000000 +vn -0.658803 0.701041 -0.272866 +vn -0.835139 -0.550005 0.000000 +vn -0.771569 -0.550005 -0.319590 +vn -0.835139 0.550005 0.000000 +vn -0.771569 0.550005 -0.319590 +vn -0.658803 -0.701041 -0.272866 +vn -0.855159 0.378430 -0.354198 +vn -0.146214 -0.978362 -0.146214 +vn -0.693838 -0.192785 -0.693838 +vn -0.398724 0.825831 -0.398724 +vn -0.654500 -0.378430 -0.654500 +vn -0.504227 0.701041 -0.504227 +vn -0.590533 -0.550005 -0.590533 +vn -0.590533 0.550005 -0.590533 +vn -0.504227 -0.701041 -0.504227 +vn -0.654500 0.378430 -0.654500 +vn -0.398724 -0.825831 -0.398724 +vn -0.693838 0.192785 -0.693838 +vn -0.277902 -0.919523 -0.277902 +vn -0.707083 0.000000 -0.707083 +vn -0.191046 0.978362 -0.079134 +vn -0.277902 0.919523 -0.277902 +vn -0.215796 -0.825831 -0.520981 +vn -0.375500 0.192785 -0.906522 +vn -0.150395 -0.919523 -0.363109 +vn -0.382672 0.000000 -0.923856 +vn -0.146214 0.978362 -0.146214 +vn -0.150395 0.919523 -0.363109 +vn -0.079134 -0.978362 -0.191046 +vn -0.375500 -0.192785 -0.906522 +vn -0.215796 0.825831 -0.520981 +vn -0.354198 -0.378430 -0.855159 +vn -0.272866 0.701041 -0.658803 +vn -0.319590 -0.550005 -0.771569 +vn -0.319590 0.550005 -0.771569 +vn -0.272866 -0.701041 -0.658803 +vn -0.354198 0.378430 -0.855159 +vn 0.000000 -0.550005 -0.835139 +vn 0.000000 0.550005 -0.835139 +vn 0.000000 -0.701041 -0.713095 +vn 0.000000 0.378430 -0.925596 +vn 0.000000 -0.825831 -0.563891 +vn 0.000000 0.192785 -0.981231 +vn 0.000000 -0.919523 -0.393017 +vn 0.000000 0.000000 -1.000000 +vn -0.079134 0.978362 -0.191046 +vn 0.000000 0.919523 -0.393017 +vn 0.000000 -0.978362 -0.206793 +vn 0.000000 -0.192785 -0.981231 +vn 0.000000 0.825831 -0.563891 +vn 0.000000 -0.378430 -0.925596 +vn 0.000000 0.701041 -0.713095 +vn 0.150395 -0.919523 -0.363109 +vn 0.382672 0.000000 -0.923856 +vn 0.150395 0.919523 -0.363109 +vn 0.375500 -0.192785 -0.906522 +vn 0.215796 0.825831 -0.520981 +vn 0.354198 -0.378430 -0.855159 +vn 0.272866 0.701041 -0.658803 +vn 0.319590 -0.550005 -0.771569 +vn 0.319590 0.550005 -0.771569 +vn 0.272866 -0.701041 -0.658803 +vn 0.354198 0.378430 -0.855159 +vn 0.215796 -0.825831 -0.520981 +vn 0.375500 0.192785 -0.906522 +vn 0.000000 0.978362 -0.206793 +vn 0.079134 0.978362 -0.191046 +vn 0.504227 -0.701041 -0.504227 +vn 0.654500 0.378430 -0.654500 +vn 0.398724 -0.825831 -0.398724 +vn 0.693838 0.192785 -0.693838 +vn 0.146214 0.978362 -0.146214 +vn 0.079134 -0.978362 -0.191046 +vn 0.277902 -0.919523 -0.277902 +vn 0.707083 0.000000 -0.707083 +vn 0.277902 0.919523 -0.277902 +vn 0.693838 -0.192785 -0.693838 +vn 0.398724 0.825831 -0.398724 +vn 0.654500 -0.378430 -0.654500 +vn 0.504227 0.701041 -0.504227 +vn 0.590533 -0.550005 -0.590533 +vn 0.590533 0.550005 -0.590533 +vn 0.855159 -0.378430 -0.354198 +vn 0.658803 0.701041 -0.272866 +vn 0.771569 -0.550005 -0.319590 +vn 0.771569 0.550005 -0.319590 +vn 0.658803 -0.701041 -0.272866 +vn 0.855159 0.378430 -0.354198 +vn 0.520981 -0.825831 -0.215796 +vn 0.906522 0.192785 -0.375500 +vn 0.191046 0.978362 -0.079134 +vn 0.146214 -0.978362 -0.146214 +vn 0.363109 -0.919523 -0.150395 +vn 0.923856 0.000000 -0.382672 +vn 0.363109 0.919523 -0.150395 +vn 0.906522 -0.192785 -0.375500 +vn 0.520981 0.825831 -0.215796 +vn 0.206793 0.978362 0.000000 +vn 0.191046 -0.978362 -0.079134 +vn 0.393017 -0.919523 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.393017 0.919523 0.000000 +vn 0.981231 -0.192785 0.000000 +vn 0.563891 0.825831 0.000000 +vn 0.925596 -0.378430 0.000000 +vn 0.713095 0.701041 0.000000 +vn 0.835139 -0.550005 0.000000 +vn 0.835139 0.550005 0.000000 +vn 0.713095 -0.701041 0.000000 +vn 0.925596 0.378430 0.000000 +vn 0.563891 -0.825831 0.000000 +vn 0.981231 0.192785 0.000000 +vn 0.771569 0.550005 0.319590 +vn 0.658803 -0.701041 0.272866 +vn 0.855159 0.378430 0.354198 +vn 0.520981 -0.825831 0.215796 +vn 0.906522 0.192785 0.375500 +vn 0.191046 0.978362 0.079134 +vn 0.206793 -0.978362 0.000000 +vn 0.363109 -0.919523 0.150395 +vn 0.923856 0.000000 0.382672 +vn 0.363109 0.919523 0.150395 +vn 0.906522 -0.192785 0.375500 +vn 0.520981 0.825831 0.215796 +vn 0.855159 -0.378430 0.354198 +vn 0.658803 0.701041 0.272866 +vn 0.771569 -0.550005 0.319590 +vn 0.693838 -0.192785 0.693838 +vn 0.398724 0.825831 0.398724 +vn 0.654500 -0.378430 0.654500 +vn 0.504227 0.701041 0.504227 +vn 0.590533 -0.550005 0.590533 +vn 0.654500 0.378430 0.654500 +vn 0.504227 -0.701041 0.504227 +vn 0.398724 -0.825831 0.398724 +vn 0.693838 0.192785 0.693838 +vn 0.146214 0.978362 0.146214 +vn 0.191046 -0.978362 0.079134 +vn 0.277902 -0.919523 0.277902 +vn 0.707083 0.000000 0.707083 +vn 0.277902 0.919523 0.277902 +vn 0.215796 -0.825831 0.520981 +vn 0.375500 0.192785 0.906522 +vn 0.079134 0.978362 0.191046 +vn 0.146214 -0.978362 0.146214 +vn 0.150395 -0.919523 0.363109 +vn 0.382672 0.000000 0.923856 +vn 0.150395 0.919523 0.363109 +vn 0.375500 -0.192785 0.906522 +vn 0.215796 0.825831 0.520981 +vn 0.354198 -0.378430 0.855159 +vn 0.590533 0.550005 0.590533 +vn 0.272866 0.701041 0.658803 +vn 0.319590 -0.550005 0.771569 +vn 0.319590 0.550005 0.771569 +vn 0.272866 -0.701041 0.658803 +vn 0.354198 0.378430 0.855159 +vn 0.000000 -0.550005 0.835139 +vn 0.000000 0.550005 0.835139 +vn 0.000000 -0.701041 0.713095 +vn 0.000000 0.378430 0.925596 +vn 0.000000 -0.825831 0.563891 +vn 0.000000 0.192785 0.981231 +vn 0.000000 0.978362 0.206793 +vn 0.079134 -0.978362 0.191046 +vn 0.000000 -0.919523 0.393017 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.919523 0.393017 +vn 0.000000 -0.192785 0.981231 +vn 0.000000 0.825831 0.563891 +vn 0.000000 -0.378430 0.925596 +vn 0.000000 0.701041 0.713095 +vn -0.354198 -0.378430 0.855159 +vn -0.272866 0.701041 0.658803 +vn -0.319590 -0.550005 0.771569 +vn -0.319590 0.550005 0.771569 +vn -0.272866 -0.701041 0.658803 +vn -0.354198 0.378430 0.855159 +vn -0.215796 -0.825831 0.520981 +vn -0.375500 0.192785 0.906522 +vn -0.150395 -0.919523 0.363109 +vn -0.382672 0.000000 0.923856 +vn -0.150395 0.919523 0.363109 +vn 0.000000 -0.978362 0.206793 +vn -0.079134 -0.978362 0.191046 +vn -0.375500 -0.192785 0.906522 +vn -0.215796 0.825831 0.520981 +vn -0.277902 -0.919523 0.277902 +vn -0.707083 0.000000 0.707083 +vn -0.079134 0.978362 0.191046 +vn -0.277902 0.919523 0.277902 +vn -0.146214 -0.978362 0.146214 +vn -0.693838 -0.192785 0.693838 +vn -0.398724 0.825831 0.398724 +vn -0.654500 -0.378430 0.654500 +vn -0.504227 0.701041 0.504227 +vn -0.590533 -0.550005 0.590533 +vn -0.590533 0.550005 0.590533 +vn -0.654500 0.378430 0.654500 +vn -0.398724 -0.825831 0.398724 +vn -0.693838 0.192785 0.693838 +vn -0.504227 -0.701041 0.504227 +vn -0.658803 -0.701041 0.272866 +vn -0.855159 0.378430 0.354198 +vn -0.520981 -0.825831 0.215796 +vn -0.906522 0.192785 0.375500 +vn -0.363109 -0.919523 0.150395 +vn -0.923856 0.000000 0.382672 +vn -0.146214 0.978362 0.146214 +vn -0.363109 0.919523 0.150395 +vn -0.191046 -0.978362 0.079134 +vn -0.906522 -0.192785 0.375500 +vn -0.520981 0.825831 0.215796 +vn -0.855159 -0.378430 0.354198 +vn -0.658803 0.701041 0.272866 +vn -0.771569 -0.550005 0.319590 +vn -0.771569 0.550005 0.319590 +vn 0.000000 0.999969 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.191046 0.978362 0.079134 +s 1 +f 13/1/1 12/2/2 28/3/3 +f 7/4/4 6/5/5 22/6/6 +f 14/7/7 13/8/1 29/9/8 +f 8/10/9 7/4/4 23/11/10 +f 2/12/11 1/13/12 17/14/13 +f 15/15/14 14/7/7 30/16/15 +f 9/17/16 8/10/9 24/18/17 +f 3/19/18 2/12/11 18/20/19 +f 10/21/20 9/17/16 25/22/21 +f 4/23/22 3/19/18 19/24/23 +f 11/25/24 10/21/20 26/26/25 +f 5/27/26 4/23/22 20/28/27 +f 12/2/2 11/25/24 27/29/28 +f 6/5/5 5/27/26 21/30/29 +f 30/16/15 29/9/8 46/31/30 +f 24/32/17 23/33/10 40/34/31 +f 18/35/19 17/14/13 34/36/32 +f 25/37/21 24/32/17 41/38/33 +f 19/39/23 18/35/19 35/40/34 +f 26/41/25 25/37/21 42/42/35 +f 20/43/27 19/39/23 36/44/36 +f 27/45/28 26/41/25 43/46/37 +f 21/47/29 20/43/27 37/48/38 +f 28/49/3 27/45/28 44/50/39 +f 22/51/6 21/47/29 38/52/40 +f 29/9/8 28/49/3 45/53/41 +f 23/33/10 22/51/6 39/54/42 +f 17/14/13 16/55/43 33/56/44 +f 44/50/39 43/46/37 59/57/45 +f 38/52/40 37/48/38 53/58/46 +f 45/53/41 44/50/39 60/59/47 +f 39/54/42 38/52/40 54/60/48 +f 33/56/44 32/61/49 48/62/50 +f 46/31/30 45/53/41 61/63/51 +f 40/34/31 39/54/42 55/64/52 +f 34/36/32 33/56/44 49/65/53 +f 41/38/33 40/34/31 56/66/54 +f 35/40/34 34/36/32 50/67/55 +f 42/42/35 41/38/33 57/68/56 +f 36/44/36 35/40/34 51/69/57 +f 43/46/37 42/42/35 58/70/58 +f 37/48/38 36/44/36 52/71/59 +f 57/68/56 56/66/54 72/72/60 +f 51/69/57 50/67/55 66/73/61 +f 58/70/58 57/68/56 73/74/62 +f 52/71/59 51/69/57 67/75/63 +f 59/57/45 58/70/58 74/76/64 +f 53/58/46 52/71/59 68/77/65 +f 60/59/47 59/57/45 75/78/66 +f 54/60/48 53/58/46 69/79/67 +f 48/62/50 47/80/68 63/81/69 +f 61/63/51 60/59/47 76/82/70 +f 55/64/52 54/60/48 70/83/71 +f 49/65/53 48/62/50 64/84/72 +f 56/66/54 55/64/52 71/85/73 +f 50/67/55 49/65/53 65/86/74 +f 76/82/70 75/78/66 90/87/75 +f 70/83/71 69/79/67 84/88/76 +f 64/84/72 63/81/69 78/89/77 +f 71/85/73 70/83/71 85/90/78 +f 65/86/74 64/84/72 79/91/79 +f 72/72/60 71/85/73 86/92/80 +f 66/73/61 65/86/74 80/93/81 +f 73/74/62 72/72/60 87/94/82 +f 67/75/63 66/73/61 81/95/83 +f 74/76/64 73/74/62 88/96/84 +f 68/77/65 67/75/63 82/97/85 +f 75/78/66 74/76/64 89/98/86 +f 69/79/67 68/77/65 83/99/87 +f 63/81/69 62/100/88 77/101/89 +f 89/98/86 88/96/84 103/102/90 +f 83/99/87 82/97/85 97/103/91 +f 90/87/75 89/98/86 104/104/92 +f 84/88/76 83/99/87 98/105/93 +f 78/89/77 77/101/89 92/106/94 +f 91/107/95 90/87/75 105/108/96 +f 85/90/78 84/88/76 99/109/97 +f 79/91/79 78/89/77 93/110/98 +f 86/92/80 85/90/78 100/111/99 +f 80/93/81 79/91/79 94/112/100 +f 87/94/82 86/92/80 101/113/101 +f 81/95/83 80/93/81 95/114/102 +f 88/96/84 87/94/82 102/115/103 +f 82/97/85 81/95/83 96/116/104 +f 102/115/103 101/113/101 116/117/105 +f 96/116/104 95/114/102 110/118/106 +f 103/102/90 102/115/103 117/119/107 +f 97/103/91 96/116/104 111/120/108 +f 104/104/92 103/102/90 118/121/109 +f 98/105/93 97/103/91 112/122/110 +f 105/108/96 104/104/92 119/123/111 +f 99/109/97 98/105/93 113/124/112 +f 93/110/98 92/106/94 107/125/113 +f 106/126/114 105/108/96 120/127/115 +f 100/111/99 99/109/97 114/128/116 +f 94/112/100 93/110/98 108/129/117 +f 101/113/101 100/111/99 115/130/118 +f 95/114/102 94/112/100 109/131/119 +f 108/129/117 107/125/113 122/132/120 +f 121/133/121 120/127/115 135/134/122 +f 115/130/118 114/128/116 129/135/123 +f 109/131/119 108/129/117 123/136/124 +f 116/117/105 115/130/118 130/137/125 +f 110/118/106 109/131/119 124/138/126 +f 117/119/107 116/117/105 131/139/127 +f 111/120/108 110/118/106 125/140/128 +f 118/121/109 117/119/107 132/141/129 +f 112/122/110 111/120/108 126/142/130 +f 119/123/111 118/121/109 133/143/131 +f 113/124/112 112/122/110 127/144/132 +f 120/127/115 119/123/111 134/145/133 +f 114/128/116 113/124/112 128/146/134 +f 127/144/132 126/142/130 141/147/135 +f 134/145/133 133/143/131 148/148/136 +f 128/146/134 127/144/132 142/149/137 +f 135/134/122 134/145/133 149/150/138 +f 129/135/123 128/146/134 143/151/139 +f 123/136/124 122/132/120 137/152/140 +f 136/153/141 135/134/122 150/154/142 +f 130/137/125 129/135/123 144/155/143 +f 124/138/126 123/136/124 138/156/144 +f 131/139/127 130/137/125 145/157/145 +f 125/140/128 124/138/126 139/158/146 +f 132/141/129 131/139/127 146/159/147 +f 126/142/130 125/140/128 140/160/148 +f 133/143/131 132/141/129 147/161/149 +f 146/159/147 145/157/145 160/162/150 +f 140/160/148 139/158/146 154/163/151 +f 147/161/149 146/159/147 161/164/152 +f 141/147/135 140/160/148 155/165/153 +f 148/148/136 147/161/149 162/166/154 +f 142/149/137 141/147/135 157/167/155 +f 149/150/138 148/148/136 163/168/156 +f 143/151/139 142/149/137 157/167/155 +f 150/154/142 149/150/138 164/169/157 +f 144/155/143 143/151/139 158/170/158 +f 138/156/144 137/152/140 152/171/159 +f 151/172/160 150/154/142 165/173/161 +f 145/157/145 144/155/143 159/174/162 +f 139/158/146 138/156/144 153/175/163 +f 165/176/161 164/177/157 179/178/164 +f 159/174/162 158/170/158 173/179/165 +f 153/175/163 152/171/159 167/180/166 +f 166/181/167 165/176/161 180/182/168 +f 160/162/150 159/174/162 174/183/169 +f 154/163/151 153/175/163 168/184/170 +f 161/164/152 160/162/150 175/185/171 +f 155/165/153 154/163/151 169/186/172 +f 162/166/154 161/164/152 176/187/173 +f 156/188/174 155/165/153 170/189/175 +f 163/168/156 162/166/154 177/190/176 +f 157/167/155 156/188/174 171/191/177 +f 164/177/157 163/168/156 178/192/178 +f 158/170/158 157/167/155 172/193/179 +f 178/192/178 177/190/176 192/194/180 +f 172/193/179 171/191/177 186/195/181 +f 179/178/164 178/192/178 193/196/182 +f 173/179/165 172/193/179 187/197/183 +f 180/182/168 179/178/164 194/198/184 +f 174/183/169 173/179/165 188/199/185 +f 168/184/170 167/180/166 182/200/186 +f 181/201/187 180/182/168 195/202/188 +f 175/185/171 174/183/169 189/203/189 +f 169/186/172 168/184/170 183/204/190 +f 176/187/173 175/185/171 190/205/191 +f 170/189/175 169/186/172 184/206/192 +f 177/190/176 176/187/173 191/207/193 +f 171/191/177 170/189/175 185/208/194 +f 191/207/193 190/205/191 206/209/195 +f 185/208/194 184/206/192 200/210/196 +f 192/194/180 191/207/193 207/211/197 +f 186/195/181 185/208/194 201/212/198 +f 193/196/182 192/194/180 208/213/199 +f 187/197/183 186/195/181 202/214/200 +f 194/198/184 193/196/182 209/215/201 +f 188/199/185 187/197/183 203/216/202 +f 195/202/188 194/198/184 210/217/203 +f 189/203/189 188/199/185 204/218/204 +f 183/204/190 182/200/186 198/219/205 +f 196/220/206 195/202/188 211/221/207 +f 190/205/191 189/203/189 205/222/208 +f 184/206/192 183/204/190 199/223/209 +f 210/217/203 209/215/201 226/224/210 +f 204/218/204 203/216/202 220/225/211 +f 198/219/205 197/226/212 214/227/213 +f 211/221/207 210/217/203 227/228/214 +f 205/222/208 204/218/204 221/229/215 +f 199/223/209 198/219/205 215/230/216 +f 206/209/195 205/222/208 222/231/217 +f 200/210/196 199/223/209 216/232/218 +f 207/211/197 206/209/195 223/233/219 +f 201/212/198 200/210/196 217/234/220 +f 208/213/199 207/211/197 223/233/219 +f 202/214/200 201/212/198 218/235/221 +f 209/215/201 208/213/199 225/236/222 +f 203/216/202 202/214/200 219/237/223 +f 224/238/224 223/233/219 239/239/225 +f 218/235/221 217/234/220 233/240/226 +f 225/236/222 224/238/224 240/241/227 +f 219/237/223 218/235/221 234/242/228 +f 226/224/210 225/236/222 241/243/229 +f 220/225/211 219/237/223 235/244/230 +f 214/227/213 213/245/231 229/246/232 +f 227/228/214 226/224/210 242/247/233 +f 221/229/215 220/225/211 236/248/234 +f 215/230/216 214/227/213 230/249/235 +f 222/231/217 221/229/215 237/250/236 +f 216/232/218 215/230/216 231/251/237 +f 223/233/219 222/231/217 238/252/238 +f 217/234/220 216/232/218 232/253/239 +f 1/13/12 212/254/240 16/55/43 +f 31/255/241 15/15/14 30/16/15 +f 31/255/241 30/16/15 46/31/30 +f 16/55/43 212/254/240 32/61/49 +f 32/61/49 212/254/240 47/80/68 +f 31/255/241 46/31/30 61/63/51 +f 47/80/68 212/254/240 62/100/88 +f 31/255/241 61/63/51 76/82/70 +f 31/255/241 76/82/70 91/107/95 +f 62/100/88 212/254/240 77/101/89 +f 77/101/89 212/254/240 92/106/94 +f 31/255/241 91/107/95 106/126/114 +f 92/106/94 212/254/240 107/125/113 +f 31/255/241 106/126/114 121/133/121 +f 31/255/241 121/133/121 136/153/141 +f 107/125/113 212/254/240 122/132/120 +f 122/132/120 212/254/240 137/152/140 +f 31/255/241 136/153/141 151/172/160 +f 137/152/140 212/254/240 152/171/159 +f 31/255/241 151/172/160 166/256/167 +f 31/255/241 166/256/167 181/257/187 +f 152/171/159 212/254/240 167/180/166 +f 167/180/166 212/254/240 182/200/186 +f 31/255/241 181/257/187 196/258/206 +f 31/255/241 196/258/206 211/259/207 +f 182/200/186 212/254/240 197/226/212 +f 31/255/241 211/259/207 227/260/214 +f 197/226/212 212/254/240 213/245/231 +f 213/245/231 212/254/240 228/261/242 +f 31/255/241 227/260/214 242/262/233 +f 31/255/241 242/262/233 15/15/14 +f 237/250/236 236/248/234 10/21/20 +f 231/251/237 230/249/235 4/23/22 +f 238/252/238 237/250/236 10/21/20 +f 232/253/239 231/251/237 5/27/26 +f 239/239/225 238/252/238 11/25/24 +f 233/240/226 232/253/239 6/5/5 +f 240/241/227 239/239/225 13/1/1 +f 234/242/228 233/240/226 7/4/4 +f 228/261/242 212/254/240 1/13/12 +f 241/243/229 240/241/227 14/263/7 +f 235/244/230 234/242/228 8/10/9 +f 229/246/232 228/261/242 2/12/11 +f 242/247/233 241/243/229 15/264/14 +f 236/248/234 235/244/230 9/17/16 +f 230/249/235 229/246/232 3/19/18 +f 12/2/2 27/29/28 28/3/3 +f 6/5/5 21/30/29 22/6/6 +f 13/8/1 28/49/3 29/9/8 +f 7/4/4 22/6/6 23/11/10 +f 1/13/12 16/55/43 17/14/13 +f 14/7/7 29/9/8 30/16/15 +f 8/10/9 23/11/10 24/18/17 +f 2/12/11 17/14/13 18/20/19 +f 9/17/16 24/18/17 25/22/21 +f 3/19/18 18/20/19 19/24/23 +f 10/21/20 25/22/21 26/26/25 +f 4/23/22 19/24/23 20/28/27 +f 11/25/24 26/26/25 27/29/28 +f 5/27/26 20/28/27 21/30/29 +f 29/9/8 45/53/41 46/31/30 +f 23/33/10 39/54/42 40/34/31 +f 17/14/13 33/56/44 34/36/32 +f 24/32/17 40/34/31 41/38/33 +f 18/35/19 34/36/32 35/40/34 +f 25/37/21 41/38/33 42/42/35 +f 19/39/23 35/40/34 36/44/36 +f 26/41/25 42/42/35 43/46/37 +f 20/43/27 36/44/36 37/48/38 +f 27/45/28 43/46/37 44/50/39 +f 21/47/29 37/48/38 38/52/40 +f 28/49/3 44/50/39 45/53/41 +f 22/51/6 38/52/40 39/54/42 +f 16/55/43 32/61/49 33/56/44 +f 43/46/37 58/70/58 59/57/45 +f 37/48/38 52/71/59 53/58/46 +f 44/50/39 59/57/45 60/59/47 +f 38/52/40 53/58/46 54/60/48 +f 32/61/49 47/80/68 48/62/50 +f 45/53/41 60/59/47 61/63/51 +f 39/54/42 54/60/48 55/64/52 +f 33/56/44 48/62/50 49/65/53 +f 40/34/31 55/64/52 56/66/54 +f 34/36/32 49/65/53 50/67/55 +f 41/38/33 56/66/54 57/68/56 +f 35/40/34 50/67/55 51/69/57 +f 42/42/35 57/68/56 58/70/58 +f 36/44/36 51/69/57 52/71/59 +f 56/66/54 71/85/73 72/72/60 +f 50/67/55 65/86/74 66/73/61 +f 57/68/56 72/72/60 73/74/62 +f 51/69/57 66/73/61 67/75/63 +f 58/70/58 73/74/62 74/76/64 +f 52/71/59 67/75/63 68/77/65 +f 59/57/45 74/76/64 75/78/66 +f 53/58/46 68/77/65 69/79/67 +f 47/80/68 62/100/88 63/81/69 +f 60/59/47 75/78/66 76/82/70 +f 54/60/48 69/79/67 70/83/71 +f 48/62/50 63/81/69 64/84/72 +f 55/64/52 70/83/71 71/85/73 +f 49/65/53 64/84/72 65/86/74 +f 91/107/95 76/82/70 90/87/75 +f 85/90/78 70/83/71 84/88/76 +f 79/91/79 64/84/72 78/89/77 +f 86/92/80 71/85/73 85/90/78 +f 80/93/81 65/86/74 79/91/79 +f 87/94/82 72/72/60 86/92/80 +f 81/95/83 66/73/61 80/93/81 +f 88/96/84 73/74/62 87/94/82 +f 82/97/85 67/75/63 81/95/83 +f 89/98/86 74/76/64 88/96/84 +f 83/99/87 68/77/65 82/97/85 +f 90/87/75 75/78/66 89/98/86 +f 84/88/76 69/79/67 83/99/87 +f 78/89/77 63/81/69 77/101/89 +f 104/104/92 89/98/86 103/102/90 +f 98/105/93 83/99/87 97/103/91 +f 105/108/96 90/87/75 104/104/92 +f 99/109/97 84/88/76 98/105/93 +f 93/110/98 78/89/77 92/106/94 +f 106/126/114 91/107/95 105/108/96 +f 100/111/99 85/90/78 99/109/97 +f 94/112/100 79/91/79 93/110/98 +f 101/113/101 86/92/80 100/111/99 +f 95/114/102 80/93/81 94/112/100 +f 102/115/103 87/94/82 101/113/101 +f 96/116/104 81/95/83 95/114/102 +f 103/102/90 88/96/84 102/115/103 +f 97/103/91 82/97/85 96/116/104 +f 117/119/107 102/115/103 116/117/105 +f 111/120/108 96/116/104 110/118/106 +f 118/121/109 103/102/90 117/119/107 +f 112/122/110 97/103/91 111/120/108 +f 119/123/111 104/104/92 118/121/109 +f 113/124/112 98/105/93 112/122/110 +f 120/127/115 105/108/96 119/123/111 +f 114/128/116 99/109/97 113/124/112 +f 108/129/117 93/110/98 107/125/113 +f 121/133/121 106/126/114 120/127/115 +f 115/130/118 100/111/99 114/128/116 +f 109/131/119 94/112/100 108/129/117 +f 116/117/105 101/113/101 115/130/118 +f 110/118/106 95/114/102 109/131/119 +f 123/136/124 108/129/117 122/132/120 +f 136/153/141 121/133/121 135/134/122 +f 130/137/125 115/130/118 129/135/123 +f 124/138/126 109/131/119 123/136/124 +f 131/139/127 116/117/105 130/137/125 +f 125/140/128 110/118/106 124/138/126 +f 132/141/129 117/119/107 131/139/127 +f 126/142/130 111/120/108 125/140/128 +f 133/143/131 118/121/109 132/141/129 +f 127/144/132 112/122/110 126/142/130 +f 134/145/133 119/123/111 133/143/131 +f 128/146/134 113/124/112 127/144/132 +f 135/134/122 120/127/115 134/145/133 +f 129/135/123 114/128/116 128/146/134 +f 142/149/137 127/144/132 141/147/135 +f 149/150/138 134/145/133 148/148/136 +f 143/151/139 128/146/134 142/149/137 +f 150/154/142 135/134/122 149/150/138 +f 144/155/143 129/135/123 143/151/139 +f 138/156/144 123/136/124 137/152/140 +f 151/172/160 136/153/141 150/154/142 +f 145/157/145 130/137/125 144/155/143 +f 139/158/146 124/138/126 138/156/144 +f 146/159/147 131/139/127 145/157/145 +f 140/160/148 125/140/128 139/158/146 +f 147/161/149 132/141/129 146/159/147 +f 141/147/135 126/142/130 140/160/148 +f 148/148/136 133/143/131 147/161/149 +f 161/164/152 146/159/147 160/162/150 +f 155/165/153 140/160/148 154/163/151 +f 162/166/154 147/161/149 161/164/152 +f 156/188/174 141/147/135 155/165/153 +f 163/168/156 148/148/136 162/166/154 +f 141/147/135 156/188/174 157/167/155 +f 164/177/157 149/150/138 163/168/156 +f 158/170/158 143/151/139 157/167/155 +f 165/173/161 150/154/142 164/169/157 +f 159/174/162 144/155/143 158/170/158 +f 153/175/163 138/156/144 152/171/159 +f 166/256/167 151/172/160 165/173/161 +f 160/162/150 145/157/145 159/174/162 +f 154/163/151 139/158/146 153/175/163 +f 180/182/168 165/176/161 179/178/164 +f 174/183/169 159/174/162 173/179/165 +f 168/184/170 153/175/163 167/180/166 +f 181/201/187 166/181/167 180/182/168 +f 175/185/171 160/162/150 174/183/169 +f 169/186/172 154/163/151 168/184/170 +f 176/187/173 161/164/152 175/185/171 +f 170/189/175 155/165/153 169/186/172 +f 177/190/176 162/166/154 176/187/173 +f 171/191/177 156/188/174 170/189/175 +f 178/192/178 163/168/156 177/190/176 +f 172/193/179 157/167/155 171/191/177 +f 179/178/164 164/177/157 178/192/178 +f 173/179/165 158/170/158 172/193/179 +f 193/196/182 178/192/178 192/194/180 +f 187/197/183 172/193/179 186/195/181 +f 194/198/184 179/178/164 193/196/182 +f 188/199/185 173/179/165 187/197/183 +f 195/202/188 180/182/168 194/198/184 +f 189/203/189 174/183/169 188/199/185 +f 183/204/190 168/184/170 182/200/186 +f 196/220/206 181/201/187 195/202/188 +f 190/205/191 175/185/171 189/203/189 +f 184/206/192 169/186/172 183/204/190 +f 191/207/193 176/187/173 190/205/191 +f 185/208/194 170/189/175 184/206/192 +f 192/194/180 177/190/176 191/207/193 +f 186/195/181 171/191/177 185/208/194 +f 190/205/191 205/222/208 206/209/195 +f 184/206/192 199/223/209 200/210/196 +f 191/207/193 206/209/195 207/211/197 +f 185/208/194 200/210/196 201/212/198 +f 192/194/180 207/211/197 208/213/199 +f 186/195/181 201/212/198 202/214/200 +f 193/196/182 208/213/199 209/215/201 +f 187/197/183 202/214/200 203/216/202 +f 194/198/184 209/215/201 210/217/203 +f 188/199/185 203/216/202 204/218/204 +f 182/200/186 197/226/212 198/219/205 +f 195/202/188 210/217/203 211/221/207 +f 189/203/189 204/218/204 205/222/208 +f 183/204/190 198/219/205 199/223/209 +f 209/215/201 225/236/222 226/224/210 +f 203/216/202 219/237/223 220/225/211 +f 197/226/212 213/245/231 214/227/213 +f 210/217/203 226/224/210 227/228/214 +f 204/218/204 220/225/211 221/229/215 +f 198/219/205 214/227/213 215/230/216 +f 205/222/208 221/229/215 222/231/217 +f 199/223/209 215/230/216 216/232/218 +f 206/209/195 222/231/217 223/233/219 +f 200/210/196 216/232/218 217/234/220 +f 224/238/224 208/213/199 223/233/219 +f 201/212/198 217/234/220 218/235/221 +f 208/213/199 224/238/224 225/236/222 +f 202/214/200 218/235/221 219/237/223 +f 223/233/219 238/252/238 239/239/225 +f 217/234/220 232/253/239 233/240/226 +f 224/238/224 239/239/225 240/241/227 +f 218/235/221 233/240/226 234/242/228 +f 225/236/222 240/241/227 241/243/229 +f 219/237/223 234/242/228 235/244/230 +f 213/245/231 228/261/242 229/246/232 +f 226/224/210 241/243/229 242/247/233 +f 220/225/211 235/244/230 236/248/234 +f 214/227/213 229/246/232 230/249/235 +f 221/229/215 236/248/234 237/250/236 +f 215/230/216 230/249/235 231/251/237 +f 222/231/217 237/250/236 238/252/238 +f 216/232/218 231/251/237 232/253/239 +f 236/248/234 9/17/16 10/21/20 +f 230/249/235 3/19/18 4/23/22 +f 11/25/24 238/252/238 10/21/20 +f 231/251/237 4/23/22 5/27/26 +f 12/2/2 239/239/225 11/25/24 +f 232/253/239 5/27/26 6/5/5 +f 239/239/225 12/2/2 13/1/1 +f 233/240/226 6/5/5 7/4/4 +f 240/241/227 13/1/1 14/263/7 +f 234/242/228 7/4/4 8/10/9 +f 228/261/242 1/13/12 2/12/11 +f 241/243/229 14/263/7 15/264/14 +f 235/244/230 8/10/9 9/17/16 +f 229/246/232 2/12/11 3/19/18 diff --git a/src/datavisualization/engine/q3dbars.cpp b/src/datavisualization/engine/q3dbars.cpp new file mode 100644 index 00000000..0a543d54 --- /dev/null +++ b/src/datavisualization/engine/q3dbars.cpp @@ -0,0 +1,620 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dbars.h" +#include "q3dbars_p.h" +#include "bars3dcontroller_p.h" +#include "q3dvalueaxis.h" +#include "q3dcategoryaxis.h" +#include "qbardataproxy.h" +#include "q3dcamera.h" + +#include <QMouseEvent> + +#include <QDebug> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + * \class Q3DBars + * \inmodule QtDataVisualization + * \brief The Q3DBars class provides methods for rendering 3D bar graphs. + * \since 1.0.0 + * + * This class enables developers to render bar graphs in 3D and to view them by rotating the scene + * freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming + * is done by mouse wheel. Selection, if enabled, is done by left mouse button. The scene can be + * reset to default camera view by clicking mouse wheel. In touch devices rotation is done + * by tap-and-move, selection by tap-and-hold and zoom by pinch. + * + * If no axes are explicitly set to Q3DBars, temporary default axes with no labels are created. + * These default axes can be modified via axis accessors, but as soon any axis is explicitly + * set for the orientation, the default axis for that orientation is destroyed. + * + * Data proxies work similarly: If no data proxy is explicitly set, Q3DBars creates a default + * proxy. If any other proxy is set as active data proxy later, the default proxy and all data + * added to it is destroyed. + * + * Methods are provided for changing bar types, themes, bar selection modes and so on. See the + * methods for more detailed descriptions. + * + * \section1 How to construct a minimal Q3DBars graph + * + * First, construct an instance of Q3DBars: + * + * \snippet doc_src_q3dbars_construction.cpp 4 + * + * After constructing Q3DBars, you can set the data window by changing the range on the row and + * column axes. It is not mandatory, as data window will default to showing all of the data in + * the data proxy. If the amount of data is large, it is usually preferable to show just a + * portion of it. For the example, let's set the data window to show first five rows and columns: + * + * \snippet doc_src_q3dbars_construction.cpp 0 + * + * Now Q3DBars is ready to receive data to be rendered. Add one row of 5 qreals into the data + * set: + * + * \snippet doc_src_q3dbars_construction.cpp 1 + * + * \note We set the data window to 5 x 5, but we are inserting only one row of data. This is ok, + * the rest of the rows will just be blank. + * + * Finally you will need to set it visible: + * + * \snippet doc_src_q3dbars_construction.cpp 2 + * + * The complete code needed to create and display this graph is: + * + * \snippet doc_src_q3dbars_construction.cpp 3 + * + * And this is what those few lines of code produce: + * + * \image q3dbars-minimal.png + * + * The scene can be rotated, zoomed into, and a bar can be selected to view it's value, + * but no other interaction is included in this minimal code example. You can learn more by + * familiarizing yourself with the examples provided, like the \l{Bars Example} or + * the \l{Custom Proxy Example}. + * + * \sa Q3DScatter, Q3DSurface, {Qt Data Visualization C++ Classes} + */ + +/*! + * Constructs a new 3D bar window. + */ +Q3DBars::Q3DBars() + : d_ptr(new Q3DBarsPrivate(this, geometry())) +{ + setVisualController(d_ptr->m_shared); + d_ptr->m_shared->initializeOpenGL(); + QObject::connect(d_ptr->m_shared, &Bars3DController::selectedBarPosChanged, this, + &Q3DBars::selectedBarPosChanged); + QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this, + &Q3DWindow::renderLater); +} + +/*! + * Destroys the 3D bar window. + */ +Q3DBars::~Q3DBars() +{ +} + +/*! + * \internal + */ +void Q3DBars::mouseDoubleClickEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseDoubleClickEvent(event); +} + +/*! + * \internal + */ +void Q3DBars::touchEvent(QTouchEvent *event) +{ + d_ptr->m_shared->touchEvent(event); +} + +/*! + * \internal + */ +void Q3DBars::mousePressEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mousePressEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DBars::mouseReleaseEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseReleaseEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DBars::mouseMoveEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseMoveEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DBars::wheelEvent(QWheelEvent *event) +{ + d_ptr->m_shared->wheelEvent(event); +} + +/*! + * \internal + */ +void Q3DBars::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + d_ptr->m_shared->setSize(width(), height()); +} + +/*! + * Sets window \a width. + */ +void Q3DBars::setWidth(const int width) +{ + d_ptr->m_shared->setWidth(width); + QWindow::setWidth(width); +} + +/*! + * Sets window \a height. + */ +void Q3DBars::setHeight(const int height) +{ + d_ptr->m_shared->setHeight(height); + QWindow::setHeight(height); +} + +/*! + * \property Q3DBars::barThickness + * + * Bar thickness ratio between X and Z dimensions. 1.0 means bars are as wide as they are deep, 0.5 + * makes them twice as deep as they are wide. It is preset to \c 1.0 by default. + */ +void Q3DBars::setBarThickness(qreal thicknessRatio) +{ + d_ptr->m_shared->setBarSpecs(GLfloat(thicknessRatio), barSpacing(), isBarSpacingRelative()); +} + +qreal Q3DBars::barThickness() +{ + return d_ptr->m_shared->barThickness(); +} + +/*! + * \property Q3DBars::barSpacing + * + * Bar spacing, ie. the empty space between bars, in X and Z dimensions. It is preset to + * \c {(1.0, 1.0)} by default. Spacing is affected by barSpacingRelative -property. + * + * \sa barSpacingRelative + */ +void Q3DBars::setBarSpacing(QSizeF spacing) +{ + d_ptr->m_shared->setBarSpecs(GLfloat(barThickness()), spacing, isBarSpacingRelative()); +} + +QSizeF Q3DBars::barSpacing() +{ + return d_ptr->m_shared->barSpacing(); +} + +/*! + * \property Q3DBars::barSpacingRelative + * + * This is used to indicate if spacing is meant to be absolute or relative to bar thickness. + * If it is true, value of 0.0 means the bars are side-to-side and for example 1.0 means + * there is one thickness in between the bars. It is preset to \c true. + */ +void Q3DBars::setBarSpacingRelative(bool relative) +{ + d_ptr->m_shared->setBarSpecs(GLfloat(barThickness()), barSpacing(), relative); +} + +bool Q3DBars::isBarSpacingRelative() +{ + return d_ptr->m_shared->isBarSpecRelative(); +} + +/*! + * Sets the bar \a style to one of the values in \c QDataVis::MeshStyle. It is preset to + * \c QDataVis::MeshStyleBars by default. A \a smooth flag can be used to set shading to smooth. + * It is \c false by default. + * + * \sa setMeshFileName() + */ +void Q3DBars::setBarType(QDataVis::MeshStyle style, bool smooth) +{ + d_ptr->m_shared->setBarType(style, smooth); +} + +/*! + * Sets a predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by + * default. Theme affects bar colors, label colors, text color, background color, window color and + * grid color. Lighting is also adjusted by themes. + * + * \sa setBarColor() + * + * \warning This method is subject to change. + */ +void Q3DBars::setTheme(QDataVis::Theme theme) +{ + d_ptr->m_shared->setTheme(theme); +} + +/*! + * Set bar color using your own color. \a baseColor sets the base color of a bar. The \a uniform + * -flag is used to define if color needs to be uniform throughout bar's length, or will the colors + * be applied by height, starting with dark at the bottom. It is \c true by default. + * + * Calling this method overrides colors from theme. + * + * \sa setTheme() + * + * \warning This method is subject to change. + */ +void Q3DBars::setBarColor(const QColor &baseColor, bool uniform) +{ + d_ptr->m_shared->setObjectColor(baseColor, uniform); +} + +/*! + * \return bar color in use. + */ +QColor Q3DBars::barColor() const +{ + return d_ptr->m_shared->objectColor(); +} + +/*! + * \property Q3DBars::selectionMode + * + * Sets bar selection \a mode to one of \c QDataVis::SelectionMode. It is preset to + * \c QDataVis::SelectionModeItem by default. + */ +void Q3DBars::setSelectionMode(QDataVis::SelectionMode mode) +{ + d_ptr->m_shared->setSelectionMode(mode); +} + +QDataVis::SelectionMode Q3DBars::selectionMode() const +{ + return d_ptr->m_shared->selectionMode(); +} + +/*! + * \property Q3DBars::meshFileName + * + * Override bar type with a mesh object located in \a objFileName. + * \note Object needs to be in Wavefront obj format and include vertices, normals and UVs. + * It also needs to be in triangles. + * + * \sa setBarType() + */ +void Q3DBars::setMeshFileName(const QString &objFileName) +{ + d_ptr->m_shared->setMeshFileName(objFileName); +} + +QString Q3DBars::meshFileName() const +{ + return d_ptr->m_shared->meshFileName(); +} + +/*! + * \property Q3DBars::font + * + * Sets the \a font for labels. It is preset to \c Arial by default. + */ +void Q3DBars::setFont(const QFont &font) +{ + d_ptr->m_shared->setFont(font); +} + +QFont Q3DBars::font() const +{ + return d_ptr->m_shared->font(); +} + +/*! + * \property Q3DBars::scene + * + * This property contains the read only Q3DScene that can be used to access e.g. camera object. + */ +Q3DScene *Q3DBars::scene() const +{ + return d_ptr->m_shared->scene(); +} + +/*! + * \property Q3DBars::labelStyle + * + * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to + * \c QDataVis::LabelStyleFromTheme by default. + */ +void Q3DBars::setLabelStyle(QDataVis::LabelStyle style) +{ + d_ptr->m_shared->setLabelStyle(style); +} + +QDataVis::LabelStyle Q3DBars::labelStyle() const +{ + return d_ptr->m_shared->labelStyle(); +} + +/*! + * \property Q3DBars::gridVisible + * + * Sets grid visibility to \a visible. It is preset to \c true by default. + */ +void Q3DBars::setGridVisible(bool visible) +{ + d_ptr->m_shared->setGridEnabled(visible); +} + +bool Q3DBars::isGridVisible() const +{ + return d_ptr->m_shared->gridEnabled(); +} + +/*! + * \property Q3DBars::backgroundVisible + * + * Sets background visibility to \a visible. It is preset to \c true by default. + */ +void Q3DBars::setBackgroundVisible(bool visible) +{ + d_ptr->m_shared->setBackgroundEnabled(visible); +} + +bool Q3DBars::isBackgroundVisible() const +{ + return d_ptr->m_shared->backgroundEnabled(); +} + +/*! + * \property Q3DBars::selectedBarPos + * + * Selects a bar in a \a position. The position is the position in data window. + * Only one bar can be selected at a time. + * To clear selection, specify an illegal \a position, e.g. (-1, -1). + */ +void Q3DBars::setSelectedBarPos(const QPoint &position) +{ + d_ptr->m_shared->setSelectedBarPos(position); +} + +QPoint Q3DBars::selectedBarPos() const +{ + return d_ptr->m_shared->selectedBarPos(); +} + +/*! + * \property Q3DBars::shadowQuality + * + * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to + * \c QDataVis::ShadowQualityMedium by default. + * + * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered + * until it is successful and shadowQualityChanged signal is emitted for each time the change is + * done. + */ +void Q3DBars::setShadowQuality(QDataVis::ShadowQuality quality) +{ + d_ptr->m_shared->setShadowQuality(quality); +} + +QDataVis::ShadowQuality Q3DBars::shadowQuality() const +{ + return d_ptr->m_shared->shadowQuality(); +} + +/*! + * Sets a user-defined row \a axis. Implicitly calls addAxis() to transfer ownership of + * the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DBars::setRowAxis(Q3DCategoryAxis *axis) +{ + d_ptr->m_shared->setAxisX(axis); +} + +/*! + * \return category axis for rows. + */ +Q3DCategoryAxis *Q3DBars::rowAxis() const +{ + return static_cast<Q3DCategoryAxis *>(d_ptr->m_shared->axisX()); +} + +/*! + * Sets a user-defined column \a axis. Implicitly calls addAxis() to transfer ownership of + * the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DBars::setColumnAxis(Q3DCategoryAxis *axis) +{ + d_ptr->m_shared->setAxisZ(axis); +} + +/*! + * \return category axis for columns. + */ +Q3DCategoryAxis *Q3DBars::columnAxis() const +{ + return static_cast<Q3DCategoryAxis *>(d_ptr->m_shared->axisZ()); +} + +/*! + * Sets a user-defined value \a axis (the Y-axis). Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DBars::setValueAxis(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisY(axis); +} + +/*! + * \return used value axis (Y-axis). + */ +Q3DValueAxis *Q3DBars::valueAxis() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY()); +} + +/*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setValueAxis(), setRowAxis(), setColumnAxis() + */ +void Q3DBars::addAxis(Q3DAbstractAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * If the released \a axis is in use, a new default axis will be created and set active. + * + * If the default axis is released and added back later, it behaves as any other axis would. + * + * \sa addAxis(), setValueAxis(), setRowAxis(), setColumnAxis() + */ +void Q3DBars::releaseAxis(Q3DAbstractAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<Q3DAbstractAxis *> Q3DBars::axes() const +{ + return d_ptr->m_shared->axes(); +} + +/*! + * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of + * the \a proxy to this graph. + * + * If the \a proxy is null, a temporary default proxy is created and activated. + * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method. + * + * \sa addDataProxy(), releaseDataProxy() + */ +void Q3DBars::setActiveDataProxy(QBarDataProxy *proxy) +{ + d_ptr->m_shared->setActiveDataProxy(proxy); +} + +/*! + * \return active data proxy. + */ +QBarDataProxy *Q3DBars::activeDataProxy() const +{ + return static_cast<QBarDataProxy *>(d_ptr->m_shared->activeDataProxy()); +} + +/*! + * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use, + * addDataProxy is simply used to give the ownership of the data \a proxy to the graph. + * The \a proxy must not be null or added to another graph. + * + * \sa releaseDataProxy(), setActiveDataProxy() + */ +void Q3DBars::addDataProxy(QBarDataProxy *proxy) +{ + d_ptr->m_shared->addDataProxy(proxy); +} + +/*! + * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph. + * If the released \a proxy is in use, a new empty default proxy is created and taken to use. + * + * If the default \a proxy is released and added back later, it behaves as any other proxy would. + * + * \sa addDataProxy(), setActiveDataProxy() + */ +void Q3DBars::releaseDataProxy(QBarDataProxy *proxy) +{ + d_ptr->m_shared->releaseDataProxy(proxy); +} + +/*! + * \return list of all added data proxies. + * + * \sa addDataProxy() + */ +QList<QBarDataProxy *> Q3DBars::dataProxies() const +{ + QList<QBarDataProxy *> retList; + QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies(); + foreach (QAbstractDataProxy *proxy, abstractList) + retList.append(static_cast<QBarDataProxy *>(proxy)); + + return retList; +} + +Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q, QRect rect) + : q_ptr(q), + m_shared(new Bars3DController(rect)) +{ + QObject::connect(m_shared, &Abstract3DController::shadowQualityChanged, this, + &Q3DBarsPrivate::handleShadowQualityUpdate); +} + +Q3DBarsPrivate::~Q3DBarsPrivate() +{ + qDebug() << "Destroying Q3DBarsPrivate"; + delete m_shared; +} + +void Q3DBarsPrivate::handleShadowQualityUpdate(QDataVis::ShadowQuality quality) +{ + emit q_ptr->shadowQualityChanged(quality); +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dbars.h b/src/datavisualization/engine/q3dbars.h new file mode 100644 index 00000000..d0ddf3fb --- /dev/null +++ b/src/datavisualization/engine/q3dbars.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DBARS_H +#define Q3DBARS_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QtDataVisualization/q3dwindow.h> +#include <QFont> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DBarsPrivate; +class Q3DAbstractAxis; +class Q3DCategoryAxis; +class Q3DValueAxis; +class QBarDataProxy; +class Q3DScene; + +class QT_DATAVISUALIZATION_EXPORT Q3DBars : public Q3DWindow +{ + Q_OBJECT + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) + Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged) + Q_PROPERTY(qreal barThickness READ barThickness WRITE setBarThickness) + Q_PROPERTY(QSizeF barSpacing READ barSpacing WRITE setBarSpacing) + Q_PROPERTY(bool barSpacingRelative READ isBarSpacingRelative WRITE setBarSpacingRelative) + Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName) + Q_PROPERTY(QFont font READ font WRITE setFont) + Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) + Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) + Q_PROPERTY(QPoint selectedBarPos READ selectedBarPos WRITE setSelectedBarPos NOTIFY selectedBarPosChanged) + Q_PROPERTY(Q3DScene* scene READ scene) + + Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) + Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) + Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) + Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) + +public: + explicit Q3DBars(); + ~Q3DBars(); + + void setBarType(QDataVis::MeshStyle style, bool smooth = false); + + void setTheme(QDataVis::Theme theme); + + void setBarThickness(qreal thicknessRatio); + qreal barThickness(); + + void setBarSpacing(QSizeF spacing); + QSizeF barSpacing(); + + void setBarSpacingRelative(bool relative); + bool isBarSpacingRelative(); + + void setBarColor(const QColor &baseColor, bool uniform = true); + QColor barColor() const; + + void setMeshFileName(const QString &objFileName); + QString meshFileName() const; + + void setSelectionMode(QDataVis::SelectionMode mode); + QDataVis::SelectionMode selectionMode() const; + + void setFont(const QFont &font); + QFont font() const; + + Q3DScene *scene() const; + + void setLabelStyle(QDataVis::LabelStyle style); + QDataVis::LabelStyle labelStyle() const; + + void setGridVisible(bool visible); + bool isGridVisible() const; + + void setWidth(const int width); + void setHeight(const int height); + + void setBackgroundVisible(bool visible); + bool isBackgroundVisible() const; + + void setSelectedBarPos(const QPoint &position); + QPoint selectedBarPos() const; + + void setShadowQuality(QDataVis::ShadowQuality quality); + QDataVis::ShadowQuality shadowQuality() const; + + void setRowAxis(Q3DCategoryAxis *axis); + Q3DCategoryAxis *rowAxis() const; + void setColumnAxis(Q3DCategoryAxis *axis); + Q3DCategoryAxis *columnAxis() const; + void setValueAxis(Q3DValueAxis *axis); + Q3DValueAxis *valueAxis() const; + void addAxis(Q3DAbstractAxis *axis); + void releaseAxis(Q3DAbstractAxis *axis); + QList<Q3DAbstractAxis *> axes() const; + + void setActiveDataProxy(QBarDataProxy *proxy); + QBarDataProxy *activeDataProxy() const; + void addDataProxy(QBarDataProxy *proxy); + void releaseDataProxy(QBarDataProxy *proxy); + QList<QBarDataProxy *> dataProxies() const; + +signals: + void shadowQualityChanged(QDataVis::ShadowQuality quality); + void selectedBarPosChanged(QPoint position); + +protected: + + void mouseDoubleClickEvent(QMouseEvent *event); + void touchEvent(QTouchEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void resizeEvent(QResizeEvent *event); + +private: + QScopedPointer<Q3DBarsPrivate> d_ptr; + Q_DISABLE_COPY(Q3DBars) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dbars_p.h b/src/datavisualization/engine/q3dbars_p.h new file mode 100644 index 00000000..653db606 --- /dev/null +++ b/src/datavisualization/engine/q3dbars_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DBARS_p_H +#define Q3DBARS_p_H + +#include "bars3dcontroller_p.h" +#include "qdatavisualizationenums.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DBars; + +class Q3DBarsPrivate : public QObject +{ +public: + Q3DBarsPrivate(Q3DBars *q, QRect rect); + ~Q3DBarsPrivate(); + + // Used to detect when shadow quality changes autonomously due to e.g. resizing. + void handleShadowQualityUpdate(QDataVis::ShadowQuality quality); + + Q3DBars *q_ptr; + Bars3DController *m_shared; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dbox.cpp b/src/datavisualization/engine/q3dbox.cpp new file mode 100644 index 00000000..43f3e90e --- /dev/null +++ b/src/datavisualization/engine/q3dbox.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "datavisualizationglobal_p.h" +#include "q3dbox.h" +#include <QtCore/QList> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + \class Q3DBox + \inmodule QtDataVisualization + \brief The Q3DBox class represents an axis-aligned box in 3D space. + \since 1.0.0 + + Q3DBox can be used to represent the bounding box of objects in a 3D + scene so that they can be easily culled if they are out of view. + + The sides of the box are always aligned with the x, y, and z axes of + the world co-ordinate system. Transforming a box with transformed() + will result in the smallest axis-aligned bounding box that contains + the transformed box. + + Boxes may be null, finite, or infinite. A null box does not occupy + any space and does not intersect with any other box. A finite + box consists of a minimum() and maximum() extent in 3D space. + An infinite box encompasses all points in 3D space. + + The extents of a finite box are also included within the box. + A box with minimum() and maximum() set to the same value + contains a single point. +*/ + +/*! + \fn Q3DBox::Q3DBox() + + Constructs a null box in 3D space. + + \sa isNull() +*/ + +/*! + \fn Q3DBox::Q3DBox(const QVector3D& corner1, const QVector3D& corner2) + + Constructs a finite box in 3D space from \a corner1 to \a corner2. + The minimum() and maximum() co-ordinates of the new box are set + to the minimum and maximum x, y, and z values from \a corner1 and + \a corner2. The \a corner1 and \a corner2 values can be any two + opposite corners that define the box. + + \sa isFinite(), minimum(), maximum() +*/ + +/*! + \fn bool Q3DBox::isNull() const + + Returns true if this box is null; false otherwise. + + \sa isFinite(), isInfinite(), setToNull() +*/ + +/*! + \fn bool Q3DBox::isFinite() const + + Returns true if this box is finite in size; false otherwise. + + \sa isNull(), isInfinite(), setExtents() +*/ + +/*! + \fn bool Q3DBox::isInfinite() const + + Returns true if this box is infinite in size; false otherwise. + + \sa isNull(), isFinite(), setToInfinite() +*/ + +/*! + \fn QVector3D Q3DBox::minimum() const + + Returns the minimum corner of this box. + + \sa maximum(), setExtents() +*/ + +/*! + \fn QVector3D Q3DBox::maximum() const + + Returns the maximum corner of this box. + + \sa minimum(), setExtents() +*/ + +/*! + \fn void Q3DBox::setExtents(const QVector3D& corner1, const QVector3D& corner2) + + Sets the extents of this box to a finite region from \a corner1 to + \a corner2. The minimum() and maximum() co-ordinates of the box are + set to the minimum and maximum x, y, and z values from \a corner1 and + \a corner2. The \a corner1 and \a corner2 values can be any two + opposite corners that define the box. + + \sa minimum(), maximum() +*/ + +/*! + \fn void Q3DBox::setToNull() + + Sets this box to null. + + \sa isNull() +*/ + +/*! + \fn void Q3DBox::setToInfinite() + + Sets this box to be infinite in size. + + \sa isInfinite() +*/ + +/*! + \fn QVector3D Q3DBox::size() const + + Returns the finite size of this box. If this box is null or + infinite, the returned value will be zero. + + \sa center(), isNull(), isInfinite() +*/ + +/*! + \fn QVector3D Q3DBox::center() const + + Returns the finite center of this box. If this box is null + or infinite, the returned value will be zero. + + \sa size(), isNull(), isInfinite() +*/ + +/*! + \fn bool Q3DBox::contains(const QVector3D& point) const + + Returns true if this box contains \a point; false otherwise. + Null boxes do not contain any points and infinite boxes contain + all points. + + Containment is not a strict test: the point is contained if it + lies on one of the faces of the box. + + \sa intersects() +*/ + +/*! + \fn bool Q3DBox::contains(const Q3DBox& box) const + + Returns true if this box completely contains \a box. If this box + is null, then it will not contain \a box. If this box is infinite, + and \a box is not null, then \a box will be contained within this box. + If \a box is infinite, then this box must also be infinite to contain it. + + \sa intersects() +*/ + +/*! + Returns true if \a box intersects this box; false otherwise. + + \sa intersect(), intersected(), contains() +*/ +bool Q3DBox::intersects(const Q3DBox& box) const +{ + if (boxtype == Null) + return false; + else if (boxtype == Infinite) + return box.boxtype != Null; + else if (box.boxtype == Null) + return false; + else if (box.boxtype == Infinite) + return true; + + if (maxcorner.x() < box.mincorner.x()) + return false; + if (mincorner.x() > box.maxcorner.x()) + return false; + + if (maxcorner.y() < box.mincorner.y()) + return false; + if (mincorner.y() > box.maxcorner.y()) + return false; + + if (maxcorner.z() < box.mincorner.z()) + return false; + if (mincorner.z() > box.maxcorner.z()) + return false; + + return true; +} + +/*! + Intersects this box with \a box. + + \sa intersected(), intersects(), unite() +*/ +void Q3DBox::intersect(const Q3DBox& box) +{ + // Handle the simple cases first. + if (boxtype == Null) { + // Null intersected with anything is null. + return; + } else if (boxtype == Infinite) { + // Infinity intersected with a box is that box. + *this = box; + return; + } else if (box.boxtype == Null) { + // Anything intersected with null is null. + setToNull(); + return; + } else if (box.boxtype == Infinite) { + // Box intersected with infinity is the box. + return; + } + + // Intersect two finite boxes. + QVector3D min1 = mincorner; + QVector3D max1 = maxcorner; + QVector3D min2 = box.mincorner; + QVector3D max2 = box.maxcorner; + if (min2.x() > min1.x()) + min1.setX(min2.x()); + if (min2.y() > min1.y()) + min1.setY(min2.y()); + if (min2.z() > min1.z()) + min1.setZ(min2.z()); + if (max2.x() < max1.x()) + max1.setX(max2.x()); + if (max2.y() < max1.y()) + max1.setY(max2.y()); + if (max2.z() < max1.z()) + max1.setZ(max2.z()); + if (min1.x() > max1.x() || min1.y() > max1.y() || min1.z() > max1.z()) { + setToNull(); + } else { + mincorner = min1; + maxcorner = max1; + } +} + +/*! + Returns a new box which is the intersection of this box with \a box. + + \sa intersect(), intersects(), united() +*/ +Q3DBox Q3DBox::intersected(const Q3DBox& box) const +{ + Q3DBox result(*this); + result.intersect(box); + return result; +} + +/*! + Unites this box with \a point by expanding it to encompass \a point. + If \a point is already contained within this box, then this box + will be unchanged. + + \sa united(), intersect() +*/ +void Q3DBox::unite(const QVector3D& point) +{ + if (boxtype == Finite) { + if (point.x() < mincorner.x()) + mincorner.setX(point.x()); + else if (point.x() > maxcorner.x()) + maxcorner.setX(point.x()); + if (point.y() < mincorner.y()) + mincorner.setY(point.y()); + else if (point.y() > maxcorner.y()) + maxcorner.setY(point.y()); + if (point.z() < mincorner.z()) + mincorner.setZ(point.z()); + else if (point.z() > maxcorner.z()) + maxcorner.setZ(point.z()); + } else if (boxtype == Null) { + boxtype = Finite; + mincorner = point; + maxcorner = point; + } +} + +/*! + Unites this box with \a box by expanding this box to encompass the + region defined by \a box. If \a box is already contained within + this box, then this box will be unchanged. + + \sa united(), intersect() +*/ +void Q3DBox::unite(const Q3DBox& box) +{ + if (box.boxtype == Finite) { + unite(box.minimum()); + unite(box.maximum()); + } else if (box.boxtype == Infinite) { + setToInfinite(); + } +} + +/*! + Returns a new box which unites this box with \a point. The returned + value will be the smallest box that contains both this box and \a point. + + \sa unite(), intersected() +*/ +Q3DBox Q3DBox::united(const QVector3D& point) const +{ + if (boxtype == Finite) { + Q3DBox result(*this); + result.unite(point); + return result; + } else if (boxtype == Null) { + return Q3DBox(point, point); + } else { + return *this; + } +} + +/*! + Returns a new box which unites this box with \a box. The returned value + will be the smallest box that contains both this box and \a box. + + \sa unite(), intersected() +*/ +Q3DBox Q3DBox::united(const Q3DBox& box) const +{ + if (boxtype == Finite) { + Q3DBox result(*this); + result.unite(box); + return result; + } else if (boxtype == Null) { + return box; + } else { + return *this; + } +} + +/*! + Transforms this box according to \a matrix. Each of the 8 box + corners are transformed and then a new box that encompasses all + of the transformed corner values is created. + + \sa transformed() +*/ +void Q3DBox::transform(const QMatrix4x4& matrix) +{ + *this = transformed(matrix); +} + +/*! + Returns this box transformed by \a matrix. Each of the 8 box + corners are transformed and then a new box that encompasses all + of the transformed corner values is returned. + + \sa transform() +*/ +Q3DBox Q3DBox::transformed(const QMatrix4x4& matrix) const +{ + if (boxtype != Finite) + return *this; + Q3DBox result; + result.unite(matrix * mincorner); + result.unite(matrix * QVector3D(mincorner.x(), mincorner.y(), maxcorner.z())); + result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), maxcorner.z())); + result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), mincorner.z())); + result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), mincorner.z())); + result.unite(matrix * QVector3D(maxcorner.x(), maxcorner.y(), mincorner.z())); + result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), maxcorner.z())); + result.unite(matrix * maxcorner); + return result; +} + +/*! + \fn bool Q3DBox::operator==(const Q3DBox& box) const + + Returns true if this box is identical to \a box. +*/ + +/*! + \fn bool Q3DBox::operator!=(const Q3DBox& box) const + + Returns true if this box is not identical to \a box. +*/ + +/*! + \fn bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2) + \relates Q3DBox + + Returns true if \a box1 and \a box2 are almost equal; false otherwise. +*/ + +#ifndef QT_NO_DEBUG_STREAM + +QDebug operator<<(QDebug dbg, const Q3DBox &box) +{ + if (box.isFinite()) { + dbg.nospace() << "Q3DBox((" + << box.minimum().x() << ", " << box.minimum().y() << ", " + << box.minimum().z() << ") - (" + << box.maximum().x() << ", " << box.maximum().y() << ", " + << box.maximum().z() << "))"; + return dbg.space(); + } else if (box.isNull()) { + dbg << "Q3DBox(null)"; + return dbg; + } else { + dbg << "Q3DBox(infinite)"; + return dbg; + } +} + +#endif + +#ifndef QT_NO_DATASTREAM + +/*! + \relates Q3DBox + + Writes the given \a box to the given \a stream and returns a + reference to the stream. +*/ +QDataStream &operator<<(QDataStream &stream, const Q3DBox &box) +{ + if (box.isNull()) { + stream << int(0); + } else if (box.isInfinite()) { + stream << int(2); + } else { + stream << int(1); + stream << box.minimum(); + stream << box.maximum(); + } + return stream; +} + +/*! + \relates Q3DBox + + Reads a 3D box from the given \a stream into the given \a box + and returns a reference to the stream. +*/ +QDataStream &operator>>(QDataStream &stream, Q3DBox &box) +{ + int type; + stream >> type; + if (type == 1) { + QVector3D minimum, maximum; + stream >> minimum; + stream >> maximum; + box = Q3DBox(minimum, maximum); + } else if (type == 2) { + box.setToInfinite(); + } else { + box.setToNull(); + } + return stream; +} + +#endif // QT_NO_DATASTREAM + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dbox.h b/src/datavisualization/engine/q3dbox.h new file mode 100644 index 00000000..aa63ec39 --- /dev/null +++ b/src/datavisualization/engine/q3dbox.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DBOX_H +#define Q3DBOX_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QtGui/QMatrix4x4> +#include <QtGui/QVector3D> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DBox; // Needed to circumvent an issue with qdoc. If this line is removed, make docs will not work for this. + +class QT_DATAVISUALIZATION_EXPORT Q3DBox +{ +public: + Q3DBox(); + Q3DBox(const QVector3D& corner1, const QVector3D& corner2); + + bool isNull() const; + bool isFinite() const; + bool isInfinite() const; + + QVector3D minimum() const; + QVector3D maximum() const; + void setExtents(const QVector3D& corner1, const QVector3D& corner2); + + void setToNull(); + void setToInfinite(); + + QVector3D size() const; + QVector3D center() const; + + bool contains(const QVector3D& point) const; + bool contains(const Q3DBox& box) const; + + bool intersects(const Q3DBox& box) const; + void intersect(const Q3DBox& box); + Q3DBox intersected(const Q3DBox& box) const; + + void unite(const QVector3D& point); + void unite(const Q3DBox& box); + + Q3DBox united(const QVector3D& point) const; + Q3DBox united(const Q3DBox& box) const; + + void transform(const QMatrix4x4& matrix); + Q3DBox transformed(const QMatrix4x4& matrix) const; + + bool operator==(const Q3DBox& box) const; + bool operator!=(const Q3DBox& box) const; + + friend bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2); + +private: + enum Type + { + Null, + Finite, + Infinite + }; + + Q3DBox::Type boxtype; + QVector3D mincorner, maxcorner; +}; + +inline Q3DBox::Q3DBox() : boxtype(Null), mincorner(0, 0, 0), maxcorner(0, 0, 0) {} + +inline Q3DBox::Q3DBox(const QVector3D& corner1, const QVector3D& corner2) + : boxtype(Finite), + mincorner(qMin(corner1.x(), corner2.x()), + qMin(corner1.y(), corner2.y()), + qMin(corner1.z(), corner2.z())), + maxcorner(qMax(corner1.x(), corner2.x()), + qMax(corner1.y(), corner2.y()), + qMax(corner1.z(), corner2.z())) {} + +inline bool Q3DBox::isNull() const { return (boxtype == Null); } +inline bool Q3DBox::isFinite() const { return (boxtype == Finite); } +inline bool Q3DBox::isInfinite() const { return (boxtype == Infinite); } + +inline QVector3D Q3DBox::minimum() const { return mincorner; } +inline QVector3D Q3DBox::maximum() const { return maxcorner; } + +inline void Q3DBox::setExtents(const QVector3D& corner1, const QVector3D& corner2) +{ + boxtype = Finite; + mincorner = QVector3D(qMin(corner1.x(), corner2.x()), + qMin(corner1.y(), corner2.y()), + qMin(corner1.z(), corner2.z())); + maxcorner = QVector3D(qMax(corner1.x(), corner2.x()), + qMax(corner1.y(), corner2.y()), + qMax(corner1.z(), corner2.z())); +} + +inline void Q3DBox::setToNull() +{ + boxtype = Null; + mincorner = QVector3D(0, 0, 0); + maxcorner = QVector3D(0, 0, 0); +} + +inline void Q3DBox::setToInfinite() +{ + boxtype = Infinite; + mincorner = QVector3D(0, 0, 0); + maxcorner = QVector3D(0, 0, 0); +} + +inline QVector3D Q3DBox::size() const { return maxcorner - mincorner; } +inline QVector3D Q3DBox::center() const { return (mincorner + maxcorner) * 0.5f; } + +inline bool Q3DBox::contains(const QVector3D& point) const +{ + if (boxtype == Finite) { + return (point.x() >= mincorner.x() && point.x() <= maxcorner.x() && + point.y() >= mincorner.y() && point.y() <= maxcorner.y() && + point.z() >= mincorner.z() && point.z() <= maxcorner.z()); + } else if (boxtype == Infinite) { + return true; + } else { + return false; + } +} + +inline bool Q3DBox::contains(const Q3DBox& box) const +{ + if (box.boxtype == Finite) + return contains(box.mincorner) && contains(box.maxcorner); + else if (box.boxtype == Infinite) + return (boxtype == Infinite); + else + return false; +} + +inline bool Q3DBox::operator==(const Q3DBox& box) const +{ + return (boxtype == box.boxtype && + mincorner == box.mincorner && + maxcorner == box.maxcorner); +} + +inline bool Q3DBox::operator!=(const Q3DBox& box) const +{ + return (boxtype != box.boxtype || + mincorner != box.mincorner || + maxcorner != box.maxcorner); +} + +inline bool qFuzzyCompare(const Q3DBox& box1, const Q3DBox& box2) +{ + return box1.boxtype == box2.boxtype && + qFuzzyCompare(box1.mincorner, box2.mincorner) && + qFuzzyCompare(box1.maxcorner, box2.maxcorner); +} + +#ifndef QT_NO_DEBUG_STREAM +QT_DATAVISUALIZATION_EXPORT QDebug operator<<(QDebug dbg, const Q3DBox &box); +#endif + +#ifndef QT_NO_DATASTREAM +QT_DATAVISUALIZATION_EXPORT QDataStream &operator<<(QDataStream &stream, const Q3DBox &box); +QT_DATAVISUALIZATION_EXPORT QDataStream &operator>>(QDataStream &stream, Q3DBox &box); +#endif + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dcamera.cpp b/src/datavisualization/engine/q3dcamera.cpp new file mode 100644 index 00000000..571af1d7 --- /dev/null +++ b/src/datavisualization/engine/q3dcamera.cpp @@ -0,0 +1,698 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dcamera.h" +#include "q3dcamera_p.h" +#include "q3dscene.h" +#include "q3dbox.h" +#include "q3dobject.h" +#include "utils_p.h" + +#include <qmath.h> +#include <QVector3D> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + \class Q3DCamera + \inmodule QtDataVisualization + \brief Representation of a camera in 3D space. + \since 1.0.0 + + Q3DCamera represents a basic orbit around centerpoint 3D camera that is used when rendering the data visualization. + The class offers simple methods for setting the orbit point in rotations, but allows also setting the 4x4 viewmatrix + directly in case a more customized camera behavior is needed. +*/ + +/*! + * Constructs a new 3D camera with position set to origo, up direction facing towards the Y-axis and looking at origo by default. An + * optional \a parent parameter can be given and is then passed to QObject constructor. + */ +Q3DCamera::Q3DCamera(QObject *parent) : + Q3DObject(parent), + d_ptr(new Q3DCameraPrivate(this)) +{ +} + +/*! + * Destroys the camera object. + */ +Q3DCamera::~Q3DCamera() +{ +} + +/*! + * Copies the 3D camera's properties from the given source camera. + * Values are copied from the \a source to this object. + */ +void Q3DCamera::copyValuesFrom(const Q3DCamera &source) +{ + Q3DObject::copyValuesFrom(source); + + d_ptr->m_target.setX(source.d_ptr->m_target.x()); + d_ptr->m_target.setY(source.d_ptr->m_target.y()); + d_ptr->m_target.setZ(source.d_ptr->m_target.z()); + + d_ptr->m_up.setX(source.d_ptr->m_up.x()); + d_ptr->m_up.setY(source.d_ptr->m_up.y()); + d_ptr->m_up.setZ(source.d_ptr->m_up.z()); + + float *values = new float[16]; + source.d_ptr->m_viewMatrix.copyDataTo(values); + d_ptr->m_viewMatrix = QMatrix4x4(values); + delete[] values; + + d_ptr->m_xRotation = source.d_ptr->m_xRotation; + d_ptr->m_yRotation = source.d_ptr->m_yRotation; + + d_ptr->m_minXRotation = source.d_ptr->m_minXRotation; + d_ptr->m_minYRotation = source.d_ptr->m_minYRotation; + d_ptr->m_maxXRotation = source.d_ptr->m_maxXRotation; + d_ptr->m_maxYRotation = source.d_ptr->m_maxYRotation; + + d_ptr->m_wrapXRotation = source.d_ptr->m_wrapXRotation; + d_ptr->m_wrapYRotation = source.d_ptr->m_wrapYRotation; + + d_ptr->m_zoomLevel = source.d_ptr->m_zoomLevel; + d_ptr->m_activePreset = source.d_ptr->m_activePreset; +} + +/*! + * \property Q3DCamera::xRotation + * + * This property contains the X-rotation angle of the camera around the target point in degrees starting from + * the current base position set by the setBaseOrientation() methods. + */ +qreal Q3DCamera::xRotation() const { + return d_ptr->m_xRotation; +} + +void Q3DCamera::setXRotation(qreal rotation) +{ + if (d_ptr->m_wrapXRotation) + rotation = Utils::wrapValue(rotation, d_ptr->m_minXRotation, d_ptr->m_maxXRotation); + else + rotation = qBound(qreal(d_ptr->m_minXRotation), qreal(rotation), qreal(d_ptr->m_maxXRotation)); + + if (d_ptr->m_xRotation != rotation) { + d_ptr->setXRotation(rotation); + if (d_ptr->m_activePreset != QDataVis::CameraPresetNone) { + d_ptr->m_activePreset = QDataVis::CameraPresetNone; + setDirty(true); + } + + emit xRotationChanged(d_ptr->m_xRotation); + } +} + +/*! + * \property Q3DCamera::yRotation + * + * This property contains the Y-rotation angle of the camera around the target point in degrees starting from + * the current base position set by the setBaseOrientation() methods. + */ +qreal Q3DCamera::yRotation() const { + return d_ptr->m_yRotation; +} + +void Q3DCamera::setYRotation(qreal rotation) +{ + if (d_ptr->m_wrapYRotation) + rotation = Utils::wrapValue(rotation, d_ptr->m_minYRotation, d_ptr->m_maxYRotation); + else + rotation = qBound(qreal(d_ptr->m_minYRotation), qreal(rotation), qreal(d_ptr->m_maxYRotation)); + + if (d_ptr->m_yRotation != rotation) { + d_ptr->setYRotation(rotation); + if (d_ptr->m_activePreset != QDataVis::CameraPresetNone) { + d_ptr->m_activePreset = QDataVis::CameraPresetNone; + setDirty(true); + } + + emit yRotationChanged(d_ptr->m_yRotation); + } +} + +/*! + * \property Q3DCamera::minXRotation + * + * This property contains the current minimum X-rotation for the camera. + * The full circle range is [-180,180] and the minimum value is limited to -180. + * Also the value can't be higher than maximum, and is adjusted if necessary. + * + * \sa wrapXRotation, maxXRotation + */ +qreal Q3DCamera::minXRotation() const +{ + return d_ptr->m_minXRotation; +} + +/*! + * \internal + */ +void Q3DCamera::setMinXRotation(qreal minRotation) +{ + minRotation = qBound(-180.0, minRotation, 180.0); + if (minRotation > d_ptr->m_maxXRotation) + minRotation = d_ptr->m_maxXRotation; + + if (d_ptr->m_minXRotation != minRotation) { + d_ptr->m_minXRotation = minRotation; + emit minXRotationChanged(minRotation); + + if (d_ptr->m_xRotation < d_ptr->m_minXRotation) + setXRotation(d_ptr->m_xRotation); + } +} + +/*! + * \property Q3DCamera::minYRotation + * + * This property contains the current minimum Y-rotation for the camera. + * The full Y angle range is [-90,90] and the minimum value is limited to -90. + * Also the value can't be higher than maximum, and is adjusted if necessary. + * + * \sa wrapYRotation, maxYRotation + */ +qreal Q3DCamera::minYRotation() const +{ + return d_ptr->m_minYRotation; +} + +/*! + * \internal + */ +void Q3DCamera::setMinYRotation(qreal minRotation) +{ + minRotation = qBound(-90.0, minRotation, 90.0); + if (minRotation > d_ptr->m_maxYRotation) + minRotation = d_ptr->m_maxYRotation; + + if (d_ptr->m_minYRotation != minRotation) { + d_ptr->m_minYRotation = minRotation; + emit minYRotationChanged(minRotation); + + if (d_ptr->m_yRotation < d_ptr->m_minYRotation) + setYRotation(d_ptr->m_yRotation); + } +} + +/*! + * \property Q3DCamera::maxXRotation + * + * This property contains the current maximum X-rotation for the camera. + * The full circle range is [-180,180] and the maximum value is limited to 180. + * Also the value can't be lower than minimum, and is adjusted if necessary. + * + * \sa wrapXRotation, minXRotation + */ +qreal Q3DCamera::maxXRotation() const +{ + return d_ptr->m_maxXRotation; +} + +/*! + * \internal + */ +void Q3DCamera::setMaxXRotation(qreal maxRotation) +{ + maxRotation = qBound(-180.0, maxRotation, 180.0); + + if (maxRotation < d_ptr->m_minXRotation) + maxRotation = d_ptr->m_minXRotation; + + if (d_ptr->m_maxXRotation != maxRotation) { + d_ptr->m_maxXRotation = maxRotation; + emit maxXRotationChanged(maxRotation); + + if (d_ptr->m_xRotation > d_ptr->m_maxXRotation) + setXRotation(d_ptr->m_xRotation); + } +} + +/*! + * \property Q3DCamera::maxYRotation + * + * This property contains the current maximum Y-rotation for the camera. + * The full Y angle range is [-90,90] and the maximum value is limited to 90. + * Also the value can't be lower than minimum, and is adjusted if necessary. + * + * \sa wrapYRotation, minYRotation + */ +qreal Q3DCamera::maxYRotation() const +{ + return d_ptr->m_maxYRotation; +} + +/*! + * \internal + */ +void Q3DCamera::setMaxYRotation(qreal maxRotation) +{ + maxRotation = qBound(-90.0, maxRotation, 90.0); + + if (maxRotation < d_ptr->m_minYRotation) + maxRotation = d_ptr->m_minYRotation; + + if (d_ptr->m_maxYRotation != maxRotation) { + d_ptr->m_maxYRotation = maxRotation; + emit maxYRotationChanged(maxRotation); + + if (d_ptr->m_yRotation > d_ptr->m_maxYRotation) + setYRotation(d_ptr->m_yRotation); + } +} + +/*! + * Sets the base values for the camera that are used when calculating the camera position using the rotation values. + * The base position of the camera is defined by \a basePosition, expectation is that the x and y values are 0. + * Look at target point is defined by \a target and the camera rotates around it. Up direction for the camera is + * defined by \a baseUp, normally this is a vector with only y values set to 1. + */ +void Q3DCamera::setBaseOrientation(const QVector3D &basePosition, + const QVector3D &target, + const QVector3D &baseUp) +{ + if (position() != basePosition + || d_ptr->m_target != target + || d_ptr->m_up != baseUp) { + setPosition(basePosition); + d_ptr->m_target = target; + d_ptr->m_up = baseUp; + setDirty(true); + } +} + +/*! + * \property Q3DCamera::viewMatrix + * + * This property contains the view matrix used in the 3D calculations. When the default orbiting camera behavior is sufficient + * there is no need to touch this property. But if the default behavior is insufficient the view matrix can be set directly. + * When setting the view matrix directly remember to set Q3DCamera::viewMatrixAutoUpdateEnabled to false. + */ +QMatrix4x4 Q3DCamera::viewMatrix() const +{ + return d_ptr->m_viewMatrix; +} + +void Q3DCamera::setViewMatrix(const QMatrix4x4 &viewMatrix) +{ + if (d_ptr->m_viewMatrix != viewMatrix) { + d_ptr->m_viewMatrix = viewMatrix; + setDirty(true); + emit viewMatrixChanged(d_ptr->m_viewMatrix); + } +} + +/*! + * \property Q3DCamera::viewMatrixAutoUpdateEnabled + * + * This property determines if view matrix is automatically updated each render cycle using the current base orientation and + * rotations. If set to false, no automatic recalculation is done and the view matrix can be set using the + * Q3DMatrix::viewMatrix property. + */ +bool Q3DCamera::isViewMatrixAutoUpdateEnabled() +{ + return d_ptr->m_isViewMatrixUpdateActive; +} + +void Q3DCamera::setViewMatrixAutoUpdateEnabled(bool isEnabled) +{ + d_ptr->m_isViewMatrixUpdateActive = isEnabled; + emit viewMatrixAutoUpdateChanged(isEnabled); +} + +/*! + * \property Q3DCamera::cameraPreset + * + * This property contains the currently active camera preset, + * if no preset is active the value is QDataVis::CameraPresetNone. + * \note The base camera orientation set by setBaseOrientation() will affect + * the presets as all calculations are based on those values. + */ +QDataVis::CameraPreset Q3DCamera::cameraPreset() +{ + return d_ptr->m_activePreset; +} + +void Q3DCamera::setCameraPreset(QDataVis::CameraPreset preset) +{ + switch (preset) { + case QDataVis::CameraPresetFrontLow: { + setXRotation(0.0); + setYRotation(0.0); + break; + } + case QDataVis::CameraPresetFront: { + setXRotation(0.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetFrontHigh: { + setXRotation(0.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetLeftLow: { + setXRotation(90.0); + setYRotation(0.0); + break; + } + case QDataVis::CameraPresetLeft: { + setXRotation(90.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetLeftHigh: { + setXRotation(90.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetRightLow: { + setXRotation(-90.0); + setYRotation(0.0); + break; + } + case QDataVis::CameraPresetRight: { + setXRotation(-90.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetRightHigh: { + setXRotation(-90.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetBehindLow: { + setXRotation(180.0); + setYRotation(0.0); + break; + } + case QDataVis::CameraPresetBehind: { + setXRotation(180.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetBehindHigh: { + setXRotation(180.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetIsometricLeft: { + setXRotation(45.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetIsometricLeftHigh: { + setXRotation(45.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetIsometricRight: { + setXRotation(-45.0); + setYRotation(22.5); + break; + } + case QDataVis::CameraPresetIsometricRightHigh: { + setXRotation(-45.0); + setYRotation(45.0); + break; + } + case QDataVis::CameraPresetDirectlyAbove: { + setXRotation(0.0); + setYRotation(90.0); + break; + } + case QDataVis::CameraPresetDirectlyAboveCW45: { + setXRotation(-45.0); + setYRotation(90.0); + break; + } + case QDataVis::CameraPresetDirectlyAboveCCW45: { + setXRotation(45.0); + setYRotation(90.0); + break; + } + case QDataVis::CameraPresetFrontBelow: { + setXRotation(0.0); + setYRotation(-45.0); + break; + } + case QDataVis::CameraPresetLeftBelow: { + setXRotation(90.0); + setYRotation(-45.0); + break; + } + case QDataVis::CameraPresetRightBelow: { + setXRotation(-90.0); + setYRotation(-45.0); + break; + } + case QDataVis::CameraPresetBehindBelow: { + setXRotation(180.0); + setYRotation(-45.0); + break; + } + case QDataVis::CameraPresetDirectlyBelow: { + setXRotation(0.0); + setYRotation(-90.0); + break; + } + default: + preset = QDataVis::CameraPresetNone; + break; + } + + if (d_ptr->m_activePreset != preset) { + d_ptr->m_activePreset = preset; + setDirty(true); + emit cameraPresetChanged(preset); + } +} + +/*! + * \property Q3DCamera::zoomLevel + * + * This property contains the the camera zoom level in percentages. + * 100% means there is no zoom in or out set in the camera. + */ +int Q3DCamera::zoomLevel() +{ + return d_ptr->m_zoomLevel; +} + +void Q3DCamera::setZoomLevel(int zoomLevel) +{ + if (d_ptr->m_zoomLevel != zoomLevel) { + d_ptr->m_zoomLevel = zoomLevel; + setDirty(true); + emit zoomLevelChanged(zoomLevel); + } +} + +/*! + * Calculates and returns a position relative to the camera using the given parameters + * and the current camera viewMatrix property. + * \a relativePosition defines the relative 3D offset to the current camera position. + * \a fixedRotation is optional, if given fixes rotation of the calculated point around the data visualization area to the given value in degrees. + * \a distanceModifier is also optional, if given modifies the distance of the calculated point from the data visualization. + * \return Calculated position relative to this camera's position. + */ +QVector3D Q3DCamera::calculatePositionRelativeToCamera(const QVector3D &relativePosition, + qreal fixedRotation, + qreal distanceModifier) const +{ + // Move the position with camera + GLfloat radiusFactor = relativePosition.z() * (1.5f + distanceModifier); + GLfloat xAngle; + GLfloat yAngle; + if (!fixedRotation) { + xAngle = qDegreesToRadians(d_ptr->m_xRotation); + yAngle = qDegreesToRadians(d_ptr->m_yRotation); + } else { + xAngle = qDegreesToRadians(fixedRotation); + yAngle = 0; + } + GLfloat radius = (radiusFactor + relativePosition.y()); // set radius to match the highest height of the position + GLfloat zPos = radius * qCos(xAngle) * qCos(yAngle); + GLfloat xPos = radius * qSin(xAngle) * qCos(yAngle); + GLfloat yPos = (radiusFactor + relativePosition.y()) * qSin(yAngle); + // Keep in the set position in relation to camera + return QVector3D(-xPos + relativePosition.x(), + yPos + relativePosition.y(), + zPos + relativePosition.z()); +} + +/*! + * \property Q3DCamera::wrapXRotation + * + * This property determines the behavior of the minimum and maximum limits in the X-rotation. + * By default the X-rotation wraps from minimum value to maximum and from maximum to minimum. + * + * If set to true the X-rotation of the camera is wrapped from minimum to maximum and from maximum to minimum. + * If set to false the X-rotation of the camera is limited to the sector determined by minimum and maximum values. + */ +bool Q3DCamera::wrapXRotation() const +{ + return d_ptr->m_wrapXRotation; +} + +void Q3DCamera::setWrapXRotation(bool isEnabled) +{ + d_ptr->m_wrapXRotation = isEnabled; +} + +/*! + * \property Q3DCamera::wrapYRotation + * + * This property determines the behavior of the minimum and maximum limits in the Y-rotation. + * By default the Y-rotation is limited between the minimum and maximum values without any wrapping. + * + * If true the Y-rotation of the camera is wrapped from minimum to maximum and from maximum to minimum. + * If false the Y-rotation of the camera is limited to the sector determined by minimum and maximum values. + */ +bool Q3DCamera::wrapYRotation() const +{ + return d_ptr->m_wrapYRotation; +} + +void Q3DCamera::setWrapYRotation(bool isEnabled) +{ + d_ptr->m_wrapYRotation = isEnabled; +} + +/*! + * Utility function that sets the camera rotations and distance.\a horizontal and \a vertical define the camera rotations to be used. + * Optional \a zoom parameter can be given to set the zoom of the camera in range of 10-500%. + */ +void Q3DCamera::setCameraPosition(qreal horizontal, qreal vertical, qreal zoom) +{ + setZoomLevel(qBound(10.0, zoom, 500.0)); + setXRotation(horizontal); + setYRotation(vertical); +} + +Q3DCameraPrivate::Q3DCameraPrivate(Q3DCamera *q) : + q_ptr(q), + m_isViewMatrixUpdateActive(true), + m_xRotation(0.0), + m_yRotation(0.0), + m_minXRotation(-180.0), + m_minYRotation(0.0), + m_maxXRotation(180.0), + m_maxYRotation(90.0), + m_wrapXRotation(true), + m_wrapYRotation(false), + m_zoomLevel(100), + m_activePreset(QDataVis::CameraPresetNone) +{ +} + +Q3DCameraPrivate::~Q3DCameraPrivate() +{ +} + +// Copies changed values from this camera to the other camera. If the other camera had same changes, +// those changes are discarded. +void Q3DCameraPrivate::sync(Q3DCamera &other) +{ + if (q_ptr->isDirty()) { + other.copyValuesFrom(*q_ptr); + q_ptr->setDirty(false); + other.setDirty(false); + } +} + +void Q3DCameraPrivate::setXRotation(const qreal rotation) +{ + if (m_xRotation != rotation) { + m_xRotation = rotation; + q_ptr->setDirty(true); + } +} + +void Q3DCameraPrivate::setYRotation(const qreal rotation) +{ + if (m_yRotation != rotation) { + m_yRotation = rotation; + q_ptr->setDirty(true); + } +} + +void Q3DCameraPrivate::setMinXRotation(const qreal rotation) +{ + if (m_minXRotation != rotation) { + m_minXRotation = rotation; + q_ptr->setDirty(true); + } +} + +void Q3DCameraPrivate::setMinYRotation(const qreal rotation) +{ + if (m_minYRotation != rotation) { + m_minYRotation = rotation; + q_ptr->setDirty(true); + } +} + +void Q3DCameraPrivate::setMaxXRotation(const qreal rotation) +{ + if (m_maxXRotation != rotation) { + m_maxXRotation = rotation; + q_ptr->setDirty(true); + } +} + +void Q3DCameraPrivate::setMaxYRotation(const qreal rotation) +{ + if (m_maxYRotation != rotation) { + m_maxYRotation = rotation; + q_ptr->setDirty(true); + } +} + +// Recalculates the view matrix based on the currently set base orientation, rotation and zoom level values. +// zoomAdjustment is adjustment to ensure that the 3D visualization stays inside the view area in the 100% zoom. +void Q3DCameraPrivate::updateViewMatrix(qreal zoomAdjustment) +{ + if (!m_isViewMatrixUpdateActive) + return; + + int zoom = m_zoomLevel * zoomAdjustment; + QMatrix4x4 viewMatrix; + + // Apply to view matrix + viewMatrix.lookAt(q_ptr->position(), m_target, m_up); + // Compensate for translation (if d_ptr->m_target is off origin) + viewMatrix.translate(m_target.x(), m_target.y(), m_target.z()); + // Apply rotations + // Handle x and z rotation when y -angle is other than 0 + viewMatrix.rotate(m_xRotation, 0, qCos(qDegreesToRadians(m_yRotation)), + qSin(qDegreesToRadians(m_yRotation))); + // y rotation is always "clean" + viewMatrix.rotate(m_yRotation, 1.0f, 0.0f, 0.0f); + // handle zoom by scaling + viewMatrix.scale((GLfloat)zoom / 100.0f); + // Compensate for translation (if d_ptr->m_target is off origin) + viewMatrix.translate(-m_target.x(), -m_target.y(), -m_target.z()); + + q_ptr->setViewMatrix(viewMatrix); +} + + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dcamera.h b/src/datavisualization/engine/q3dcamera.h new file mode 100644 index 00000000..ee750cec --- /dev/null +++ b/src/datavisualization/engine/q3dcamera.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DCAMERA_H +#define Q3DCAMERA_H + +#include <QtDataVisualization/q3dobject.h> +#include <QMatrix4x4> + +class QVector3D; +class QPoint; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DCameraPrivate; + +class QT_DATAVISUALIZATION_EXPORT Q3DCamera : public Q3DObject +{ + Q_OBJECT + Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation NOTIFY xRotationChanged) + Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation NOTIFY yRotationChanged) + Q_PROPERTY(qreal minXRotation READ minXRotation NOTIFY minXRotationChanged) + Q_PROPERTY(qreal minYRotation READ minYRotation NOTIFY minYRotationChanged) + Q_PROPERTY(qreal maxXRotation READ maxXRotation NOTIFY maxXRotationChanged) + Q_PROPERTY(qreal maxYRotation READ maxYRotation NOTIFY maxYRotationChanged) + Q_PROPERTY(int zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged) + Q_PROPERTY(QMatrix4x4 viewMatrix READ viewMatrix WRITE setViewMatrix NOTIFY viewMatrixChanged) + Q_PROPERTY(QtDataVisualization::QDataVis::CameraPreset cameraPreset READ cameraPreset WRITE setCameraPreset NOTIFY cameraPresetChanged) + Q_PROPERTY(bool viewMatrixAutoUpdateEnabled READ isViewMatrixAutoUpdateEnabled WRITE setViewMatrixAutoUpdateEnabled NOTIFY viewMatrixAutoUpdateChanged) + Q_PROPERTY(bool wrapXRotation READ wrapXRotation WRITE setWrapXRotation NOTIFY wrapXRotationChanged ) + Q_PROPERTY(bool wrapYRotation READ wrapYRotation WRITE setWrapYRotation NOTIFY wrapYRotationChanged ) + Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) + +public: + Q3DCamera(QObject *parent = 0); + virtual ~Q3DCamera(); + + qreal xRotation() const; + void setXRotation(qreal rotation); + qreal yRotation() const; + void setYRotation(qreal rotation); + + qreal minXRotation() const; + qreal maxXRotation() const; + + qreal minYRotation() const; + qreal maxYRotation() const; + + bool wrapXRotation() const; + void setWrapXRotation(bool isEnabled); + + bool wrapYRotation() const; + void setWrapYRotation(bool isEnabled); + + void copyValuesFrom(const Q3DCamera &source); + + QMatrix4x4 viewMatrix() const; + void setViewMatrix(const QMatrix4x4 &viewMatrix); + + bool isViewMatrixAutoUpdateEnabled(); + void setViewMatrixAutoUpdateEnabled(bool isEnabled); + + QDataVis::CameraPreset cameraPreset(); + void setCameraPreset(QDataVis::CameraPreset preset); + + int zoomLevel(); + void setZoomLevel(int zoomLevel); + + void setBaseOrientation(const QVector3D &defaultPosition, + const QVector3D &defaultTarget, + const QVector3D &defaultUp); + + QVector3D calculatePositionRelativeToCamera(const QVector3D &relativePosition, + qreal fixedRotation, + qreal distanceModifier) const; + void setCameraPosition(qreal horizontal, qreal vertical, qreal distance = 100.0); + +signals: + void xRotationChanged(qreal rotation); + void yRotationChanged(qreal rotation); + void minXRotationChanged(qreal rotation); + void minYRotationChanged(qreal rotation); + void maxXRotationChanged(qreal rotation); + void maxYRotationChanged(qreal rotation); + void zoomLevelChanged(int zoomLevel); + void viewMatrixChanged(QMatrix4x4 viewMatrix); + void cameraPresetChanged(QDataVis::CameraPreset preset); + void viewMatrixAutoUpdateChanged(bool enabled); + void wrapXRotationChanged(bool isEnabled); + void wrapYRotationChanged(bool isEnabled); + +protected: + void setMinXRotation(qreal rotation); + void setMinYRotation(qreal rotation); + void setMaxXRotation(qreal rotation); + void setMaxYRotation(qreal rotation); + +private: + QScopedPointer<Q3DCameraPrivate> d_ptr; + + Q_DISABLE_COPY(Q3DCamera) + + friend class Q3DCameraPrivate; + friend class Q3DScenePrivate; + friend class Bars3DRenderer; + friend class Surface3DRenderer; + friend class Scatter3DRenderer; + friend class SelectionPointer; + friend class Q3DInputHandler; + friend class QTouch3DInputHandlerPrivate; + friend class QMac3DInputHandler; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DCAMERA_H diff --git a/src/datavisualization/engine/q3dcamera_p.h b/src/datavisualization/engine/q3dcamera_p.h new file mode 100644 index 00000000..e0528dcc --- /dev/null +++ b/src/datavisualization/engine/q3dcamera_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DCAMERA_P_H +#define Q3DCAMERA_P_H + +#include "datavisualizationglobal_p.h" +#include "q3dcamera.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DCamera; + +class Q3DCameraPrivate +{ +public: + Q3DCameraPrivate(Q3DCamera *q); + ~Q3DCameraPrivate(); + + void sync(Q3DCamera &other); + + void setXRotation(qreal rotation); + void setYRotation(qreal rotation); + void setMinXRotation(qreal rotation); + void setMinYRotation(qreal rotation); + void setMaxXRotation(qreal rotation); + void setMaxYRotation(qreal rotation); + + void updateViewMatrix(qreal zoomAdjustment); + +public: + Q3DCamera *q_ptr; + + QVector3D m_target; + QVector3D m_up; + + QMatrix4x4 m_viewMatrix; + bool m_isViewMatrixUpdateActive; + + GLfloat m_xRotation; + GLfloat m_yRotation; + GLfloat m_minXRotation; + GLfloat m_minYRotation; + GLfloat m_maxXRotation; + GLfloat m_maxYRotation; + bool m_wrapXRotation; + bool m_wrapYRotation; + int m_zoomLevel; + QDataVis::CameraPreset m_activePreset; + + friend class Bars3DRenderer; + friend class Surface3DRenderer; + friend class Scatter3DRenderer; + friend class SelectionPointer; + friend class Q3DInputHandler; + friend class QTouch3DInputHandler; + friend class QMac3DInputHandler; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DCAMERA_P_H diff --git a/src/datavisualization/engine/q3dlight.cpp b/src/datavisualization/engine/q3dlight.cpp new file mode 100644 index 00000000..c482e62a --- /dev/null +++ b/src/datavisualization/engine/q3dlight.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dlight.h" +#include "q3dscene.h" +#include "q3dlight_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + \class Q3DLight + \inmodule QtDataVisualization + \brief Representation of a light source in 3D space. + \since 1.0.0 + + Q3DLight represents a monochrome non variable light source in 3D space. +*/ + +/*! + * Constructs a new 3D light located at origo. An optional \a parent parameter can be given + * and is then passed to QObject constructor. + */ +Q3DLight::Q3DLight(QObject *parent) : + Q3DObject(parent), + d_ptr(new Q3DLightPrivate(this)) +{ +} + +/*! + * Copies the properties of the 3D light from the given source \a source light to this light instance. + */ +void Q3DLight::copyValuesFrom(const Q3DLight &source) +{ + Q3DObject::copyValuesFrom(source); +} + +/*! + * Destroys the light object. + */ +Q3DLight::~Q3DLight() +{ +} + +Q3DLightPrivate::Q3DLightPrivate(Q3DLight *q) : + q_ptr(q) +{ +} + +Q3DLightPrivate::~Q3DLightPrivate() +{ +} + +void Q3DLightPrivate::sync(Q3DLight &other) +{ + // Copies changed values from this light to the other light. If the other light had same changes, + // those changes are discarded. + if (q_ptr->isDirty()) { + other.copyValuesFrom(*q_ptr); + q_ptr->setDirty(false); + other.setDirty(false); + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dlight.h b/src/datavisualization/engine/q3dlight.h new file mode 100644 index 00000000..0a4ba174 --- /dev/null +++ b/src/datavisualization/engine/q3dlight.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DLIGHT_H +#define Q3DLIGHT_H + +#include <QtDataVisualization/q3dobject.h> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DLightPrivate; +class Q3DScene; + +class QT_DATAVISUALIZATION_EXPORT Q3DLight : public Q3DObject +{ + Q_OBJECT + +public: + Q3DLight(QObject *parent = 0); + virtual ~Q3DLight(); + + void copyValuesFrom(const Q3DLight &source); + +private: + QScopedPointer<Q3DLightPrivate> d_ptr; + + Q_DISABLE_COPY(Q3DLight) + + friend class Q3DLightPrivate; + friend class Q3DScenePrivate; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DLIGHT_H diff --git a/src/datavisualization/engine/q3dlight_p.h b/src/datavisualization/engine/q3dlight_p.h new file mode 100644 index 00000000..dad6d670 --- /dev/null +++ b/src/datavisualization/engine/q3dlight_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DLIGHT_P_H +#define Q3DLIGHT_P_H + +#include "datavisualizationglobal_p.h" +#include "q3dlight.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DScene; +class Q3DLight; + +class Q3DLightPrivate +{ +public: + Q3DLightPrivate(Q3DLight *q); + ~Q3DLightPrivate(); + + void sync(Q3DLight &other); + +public: + Q3DLight *q_ptr; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DLIGHT_P_H + + + + + diff --git a/src/datavisualization/engine/q3dobject.cpp b/src/datavisualization/engine/q3dobject.cpp new file mode 100644 index 00000000..ae13af7d --- /dev/null +++ b/src/datavisualization/engine/q3dobject.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dobject.h" +#include "q3dobject_p.h" +#include "q3dscene.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + \class Q3DObject + \inmodule QtDataVisualization + \brief Simple baseclass for all the objects in the 3D scene. + \since 1.0.0 + + Q3DObject is a baseclass that contains only position information for an object in 3D scene. + The object is considered to be a single point in the coordinate space without dimensions. +*/ + +/*! + * Constructs a new 3D object with position set to origo by default. An + * optional \a parent parameter can be given and is then passed to QObject constructor. + */ +Q3DObject::Q3DObject(QObject *parent) : + QObject(parent), + d_ptr(new Q3DObjectPrivate(this)) +{ +} + +/*! + * Destroys the 3D object. + */ +Q3DObject::~Q3DObject() +{ +} + +/*! + * Copies the 3D object position from the given \a source 3D object to this 3D object instance. + */ +void Q3DObject::copyValuesFrom(const Q3DObject &source) +{ + d_ptr->m_position.setX(source.d_ptr->m_position.x()); + d_ptr->m_position.setY(source.d_ptr->m_position.y()); + d_ptr->m_position.setZ(source.d_ptr->m_position.z()); + setDirty(true); +} + +/*! + * \property Q3DObject::parentScene + * + * This property contains the parent scene as read only value. + * If the object has no parent scene the value is 0. + */ +Q3DScene *Q3DObject::parentScene() +{ + return qobject_cast<Q3DScene *>(parent()); +} + +/*! + * \property Q3DObject::position + * + * This property contains the 3D position of the object. + */ +QVector3D Q3DObject::position() const +{ + return d_ptr->m_position; +} + +void Q3DObject::setPosition(const QVector3D &position) +{ + if (d_ptr->m_position != position) { + d_ptr->m_position = position; + setDirty(true); + emit positionChanged(d_ptr->m_position); + } +} + +/*! + * Sets and clears the \a dirty flag that is used to track + * when the 3D object has changed since last update. + */ +void Q3DObject::setDirty(bool dirty) +{ + d_ptr->m_isDirty = dirty; +} + +/*! + * \return flag that indicates if the 3D object has changed. + */ +bool Q3DObject::isDirty() const +{ + return d_ptr->m_isDirty; +} + +Q3DObjectPrivate::Q3DObjectPrivate(Q3DObject *q) : + q_ptr(q), + m_isDirty(true) +{ +} + +Q3DObjectPrivate::~Q3DObjectPrivate() +{ + +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dobject.h b/src/datavisualization/engine/q3dobject.h new file mode 100644 index 00000000..930bb022 --- /dev/null +++ b/src/datavisualization/engine/q3dobject.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DOBJECT_H +#define Q3DOBJECT_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QtDataVisualization/q3dscene.h> + +#include <QObject> +#include <QVector3D> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE +class Q3DObjectPrivate; + +class Q3DObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(Q3DScene* parentScene READ parentScene) + Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) + +public: + Q3DObject(QObject *parent = 0); + virtual ~Q3DObject(); + + void copyValuesFrom(const Q3DObject &source); + + Q3DScene *parentScene(); + + QVector3D position() const; + void setPosition(const QVector3D &position); + +signals: + void positionChanged(QVector3D position); + +protected: + void setDirty(bool dirty); + bool isDirty() const; + +private: + QScopedPointer<Q3DObjectPrivate> d_ptr; + + Q_DISABLE_COPY(Q3DObject) + + friend class Q3DScenePrivate; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DOBJECT_H diff --git a/src/datavisualization/engine/q3dobject_p.h b/src/datavisualization/engine/q3dobject_p.h new file mode 100644 index 00000000..bac18cfe --- /dev/null +++ b/src/datavisualization/engine/q3dobject_p.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DOBJECT_P_H +#define Q3DOBJECT_P_H + +#include "datavisualizationglobal_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DObject; +class Q3DScene; + +class Q3DObjectPrivate +{ +public: + Q3DObjectPrivate(Q3DObject *q); + ~Q3DObjectPrivate(); + +public: + Q3DObject *q_ptr; + QVector3D m_position; + bool m_isDirty; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DOBJECT_P_H diff --git a/src/datavisualization/engine/q3dscatter.cpp b/src/datavisualization/engine/q3dscatter.cpp new file mode 100644 index 00000000..a5053bf3 --- /dev/null +++ b/src/datavisualization/engine/q3dscatter.cpp @@ -0,0 +1,568 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dscatter.h" +#include "q3dscatter_p.h" +#include "scatter3dcontroller_p.h" +#include "q3dvalueaxis.h" +#include "qscatterdataproxy.h" +#include "q3dcamera.h" + +#include <QMouseEvent> +#include <QDebug> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + * \class Q3DScatter + * \inmodule QtDataVisualization + * \brief The Q3DScatter class provides methods for rendering 3D scatter graphs. + * \since 1.0.0 + * + * This class enables developers to render scatter graphs in 3D and to view them by rotating the scene + * freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming + * is done by mouse wheel. Selection, if enabled, is done by left mouse button. The scene can be + * reset to default camera view by clicking mouse wheel. In touch devices rotation is done + * by tap-and-move, selection by tap-and-hold and zoom by pinch. + * + * If no axes are explicitly set to Q3DScatter, temporary default axes with no labels are created. + * These default axes can be modified via axis accessors, but as soon any axis is explicitly + * set for the orientation, the default axis for that orientation is destroyed. + * + * Data proxies work similarly: If no data proxy is explicitly set, Q3DScatter creates a default + * proxy. If any other proxy is set as active data proxy later, the default proxy and all data + * added to it is destroyed. + * + * Methods are provided for changing item styles, themes, item selection modes and so on. See the + * methods for more detailed descriptions. + * + * \section1 How to construct a minimal Q3DScatter graph + * + * First, construct Q3DScatter: + * + * \snippet doc_src_q3dscatter_construction.cpp 0 + * + * Now Q3DScatter is ready to receive data to be rendered. Add one set of 3 QVector3D items: + * + * \snippet doc_src_q3dscatter_construction.cpp 1 + * + * Finally you will need to set it visible: + * + * \snippet doc_src_q3dscatter_construction.cpp 2 + * + * The complete code needed to create and display this graph is: + * + * \snippet doc_src_q3dscatter_construction.cpp 3 + * + * And this is what those few lines of code produce: + * + * \image q3dscatter-minimal.png + * + * The scene can be rotated and zoomed into, but no other interaction is included in this minimal + * code example. You can learn more by familiarizing yourself with the examples provided, like + * the \l{Scatter Example}. + * + * \sa Q3DBars, Q3DSurface, {Qt Data Visualization C++ Classes} + */ + +/*! + * Constructs a new 3D scatter window. + */ +Q3DScatter::Q3DScatter() + : d_ptr(new Q3DScatterPrivate(this, geometry())) +{ + setVisualController(d_ptr->m_shared); + d_ptr->m_shared->initializeOpenGL(); + QObject::connect(d_ptr->m_shared, &Scatter3DController::selectedItemIndexChanged, this, + &Q3DScatter::selectedItemIndexChanged); + QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this, + &Q3DWindow::renderLater); +} + +/*! + * Destroys the 3D scatter window. + */ +Q3DScatter::~Q3DScatter() +{ +} + +/*! + * \internal + */ +void Q3DScatter::mouseDoubleClickEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseDoubleClickEvent(event); +} + +/*! + * \internal + */ +void Q3DScatter::touchEvent(QTouchEvent *event) +{ + d_ptr->m_shared->touchEvent(event); +} + +/*! + * \internal + */ +void Q3DScatter::mousePressEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mousePressEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DScatter::mouseReleaseEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseReleaseEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DScatter::mouseMoveEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseMoveEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DScatter::wheelEvent(QWheelEvent *event) +{ + d_ptr->m_shared->wheelEvent(event); +} + +/*! + * \internal + */ +void Q3DScatter::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + d_ptr->m_shared->setSize(width(), height()); +} + +/*! + * Sets window \a width. + */ +void Q3DScatter::setWidth(const int width) +{ + d_ptr->m_shared->setWidth(width); + QWindow::setWidth(width); +} + +/*! + * Sets window \a height. + */ +void Q3DScatter::setHeight(const int height) +{ + d_ptr->m_shared->setHeight(height); + QWindow::setHeight(height); +} + +/*! + * Sets the item \a style to one of the values in \c QDataVis::MeshStyle. It is preset to + * \c QDataVis::MeshStyleSpheres by default. A \a smooth flag can be used to set shading to smooth. + * It is \c false by default. + * + * \sa setMeshFileName() + */ +void Q3DScatter::setObjectType(QDataVis::MeshStyle style, bool smooth) +{ + d_ptr->m_shared->setObjectType(style, smooth); +} + +/*! + * Sets a predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by + * default. Theme affects bar colors, label colors, text color, background color, window color and + * grid color. Lighting is also adjusted by themes. + * + * \sa setObjectColor() + * + * \warning This method is subject to change. + */ +void Q3DScatter::setTheme(QDataVis::Theme theme) +{ + d_ptr->m_shared->setTheme(theme); +} + +/*! + * Set item color using your own colors. \a baseColor sets the base color of a item. The \a uniform + * -flag is used to define if color needs to be uniform throughout item's length, or will the colors + * be applied by height. It is \c true by default. + * + * Calling this method overrides colors from theme. + * + * \sa setTheme() + * + * \warning This method is subject to change. + */ +void Q3DScatter::setObjectColor(const QColor &baseColor, bool uniform) +{ + d_ptr->m_shared->setObjectColor(baseColor, uniform); +} + +/*! + * \return item color in use. + */ +QColor Q3DScatter::objectColor() const +{ + return d_ptr->m_shared->objectColor(); +} + +/*! + * \property Q3DScatter::selectionMode + * + * Sets item selection \a mode to one of \c QDataVis::SelectionMode. It is preset to + * \c QDataVis::SelectionModeItem by default. + */ +void Q3DScatter::setSelectionMode(QDataVis::SelectionMode mode) +{ + d_ptr->m_shared->setSelectionMode(mode); +} + +QDataVis::SelectionMode Q3DScatter::selectionMode() const +{ + return d_ptr->m_shared->selectionMode(); +} + +/*! + * \property Q3DScatter::meshFileName + * + * Override item type with a mesh object located in \a objFileName. + * \note Object needs to be in Wavefront obj format and include vertices, normals and UVs. + * It also needs to be in triangles. + * + * \sa setObjectType() + */ +void Q3DScatter::setMeshFileName(const QString &objFileName) +{ + d_ptr->m_shared->setMeshFileName(objFileName); +} + +QString Q3DScatter::meshFileName() const +{ + return d_ptr->m_shared->meshFileName(); +} + +/*! + * \property Q3DScatter::font + * + * Sets the \a font for labels. It is preset to \c Arial by default. + */ +void Q3DScatter::setFont(const QFont &font) +{ + d_ptr->m_shared->setFont(font); +} + +QFont Q3DScatter::font() const +{ + return d_ptr->m_shared->font(); +} + +/*! + * \property Q3DScatter::scene + * + * This property contains the read only Q3DScene that can be used to access e.g. camera object. + */ +Q3DScene *Q3DScatter::scene() const +{ + return d_ptr->m_shared->scene(); +} + +/*! + * \property Q3DScatter::labelStyle + * + * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to + * \c QDataVis::LabelStyleFromTheme by default. + */ +void Q3DScatter::setLabelStyle(QDataVis::LabelStyle style) +{ + d_ptr->m_shared->setLabelStyle(style); +} + +QDataVis::LabelStyle Q3DScatter::labelStyle() const +{ + return d_ptr->m_shared->labelStyle(); +} + +/*! + * \property Q3DScatter::gridVisible + * + * Sets grid visibility to \a visible. It is preset to \c true by default. + */ +void Q3DScatter::setGridVisible(bool visible) +{ + d_ptr->m_shared->setGridEnabled(visible); +} + +bool Q3DScatter::isGridVisible() const +{ + return d_ptr->m_shared->gridEnabled(); +} + +/*! + * \property Q3DScatter::backgroundVisible + * + * Sets background visibility to \a visible. It is preset to \c true by default. + */ +void Q3DScatter::setBackgroundVisible(bool visible) +{ + d_ptr->m_shared->setBackgroundEnabled(visible); +} + +bool Q3DScatter::isBackgroundVisible() const +{ + return d_ptr->m_shared->backgroundEnabled(); +} + +/*! + * \property Q3DScatter::selectedItemIndex + * + * Selects an item in the \a index. Only one item can be selected at a time. + * To clear selection, specify an illegal \a index, e.g. -1. + */ +void Q3DScatter::setSelectedItemIndex(int index) +{ + d_ptr->m_shared->setSelectedItemIndex(index); +} + +int Q3DScatter::selectedItemIndex() const +{ + return d_ptr->m_shared->selectedItemIndex(); +} + +/*! + * \property Q3DScatter::shadowQuality + * + * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to + * \c QDataVis::ShadowQualityMedium by default. + * + * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered + * until it is successful and shadowQualityChanged signal is emitted for each time the change is + * done. + */ +void Q3DScatter::setShadowQuality(QDataVis::ShadowQuality quality) +{ + return d_ptr->m_shared->setShadowQuality(quality); +} + +QDataVis::ShadowQuality Q3DScatter::shadowQuality() const +{ + return d_ptr->m_shared->shadowQuality(); +} + +/*! + * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DScatter::setAxisX(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisX(axis); +} + +/*! + * \return used X-axis. + */ +Q3DValueAxis *Q3DScatter::axisX() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisX()); +} + +/*! + * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DScatter::setAxisY(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisY(axis); +} + +/*! + * \return used Y-axis. + */ +Q3DValueAxis *Q3DScatter::axisY() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY()); +} + +/*! + * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DScatter::setAxisZ(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisZ(axis); +} + +/*! + * \return used Z-axis. + */ +Q3DValueAxis *Q3DScatter::axisZ() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisZ()); +} + +/*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DScatter::addAxis(Q3DValueAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * If the released \a axis is in use, a new default axis will be created and set active. + * + * If the default axis is released and added back later, it behaves as any other axis would. + * + * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DScatter::releaseAxis(Q3DValueAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<Q3DValueAxis *> Q3DScatter::axes() const +{ + QList<Q3DAbstractAxis *> abstractAxes = d_ptr->m_shared->axes(); + QList<Q3DValueAxis *> retList; + foreach (Q3DAbstractAxis *axis, abstractAxes) + retList.append(static_cast<Q3DValueAxis *>(axis)); + + return retList; +} + +/*! + * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of + * the \a proxy to this graph. + * + * If the \a proxy is null, a temporary default proxy is created and activated. + * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method. + * + * \sa addDataProxy(), releaseDataProxy() + */ +void Q3DScatter::setActiveDataProxy(QScatterDataProxy *proxy) +{ + d_ptr->m_shared->setActiveDataProxy(proxy); +} + +/*! + * \return active data proxy. + */ +QScatterDataProxy *Q3DScatter::activeDataProxy() const +{ + return static_cast<QScatterDataProxy *>(d_ptr->m_shared->activeDataProxy()); +} + +/*! + * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use, + * addDataProxy is simply used to give the ownership of the data \a proxy to the graph. + * The \a proxy must not be null or added to another graph. + * + * \sa releaseDataProxy(), setActiveDataProxy() + */ +void Q3DScatter::addDataProxy(QScatterDataProxy *proxy) +{ + d_ptr->m_shared->addDataProxy(proxy); +} + +/*! + * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph. + * If the released \a proxy is in use, a new empty default proxy is created and taken to use. + * + * If the default \a proxy is released and added back later, it behaves as any other proxy would. + * + * \sa addDataProxy(), setActiveDataProxy() + */ +void Q3DScatter::releaseDataProxy(QScatterDataProxy *proxy) +{ + d_ptr->m_shared->releaseDataProxy(proxy); +} + +/*! + * \return list of all added data proxies. + * + * \sa addDataProxy() + */ +QList<QScatterDataProxy *> Q3DScatter::dataProxies() const +{ + QList<QScatterDataProxy *> retList; + QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies(); + foreach (QAbstractDataProxy *proxy, abstractList) + retList.append(static_cast<QScatterDataProxy *>(proxy)); + + return retList; +} + +/*! + * \fn void Q3DScatter::shadowQualityChanged(QDataVis::ShadowQuality quality) + * + * This signal is emitted when shadow \a quality changes. + */ + +Q3DScatterPrivate::Q3DScatterPrivate(Q3DScatter *q, QRect rect) + : q_ptr(q), + m_shared(new Scatter3DController(rect)) +{ + QObject::connect(m_shared, &Abstract3DController::shadowQualityChanged, this, + &Q3DScatterPrivate::handleShadowQualityUpdate); +} + +Q3DScatterPrivate::~Q3DScatterPrivate() +{ + qDebug() << "Destroying Q3DScatterPrivate"; + delete m_shared; +} + +void Q3DScatterPrivate::handleShadowQualityUpdate(QDataVis::ShadowQuality quality) +{ + emit q_ptr->shadowQualityChanged(quality); +} + +QT_DATAVISUALIZATION_END_NAMESPACE + diff --git a/src/datavisualization/engine/q3dscatter.h b/src/datavisualization/engine/q3dscatter.h new file mode 100644 index 00000000..fdea604e --- /dev/null +++ b/src/datavisualization/engine/q3dscatter.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DSCATTER_H +#define Q3DSCATTER_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QtDataVisualization/q3dwindow.h> +#include <QtDataVisualization/q3dscene.h> +#include <QFont> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DScatterPrivate; +class LabelItem; +class Q3DValueAxis; +class Q3DCategoryAxis; +class QScatterDataProxy; + +class QT_DATAVISUALIZATION_EXPORT Q3DScatter : public Q3DWindow +{ + Q_OBJECT + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) + Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) + Q_PROPERTY(QString meshFileName READ meshFileName WRITE setMeshFileName) + Q_PROPERTY(QFont font READ font WRITE setFont) + Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) + Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) + Q_PROPERTY(int selectedItemIndex READ selectedItemIndex WRITE setSelectedItemIndex NOTIFY selectedItemIndexChanged) + Q_PROPERTY(Q3DScene* scene READ scene) + Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) + Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) + Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) + Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) + +public: + explicit Q3DScatter(); + ~Q3DScatter(); + + void setObjectType(QDataVis::MeshStyle style, bool smooth = false); + + void setTheme(QDataVis::Theme theme); + + void setObjectColor(const QColor &baseColor, bool uniform = true); + QColor objectColor() const; + + void setMeshFileName(const QString &objFileName); + QString meshFileName() const; + + void setSelectionMode(QDataVis::SelectionMode mode); + QDataVis::SelectionMode selectionMode() const; + + void setFont(const QFont &font); + QFont font() const; + + Q3DScene *scene() const; + + void setLabelStyle(QDataVis::LabelStyle style); + QDataVis::LabelStyle labelStyle() const; + + void setGridVisible(bool visible); + bool isGridVisible() const; + + void setWidth(const int width); + void setHeight(const int height); + + void setBackgroundVisible(bool visible); + bool isBackgroundVisible() const; + + void setSelectedItemIndex(int index); + int selectedItemIndex() const; + + void setShadowQuality(QDataVis::ShadowQuality quality); + QDataVis::ShadowQuality shadowQuality() const; + + void setAxisX(Q3DValueAxis *axis); + Q3DValueAxis *axisX() const; + void setAxisY(Q3DValueAxis *axis); + Q3DValueAxis *axisY() const; + void setAxisZ(Q3DValueAxis *axis); + Q3DValueAxis *axisZ() const; + void addAxis(Q3DValueAxis *axis); + void releaseAxis(Q3DValueAxis *axis); + QList<Q3DValueAxis *> axes() const; + + void setActiveDataProxy(QScatterDataProxy *proxy); + QScatterDataProxy *activeDataProxy() const; + void addDataProxy(QScatterDataProxy *proxy); + void releaseDataProxy(QScatterDataProxy *proxy); + QList<QScatterDataProxy *> dataProxies() const; + +signals: + void shadowQualityChanged(QDataVis::ShadowQuality quality); + void selectedItemIndexChanged(int index); + +protected: + void mouseDoubleClickEvent(QMouseEvent *event); + void touchEvent(QTouchEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void resizeEvent(QResizeEvent *event); + +private: + QScopedPointer<Q3DScatterPrivate> d_ptr; + Q_DISABLE_COPY(Q3DScatter) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dscatter_p.h b/src/datavisualization/engine/q3dscatter_p.h new file mode 100644 index 00000000..775344d0 --- /dev/null +++ b/src/datavisualization/engine/q3dscatter_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSCATTER_p_H +#define Q3DSCATTER_p_H + +#include "scatter3dcontroller_p.h" +#include "qdatavisualizationenums.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DScatter; + +class Q3DScatterPrivate : public QObject +{ +public: + Q3DScatterPrivate(Q3DScatter *q, QRect rect); + ~Q3DScatterPrivate(); + + // Used to detect when shadow quality changes autonomously due to e.g. resizing. + void handleShadowQualityUpdate(QDataVis::ShadowQuality quality); + + Q3DScatter *q_ptr; + Scatter3DController *m_shared; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dscene.cpp b/src/datavisualization/engine/q3dscene.cpp new file mode 100644 index 00000000..4908bde4 --- /dev/null +++ b/src/datavisualization/engine/q3dscene.cpp @@ -0,0 +1,375 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include <qmath.h> + +#include "datavisualizationglobal_p.h" + +#include "q3dscene.h" +#include "q3dscene_p.h" +#include "q3dcamera_p.h" +#include "q3dlight_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE +/*! + * \class Q3DScene + * \inmodule QtDataVisualization + * \brief Q3DScene class provides description of the 3D scene being visualized. + * \since 1.0.0 + * + * The 3D scene contains a single active camera and a single active light source. + * Visualized data is assumed to be at a fixed location. + * + * The 3D scene also keeps track of the viewport in which visualization rendering is done, + * the primary subviewport inside the viewport where the main 3D data visualization view resides + * and the secondary subviewport where the 2D sliced view of the data resides. + * + * Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not. + * \note Not all visualizations support the secondary 2D slicing view. + */ + +/*! + * Constructs a basic scene with one light and one camera in it. An + * optional \a parent parameter can be given and is then passed to QObject constructor. + */ +Q3DScene::Q3DScene(QObject *parent) : + QObject(parent), + d_ptr(new Q3DScenePrivate(this)) +{ + setActiveCamera(new Q3DCamera(0)); + setActiveLight(new Q3DLight(0)); +} + +/*! + * Destroys the 3D scene and all the objects contained within it. + */ +Q3DScene::~Q3DScene() +{ +} + +/*! + * \property Q3DScene::viewport + * + * This property contains the current viewport rectangle where all 3D rendering + * is targeted. + */ +QRect Q3DScene::viewport() const +{ + return d_ptr->m_viewport; +} + +void Q3DScene::setViewport(const QRect &viewport) +{ + if (d_ptr->m_viewport.width() != viewport.width() + || d_ptr->m_viewport.height() != viewport.height()) { + d_ptr->m_viewport = viewport; + d_ptr->m_viewport.setX(0); + d_ptr->m_viewport.setY(0); + d_ptr->m_changeTracker.viewportChanged = true; + emit viewportChanged(viewport); + } +} + +/*! + * Sets the \a width and \a height of the viewport only, without changing its location. + */ +void Q3DScene::setViewportSize(int width, int height) +{ + if (d_ptr->m_viewport.width() != width + || d_ptr->m_viewport.height() != height) { + d_ptr->m_viewport.setWidth(width); + d_ptr->m_viewport.setHeight(height); + d_ptr->m_changeTracker.viewportChanged = true; + emit viewportChanged(d_ptr->m_viewport); + } +} + +/*! + * \property Q3DScene::primarySubViewport + * + * This property contains the current main viewport rectangle inside the viewport where the + * primary view of the data visualization is targeted to. + */ +QRect Q3DScene::primarySubViewport() const +{ + return d_ptr->m_primarySubViewport; +} + +void Q3DScene::setPrimarySubViewport(const QRect &primarySubViewport) +{ + if (d_ptr->m_primarySubViewport != primarySubViewport) { + d_ptr->m_primarySubViewport = primarySubViewport; + d_ptr->m_changeTracker.primarySubViewportChanged = true; + emit primarySubViewportChanged(primarySubViewport); + } +} + +/*! + * Returns whether the given \a point resides inside the primary subview or not. + * The method takes care of correctly mapping between OpenGL coordinates used in the + * viewport definitions and the Qt event coordinate system used in the input system. + * \return true if the point is inside the primary subview. + */ +bool Q3DScene::isPointInPrimarySubView(const QPoint &point) +{ + // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently. + int x = point.x(); + int y = point.y(); + int areaMinX = d_ptr->m_primarySubViewport.x(); + int areaMaxX = d_ptr->m_primarySubViewport.x() + d_ptr->m_primarySubViewport.width(); + int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_primarySubViewport.y(); + int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_primarySubViewport.y() + d_ptr->m_primarySubViewport.height()); + + return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY ); +} + +/*! + * Returns whether the given \a point resides inside the secondary subview or not. + * The method takes care of correctly mapping between OpenGL coordinates used in the + * viewport definitions and the Qt event coordinate system used in the input system. + * \return true if the point is inside the secondary subview. + */ +bool Q3DScene::isPointInSecondarySubView(const QPoint &point) +{ + // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently. + int x = point.x(); + int y = point.y(); + int areaMinX = d_ptr->m_secondarySubViewport.x(); + int areaMaxX = d_ptr->m_secondarySubViewport.x() + d_ptr->m_secondarySubViewport.width(); + int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_secondarySubViewport.y(); + int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_secondarySubViewport.y() + d_ptr->m_secondarySubViewport.height()); + + return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY ); +} + +/*! + * \property Q3DScene::secondarySubViewport + * + * This property contains the secondary viewport rectangle inside the viewport. The secondary + * viewport is used for drawing the 2D slice view in some visualizations. + */ +QRect Q3DScene::secondarySubViewport() const +{ + return d_ptr->m_secondarySubViewport; +} + +void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport) +{ + if (d_ptr->m_secondarySubViewport != secondarySubViewport) { + d_ptr->m_secondarySubViewport = secondarySubViewport; + d_ptr->m_changeTracker.secondarySubViewportChanged = true; + emit secondarySubViewportChanged(secondarySubViewport); + } +} + +/*! + * \property Q3DScene::slicingActive + * + * This property contains whether 2D slicing view is currently active or not. + * \note Not all visualizations support the 2D slicing view. + */ +bool Q3DScene::isSlicingActive() const +{ + return d_ptr->m_isSlicingActive; +} + +void Q3DScene::setSlicingActive(bool isSlicing) +{ + if (d_ptr->m_isSlicingActive != isSlicing) { + d_ptr->m_isSlicingActive = isSlicing; + d_ptr->m_changeTracker.slicingActivatedChanged = true; + emit slicingActiveChanged(isSlicing); + emitNeedRender(); + } +} + +/*! + * \property Q3DScene::activeCamera + * + * This property contains the currently active camera in the 3D scene. + * When a new Q3DCamera objects is set in the property it gets automatically added as child of the scene. + */ +Q3DCamera *Q3DScene::activeCamera() const +{ + return d_ptr->m_camera; +} + +void Q3DScene::setActiveCamera(Q3DCamera *camera) +{ + Q_ASSERT(camera); + + // Add new camera as child of the scene + if (camera->parent() != this) + camera->setParent(this); + + if (camera != d_ptr->m_camera) { + if (d_ptr->m_camera) { + disconnect(d_ptr->m_camera, &Q3DCamera::xRotationChanged, this, + &Q3DScene::emitNeedRender); + disconnect(d_ptr->m_camera, &Q3DCamera::yRotationChanged, this, + &Q3DScene::emitNeedRender); + } + + d_ptr->m_camera = camera; + d_ptr->m_changeTracker.cameraChanged = true; + + if (camera) { + connect(camera, &Q3DCamera::xRotationChanged, this, + &Q3DScene::emitNeedRender); + connect(camera, &Q3DCamera::yRotationChanged, this, + &Q3DScene::emitNeedRender); + } + + emit activeCameraChanged(camera); + emitNeedRender(); + } +} + +void Q3DScene::emitNeedRender() +{ + emit needRender(); +} + +/*! + * \property Q3DScene::activeLight + * + * This property contains the currently active light in the 3D scene. + * When a new Q3DLight objects is set in the property it gets automatically added as child of the scene. + */ +Q3DLight *Q3DScene::activeLight() const +{ + return d_ptr->m_light; +} + +void Q3DScene::setActiveLight(Q3DLight *light) +{ + Q_ASSERT(light); + + // Add new light as child of the scene + if (light->parent() != this) + light->setParent(this); + + if (light != d_ptr->m_light) { + d_ptr->m_light = light; + d_ptr->m_changeTracker.lightChanged = true; + emit activeLightChanged(light); + } +} + +/*! + * \property Q3DScene::devicePixelRatio + * + * This property contains the current device pixel ratio that is used when mapping input + * coordinates to pixel coordinates. + */ +qreal Q3DScene::devicePixelRatio() const +{ + return d_ptr->m_devicePixelRatio; +} + +void Q3DScene::setDevicePixelRatio(qreal pixelRatio) +{ + if (d_ptr->m_devicePixelRatio != pixelRatio) { + d_ptr->m_devicePixelRatio = pixelRatio; + emit devicePixelRatioChanged(pixelRatio); + } +} + +/*! + * Calculates and sets the light position relative to the currently active camera using the given parameters. + * \a relativePosition defines the relative 3D offset to the current camera position. + * Optional \a fixedRotation fixes the light rotation around the data visualization area to the given value in degrees. + * Optional \a distanceModifier modifies the distance of the light from the data visualization. + */ +void Q3DScene::setLightPositionRelativeToCamera(const QVector3D &relativePosition, + qreal fixedRotation, qreal distanceModifier) +{ + d_ptr->m_light->setPosition( + d_ptr->m_camera->calculatePositionRelativeToCamera(relativePosition, + fixedRotation, + distanceModifier)); +} + +/*! + * \fn Q3DScene::needRender() + * \internal + */ + +Q3DScenePrivate::Q3DScenePrivate(Q3DScene *q) : + q_ptr(q), + m_devicePixelRatio(1.f), + m_camera(), + m_light(), + m_isUnderSideCameraEnabled(false), + m_isSlicingActive(false) +{ +} + +Q3DScenePrivate::~Q3DScenePrivate() +{ + delete m_camera; + delete m_light; +} + +// Copies changed values from this scene to the other scene. If the other scene had same changes, +// those changes are discarded. +void Q3DScenePrivate::sync(Q3DScenePrivate &other) +{ + if (m_changeTracker.viewportChanged) { + other.q_ptr->setViewport(q_ptr->viewport()); + m_changeTracker.viewportChanged = false; + other.m_changeTracker.viewportChanged = false; + } + if (m_changeTracker.primarySubViewportChanged) { + other.q_ptr->setPrimarySubViewport(q_ptr->primarySubViewport()); + m_changeTracker.primarySubViewportChanged = false; + other.m_changeTracker.primarySubViewportChanged = false; + } + if (m_changeTracker.secondarySubViewportChanged) { + other.q_ptr->setSecondarySubViewport(q_ptr->secondarySubViewport()); + m_changeTracker.secondarySubViewportChanged = false; + other.m_changeTracker.secondarySubViewportChanged = false; + } + if (m_changeTracker.cameraChanged) { + m_camera->setDirty(true); + m_changeTracker.cameraChanged = false; + other.m_changeTracker.cameraChanged = false; + } + m_camera->d_ptr->sync(*other.m_camera); + + if (m_changeTracker.lightChanged) { + m_light->setDirty(true); + m_changeTracker.lightChanged = false; + other.m_changeTracker.lightChanged = false; + } + m_light->d_ptr->sync(*other.m_light); + + if (m_changeTracker.slicingActivatedChanged) { + other.q_ptr->setSlicingActive(q_ptr->isSlicingActive()); + m_changeTracker.slicingActivatedChanged = false; + other.m_changeTracker.slicingActivatedChanged = false; + } + + if (m_changeTracker.devicePixelRatioChanged) { + other.q_ptr->setDevicePixelRatio(q_ptr->devicePixelRatio()); + m_changeTracker.devicePixelRatioChanged = false; + other.m_changeTracker.devicePixelRatioChanged = false; + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dscene.h b/src/datavisualization/engine/q3dscene.h new file mode 100644 index 00000000..745cef72 --- /dev/null +++ b/src/datavisualization/engine/q3dscene.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DSCENE_H +#define Q3DSCENE_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QObject> +#include <QRect> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DCamera; +class Q3DBox; +class Q3DLight; +class Q3DScenePrivate; + +class QT_DATAVISUALIZATION_EXPORT Q3DScene : public QObject +{ + Q_OBJECT + Q_PROPERTY(QRect viewport READ viewport WRITE setViewport NOTIFY viewportChanged) + Q_PROPERTY(QRect primarySubViewport READ primarySubViewport WRITE setPrimarySubViewport NOTIFY primarySubViewportChanged) + Q_PROPERTY(QRect secondarySubViewport READ secondarySubViewport WRITE setSecondarySubViewport NOTIFY secondarySubViewportChanged) + Q_PROPERTY(bool slicingActive READ isSlicingActive WRITE setSlicingActive NOTIFY slicingActiveChanged) + Q_PROPERTY(Q3DCamera* activeCamera READ activeCamera WRITE setActiveCamera NOTIFY activeCameraChanged) + Q_PROPERTY(Q3DLight* activeLight READ activeLight WRITE setActiveLight NOTIFY activeLightChanged) + Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged) + +public: + Q3DScene(QObject *parent = 0); + ~Q3DScene(); + + QRect viewport() const; + void setViewport(const QRect &viewport); + void setViewportSize(int width, int height); + + QRect primarySubViewport() const; + void setPrimarySubViewport(const QRect &primarySubViewport); + bool isPointInPrimarySubView(const QPoint &point); + + QRect secondarySubViewport() const; + void setSecondarySubViewport(const QRect &secondarySubViewport); + bool isPointInSecondarySubView(const QPoint &point); + + void setSlicingActive(bool isSlicing); + bool isSlicingActive() const; + + Q3DCamera *activeCamera() const; + void setActiveCamera(Q3DCamera *camera); + + Q3DLight *activeLight() const; + void setActiveLight(Q3DLight *light); + + qreal devicePixelRatio() const; + void setDevicePixelRatio(qreal pixelRatio); + + void setLightPositionRelativeToCamera(const QVector3D &relativePosition, + qreal fixedRotation = 0.0, + qreal distanceModifier = 0.0); +private: + void emitNeedRender(); + +signals: + void viewportChanged(QRect viewport); + void primarySubViewportChanged(QRect subViewport); + void secondarySubViewportChanged(QRect subViewport); + void slicingActiveChanged(bool isSlicingActive); + void activeCameraChanged(const Q3DCamera *camera); + void activeLightChanged(const Q3DLight *light); + void devicePixelRatioChanged(qreal pixelRatio); + void needRender(); + +private: + QScopedPointer<Q3DScenePrivate> d_ptr; + + Q_DISABLE_COPY(Q3DScene) + + friend class Q3DScenePrivate; + friend class Abstract3DRenderer; + friend class Bars3DRenderer; + friend class Surface3DRenderer; + friend class Scatter3DRenderer; + friend class Q3DCameraPrivate; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DSCENE_H diff --git a/src/datavisualization/engine/q3dscene_p.h b/src/datavisualization/engine/q3dscene_p.h new file mode 100644 index 00000000..b28baaae --- /dev/null +++ b/src/datavisualization/engine/q3dscene_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSCENE_P_H +#define Q3DSCENE_P_H + +#include "datavisualizationglobal_p.h" +#include <QRect> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DCamera; +class Q3DLight; +class Q3DScene; + +struct Q3DSceneChangeBitField { + bool viewportChanged : 1; + bool primarySubViewportChanged : 1; + bool secondarySubViewportChanged : 1; + bool cameraChanged : 1; + bool lightChanged : 1; + bool slicingActivatedChanged : 1; + bool devicePixelRatioChanged : 1; + + Q3DSceneChangeBitField() + : viewportChanged(true), + primarySubViewportChanged(true), + secondarySubViewportChanged(true), + cameraChanged(true), + lightChanged(true), + slicingActivatedChanged(true), + devicePixelRatioChanged(true) + { + } +}; + +class Q3DScenePrivate +{ +public: + Q3DScenePrivate(Q3DScene *q); + ~Q3DScenePrivate(); + + void sync(Q3DScenePrivate &other); + + Q3DScene *q_ptr; + Q3DSceneChangeBitField m_changeTracker; + + QRect m_viewport; + QRect m_primarySubViewport; + QRect m_secondarySubViewport; + qreal m_devicePixelRatio; + Q3DCamera *m_camera; + Q3DLight *m_light; + bool m_isUnderSideCameraEnabled; + bool m_isSlicingActive; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DSCENE_P_H diff --git a/src/datavisualization/engine/q3dsurface.cpp b/src/datavisualization/engine/q3dsurface.cpp new file mode 100644 index 00000000..7990f362 --- /dev/null +++ b/src/datavisualization/engine/q3dsurface.cpp @@ -0,0 +1,542 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dsurface.h" +#include "q3dsurface_p.h" +#include "q3dvalueaxis.h" +#include "qsurfacedataproxy.h" +#include "q3dcamera.h" + +#include <QMouseEvent> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + * \class Q3DSurface + * \inmodule QtDataVisualization + * \brief The Q3DSurface class provides methods for rendering 3D surface plots. + * \since 1.0.0 + * + * This class enables developers to render 3D surface plots and to view them by rotating the scene + * freely. The class provides configurable gradient texture to illustrate the height on the data. The + * surface plotting includes also gridline that can be set on or off. The visual appearance of the + * surface can be changed by controlling the smooth status. + * + * The Q3DSurface supports selection by showing a highlighted ball on the data point where the user has clicked + * with left mouse button (when default input handler is in use). The selection pointer is accompanied with + * a label which in default case shows the value of the data point and the coordinates of the point. + * + * The value range and the label format shown on the axis can be controlled through Q3DValueAxis. + * The Q3DSurface supports only a grid with fixed steps, so when setting ranges set a value that matches + * the grid step. To calculate the steps divide the whole data range with the number of segments. + * + * To rotate the graph, hold down the right mouse button and move the mouse. Zooming is done using mouse + * wheel. Both assume the default input handler is in use. + * + * If no axes are explicitly set to Q3DSurface, temporary default axes with no labels are created. + * These default axes can be modified via axis accessors, but as soon any axis is explicitly + * set for the orientation, the default axis for that orientation is destroyed. + * + * Data proxies work similarly: If no data proxy is explicitly set, Q3DSurface creates a default + * proxy. If any other proxy is set as active data proxy later, the default proxy and all data + * added to it is destroyed. + * + * \section1 How to construct a minimal Q3DSurface graph + * + * First, construct Q3DSurface: + * + * \snippet doc_src_q3dsurface_construction.cpp 0 + * + * Now Q3DSurface is ready to receive data to be rendered. Create data elements to receive values: + * + * \snippet doc_src_q3dsurface_construction.cpp 1 + * + * First feed the data to the row element and then add it's pointer to the data element: + * + * \snippet doc_src_q3dsurface_construction.cpp 2 + * + * For the active data proxy set pointer of the data element: + * + * \snippet doc_src_q3dsurface_construction.cpp 3 + * + * Finally you will need to set it visible: + * + * \snippet doc_src_q3dsurface_construction.cpp 4 + * + * The complete code needed to create and display this graph is: + * + * \snippet doc_src_q3dsurface_construction.cpp 5 + * + * And this is what those few lines of code produce: + * + * \image q3dsurface-minimal.png + * + * The scene can be rotated and zoomed into, but no other interaction is included in this minimal + * code example. + * + * + * \sa Q3DBars, Q3DScatter, {Qt Data Visualization C++ Classes} + */ + +/*! + * Constructs a new 3D surface window. + */ +Q3DSurface::Q3DSurface() + : d_ptr(new Q3DSurfacePrivate(this, geometry())) +{ + setVisualController(d_ptr->m_shared); + d_ptr->m_shared->initializeOpenGL(); + QObject::connect(d_ptr->m_shared, &Abstract3DController::needRender, this, + &Q3DWindow::renderLater); +} + +/*! + * Destroys the 3D surface window. + */ +Q3DSurface::~Q3DSurface() +{ +} + +/*! + * \internal + */ +void Q3DSurface::mouseDoubleClickEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseDoubleClickEvent(event); +} + +/*! + * \internal + */ +void Q3DSurface::touchEvent(QTouchEvent *event) +{ + d_ptr->m_shared->touchEvent(event); +} + +/*! + * \internal + */ +void Q3DSurface::mousePressEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mousePressEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DSurface::mouseReleaseEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseReleaseEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DSurface::mouseMoveEvent(QMouseEvent *event) +{ + d_ptr->m_shared->mouseMoveEvent(event, event->pos()); +} + +/*! + * \internal + */ +void Q3DSurface::wheelEvent(QWheelEvent *event) +{ + d_ptr->m_shared->wheelEvent(event); +} + +/*! + * \internal + */ +void Q3DSurface::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + d_ptr->m_shared->setWidth(width()); + d_ptr->m_shared->setHeight(height()); +} + +/*! + * \property Q3DSurface::gridVisible + * + * Sets grid visibility to \a visible. It is preset to \c true by default. + */ +void Q3DSurface::setGridVisible(bool visible) +{ + d_ptr->m_shared->setGridEnabled(visible); +} + +bool Q3DSurface::isGridVisible() const +{ + return d_ptr->m_shared->gridEnabled(); +} + +/*! + * \property Q3DSurface::backgroundVisible + * + * Sets background visibility to \a visible. It is preset to \c true by default. + */ +void Q3DSurface::setBackgroundVisible(bool visible) +{ + d_ptr->m_shared->setBackgroundEnabled(visible); +} + +bool Q3DSurface::isBackgroundVisible() const +{ + return d_ptr->m_shared->backgroundEnabled(); +} + +/*! + * \property Q3DSurface::theme + * + * A predefined \a theme from \c QDataVis::Theme. It is preset to \c QDataVis::ThemeQt by + * default. Theme affects label colors, text color, background color, window color and + * grid color. Lighting is also adjusted by themes. + * + * \warning This property is subject to change. + */ +void Q3DSurface::setTheme(QDataVis::Theme theme) +{ + d_ptr->m_shared->setTheme(theme); +} + +QDataVis::Theme Q3DSurface::theme() const +{ + return d_ptr->m_shared->theme().theme(); +} + +/*! + * \property Q3DSurface::shadowQuality + * + * Sets shadow \a quality to one of \c QDataVis::ShadowQuality. It is preset to + * \c QDataVis::ShadowQualityMedium by default. + * + * \note If setting QDataVis::ShadowQuality of a certain level fails, a level is lowered + * until it is successful and shadowQualityChanged signal is emitted for each time the change is + * done. + */ +void Q3DSurface::setShadowQuality(QDataVis::ShadowQuality quality) +{ + return d_ptr->m_shared->setShadowQuality(quality); +} + +QDataVis::ShadowQuality Q3DSurface::shadowQuality() const +{ + return d_ptr->m_shared->shadowQuality(); +} + +/*! + * \property Q3DSurface::smoothSurfaceEnabled + * + * Sets surface smoothing to \a enabled. It is preset to \c false by default. + * When enabled the normals on the surface are interpolated making edges looking round. If turned + * off the normals are kept same on a triangle making the color of the triangle solid. This makes + * the data more readable from the model. + */ +void Q3DSurface::setSmoothSurfaceEnabled(bool enabled) +{ + d_ptr->m_shared->setSmoothSurface(enabled); +} + +bool Q3DSurface::isSmoothSurfaceEnabled() const +{ + return d_ptr->m_shared->smoothSurface(); +} + +/*! + * \property Q3DSurface::selectionMode + * + * Sets point selection \a mode to one of \c QDataVis::SelectionMode. Surface supports SelectionModeItem, + * SelectionModeSliceRow and SelectionModeSliceColumn. It is preset to \c QDataVis::SelectionModeItem by default. + */ +void Q3DSurface::setSelectionMode(QDataVis::SelectionMode mode) +{ + d_ptr->m_shared->setSelectionMode(mode); +} + +QDataVis::SelectionMode Q3DSurface::selectionMode() const +{ + return d_ptr->m_shared->selectionMode(); +} + + +/*! + * \property Q3DSurface::surfaceGridEnabled + * + * Sets surface grid to \a enabled. It is preset to \c true by default. + */ +void Q3DSurface::setSurfaceGridEnabled(bool enabled) +{ + d_ptr->m_shared->setSurfaceGrid(enabled); +} + +bool Q3DSurface::isSurfaceGridEnabled() const +{ + return d_ptr->m_shared->surfaceGrid(); +} + +/*! + * \property Q3DSurface::gradient + * + * The current surface gradient. Setting this property replaces the previous gradient with + * the given \a gradient. + */ +void Q3DSurface::setGradient(const QLinearGradient &gradient) +{ + d_ptr->m_shared->setGradient(gradient); +} + +QLinearGradient Q3DSurface::gradient() const +{ + return d_ptr->m_shared->gradient(); +} + +/*! + * \property Q3DSurface::font + * + * Sets the \a font for labels. It is preset to \c Arial by default. + */ +void Q3DSurface::setFont(const QFont &font) +{ + d_ptr->m_shared->setFont(font); +} + +QFont Q3DSurface::font() const +{ + return d_ptr->m_shared->font(); +} + +/*! + * \property Q3DSurface::scene + * + * This property contains the read only Q3DScene that can be used to access e.g. camera object. + */ +Q3DScene *Q3DSurface::scene() const +{ + return d_ptr->m_shared->scene(); +} + +/*! + * \property Q3DSurface::labelStyle + * + * Sets label \a style to one of \c QDataVis::LabelStyle. It is preset to + * \c QDataVis::LabelStyleFromTheme by default. + */ +void Q3DSurface::setLabelStyle(QDataVis::LabelStyle style) +{ + d_ptr->m_shared->setLabelStyle(style); +} + +QDataVis::LabelStyle Q3DSurface::labelStyle() const +{ + return d_ptr->m_shared->labelStyle(); +} + +/*! + * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisX(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisX(axis); +} + +/*! + * \return used X-axis. + */ +Q3DValueAxis *Q3DSurface::axisX() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisX()); +} + +/*! + * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisY(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisY(axis); +} + +/*! + * \return used Y-axis. + */ +Q3DValueAxis *Q3DSurface::axisY() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisY()); +} + +/*! + * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, a temporary default axis with no labels and automatically adjusting + * range is created. + * This temporary axis is destroyed if another \a axis is explicitly set to same orientation. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisZ(Q3DValueAxis *axis) +{ + d_ptr->m_shared->setAxisZ(axis); +} + +/*! + * \return used Z-axis. + */ +Q3DValueAxis *Q3DSurface::axisZ() const +{ + return static_cast<Q3DValueAxis *>(d_ptr->m_shared->axisZ()); +} + +/*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DSurface::addAxis(Q3DValueAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * If the released \a axis is in use, a new default axis will be created and set active. + * + * If the default axis is released and added back later, it behaves as any other axis would. + * + * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DSurface::releaseAxis(Q3DValueAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<Q3DValueAxis *> Q3DSurface::axes() const +{ + QList<Q3DAbstractAxis *> abstractAxes = d_ptr->m_shared->axes(); + QList<Q3DValueAxis *> retList; + foreach (Q3DAbstractAxis *axis, abstractAxes) + retList.append(static_cast<Q3DValueAxis *>(axis)); + + return retList; +} + +/*! + * Sets the active data \a proxy. Implicitly calls addDataProxy() to transfer ownership of + * the \a proxy to this graph. + * + * If the \a proxy is null, a temporary default proxy is created and activated. + * This temporary proxy is destroyed if another \a proxy is explicitly set active via this method. + * + * \sa addDataProxy(), releaseDataProxy() + */ +void Q3DSurface::setActiveDataProxy(QSurfaceDataProxy *proxy) +{ + d_ptr->m_shared->setActiveDataProxy(proxy); +} + +/*! + * \return active data proxy. + */ +QSurfaceDataProxy *Q3DSurface::activeDataProxy() const +{ + return static_cast<QSurfaceDataProxy *>(d_ptr->m_shared->activeDataProxy()); +} + +/*! + * Adds data \a proxy to the graph. The proxies added via addDataProxy are not yet taken to use, + * addDataProxy is simply used to give the ownership of the data \a proxy to the graph. + * The \a proxy must not be null or added to another graph. + * + * \sa releaseDataProxy(), setActiveDataProxy() + */ +void Q3DSurface::addDataProxy(QSurfaceDataProxy *proxy) +{ + d_ptr->m_shared->addDataProxy(proxy); +} + +/*! + * Releases the ownership of the data \a proxy back to the caller, if it is added to this graph. + * If the released \a proxy is in use, a new empty default proxy is created and taken to use. + * + * If the default \a proxy is released and added back later, it behaves as any other proxy would. + * + * \sa addDataProxy(), setActiveDataProxy() + */ +void Q3DSurface::releaseDataProxy(QSurfaceDataProxy *proxy) +{ + d_ptr->m_shared->releaseDataProxy(proxy); +} + +/*! + * \return list of all added data proxies. + * + * \sa addDataProxy() + */ +QList<QSurfaceDataProxy *> Q3DSurface::dataProxies() const +{ + QList<QSurfaceDataProxy *> retList; + QList<QAbstractDataProxy *> abstractList = d_ptr->m_shared->dataProxies(); + foreach (QAbstractDataProxy *proxy, abstractList) + retList.append(static_cast<QSurfaceDataProxy *>(proxy)); + + return retList; +} + + +/*! + * Modifies the current surface gradient. Sets gradient color to \a color at \a pos. + */ +void Q3DSurface::setGradientColorAt(qreal pos, const QColor &color) +{ + d_ptr->m_shared->setGradientColorAt(pos, color); +} + +/////////////////// PRIVATE /////////////////////////////////// + +Q3DSurfacePrivate::Q3DSurfacePrivate(Q3DSurface *q, QRect rect) + : q_ptr(q), + m_shared(new Surface3DController(rect)) +{ +} + +Q3DSurfacePrivate::~Q3DSurfacePrivate() +{ + delete m_shared; +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dsurface.h b/src/datavisualization/engine/q3dsurface.h new file mode 100644 index 00000000..1b572a36 --- /dev/null +++ b/src/datavisualization/engine/q3dsurface.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DSURFACE_H +#define Q3DSURFACE_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QtDataVisualization/q3dwindow.h> +#include <QtDataVisualization/q3dscene.h> +#include <QFont> +#include <QLinearGradient> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DSurfacePrivate; +class Q3DValueAxis; +class QSurfaceDataProxy; + +class QT_DATAVISUALIZATION_EXPORT Q3DSurface : public Q3DWindow +{ + Q_OBJECT + Q_PROPERTY(QtDataVisualization::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) + Q_PROPERTY(QtDataVisualization::QDataVis::LabelStyle labelStyle READ labelStyle WRITE setLabelStyle) + Q_PROPERTY(QtDataVisualization::QDataVis::Theme theme READ theme WRITE setTheme) + Q_PROPERTY(QtDataVisualization::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) + Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible) + Q_PROPERTY(bool backgroundVisible READ isBackgroundVisible WRITE setBackgroundVisible) + Q_PROPERTY(bool smoothSurfaceEnabled READ isSmoothSurfaceEnabled WRITE setSmoothSurfaceEnabled) + Q_PROPERTY(bool surfaceGridEnabled READ isSurfaceGridEnabled WRITE setSurfaceGridEnabled) + Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient) + Q_PROPERTY(QFont font READ font WRITE setFont) + Q_PROPERTY(Q3DScene* scene READ scene) + Q_ENUMS(QtDataVisualization::QDataVis::SelectionMode) + Q_ENUMS(QtDataVisualization::QDataVis::ShadowQuality) + Q_ENUMS(QtDataVisualization::QDataVis::LabelStyle) + Q_ENUMS(QtDataVisualization::QDataVis::CameraPreset) + +public: + explicit Q3DSurface(); + ~Q3DSurface(); + + void setGridVisible(bool visible); + bool isGridVisible() const; + + void setBackgroundVisible(bool visible); + bool isBackgroundVisible() const; + + void setTheme(QDataVis::Theme theme); + QDataVis::Theme theme() const; + + void setShadowQuality(QDataVis::ShadowQuality quality); + QDataVis::ShadowQuality shadowQuality() const; + + void setSmoothSurfaceEnabled(bool enabled); + bool isSmoothSurfaceEnabled() const; + + void setSelectionMode(QDataVis::SelectionMode mode); + QDataVis::SelectionMode selectionMode() const; + void setSurfaceGridEnabled(bool enabled); + bool isSurfaceGridEnabled() const; + + void setGradient(const QLinearGradient &gradient); + QLinearGradient gradient() const; + + void setGradientColorAt(qreal pos, const QColor &color); + + // Axes + void setAxisX(Q3DValueAxis *axis); + Q3DValueAxis *axisX() const; + void setAxisY(Q3DValueAxis *axis); + Q3DValueAxis *axisY() const; + void setAxisZ(Q3DValueAxis *axis); + Q3DValueAxis *axisZ() const; + void addAxis(Q3DValueAxis *axis); + void releaseAxis(Q3DValueAxis *axis); + QList<Q3DValueAxis *> axes() const; + + void setActiveDataProxy(QSurfaceDataProxy *proxy); + QSurfaceDataProxy *activeDataProxy() const; + void addDataProxy(QSurfaceDataProxy *proxy); + void releaseDataProxy(QSurfaceDataProxy *proxy); + QList<QSurfaceDataProxy *> dataProxies() const; + + void setFont(const QFont &font); + QFont font() const; + + Q3DScene *scene() const; + + void setLabelStyle(QDataVis::LabelStyle style); + QDataVis::LabelStyle labelStyle() const; + +protected: + void mouseDoubleClickEvent(QMouseEvent *event); + void touchEvent(QTouchEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void resizeEvent(QResizeEvent *event); + +private: + QScopedPointer<Q3DSurfacePrivate> d_ptr; + Q_DISABLE_COPY(Q3DSurface) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DSURFACE_H diff --git a/src/datavisualization/engine/q3dsurface_p.h b/src/datavisualization/engine/q3dsurface_p.h new file mode 100644 index 00000000..7c70d08c --- /dev/null +++ b/src/datavisualization/engine/q3dsurface_p.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSURFACE_P_H +#define Q3DSURFACE_P_H + +#include "surface3dcontroller_p.h" +#include "qdatavisualizationenums.h" + +#include <QList> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DSurface; + +class Q3DSurfacePrivate : public QObject +{ +public: + Q3DSurfacePrivate(Q3DSurface *q, QRect rect); + ~Q3DSurfacePrivate(); + + Q3DSurface *q_ptr; + Surface3DController *m_shared; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // Q3DSURFACE_P_H diff --git a/src/datavisualization/engine/q3dwindow.cpp b/src/datavisualization/engine/q3dwindow.cpp new file mode 100644 index 00000000..9b607e1d --- /dev/null +++ b/src/datavisualization/engine/q3dwindow.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "q3dwindow.h" +#include "q3dwindow_p.h" +#include "abstract3dcontroller_p.h" +#include <QGuiApplication> + +#include <QOpenGLContext> +#include <QOpenGLPaintDevice> +#include <QPainter> + +#include <QDebug> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + * \class Q3DWindow + * \inmodule QtDataVisualization + * \brief The Q3DWindow class provides a window and render loop. + * \since 1.0.0 + * + * This class creates a QWindow and provides render loop for visualization types inheriting it. + * \warning This class is not intended to be used directly by developers. + * + * \sa Q3DBars, Q3DScatter, Q3DSurface, {Qt Data Visualization C++ Classes} + */ + +/*! + * Constructs Q3DWindow with \a parent. It creates a QWindow and an OpenGL context. It also sets + * surface format and initializes OpenGL functions for use. + */ +Q3DWindow::Q3DWindow(QWindow *parent) + : QWindow(parent), + d_ptr(new Q3DWindowPrivate(this)) +{ + setSurfaceType(QWindow::OpenGLSurface); + QSurfaceFormat surfaceFormat; + surfaceFormat.setDepthBufferSize(16); +#if !defined(QT_OPENGL_ES_2) + surfaceFormat.setSamples(8); + surfaceFormat.setRenderableType(QSurfaceFormat::OpenGL); +#else + surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); +#endif + surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + setFormat(surfaceFormat); + + create(); + + d_ptr->m_context->setFormat(requestedFormat()); + d_ptr->m_context->create(); + d_ptr->m_context->makeCurrent(this); + + qDebug() << "initializeOpenGLFunctions()"; + initializeOpenGLFunctions(); + + const GLubyte *version = glGetString(GL_VERSION); + qDebug() << "OpenGL version:" << (const char *)version; + version = glGetString(GL_SHADING_LANGUAGE_VERSION); + qDebug() << "GLSL version:" << (const char *)version; +#if !defined(QT_OPENGL_ES_2) + // If we have real OpenGL, GLSL version must be 1.2 or over. Quit if not. + QStringList splitversionstr = QString::fromLatin1((const char *)version).split(QChar::fromLatin1(' ')); + if (splitversionstr[0].toFloat() < 1.2) + qFatal("GLSL version must be 1.20 or higher. Try installing latest display drivers."); +#endif + renderLater(); +} + +/*! + * Destroys Q3DWindow. + */ +Q3DWindow::~Q3DWindow() +{ +} + +/*! + * \internal + */ +void Q3DWindow::setVisualController(Abstract3DController *controller) +{ + d_ptr->m_visualController = controller; +} + +/*! + * \internal + */ +void Q3DWindow::handleDevicePixelRatioChange() +{ + if (QWindow::devicePixelRatio() == d_ptr->m_devicePixelRatio || !d_ptr->m_visualController) + return; + + // Device pixel ratio changed, resize accordingly and inform the scene + d_ptr->m_devicePixelRatio = QWindow::devicePixelRatio(); + d_ptr->m_visualController->updateDevicePixelRatio(d_ptr->m_devicePixelRatio); + +} + +/*! + * \internal + */ +void Q3DWindow::render() +{ + handleDevicePixelRatioChange(); + d_ptr->m_visualController->synchDataToRenderer(); + d_ptr->m_visualController->render(); +} + +/*! + * \internal + */ +void Q3DWindow::renderLater() +{ + if (!d_ptr->m_updatePending) { + d_ptr->m_updatePending = true; + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + } +} + +/*! + * \internal + */ +bool Q3DWindow::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::UpdateRequest: + renderNow(); + return true; + case QEvent::TouchBegin: + case QEvent::TouchCancel: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + d_ptr->m_visualController->touchEvent(static_cast<QTouchEvent *>(event)); + return true; + default: + return QWindow::event(event); + } +} + +/*! + * \internal + */ +void Q3DWindow::exposeEvent(QExposeEvent *event) +{ + Q_UNUSED(event); + + if (isExposed()) + renderNow(); +} + +/*! + * \internal + */ +void Q3DWindow::renderNow() +{ + if (!isExposed()) + return; + + d_ptr->m_updatePending = false; + + d_ptr->m_context->makeCurrent(this); + + render(); + + d_ptr->m_context->swapBuffers(this); +} + +Q3DWindowPrivate::Q3DWindowPrivate(Q3DWindow *q) + : q_ptr(q), + m_updatePending(false), + m_context(new QOpenGLContext(q)), + m_visualController(0), + m_devicePixelRatio(1.f) +{ +} + +Q3DWindowPrivate::~Q3DWindowPrivate() +{ +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/q3dwindow.h b/src/datavisualization/engine/q3dwindow.h new file mode 100644 index 00000000..1848ff29 --- /dev/null +++ b/src/datavisualization/engine/q3dwindow.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef Q3DWINDOW_H +#define Q3DWINDOW_H + +#include <QtDataVisualization/qdatavisualizationenums.h> + +#include <QWindow> +#include <QOpenGLFunctions> +#include <QScreen> + +class QPainter; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DWindowPrivate; +class Abstract3DController; + +class QT_DATAVISUALIZATION_EXPORT Q3DWindow : public QWindow, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + explicit Q3DWindow(QWindow *parent = 0); + virtual ~Q3DWindow(); + +protected slots: + void renderLater(); + void renderNow(); + +protected: + virtual void render(); + + bool event(QEvent *event); + void exposeEvent(QExposeEvent *event); + void setVisualController(Abstract3DController *controller); + void handleDevicePixelRatioChange(); + +private: + QScopedPointer<Q3DWindowPrivate> d_ptr; + + friend class Q3DBars; + friend class Q3DScatter; + friend class Q3DSurface; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/q3dwindow_p.h b/src/datavisualization/engine/q3dwindow_p.h new file mode 100644 index 00000000..6bef7e10 --- /dev/null +++ b/src/datavisualization/engine/q3dwindow_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DWINDOW_p_H +#define Q3DWINDOW_p_H + +#include "datavisualizationglobal_p.h" + +class QOpenGLContext; +class QOpenGLPaintDevice; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Q3DWindow; +class Abstract3DController; + +class Q3DWindowPrivate +{ +public: + Q3DWindowPrivate(Q3DWindow *q); + ~Q3DWindowPrivate(); + +public: + Q3DWindow *q_ptr; + + bool m_updatePending; + QOpenGLContext *m_context; + Abstract3DController *m_visualController; + qreal m_devicePixelRatio; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp new file mode 100644 index 00000000..9f43d94e --- /dev/null +++ b/src/datavisualization/engine/scatter3dcontroller.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "scatter3dcontroller_p.h" +#include "scatter3drenderer_p.h" +#include "camerahelper_p.h" +#include "q3dabstractaxis_p.h" +#include "q3dvalueaxis_p.h" +#include "qscatterdataproxy_p.h" + +#include <QMatrix4x4> +#include <qmath.h> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Scatter3DController::Scatter3DController(QRect boundRect) + : Abstract3DController(boundRect), + m_renderer(0), + m_selectedItemIndex(noSelectionIndex()) +{ + // Default object type; specific to scatter + setObjectType(QDataVis::MeshStyleSpheres, false); + + setActiveDataProxy(new QScatterDataProxy); + + // Setting a null axis creates a new default axis according to orientation and graph type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); +} + +Scatter3DController::~Scatter3DController() +{ +} + +void Scatter3DController::initializeOpenGL() +{ + // Initialization is called multiple times when Qt Quick components are used + if (isInitialized()) + return; + + m_renderer = new Scatter3DRenderer(this); + setRenderer(m_renderer); + synchDataToRenderer(); + + QObject::connect(m_renderer, &Scatter3DRenderer::selectedItemIndexChanged, this, + &Scatter3DController::handleSelectedItemIndexChanged, Qt::QueuedConnection); + emitNeedRender(); +} + +void Scatter3DController::synchDataToRenderer() +{ + Abstract3DController::synchDataToRenderer(); + + if (!isInitialized()) + return; + + // Notify changes to renderer + if (m_changeTracker.slicingActiveChanged) { + // TODO: Add notification. + m_changeTracker.slicingActiveChanged = false; + } + + if (m_changeTracker.selectedItemIndexChanged) { + m_renderer->updateSelectedItemIndex(m_selectedItemIndex); + m_changeTracker.selectedItemIndexChanged = false; + } + + if (m_isDataDirty) { + m_renderer->updateDataModel(static_cast<QScatterDataProxy *>(m_data)); + m_isDataDirty = false; + } +} + + +void Scatter3DController::setActiveDataProxy(QAbstractDataProxy *proxy) +{ + // Setting null proxy indicates default proxy + if (!proxy) { + proxy = new QScatterDataProxy; + proxy->d_ptr->setDefaultProxy(true); + } + + Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeScatter); + + Abstract3DController::setActiveDataProxy(proxy); + + QScatterDataProxy *scatterDataProxy = static_cast<QScatterDataProxy *>(m_data); + + QObject::connect(scatterDataProxy, &QScatterDataProxy::arrayReset, + this, &Scatter3DController::handleArrayReset); + QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsAdded, + this, &Scatter3DController::handleItemsAdded); + QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsChanged, + this, &Scatter3DController::handleItemsChanged); + QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsRemoved, + this, &Scatter3DController::handleItemsRemoved); + QObject::connect(scatterDataProxy, &QScatterDataProxy::itemsInserted, + this, &Scatter3DController::handleItemsInserted); + + adjustValueAxisRange(); + setSelectedItemIndex(noSelectionIndex()); + setSlicingActive(false); + m_isDataDirty = true; + emitNeedRender(); +} + +void Scatter3DController::handleArrayReset() +{ + setSlicingActive(false); + adjustValueAxisRange(); + m_isDataDirty = true; + setSelectedItemIndex(noSelectionIndex()); + emitNeedRender(); +} + +void Scatter3DController::handleItemsAdded(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should dirty only affected values? + adjustValueAxisRange(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Scatter3DController::handleItemsChanged(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should dirty only affected values? + adjustValueAxisRange(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Scatter3DController::handleItemsRemoved(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should dirty only affected values? + adjustValueAxisRange(); + m_isDataDirty = true; + if (startIndex >= static_cast<QScatterDataProxy *>(m_data)->itemCount()) + setSelectedItemIndex(noSelectionIndex()); + emitNeedRender(); +} + +void Scatter3DController::handleItemsInserted(int startIndex, int count) +{ + Q_UNUSED(startIndex) + Q_UNUSED(count) + // TODO should dirty only affected values? + adjustValueAxisRange(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Scatter3DController::handleSelectedItemIndexChanged(int index) +{ + if (index != m_selectedItemIndex) { + m_selectedItemIndex = index; + emit selectedItemIndexChanged(index); + emitNeedRender(); + } +} + +void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation( + Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) +{ + Q_UNUSED(orientation) + Q_UNUSED(autoAdjust) + adjustValueAxisRange(); +} + +void Scatter3DController::setObjectType(QDataVis::MeshStyle style, bool smooth) +{ + QString objFile; + if (style == QDataVis::MeshStyleSpheres) { + if (smooth) + objFile = QStringLiteral(":/defaultMeshes/sphereSmooth"); + else + objFile = QStringLiteral(":/defaultMeshes/sphere"); + } else { + if (smooth) + objFile = QStringLiteral(":/defaultMeshes/dotSmooth"); + else + objFile = QStringLiteral(":/defaultMeshes/dot"); + } + Abstract3DController::setMeshFileName(objFile); +} + +void Scatter3DController::setSelectionMode(QDataVis::SelectionMode mode) +{ + if (mode > QDataVis::SelectionModeItem) { + qWarning("Unsupported selection mode."); + return; + } + // Disable zoom if selection mode changes + setSlicingActive(false); + Abstract3DController::setSelectionMode(mode); +} + +void Scatter3DController::setSelectedItemIndex(int index) +{ + // TODO If items not within axis ranges are culled from drawing, should they be + // TODO unselectable as well? + if (index < 0 || index >= static_cast<QScatterDataProxy *>(m_data)->itemCount()) + index = noSelectionIndex(); + + if (index != m_selectedItemIndex) { + m_selectedItemIndex = index; + m_changeTracker.selectedItemIndexChanged = true; + emit selectedItemIndexChanged(index); + emitNeedRender(); + } +} + +int Scatter3DController::selectedItemIndex() const +{ + return m_selectedItemIndex; +} + +void Scatter3DController::adjustValueAxisRange() +{ + if (m_data) { + QVector3D limits = static_cast<QScatterDataProxy *>(m_data)->dptr()->limitValues(); + Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisX); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.x() > 0) + valueAxis->dptr()->setRange(-limits.x(), limits.x()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } + + valueAxis = static_cast<Q3DValueAxis *>(m_axisY); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.y() > 0) + valueAxis->dptr()->setRange(-limits.y(), limits.y()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } + + valueAxis = static_cast<Q3DValueAxis *>(m_axisZ); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.z() > 0) + valueAxis->dptr()->setRange(-limits.z(), limits.z()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h new file mode 100644 index 00000000..63735aca --- /dev/null +++ b/src/datavisualization/engine/scatter3dcontroller_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSCATTERCONTROLLER_p_H +#define Q3DSCATTERCONTROLLER_p_H + +#include "datavisualizationglobal_p.h" +#include "abstract3dcontroller_p.h" + +//#define DISPLAY_RENDER_SPEED + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Scatter3DRenderer; +class QScatterDataProxy; + +struct Scatter3DChangeBitField { + bool slicingActiveChanged : 1; + bool selectedItemIndexChanged : 1; + + Scatter3DChangeBitField() : + slicingActiveChanged(true), + selectedItemIndexChanged(true) + { + } +}; + +class QT_DATAVISUALIZATION_EXPORT Scatter3DController : public Abstract3DController +{ + Q_OBJECT + +private: + Scatter3DChangeBitField m_changeTracker; + + // Rendering + Scatter3DRenderer *m_renderer; + int m_selectedItemIndex; + +public: + explicit Scatter3DController(QRect rect); + ~Scatter3DController(); + + void initializeOpenGL(); + + // Object type + void setObjectType(QDataVis::MeshStyle style, bool smooth = false); + + // Change selection mode + void setSelectionMode(QDataVis::SelectionMode mode); + + void setSelectedItemIndex(int index); + int selectedItemIndex() const; + static inline int noSelectionIndex() { return -1; } + + virtual void setActiveDataProxy(QAbstractDataProxy *proxy); + + void synchDataToRenderer(); + + virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); + +public slots: + void handleArrayReset(); + void handleItemsAdded(int startIndex, int count); + void handleItemsChanged(int startIndex, int count); + void handleItemsRemoved(int startIndex, int count); + void handleItemsInserted(int startIndex, int count); + void handleSelectedItemIndexChanged(int index); + +signals: + void selectedItemIndexChanged(int index); + +private: + void adjustValueAxisRange(); + + Q_DISABLE_COPY(Scatter3DController) +}; + + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp new file mode 100644 index 00000000..a482cc42 --- /dev/null +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -0,0 +1,1623 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "scatter3drenderer_p.h" +#include "scatter3dcontroller_p.h" +#include "q3dcamera.h" +#include "q3dcamera_p.h" +#include "shaderhelper_p.h" +#include "objecthelper_p.h" +#include "texturehelper_p.h" +#include "utils_p.h" +#include "q3dlight.h" + +#include <QMatrix4x4> +#include <QMouseEvent> +#include <QThread> +#include <qmath.h> +#include <QDebug> + +// Commenting this draws the shadow map with perspective projection. Otherwise it's drawn in +// orthographic projection. +//#define USE_WIDER_SHADOWS + +// You can verify that depth buffer drawing works correctly by uncommenting this. +// You should see the scene from where the light is +//#define SHOW_DEPTH_TEXTURE_SCENE + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +//#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values + +const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd. +const GLfloat labelMargin = 0.05f; +// TODO: Make margin modifiable? +const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background) +const GLfloat gridLineWidth = 0.005f; +static QVector3D selectionSkipColor = QVector3D(255, 255, 255); // Selection texture's background color + +Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) + : Abstract3DRenderer(controller), + m_controller(controller), + m_selectedItem(0), + m_xFlipped(false), + m_zFlipped(false), + m_yFlipped(false), + m_updateLabels(false), + m_dotShader(0), + m_depthShader(0), + m_selectionShader(0), + m_backgroundShader(0), + m_labelShader(0), + m_dotObj(0), + m_backgroundObj(0), + m_gridLineObj(0), + m_labelObj(0), + m_bgrTexture(0), + m_depthTexture(0), + m_selectionTexture(0), + m_depthFrameBuffer(0), + m_selectionFrameBuffer(0), + m_selectionDepthBuffer(0), + m_shadowQualityToShader(100.0f), + m_shadowQualityMultiplier(3), + m_heightNormalizer(1.0f), + m_scaleFactor(0), + m_selection(selectionSkipColor), + m_previousSelection(selectionSkipColor), + m_areaSize(QSizeF(0.0, 0.0)), + m_dotSizeScale(1.0f), + m_hasHeightAdjustmentChanged(true) +{ + initializeOpenGLFunctions(); + initializeOpenGL(); +} + +Scatter3DRenderer::~Scatter3DRenderer() +{ + m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); + m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); + m_textureHelper->deleteTexture(&m_selectionTexture); + m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); + m_textureHelper->deleteTexture(&m_bgrTexture); + delete m_dotShader; + delete m_depthShader; + delete m_selectionShader; + delete m_backgroundShader; + delete m_labelShader; + delete m_dotObj; + delete m_backgroundObj; + delete m_gridLineObj; + delete m_labelObj; +} + +void Scatter3DRenderer::initializeOpenGL() +{ + Abstract3DRenderer::initializeOpenGL(); + + // Initialize shaders + handleShadowQualityChange(); + + initLabelShaders(QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + +#if !defined(QT_OPENGL_ES_2) + // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api. + initDepthShader(); +#endif + + // Init selection shader + initSelectionShader(); + + // Load grid line mesh + loadGridLineMesh(); + + // Load label mesh + loadLabelMesh(); + + // Set view port + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + // Load background mesh (we need to be initialized first) + loadBackgroundMesh(); +} + +void Scatter3DRenderer::updateDataModel(QScatterDataProxy *dataProxy) +{ + const QScatterDataArray &dataArray = *dataProxy->array(); + calculateSceneScalingFactors(); + int dataSize = dataArray.size(); + float minX = float(m_axisCacheX.min()); + float maxX = float(m_axisCacheX.max()); + float minY = float(m_axisCacheY.min()); + float maxY = float(m_axisCacheY.max()); + float minZ = float(m_axisCacheZ.min()); + float maxZ = float(m_axisCacheZ.max()); + + if (dataSize != m_renderItemArray.size()) + m_renderItemArray.resize(dataSize); + for (int i = 0; i < dataSize ; i++) { + QVector3D dotPos = dataArray.at(i).position(); + // TODO: Check if this still works always when ranges are no longer required to be zero centered + // TODO: qreal -> float conversion for axis min/max may cause issues like in surface + if ((dotPos.x() >= minX && dotPos.x() <= maxX ) + && (dotPos.y() >= minY && dotPos.y() <= maxY) + && (dotPos.z() >= minZ && dotPos.z() <= maxZ)) { + m_renderItemArray[i].setPosition(dotPos); + m_renderItemArray[i].setVisible(true); + calculateTranslation(m_renderItemArray[i]); + } else { + m_renderItemArray[i].setVisible(false); + } + } + m_dotSizeScale = (GLfloat)qBound(0.01, (2.0 / qSqrt((qreal)dataSize)), 0.1); + m_selectedItem = 0; + + Abstract3DRenderer::updateDataModel(dataProxy); +} + +void Scatter3DRenderer::updateScene(Q3DScene *scene) +{ + // TODO: Move these to more suitable place e.g. controller should be controlling the viewports. + scene->setPrimarySubViewport(m_mainViewPort); + + // TODO: See QTRD-2374 + scene->activeCamera()->setMinYRotation(-90.0f); + + if (m_hasHeightAdjustmentChanged) { + // Set initial m_cachedScene->activeCamera() position. Also update if height adjustment has changed. + scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + m_hasHeightAdjustmentChanged = false; + } + + scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment); + // Set light position (rotate light with m_cachedScene->activeCamera(), a bit above it (as set in defaultLightPos)) + scene->setLightPositionRelativeToCamera(defaultLightPos); + + Abstract3DRenderer::updateScene(scene); +} + +void Scatter3DRenderer::render(GLuint defaultFboHandle) +{ + // Handle GL state setup for FBO buffers and clearing of the render surface + Abstract3DRenderer::render(defaultFboHandle); + + // Draw dots scene + drawScene(defaultFboHandle); +} + +void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) +{ + GLfloat backgroundRotation = 0; + + // Specify viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f); + + // Calculate view matrix + QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix(); + + // Calculate label flipping + if (viewMatrix.row(0).x() > 0) + m_zFlipped = false; + else + m_zFlipped = true; + if (viewMatrix.row(0).z() <= 0) + m_xFlipped = false; + else + m_xFlipped = true; + + // Check if we're viewing the scene from below + if (viewMatrix.row(2).y() < 0) + m_yFlipped = true; + else + m_yFlipped = false; + + // Calculate background rotation + if (!m_zFlipped && !m_xFlipped) + backgroundRotation = 270.0f; + else if (!m_zFlipped && m_xFlipped) + backgroundRotation = 180.0f; + else if (m_zFlipped && m_xFlipped) + backgroundRotation = 90.0f; + else if (m_zFlipped && !m_xFlipped) + backgroundRotation = 0.0f; + + // Get light position from the scene + QVector3D lightPos = m_cachedScene->activeLight()->position(); + + // Map adjustment direction to model matrix scaling + // TODO: Let's use these for testing the autoscaling of dots based on their number + GLfloat heightMultiplier = m_dotSizeScale; //1.0f; + GLfloat widthMultiplier = m_dotSizeScale; //1.0f; + GLfloat depthMultiplier = m_dotSizeScale; //1.0f; + GLfloat heightScaler = 0.0f; + GLfloat widthScaler = 0.0f; + GLfloat depthScaler = 0.0f; + + // Introduce regardless of shadow quality to simplify logic + QMatrix4x4 depthViewMatrix; + QMatrix4x4 depthProjectionMatrix; + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Render scene into a depth texture for using with shadow mapping + // Bind depth shader + m_depthShader->bind(); + + // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows. + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width() * m_shadowQualityMultiplier, + m_mainViewPort.height() * m_shadowQualityMultiplier); + + // Enable drawing to framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer); + glClear(GL_DEPTH_BUFFER_BIT); + + // Set front face culling to reduce self-shadowing issues + glCullFace(GL_FRONT); + + // Get the depth view matrix + // It may be possible to hack lightPos here if we want to make some tweaks to shadow + QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera( + defaultLightPos, 0.0f, 1.0f / m_autoScaleAdjustment); + depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? + // That causes the scene to be not drawn from above -> must be fixed + // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3); + // Set the depth projection matrix +#ifndef USE_WIDER_SHADOWS + // Use this for perspective shadows + depthProjectionMatrix.perspective(15.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f); +#else + // Use these for orthographic shadows + //depthProjectionMatrix.ortho(-aspectRatio * 2.0f, aspectRatio * 2.0f, + // -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f, + // 0.0f, 100.0f); + GLfloat testAspectRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height(); + depthProjectionMatrix.ortho(-testAspectRatio * 2.0f, testAspectRatio * 2.0f, + -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f, + 0.0f, 100.0f); +#endif + // Draw dots to depth buffer + for (int dot = 0; dot < m_renderItemArray.size(); dot++) { + const ScatterRenderItem &item = m_renderItemArray.at(dot); + if (!item.isVisible()) + continue; + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + modelMatrix.translate(item.translation().x(), + item.translation().y(), + item.translation().z()); + modelMatrix.scale(QVector3D(widthMultiplier + widthScaler, + heightMultiplier + heightScaler, + depthMultiplier + depthScaler)); + //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, + // heightMultiplier * item.size() + heightScaler, + // depthMultiplier * item.size() + depthScaler)); + + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_depthShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, m_dotObj->vertexBuf()); + glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_dotObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, m_dotObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_depthShader->posAtt()); + } + + // Disable drawing to framebuffer (= enable drawing to screen) + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Reset culling to normal + glCullFace(GL_BACK); + + // Release depth shader + m_depthShader->release(); + + // Revert to original viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + +#if 0 // Use this if you want to see what is being drawn to the framebuffer + // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it) + m_labelShader->bind(); + glEnable(GL_TEXTURE_2D); + QMatrix4x4 modelMatrix; + QMatrix4x4 viewmatrix; + viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + modelMatrix.translate(0.0, 0.0, zComp); + QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + m_drawer->drawObject(m_labelShader, m_labelObj, + m_depthTexture); + glDisable(GL_TEXTURE_2D); + m_labelShader->release(); +#endif + } +#endif + + // Skip selection mode drawing if we have no selection mode + if (m_cachedSelectionMode > QDataVis::SelectionModeNone) { + // Bind selection shader + m_selectionShader->bind(); + + // Draw dots to selection buffer + glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); + glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (= skipColor) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer + glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled + + int arraySize = m_renderItemArray.size(); + if (arraySize > 0xfffffe) // Max possible different selection colors, 0xffffff being skipColor + qFatal("Too many objects"); + + for (int dot = 0; dot < arraySize; dot++) { + const ScatterRenderItem &item = m_renderItemArray.at(dot); + if (!item.isVisible()) + continue; + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + modelMatrix.translate(item.translation().x(), + item.translation().y(), + item.translation().z()); + modelMatrix.scale(QVector3D(widthMultiplier + widthScaler, + heightMultiplier + heightScaler, + depthMultiplier + depthScaler)); + //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, + // heightMultiplier * item.size() + heightScaler, + // depthMultiplier * item.size() + depthScaler)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + + QVector3D dotColor = indexToSelectionColor(dot); + dotColor /= 255.0f; + + m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); + m_selectionShader->setUniformValue(m_selectionShader->color(), dotColor); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_selectionShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, m_dotObj->vertexBuf()); + glVertexAttribPointer(m_selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_dotObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, m_dotObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_selectionShader->posAtt()); + } + glEnable(GL_DITHER); + + // Read color under cursor + if (QDataVis::InputStateOnScene == m_controller->inputState()) { + m_selection = Utils::getSelection(m_controller->inputPosition(), + m_cachedBoundingRect.height()); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Release selection shader + m_selectionShader->release(); + +#if 0 // Use this if you want to see what is being drawn to the framebuffer + m_labelShader->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + QMatrix4x4 modelMatrix; + QMatrix4x4 viewmatrix; + viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + modelMatrix.translate(0.0, 0.0, zComp); + QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + m_drawer->drawObject(m_labelShader, m_labelObj, + m_selectionTexture); + glDisable(GL_TEXTURE_2D); + m_labelShader->release(); +#endif + } + + // Bind dot shader + m_dotShader->bind(); + + // Enable texture + glEnable(GL_TEXTURE_2D); + + // Draw dots + bool dotSelectionFound = false; + int selectedIndex; + if (m_selection == selectionSkipColor) { + selectedIndex = Scatter3DController::noSelectionIndex(); + } else { + selectedIndex = int(m_selection.x()) + + (int(m_selection.y()) << 8) + + (int(m_selection.z()) << 16); + } + + if (m_selection != m_previousSelection) { + emit selectedItemIndexChanged(selectedIndex); + m_previousSelection = m_selection; + } + + ScatterRenderItem *selectedItem(0); + + for (int dot = 0; dot < m_renderItemArray.size(); dot++) { + ScatterRenderItem &item = m_renderItemArray[dot]; + if (!item.isVisible()) + continue; + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(item.translation().x(), + item.translation().y(), + item.translation().z()); + modelMatrix.scale(QVector3D(widthMultiplier + widthScaler, + heightMultiplier + heightScaler, + depthMultiplier + depthScaler)); + //modelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, + // heightMultiplier * item.size() + heightScaler, + // depthMultiplier * item.size() + depthScaler)); + itModelMatrix.scale(QVector3D(widthMultiplier + widthScaler, + heightMultiplier + heightScaler, + depthMultiplier + depthScaler)); + //itModelMatrix.scale(QVector3D(widthMultiplier * item.size() + widthScaler, + // heightMultiplier * item.size() + heightScaler, + // depthMultiplier * item.size() + depthScaler)); + +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; +#else + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + +#if 0 + QVector3D baseColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor); + QVector3D heightColor = + Utils::vectorFromColor(m_cachedTheme.m_heightColor) * item.translation().y(); + + QVector3D dotColor = baseColor + heightColor; +#else + QVector3D dotColor = Utils::vectorFromColor(m_cachedTheme.m_baseColor); +#endif + + GLfloat lightStrength = m_cachedTheme.m_lightStrength; + if (m_cachedSelectionMode > QDataVis::SelectionModeNone && (selectedIndex == dot)) { + dotColor = Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor); + lightStrength = m_cachedTheme.m_highlightLightStrength; + // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one + selectedItem = &item; + dotSelectionFound = true; + } + + // Set shader bindings + m_dotShader->setUniformValue(m_dotShader->lightP(), lightPos); + m_dotShader->setUniformValue(m_dotShader->view(), viewMatrix); + m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); + m_dotShader->setUniformValue(m_dotShader->nModel(), + itModelMatrix.inverted().transposed()); + m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); + m_dotShader->setUniformValue(m_dotShader->color(), dotColor); + m_dotShader->setUniformValue(m_dotShader->ambientS(), m_cachedTheme.m_ambientStrength); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); + m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); + m_dotShader->setUniformValue(m_dotShader->lightS(), lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_dotObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_dotShader->setUniformValue(m_dotShader->lightS(), lightStrength); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_dotObj); + } + } + + // Release dot shader + m_dotShader->release(); + + // Bind background shader + m_backgroundShader->bind(); + + glCullFace(GL_BACK); + + // Draw background + if (m_cachedIsBackgroundEnabled && m_backgroundObj) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + QVector3D bgScale((aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, + backgroundMargin, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor); +#else // ..and this if we want uniform scaling based on largest dimension + QVector3D bgScale((aspectRatio * backgroundMargin), + backgroundMargin, + (aspectRatio * backgroundMargin)); +#endif + modelMatrix.translate(0.0f, 0.0f, zComp); + modelMatrix.scale(bgScale); + itModelMatrix.scale(bgScale); + // If we're viewing from below, background object must be flipped + if (m_yFlipped) { + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + modelMatrix.rotate(270.0f - backgroundRotation, 0.0f, 1.0f, 0.0f); + } else { + modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); + } + +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; +#else + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor); + + // Set shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos); + m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->nModel(), + itModelMatrix.inverted().transposed()); + m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor); + m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(), + m_cachedTheme.m_ambientStrength * 2.0f); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(), + m_shadowQualityToShader); + m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj); + } + } + + // Release background shader + m_backgroundShader->release(); + + // Disable textures + glDisable(GL_TEXTURE_2D); + + // Draw grid lines +#ifdef USE_UNIFORM_SCALING + AxisRenderCache *axisCacheMax; + if (m_axisCacheZ.max() > m_axisCacheX.max()) + axisCacheMax = &m_axisCacheZ; + else + axisCacheMax = &m_axisCacheX; +#endif + + if (m_cachedIsGridEnabled && m_heightNormalizer) { + ShaderHelper *lineShader = m_backgroundShader; + // Bind line shader + lineShader->bind(); + + // Set unchanging shader bindings + QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine); + lineShader->setUniformValue(lineShader->lightP(), lightPos); + lineShader->setUniformValue(lineShader->view(), viewMatrix); + lineShader->setUniformValue(lineShader->color(), lineColor); + lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength); + + // Rows (= Z) + if (m_axisCacheZ.segmentCount() > 0) { + // Floor lines +#ifndef USE_UNIFORM_SCALING + GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep(); + GLfloat linePos = -aspectRatio * m_axisCacheZ.min(); // Start line + int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); +#else + GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); + GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line + int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); +#endif + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_yFlipped) + modelMatrix.translate(0.0f, backgroundMargin, linePos / m_scaleFactor + zComp); + else + modelMatrix.translate(0.0f, -backgroundMargin, linePos / m_scaleFactor + zComp); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + modelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, + gridLineWidth, gridLineWidth)); + itModelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, + gridLineWidth, gridLineWidth)); +#else // ..and this if we want uniform scaling based on largest dimension + modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, + gridLineWidth, gridLineWidth)); +#endif + + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos -= lineStep; + } + + // Side wall lines +#ifndef USE_UNIFORM_SCALING + GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; + linePos = -aspectRatio * m_axisCacheZ.min(); // Start line +#else + GLfloat lineXTrans = aspectRatio * backgroundMargin; + linePos = -aspectRatio * m_scaleFactor; // Start line +#endif + if (!m_xFlipped) + lineXTrans = -lineXTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(lineXTrans, 0.0f, linePos / m_scaleFactor + zComp); + modelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth)); + itModelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos -= lineStep; + } + } + + // Columns (= X) + if (m_axisCacheX.segmentCount() > 0) { + // Floor lines +#ifndef USE_UNIFORM_SCALING + GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep(); + GLfloat linePos = aspectRatio * m_axisCacheX.min(); + int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); +#else + GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); + GLfloat linePos = -aspectRatio * m_scaleFactor; + int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); +#endif + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_yFlipped) + modelMatrix.translate(linePos / m_scaleFactor, backgroundMargin, zComp); + else + modelMatrix.translate(linePos / m_scaleFactor, -backgroundMargin, zComp); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + modelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + itModelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); +#else // ..and this if we want uniform scaling based on largest dimension + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); +#endif + + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + + // Back wall lines +#ifndef USE_UNIFORM_SCALING + GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; + linePos = aspectRatio * m_axisCacheX.min(); +#else + GLfloat lineZTrans = aspectRatio * backgroundMargin; + linePos = -aspectRatio * m_scaleFactor; +#endif + if (!m_zFlipped) + lineZTrans = -lineZTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(linePos / m_scaleFactor, 0.0f, lineZTrans + zComp); + modelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth)); + itModelMatrix.scale(QVector3D(gridLineWidth, backgroundMargin, gridLineWidth)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + } + + // Horizontal wall lines + if (m_axisCacheY.segmentCount() > 0) { + // Back wall + GLfloat lineStep = m_axisCacheY.subSegmentStep(); + GLfloat linePos = m_axisCacheY.min(); + int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; +#else // ..and this if we want uniform scaling based on largest dimension + GLfloat lineZTrans = aspectRatio * backgroundMargin; +#endif + if (!m_zFlipped) + lineZTrans = -lineZTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, linePos / m_heightNormalizer, lineZTrans + zComp); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + modelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), + gridLineWidth, gridLineWidth)); +#else // ..and this if we want uniform scaling based on largest dimension + modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, + gridLineWidth, gridLineWidth)); +#endif + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + + // Side wall + linePos = m_axisCacheY.min(); + lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; +#else // ..and this if we want uniform scaling based on largest dimension + GLfloat lineXTrans = aspectRatio * backgroundMargin; +#endif + if (!m_xFlipped) + lineXTrans = -lineXTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(lineXTrans, linePos / m_heightNormalizer, zComp); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + modelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + itModelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + +#else // ..and this if we want uniform scaling based on largest dimension + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin))); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); + +#endif + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + } + + // Release line shader + lineShader->release(); + } + + // Draw axis labels + // TODO: Calculations done temporarily here. Should be done when calculating lines to avoid + // extra for -loops? + // Bind label shader + m_labelShader->bind(); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Z Labels + if (m_axisCacheZ.segmentCount() > 0) { +#ifndef USE_UNIFORM_SCALING + GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep(); + GLfloat labelPos = -aspectRatio * m_axisCacheZ.min(); + int lastSegment = m_axisCacheZ.segmentCount(); +#else + GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); + GLfloat labelPos = aspectRatio * m_scaleFactor; + int lastSegment = axisCacheMax->segmentCount(); +#endif + int labelNbr = 0; + for (int segment = 0; segment <= lastSegment; segment++) { +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + if (m_axisCacheZ.labelItems().size() > labelNbr) { + GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor + labelMargin; +#else // ..and this if we want uniform scaling based on largest dimension + if (axisCacheMax->labelItems().size() > labelNbr) { + GLfloat labelXTrans = aspectRatio * backgroundMargin + labelMargin; +#endif + GLfloat labelYTrans = -backgroundMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 0.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + if (m_xFlipped) { + labelXTrans = -labelXTrans; + alignment = Qt::AlignLeft; + } + if (m_yFlipped) { + rotLabelZ += 180.0f; + rotLabelY += 180.0f; + labelYTrans = -labelYTrans; + } + QVector3D labelTrans = QVector3D(labelXTrans, + labelYTrans, + labelPos / m_scaleFactor + zComp); + + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); +#ifndef USE_UNIFORM_SCALING + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); +#else + const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); +#endif + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + labelNbr++; + labelPos -= posStep; + } + } + // X Labels + if (m_axisCacheX.segmentCount() > 0) { +#ifndef USE_UNIFORM_SCALING + GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep(); + GLfloat labelPos = aspectRatio * m_axisCacheX.min(); + int lastSegment = m_axisCacheX.segmentCount(); +#else + GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); + GLfloat labelPos = -aspectRatio * m_scaleFactor; + int lastSegment = axisCacheMax->segmentCount(); +#endif + int labelNbr = 0; + for (int segment = 0; segment <= lastSegment; segment++) { +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + if (m_axisCacheX.labelItems().size() > labelNbr) { + GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor + labelMargin; +#else // ..and this if we want uniform scaling based on largest dimension + if (axisCacheMax->labelItems().size() > labelNbr) { + GLfloat labelZTrans = aspectRatio * backgroundMargin + labelMargin; +#endif + GLfloat labelYTrans = -backgroundMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (m_xFlipped) + rotLabelY = -90.0f; + if (m_zFlipped) { + labelZTrans = -labelZTrans; + alignment = Qt::AlignRight; + } + if (m_yFlipped) { + rotLabelZ += 180.0f; + rotLabelY += 180.0f; + labelYTrans = -labelYTrans; + } + QVector3D labelTrans = QVector3D(labelPos / m_scaleFactor, + labelYTrans, + labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); +#ifndef USE_UNIFORM_SCALING + const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); +#else + const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); +#endif + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + labelNbr++; + labelPos += posStep; + } + } + // Y Labels + if (m_axisCacheY.segmentCount() > 0) { + GLfloat posStep = m_axisCacheY.segmentStep(); + GLfloat labelPos = m_axisCacheY.min(); + int labelNbr = 0; + for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + if (m_axisCacheY.labelItems().size() > labelNbr) { +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; + GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; +#else // ..and this if we want uniform scaling based on largest dimension + GLfloat labelXTrans = aspectRatio * backgroundMargin; + GLfloat labelZTrans = labelXTrans; +#endif + GLfloat labelMarginXTrans = labelMargin; + GLfloat labelMarginZTrans = labelMargin; + GLfloat labelYTrans = labelPos / m_heightNormalizer; + GLfloat rotLabelX = 0.0f; + GLfloat rotLabelY = -90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (!m_xFlipped) { + labelXTrans = -labelXTrans; + labelMarginXTrans = -labelMargin; + rotLabelY = 90.0f; + } + if (m_zFlipped) { + labelZTrans = -labelZTrans; + labelMarginZTrans = -labelMargin; + alignment = Qt::AlignRight; + } + + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + + // Back wall + QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, + labelZTrans + labelMarginZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + + // Side wall + if (m_xFlipped) + alignment = Qt::AlignLeft; + else + alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + else + rotLabelY = 0.0f; + + labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelYTrans, + -labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), true, true, Drawer::LabelMid, + alignment); + } + labelNbr++; + labelPos += posStep; + } + } + + // Handle selection clearing and selection label drawing + if (!dotSelectionFound) { + // We have no ownership, don't delete. Just NULL the pointer. + m_selectedItem = NULL; + } else { + glDisable(GL_DEPTH_TEST); + // Draw the selection label + LabelItem &labelItem = selectedItem->selectionLabelItem(); + if (m_selectedItem != selectedItem || m_updateLabels + || !labelItem.textureId()) { + QString labelText = selectedItem->selectionLabel(); + if (labelText.isNull()) { + static const QString xTitleTag(QStringLiteral("@xTitle")); + static const QString yTitleTag(QStringLiteral("@yTitle")); + static const QString zTitleTag(QStringLiteral("@zTitle")); + static const QString xLabelTag(QStringLiteral("@xLabel")); + static const QString yLabelTag(QStringLiteral("@yLabel")); + static const QString zLabelTag(QStringLiteral("@zLabel")); + + labelText = itemLabelFormat(); + + labelText.replace(xTitleTag, m_axisCacheX.title()); + labelText.replace(yTitleTag, m_axisCacheY.title()); + labelText.replace(zTitleTag, m_axisCacheZ.title()); + + if (labelText.contains(xLabelTag)) { + QString labelFormat = m_axisCacheX.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, + selectedItem->position().x()); + labelText.replace(xLabelTag, valueLabelText); + } + if (labelText.contains(yLabelTag)) { + QString labelFormat = m_axisCacheY.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, + selectedItem->position().y()); + labelText.replace(yLabelTag, valueLabelText); + } + if (labelText.contains(zLabelTag)) { + QString labelFormat = m_axisCacheZ.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, + selectedItem->position().z()); + labelText.replace(zLabelTag, valueLabelText); + } + + selectedItem->setSelectionLabel(labelText); + } + m_drawer->generateLabelItem(labelItem, labelText); + m_selectedItem = selectedItem; + } + + m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 0.0f, 0.0f), 0, + m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), true, false, + Drawer::LabelMid); + + // Reset label update flag; they should have been updated when we get here + m_updateLabels = false; + glEnable(GL_DEPTH_TEST); + } + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // Release label shader + m_labelShader->release(); +} + +void Scatter3DRenderer::updateSelectedItemIndex(int index) +{ + if (index == Scatter3DController::noSelectionIndex()) + m_selection = selectionSkipColor; + else + m_selection = indexToSelectionColor(index); +} + +void Scatter3DRenderer::handleResize() +{ + if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0) + return; + + // Set view port + m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + + Abstract3DRenderer::handleResize(); +} + +void Scatter3DRenderer::updateBackgroundEnabled(bool enable) +{ + if (enable != m_cachedIsBackgroundEnabled) { + Abstract3DRenderer::updateBackgroundEnabled(enable); + loadMeshFile(); // Load changed dot type + } +} + +void Scatter3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality) +{ + m_cachedShadowQuality = quality; + switch (quality) { + case QDataVis::ShadowQualityLow: + m_shadowQualityToShader = 33.3f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualityMedium: + m_shadowQualityToShader = 100.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualityHigh: + m_shadowQualityToShader = 200.0f; + m_shadowQualityMultiplier = 5; + break; + case QDataVis::ShadowQualitySoftLow: + m_shadowQualityToShader = 5.0f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualitySoftMedium: + m_shadowQualityToShader = 10.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualitySoftHigh: + m_shadowQualityToShader = 15.0f; + m_shadowQualityMultiplier = 4; + break; + default: + m_shadowQualityToShader = 0.0f; + m_shadowQualityMultiplier = 1; + break; + } + + handleShadowQualityChange(); + +#if !defined(QT_OPENGL_ES_2) + // Re-init depth buffer + updateDepthBuffer(); +#endif +} + +void Scatter3DRenderer::loadMeshFile() +{ + QString objectFileName = m_cachedObjFile; + if (m_dotObj) + delete m_dotObj; + m_dotObj = new ObjectHelper(objectFileName); + m_dotObj->load(); +} + +void Scatter3DRenderer::loadBackgroundMesh() +{ + if (m_backgroundObj) + delete m_backgroundObj; + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); + m_backgroundObj->load(); +} + +void Scatter3DRenderer::loadGridLineMesh() +{ + if (m_gridLineObj) + delete m_gridLineObj; + m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar")); + m_gridLineObj->load(); +} + +void Scatter3DRenderer::loadLabelMesh() +{ + if (m_labelObj) + delete m_labelObj; + m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); + m_labelObj->load(); +} + +void Scatter3DRenderer::updateTextures() +{ + // Drawer has changed; this flag needs to be checked when checking if we need to update labels + m_updateLabels = true; +} + +void Scatter3DRenderer::updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, + qreal min, qreal max) +{ + Abstract3DRenderer::updateAxisRange(orientation, min, max); +} + +void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item) +{ + // Origin should be in the center of scene, ie. both positive and negative values are drawn + // above background + + // We need to normalize translations + GLfloat xTrans = (aspectRatio * item.position().x()) / m_scaleFactor; + GLfloat zTrans = -(aspectRatio * item.position().z()) / m_scaleFactor; + GLfloat yTrans = item.position().y() / m_heightNormalizer; + item.setTranslation(QVector3D(xTrans, yTrans, zTrans + zComp)); + //qDebug() << item.translation(); +} + +void Scatter3DRenderer::calculateSceneScalingFactors() +{ + m_heightNormalizer = (GLfloat)qMax(qAbs(m_axisCacheY.max()), qAbs(m_axisCacheY.min())); + m_areaSize.setHeight(qMax(qAbs(m_axisCacheZ.max()), qAbs(m_axisCacheZ.min()))); + m_areaSize.setWidth(qMax(qAbs(m_axisCacheX.max()), qAbs(m_axisCacheX.min()))); + m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); + //qDebug() << m_heightNormalizer << m_areaSize << m_scaleFactor << m_axisCacheY.max() << m_axisCacheX.max() << m_axisCacheZ.max(); +} + +QRect Scatter3DRenderer::mainViewPort() +{ + return m_mainViewPort; +} + +void Scatter3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_dotShader) + delete m_dotShader; + m_dotShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_dotShader->initialize(); +} + +void Scatter3DRenderer::initSelectionShader() +{ + if (m_selectionShader) + delete m_selectionShader; + m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSelection"), + QStringLiteral(":/shaders/fragmentSelection")); + m_selectionShader->initialize(); +} + +void Scatter3DRenderer::initSelectionBuffer() +{ + if (m_selectionTexture) + m_textureHelper->deleteTexture(&m_selectionTexture); + + m_selectionTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(), + m_selectionFrameBuffer, + m_selectionDepthBuffer); +} + +#if !defined(QT_OPENGL_ES_2) +void Scatter3DRenderer::initDepthShader() +{ + if (m_depthShader) + delete m_depthShader; + m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), + QStringLiteral(":/shaders/fragmentDepth")); + m_depthShader->initialize(); +} + +void Scatter3DRenderer::updateDepthBuffer() +{ + if (m_depthTexture) { + m_textureHelper->deleteTexture(&m_depthTexture); + m_depthTexture = 0; + } + + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(), + m_depthFrameBuffer, + m_shadowQualityMultiplier); + if (!m_depthTexture) { + switch (m_cachedShadowQuality) { + case QDataVis::ShadowQualityHigh: + qWarning("Creating high quality shadows failed. Changing to medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium); + updateShadowQuality(QDataVis::ShadowQualityMedium); + break; + case QDataVis::ShadowQualityMedium: + qWarning("Creating medium quality shadows failed. Changing to low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow); + updateShadowQuality(QDataVis::ShadowQualityLow); + break; + case QDataVis::ShadowQualityLow: + qWarning("Creating low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + case QDataVis::ShadowQualitySoftHigh: + qWarning("Creating soft high quality shadows failed. Changing to soft medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium); + updateShadowQuality(QDataVis::ShadowQualitySoftMedium); + break; + case QDataVis::ShadowQualitySoftMedium: + qWarning("Creating soft medium quality shadows failed. Changing to soft low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow); + updateShadowQuality(QDataVis::ShadowQualitySoftLow); + break; + case QDataVis::ShadowQualitySoftLow: + qWarning("Creating soft low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + default: + // You'll never get here + break; + } + } + } +} +#endif + +void Scatter3DRenderer::initBackgroundShaders(const QString &vertexShader, + const QString &fragmentShader) +{ + if (m_backgroundShader) + delete m_backgroundShader; + m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_backgroundShader->initialize(); +} + +void Scatter3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_labelShader) + delete m_labelShader; + m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_labelShader->initialize(); +} + +QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index) +{ + GLubyte dotIdxRed = index & 0xff; + GLubyte dotIdxGreen = (index & 0xff00) >> 8; + GLubyte dotIdxBlue = (index & 0xff0000) >> 16; + + return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue); +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h new file mode 100644 index 00000000..f444f891 --- /dev/null +++ b/src/datavisualization/engine/scatter3drenderer_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSCATTERRENDERER_P_H +#define Q3DSCATTERRENDERER_P_H + +#include "datavisualizationglobal_p.h" +#include "scatter3dcontroller_p.h" +#include "abstract3drenderer_p.h" +#include "qscatterdataproxy.h" +#include "scatterrenderitem_p.h" + +class QPoint; +class QSizeF; +class QOpenGLShaderProgram; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class ShaderHelper; +class ObjectHelper; +class LabelItem; +class Q3DScene; +class QAbstractAxisPrivate; + +class QT_DATAVISUALIZATION_EXPORT Scatter3DRenderer : public Abstract3DRenderer +{ + Q_OBJECT + +private: + // TODO: Filter to the set of attributes to be moved to the model object. + // * All GL rendering only related attribs should be moved out of this public set. + // * All attribs that are modifiable from QML need to e in this set. + + Scatter3DController *m_controller; + + // Internal state + ScatterRenderItem *m_selectedItem; // points to renderitem array + bool m_xFlipped; + bool m_zFlipped; + bool m_yFlipped; + QRect m_mainViewPort; + bool m_updateLabels; + ShaderHelper *m_dotShader; + ShaderHelper *m_depthShader; + ShaderHelper *m_selectionShader; + ShaderHelper *m_backgroundShader; + ShaderHelper *m_labelShader; + ObjectHelper *m_dotObj; + ObjectHelper *m_backgroundObj; + ObjectHelper *m_gridLineObj; + ObjectHelper *m_labelObj; + GLuint m_bgrTexture; + GLuint m_depthTexture; + GLuint m_selectionTexture; + GLuint m_depthFrameBuffer; + GLuint m_selectionFrameBuffer; + GLuint m_selectionDepthBuffer; + GLfloat m_shadowQualityToShader; + GLint m_shadowQualityMultiplier; + GLfloat m_heightNormalizer; + GLfloat m_scaleFactor; + QVector3D m_selection; + QVector3D m_previousSelection; + QSizeF m_areaSize; + GLfloat m_dotSizeScale; + + bool m_hasHeightAdjustmentChanged; + ScatterRenderItem m_dummyRenderItem; + + ScatterRenderItemArray m_renderItemArray; + +public: + explicit Scatter3DRenderer(Scatter3DController *controller); + ~Scatter3DRenderer(); + + void updateDataModel(QScatterDataProxy *dataProxy); + void updateScene(Q3DScene *scene); + void render(GLuint defaultFboHandle); + + QRect mainViewPort(); + +protected: + virtual void initializeOpenGL(); + virtual void loadMeshFile(); + +private: + virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); + virtual void updateShadowQuality(QDataVis::ShadowQuality quality); + virtual void updateTextures(); + + void drawScene(GLuint defaultFboHandle); + void handleResize(); + + void loadBackgroundMesh(); + void loadGridLineMesh(); + void loadLabelMesh(); + void initSelectionShader(); + void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader); + void initLabelShaders(const QString &vertexShader, const QString &fragmentShader); + void initSelectionBuffer(); +#if !defined(QT_OPENGL_ES_2) + void initDepthShader(); + void updateDepthBuffer(); +#endif + void calculateTranslation(ScatterRenderItem &item); + void calculateSceneScalingFactors(); + + Q_DISABLE_COPY(Scatter3DRenderer) + + friend class ScatterRenderItem; + +public slots: + void updateBackgroundEnabled(bool enable); + + // Overloaded from abstract renderer + virtual void updateAxisRange(Q3DAbstractAxis::AxisOrientation orientation, qreal min, qreal max); + + void updateSelectedItemIndex(int index); + +signals: + void selectionUpdated(QVector3D selection); + void selectedItemIndexChanged(int index); + +private: + QVector3D indexToSelectionColor(GLint index); +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/engine/selectionpointer.cpp b/src/datavisualization/engine/selectionpointer.cpp new file mode 100644 index 00000000..6c3e0c8b --- /dev/null +++ b/src/datavisualization/engine/selectionpointer.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "selectionpointer_p.h" +#include "surface3dcontroller_p.h" +#include "shaderhelper_p.h" +#include "objecthelper_p.h" +#include "texturehelper_p.h" +#include "q3dcamera.h" +#include "q3dcamera_p.h" +#include "drawer_p.h" +#include "utils_p.h" +#include "q3dlight.h" + +#include <QImage> +#include <QMatrix4x4> + +#include <QDebug> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +const GLfloat sliceUnits = 2.5; + +SelectionPointer::SelectionPointer(Drawer *drawer) + : QObject(0), + m_labelShader(0), + m_pointShader(0), + m_labelObj(0), + m_pointObj(0), + m_textureHelper(0), + m_isInitialized(false), + m_cachedTheme(drawer->theme()), + m_labelStyle(QDataVis::LabelStyleFromTheme), + m_drawer(drawer), + m_cachedScene(0) +{ + initializeOpenGL(); + + QObject::connect(m_drawer, &Drawer::drawerChanged, + this, &SelectionPointer::handleDrawerChange); +} + +SelectionPointer::~SelectionPointer() +{ + delete m_labelShader; + delete m_pointShader; + delete m_labelObj; + delete m_pointObj; + delete m_textureHelper; +} + +void SelectionPointer::initializeOpenGL() +{ + if (m_isInitialized) + return; + + initializeOpenGLFunctions(); + + m_textureHelper = new TextureHelper(); + m_drawer->initializeOpenGL(); + + initShaders(); + + loadLabelMesh(); + loadPointMesh(); + + // Set initialized -flag + m_isInitialized = true; +} + +void SelectionPointer::updateScene(Q3DScene *scene) +{ + m_cachedScene = scene; +} + +void SelectionPointer::render(GLuint defaultFboHandle) +{ + Q_UNUSED(defaultFboHandle) + + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + Q3DCamera *camera = m_cachedScene->activeCamera(); + QSize textureSize = m_labelItem.size(); + + QMatrix4x4 itModelMatrix; + + // Get view matrix + QMatrix4x4 viewMatrix; + QMatrix4x4 projectionMatrix; + if (m_cachedIsSlicingActivated) { + GLfloat aspect = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height(); + viewMatrix.lookAt(QVector3D(0.0f, 0.0f, zComp + 1.0), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + projectionMatrix.ortho(-sliceUnits * aspect, sliceUnits * aspect, + -sliceUnits, sliceUnits, -1.0f, 14.0f); + } else { + viewMatrix = camera->viewMatrix(); + projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f); + } + + // Calculate scale factor to get uniform font size + GLfloat scaledFontSize = 0.05f + m_drawer->font().pointSizeF() / 500.0f; + GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height(); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + // Position the pointer ball + modelMatrix.translate(m_position + QVector3D(0.0f, 0.0f, zComp)); + + // Scale the point with fixed values (at this point) + modelMatrix.scale(QVector3D(0.05f, 0.05f, 0.05f)); + + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + + // Enable texturing + glEnable(GL_TEXTURE_2D); + + QVector3D lightPos = m_cachedScene->activeLight()->position(); + + // + // Draw the point + // + m_pointShader->bind(); + m_pointShader->setUniformValue(m_pointShader->lightP(), lightPos); + m_pointShader->setUniformValue(m_pointShader->view(), viewMatrix); + m_pointShader->setUniformValue(m_pointShader->model(), modelMatrix); + m_pointShader->setUniformValue(m_pointShader->nModel(), itModelMatrix.inverted().transposed()); + m_pointShader->setUniformValue(m_pointShader->color(), + Utils::vectorFromColor(m_cachedTheme.m_highlightBarColor)); + m_pointShader->setUniformValue(m_pointShader->MVP(), MVPMatrix); + m_pointShader->setUniformValue(m_pointShader->ambientS(), m_cachedTheme.m_ambientStrength); + m_pointShader->setUniformValue(m_pointShader->lightS(), m_cachedTheme.m_lightStrength * 2.0f); + + m_drawer->drawObject(m_pointShader, m_pointObj); + + m_pointShader->release(); + + // + // Draw the label + // + QMatrix4x4 modelMatrixLabel; + + // Position label + QVector3D labelAlign(0.0f, 1.0f * scaledFontSize + 0.05f, 0.0f); + modelMatrixLabel.translate(m_position + labelAlign + QVector3D(0.0f, 0.0f, zComp)); + + // Position the label towards the camera + qreal camRotationsX = camera->xRotation(); + qreal camRotationsY = camera->yRotation(); + if (!m_cachedIsSlicingActivated) { + modelMatrixLabel.rotate(-camRotationsX, 0.0f, 1.0f, 0.0f); + modelMatrixLabel.rotate(-camRotationsY, 1.0f, 0.0f, 0.0f); + } + + // Scale label based on text size + modelMatrixLabel.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor, + scaledFontSize, + 0.0f)); + + // Make label to be always on top + glDisable(GL_DEPTH_TEST); + + // Make label transparent + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + m_labelShader->bind(); + + // Set shader bindings + MVPMatrix = projectionMatrix * viewMatrix * modelMatrixLabel; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + + // Draw the object + m_drawer->drawObject(m_labelShader, m_labelObj, m_labelItem.textureId()); + + m_labelShader->release(); + + // Disable textures + glDisable(GL_TEXTURE_2D); + + // Disable transparency + glDisable(GL_BLEND); + + // Depth test back to normal + glEnable(GL_DEPTH_TEST); +} + +void SelectionPointer::setPosition(QVector3D position) +{ + m_position = position; +} + +void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment) +{ + m_cachedIsSlicingActivated = sliceActivated; + m_autoScaleAdjustment = autoScaleAdjustment; +} + +void SelectionPointer::setLabel(QString label) +{ + m_label = label; + + m_drawer->generateLabelItem(m_labelItem, m_label); +} + +void SelectionPointer::handleDrawerChange() +{ + m_cachedTheme = m_drawer->theme(); + setLabel(m_label); +} + +void SelectionPointer::updateBoundingRect(QRect rect) +{ + m_mainViewPort = rect; +} + +void SelectionPointer::initShaders() +{ + // The shader for printing the text label + if (m_labelShader) + delete m_labelShader; + m_labelShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + m_labelShader->initialize(); + + // The shader for the small point ball + if (m_pointShader) + delete m_pointShader; +#if defined (Q_OS_ANDROID) + m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexES2"), + QStringLiteral(":/shaders/fragmentES2")); +#else + m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"), + QStringLiteral(":/shaders/fragment")); +#endif + m_pointShader->initialize(); + +} + +void SelectionPointer::loadLabelMesh() +{ + if (m_labelObj) + delete m_labelObj; + m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); + m_labelObj->load(); +} + +void SelectionPointer::loadPointMesh() +{ + if (m_pointObj) + delete m_pointObj; + m_pointObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/sphereSmooth")); + m_pointObj->load(); +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/selectionpointer_p.h b/src/datavisualization/engine/selectionpointer_p.h new file mode 100644 index 00000000..0e766035 --- /dev/null +++ b/src/datavisualization/engine/selectionpointer_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef NOTIFICATIONLABEL_P_H +#define NOTIFICATIONLABEL_P_H + +#include <QtCore/QObject> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QFont> +#include <QWindow> +#include <QVector3D> + +#include "q3dscene.h" +#include "datavisualizationglobal_p.h" +#include "surface3dcontroller_p.h" + +class QOpenGLShaderProgram; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class ShaderHelper; +class ObjectHelper; +class SurfaceObject; +class TextureHelper; +class Theme; +class Drawer; +class Q3DCamera; + +class QT_DATAVISUALIZATION_EXPORT SelectionPointer : public QObject, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + explicit SelectionPointer(Drawer *drawer); + ~SelectionPointer(); + + void initializeOpenGL(); + void render(GLuint defaultFboHandle = 0); + void setPosition(QVector3D position); + void setLabel(QString label); + void handleDrawerChange(); + void updateBoundingRect(QRect rect); + void updateScene(Q3DScene *scene); + void updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment); + +private: + void initShaders(); + void loadLabelMesh(); + void loadPointMesh(); + +private: + ShaderHelper *m_labelShader; + ShaderHelper *m_pointShader; + ObjectHelper *m_labelObj; + ObjectHelper *m_pointObj; + TextureHelper *m_textureHelper; + bool m_isInitialized; + Theme m_cachedTheme; + QDataVis::LabelStyle m_labelStyle; + LabelItem m_labelItem; + Drawer *m_drawer; + QRect m_mainViewPort; + QVector3D m_position; + Q3DScene *m_cachedScene; + QString m_label; + bool m_cachedIsSlicingActivated; + GLfloat m_autoScaleAdjustment; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // NOTIFICATIONLABEL_P_H diff --git a/src/datavisualization/engine/shaders/ambient.frag b/src/datavisualization/engine/shaders/ambient.frag new file mode 100644 index 00000000..88f850f3 --- /dev/null +++ b/src/datavisualization/engine/shaders/ambient.frag @@ -0,0 +1,32 @@ +#version 120 + +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +void main() { + highp vec3 lightColor = vec3(1.0, 1.0, 1.0); + highp float lightPower = 10.0; + highp vec3 materialAmbientColor = vec3(0.5, 0.5, 0.5) * color_mdl; + highp vec3 materialSpecularColor = vec3(0.3, 0.3, 0.3) * color_mdl; + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialSpecularColor * lightColor * lightPower * pow(cosAlpha, 5) / (distance * distance); + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/colorOnY.frag b/src/datavisualization/engine/shaders/colorOnY.frag new file mode 100644 index 00000000..80e54a61 --- /dev/null +++ b/src/datavisualization/engine/shaders/colorOnY.frag @@ -0,0 +1,36 @@ +#version 120 + +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec2 coords_mdl; + +void main() { + highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom + highp vec3 materialDiffuseColor = heightMod * color_mdl; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance + + materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance; + gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0); + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/colorOnY_ES2.frag b/src/datavisualization/engine/shaders/colorOnY_ES2.frag new file mode 100644 index 00000000..aba52cfe --- /dev/null +++ b/src/datavisualization/engine/shaders/colorOnY_ES2.frag @@ -0,0 +1,37 @@ +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec2 coords_mdl; + +void main() { + highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom + highp vec3 materialDiffuseColor = heightMod * color_mdl; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = dot(n, l); + if (cosTheta < 0.0) cosTheta = 0.0; + else if (cosTheta > 1.0) cosTheta = 1.0; + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = dot(E, R); + if (cosAlpha < 0.0) cosAlpha = 0.0; + else if (cosAlpha > 1.0) cosAlpha = 1.0; + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance + + materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/default.frag b/src/datavisualization/engine/shaders/default.frag new file mode 100644 index 00000000..fba1ce4a --- /dev/null +++ b/src/datavisualization/engine/shaders/default.frag @@ -0,0 +1,36 @@ +#version 120 + +varying highp vec2 UV; +varying highp vec2 coords_mdl; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +void main() { + highp vec3 materialDiffuseColor = color_mdl.rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance + + materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/default.vert b/src/datavisualization/engine/shaders/default.vert new file mode 100644 index 00000000..14f77773 --- /dev/null +++ b/src/datavisualization/engine/shaders/default.vert @@ -0,0 +1,28 @@ +#version 120 + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec2 vertexUV; +attribute highp vec3 vertexNormal_mdl; + +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp vec3 lightPosition_wrld; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec2 coords_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + coords_mdl = vertexPosition_mdl.xy; + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz; + lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; +} diff --git a/src/datavisualization/engine/shaders/default_ES2.frag b/src/datavisualization/engine/shaders/default_ES2.frag new file mode 100644 index 00000000..7d6214b2 --- /dev/null +++ b/src/datavisualization/engine/shaders/default_ES2.frag @@ -0,0 +1,38 @@ +varying highp vec2 UV; +varying highp vec2 coords_mdl; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +void main() { + highp vec3 materialDiffuseColor = color_mdl.rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = dot(n, l); + if (cosTheta < 0.0) cosTheta = 0.0; + else if (cosTheta > 1.0) cosTheta = 1.0; + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = dot(E, R); + if (cosAlpha < 0.0) cosAlpha = 0.0; + else if (cosAlpha > 1.0) cosAlpha = 1.0; + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance + + materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/default_ES2.vert b/src/datavisualization/engine/shaders/default_ES2.vert new file mode 100644 index 00000000..efb40862 --- /dev/null +++ b/src/datavisualization/engine/shaders/default_ES2.vert @@ -0,0 +1,26 @@ +attribute highp vec3 vertexPosition_mdl; +attribute highp vec2 vertexUV; +attribute highp vec3 vertexNormal_mdl; + +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp vec3 lightPosition_wrld; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec2 coords_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + coords_mdl = vertexPosition_mdl.xy; + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz; + lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; +} diff --git a/src/datavisualization/engine/shaders/depth.frag b/src/datavisualization/engine/shaders/depth.frag new file mode 100644 index 00000000..5cfd4b10 --- /dev/null +++ b/src/datavisualization/engine/shaders/depth.frag @@ -0,0 +1,3 @@ +void main() { + gl_FragDepth = gl_FragCoord.z; +} diff --git a/src/datavisualization/engine/shaders/depth.vert b/src/datavisualization/engine/shaders/depth.vert new file mode 100644 index 00000000..9fe5a193 --- /dev/null +++ b/src/datavisualization/engine/shaders/depth.vert @@ -0,0 +1,8 @@ +uniform highp mat4 MVP; + +attribute highp vec3 vertexPosition_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); +} + diff --git a/src/datavisualization/engine/shaders/label.frag b/src/datavisualization/engine/shaders/label.frag new file mode 100644 index 00000000..86021410 --- /dev/null +++ b/src/datavisualization/engine/shaders/label.frag @@ -0,0 +1,8 @@ +uniform sampler2D textureSampler; + +varying highp vec2 UV; + +void main() { + gl_FragColor = texture2D(textureSampler, UV); +} + diff --git a/src/datavisualization/engine/shaders/label.vert b/src/datavisualization/engine/shaders/label.vert new file mode 100644 index 00000000..b4debe53 --- /dev/null +++ b/src/datavisualization/engine/shaders/label.vert @@ -0,0 +1,11 @@ +uniform highp mat4 MVP; + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec2 vertexUV; + +varying highp vec2 UV; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + UV = vertexUV; +} diff --git a/src/datavisualization/engine/shaders/selection.frag b/src/datavisualization/engine/shaders/selection.frag new file mode 100644 index 00000000..099c87a1 --- /dev/null +++ b/src/datavisualization/engine/shaders/selection.frag @@ -0,0 +1,7 @@ +uniform highp vec3 color_mdl; + +void main() { + gl_FragColor.rgb = color_mdl; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/selection.vert b/src/datavisualization/engine/shaders/selection.vert new file mode 100644 index 00000000..64d17e15 --- /dev/null +++ b/src/datavisualization/engine/shaders/selection.vert @@ -0,0 +1,7 @@ +uniform highp mat4 MVP; + +attribute highp vec3 vertexPosition_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); +} diff --git a/src/datavisualization/engine/shaders/shadow.frag b/src/datavisualization/engine/shaders/shadow.frag new file mode 100644 index 00000000..5309b5bb --- /dev/null +++ b/src/datavisualization/engine/shaders/shadow.frag @@ -0,0 +1,82 @@ +#version 120 + +uniform highp float lightStrength; +uniform highp float ambientStrength; +uniform highp float shadowQuality; +uniform highp sampler2D textureSampler; +uniform highp sampler2DShadow shadowMap; + +varying highp vec4 shadowCoord; +varying highp vec2 UV; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216), + vec2(0.94558609, -0.76890725), + vec2(-0.094184101, -0.92938870), + vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), + vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), + vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), + vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), + vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), + vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), + vec2(0.14383161, -0.14100790)); + +/*float random(vec3 seed, int i) { + vec4 seed4 = vec4(seed, i); + float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673)); + return fract(sin(dot_product) * 43758.5453); +}*/ + +void main() { + highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(0.2, 0.2, 0.2); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + highp float bias = 0.005 * tan(acos(cosTheta)); + bias = clamp(bias, 0.0, 0.01); + + vec4 shadCoords = shadowCoord; + shadCoords.z -= bias; + // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1) + // direct method; needs large shadow texture to look good + //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25; + // poisson disk sampling; smoothes edges + highp float visibility = 0.6; + for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality; + shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality; + visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r; + } + // stratified poisson; produces noise but hides pixel edges well + /*for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + int index = int(16.0 * random(gl_FragCoord.xyy, i)); + shadCoordsPD.xy += poissonDisk[index] / 150.0; + visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r; + } + */ + + gl_FragColor.rgb = + visibility * (materialAmbientColor + + materialDiffuseColor * lightStrength * cosTheta + + materialSpecularColor * lightStrength * pow(cosAlpha, 10)); + gl_FragColor.a = texture2D(textureSampler, UV).a; +} diff --git a/src/datavisualization/engine/shaders/shadow.vert b/src/datavisualization/engine/shaders/shadow.vert new file mode 100644 index 00000000..e29a8a30 --- /dev/null +++ b/src/datavisualization/engine/shaders/shadow.vert @@ -0,0 +1,37 @@ +#version 120 + +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp mat4 depthMVP; +uniform highp vec3 lightPosition_wrld; + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec3 vertexNormal_mdl; +attribute highp vec2 vertexUV; + +varying highp vec2 UV; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec4 shadowCoord; +varying highp vec2 coords_mdl; + +const highp mat4 bias = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + coords_mdl = vertexPosition_mdl.xy; + shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0); + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + lightDirection_cmr = (V * vec4(lightPosition_wrld, 0.0)).xyz; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; + UV = vertexUV; +} diff --git a/src/datavisualization/engine/shaders/shadowNoTex.frag b/src/datavisualization/engine/shaders/shadowNoTex.frag new file mode 100644 index 00000000..0252ba49 --- /dev/null +++ b/src/datavisualization/engine/shaders/shadowNoTex.frag @@ -0,0 +1,98 @@ +#version 120 + +uniform highp float lightStrength; +uniform highp float ambientStrength; +uniform highp float shadowQuality; +uniform highp vec3 color_mdl; +uniform highp sampler2DShadow shadowMap; + +varying highp vec4 shadowCoord; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216), + vec2(0.94558609, -0.76890725), + vec2(-0.094184101, -0.92938870), + vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), + vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), + vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), + vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), + vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), + vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), + vec2(0.14383161, -0.14100790)); + +/*highp vec2 poissonDisk[16] = vec2[16](vec2(-0.25, -0.25), + vec2(0.25, -0.25), + vec2(-0.25, 0.25), + vec2(0.25, 0.25), + vec2(-0.5, -0.5), + vec2(0.5, -0.5), + vec2(-0.5, 0.5), + vec2(0.5, 0.5), + vec2(-0.75, -0.75), + vec2(0.75, -0.75), + vec2(-0.75, 0.75), + vec2(0.75, 0.75), + vec2(-1.0, -1.0), + vec2(1.0, -1.0), + vec2(-1.0, 1.0), + vec2(1.0, 1.0));*/ + +/*float random(vec3 seed, int i) { + vec4 seed4 = vec4(seed, i); + float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673)); + return fract(sin(dot_product) * 43758.5453); +}*/ + +void main() { + highp vec3 materialDiffuseColor = color_mdl.rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + highp float bias = 0.005 * tan(acos(cosTheta)); + bias = clamp(bias, 0.0, 0.01); + + vec4 shadCoords = shadowCoord; + shadCoords.z -= bias; + // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1) + // direct method; needs large shadow texture to look good + //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25; + // poisson disk sampling; smoothes edges + highp float visibility = 0.6; + for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality; + shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality; + visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r; + } + // stratified poisson; produces noise but hides pixel edges well + /*for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + int index = int(16.0 * random(gl_FragCoord.xyy, i)); + shadCoordsPD.xy += poissonDisk[index] / 150.0; + visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r; + } + */ + + gl_FragColor.rgb = + visibility * (materialAmbientColor + + materialDiffuseColor * lightStrength * cosTheta + + materialSpecularColor * lightStrength * pow(cosAlpha, 10)); + gl_FragColor.a = 1.0; +} diff --git a/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag new file mode 100644 index 00000000..68ba2368 --- /dev/null +++ b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag @@ -0,0 +1,82 @@ +#version 120 + +uniform highp float lightStrength; +uniform highp float ambientStrength; +uniform highp float shadowQuality; +uniform highp vec3 color_mdl; +uniform highp sampler2DShadow shadowMap; + +varying highp vec4 shadowCoord; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec2 coords_mdl; + +highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216), + vec2(0.94558609, -0.76890725), + vec2(-0.094184101, -0.92938870), + vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), + vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), + vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), + vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), + vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), + vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), + vec2(0.14383161, -0.14100790)); + +/*float random(vec3 seed, int i) { + vec4 seed4 = vec4(seed, i); + float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673)); + return fract(sin(dot_product) * 43758.5453); +}*/ + +void main() { + highp float heightMod = (coords_mdl.y * 0.3) + 0.7; // Add 30% black to the bottom + highp vec3 materialDiffuseColor = heightMod * color_mdl; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + highp float bias = 0.005 * tan(acos(cosTheta)); + bias = clamp(bias, 0.0, 0.01); + + vec4 shadCoords = shadowCoord; + shadCoords.z -= bias; + // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1) + // direct method; needs large shadow texture to look good + //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25; + // poisson disk sampling; smoothes edges + highp float visibility = 0.6; + for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality; + shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality; + visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r; + } + /*for (int i = 0; i < 15; i++) { + vec4 shadCoordsPD = shadCoords; + int index = int(16.0 * random(gl_FragCoord.xyy, i)); + shadCoordsPD.xy += poissonDisk[index] / 150.0; + visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r; + }*/ + + gl_FragColor.rgb = + visibility * (materialAmbientColor + + materialDiffuseColor * lightStrength * cosTheta + + materialSpecularColor * lightStrength * pow(cosAlpha, 10)); + gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0); + gl_FragColor.a = 1.0; +} diff --git a/src/datavisualization/engine/shaders/surface.frag b/src/datavisualization/engine/shaders/surface.frag new file mode 100644 index 00000000..4b1357b1 --- /dev/null +++ b/src/datavisualization/engine/shaders/surface.frag @@ -0,0 +1,36 @@ +#version 120 + +varying highp vec3 coords_mdl; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +uniform sampler2D textureSampler; +uniform highp vec3 lightPosition_wrld; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +void main() { + highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.001) / 2.0); // 1000 pixel texture, we need a margin for 1/1000 rounding error + highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance + + materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/surface.vert b/src/datavisualization/engine/shaders/surface.vert new file mode 100644 index 00000000..28152abc --- /dev/null +++ b/src/datavisualization/engine/shaders/surface.vert @@ -0,0 +1,25 @@ +attribute highp vec3 vertexPosition_mdl; +attribute highp vec3 vertexNormal_mdl; + +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp vec3 lightPosition_wrld; + +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec3 coords_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + coords_mdl = vertexPosition_mdl; + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz; + lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; +} diff --git a/src/datavisualization/engine/shaders/surfaceFlat.frag b/src/datavisualization/engine/shaders/surfaceFlat.frag new file mode 100644 index 00000000..a8a3dbb1 --- /dev/null +++ b/src/datavisualization/engine/shaders/surfaceFlat.frag @@ -0,0 +1,36 @@ +#version 150 + +varying highp vec3 coords_mdl; +varying highp vec3 position_wrld; +flat in highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +uniform sampler2D textureSampler; +uniform highp vec3 lightPosition_wrld; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +void main() { + highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.001) / 2.0); // 1000 pixel texture, we need a margin for 1/1000 rounding error + highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance + + materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/surfaceFlat.vert b/src/datavisualization/engine/shaders/surfaceFlat.vert new file mode 100644 index 00000000..7e248d02 --- /dev/null +++ b/src/datavisualization/engine/shaders/surfaceFlat.vert @@ -0,0 +1,27 @@ +#version 150 + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec3 vertexNormal_mdl; + +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp vec3 lightPosition_wrld; + +varying highp vec3 position_wrld; +flat out highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; +varying highp vec3 coords_mdl; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + coords_mdl = vertexPosition_mdl; + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz; + lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; +} diff --git a/src/datavisualization/engine/shaders/surfaceGrid.frag b/src/datavisualization/engine/shaders/surfaceGrid.frag new file mode 100644 index 00000000..1658b316 --- /dev/null +++ b/src/datavisualization/engine/shaders/surfaceGrid.frag @@ -0,0 +1,6 @@ +uniform highp vec3 color_mdl; + +void main() { + gl_FragColor.rgb = color_mdl; +} + diff --git a/src/datavisualization/engine/shaders/surfaceGrid.vert b/src/datavisualization/engine/shaders/surfaceGrid.vert new file mode 100644 index 00000000..5582d633 --- /dev/null +++ b/src/datavisualization/engine/shaders/surfaceGrid.vert @@ -0,0 +1,6 @@ +attribute highp vec3 vertexPosition_mdl; +uniform highp mat4 MVP; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); +} diff --git a/src/datavisualization/engine/shaders/surface_ES2.frag b/src/datavisualization/engine/shaders/surface_ES2.frag new file mode 100644 index 00000000..a9aec528 --- /dev/null +++ b/src/datavisualization/engine/shaders/surface_ES2.frag @@ -0,0 +1,39 @@ +varying highp vec2 UV; +varying highp vec3 coords_mdl; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +uniform sampler2D textureSampler; +uniform highp vec3 lightPosition_wrld; +uniform highp float lightStrength; +uniform highp float ambientStrength; + +void main() { + highp vec2 gradientUV = vec2(0.5, (coords_mdl.y + 1.0) / 2.0); + highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = dot(n, l); + if (cosTheta < 0.0) cosTheta = 0.0; + else if (cosTheta > 1.0) cosTheta = 1.0; + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = dot(E, R); + if (cosAlpha < 0.0) cosAlpha = 0.0; + else if (cosAlpha > 1.0) cosAlpha = 1.0; + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * cosTheta * cosTheta / distance + + materialSpecularColor * lightStrength * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha / distance; + gl_FragColor.a = 1.0; +} + diff --git a/src/datavisualization/engine/shaders/texture.frag b/src/datavisualization/engine/shaders/texture.frag new file mode 100644 index 00000000..a6d7b2eb --- /dev/null +++ b/src/datavisualization/engine/shaders/texture.frag @@ -0,0 +1,35 @@ +#version 120 + +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; +uniform sampler2D textureSampler; + +varying highp vec2 UV; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +void main() { + highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = clamp(dot(n, l), 0.0, 1.0); + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0); + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance + + materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance; + gl_FragColor.a = texture2D(textureSampler, UV).a; +} + diff --git a/src/datavisualization/engine/shaders/texture.vert b/src/datavisualization/engine/shaders/texture.vert new file mode 100644 index 00000000..01f922e0 --- /dev/null +++ b/src/datavisualization/engine/shaders/texture.vert @@ -0,0 +1,26 @@ +uniform highp mat4 MVP; +uniform highp mat4 V; +uniform highp mat4 M; +uniform highp mat4 itM; +uniform highp vec3 lightPosition_wrld; + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec2 vertexUV; +attribute highp vec3 vertexNormal_mdl; + +varying highp vec2 UV; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz; + vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz; + eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr; + vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz; + lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr; + normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz; + UV = vertexUV; +} diff --git a/src/datavisualization/engine/shaders/texture_ES2.frag b/src/datavisualization/engine/shaders/texture_ES2.frag new file mode 100644 index 00000000..58097ba5 --- /dev/null +++ b/src/datavisualization/engine/shaders/texture_ES2.frag @@ -0,0 +1,37 @@ +uniform highp vec3 lightPosition_wrld; +uniform highp vec3 color_mdl; +uniform highp float lightStrength; +uniform highp float ambientStrength; +uniform sampler2D textureSampler; + +varying highp vec2 UV; +varying highp vec3 position_wrld; +varying highp vec3 normal_cmr; +varying highp vec3 eyeDirection_cmr; +varying highp vec3 lightDirection_cmr; + +void main() { + highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb; + highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor; + highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0); + + highp float distance = length(lightPosition_wrld - position_wrld); + highp vec3 n = normalize(normal_cmr); + highp vec3 l = normalize(lightDirection_cmr); + highp float cosTheta = dot(n, l); + if (cosTheta < 0.0) cosTheta = 0.0; + else if (cosTheta > 1.0) cosTheta = 1.0; + + highp vec3 E = normalize(eyeDirection_cmr); + highp vec3 R = reflect(-l, n); + highp float cosAlpha = dot(E, R); + if (cosAlpha < 0.0) cosAlpha = 0.0; + else if (cosAlpha > 1.0) cosAlpha = 1.0; + + gl_FragColor.rgb = + materialAmbientColor + + materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance + + materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance; + gl_FragColor.a = texture2D(textureSampler, UV).a; +} + diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp new file mode 100644 index 00000000..2272b731 --- /dev/null +++ b/src/datavisualization/engine/surface3dcontroller.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "surface3dcontroller_p.h" +#include "surface3drenderer_p.h" +#include "camerahelper_p.h" +#include "q3dabstractaxis_p.h" +#include "q3dvalueaxis_p.h" +#include "q3dcategoryaxis.h" +#include "qsurfacedataproxy_p.h" + +#include <QMatrix4x4> + +#include <QDebug> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Surface3DController::Surface3DController(QRect rect) + : Abstract3DController(rect), + m_renderer(0), + m_isSmoothSurfaceEnabled(false), + m_isSurfaceGridEnabled(true) +{ + setActiveDataProxy(0); + + // Setting a null axis creates a new default axis according to orientation and graph type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); + + // Set the default from the theme + m_userDefinedGradient = theme().m_surfaceGradient; +} + +Surface3DController::~Surface3DController() +{ +} + +void Surface3DController::initializeOpenGL() +{ + // Initialization is called multiple times when Qt Quick components are used + if (isInitialized()) + return; + + m_renderer = new Surface3DRenderer(this); + setRenderer(m_renderer); + synchDataToRenderer(); + emitNeedRender(); +} + +void Surface3DController::synchDataToRenderer() +{ + Abstract3DController::synchDataToRenderer(); + + if (!isInitialized()) + return; + + // Notify changes to renderer + if (m_changeTracker.gradientColorChanged) { + m_renderer->updateSurfaceGradient(m_userDefinedGradient); + m_changeTracker.gradientColorChanged = false; + } + + if (m_changeTracker.smoothStatusChanged) { + m_isSmoothSurfaceEnabled = m_renderer->updateSmoothStatus(m_isSmoothSurfaceEnabled); + m_changeTracker.smoothStatusChanged = false; + } + + if (m_changeTracker.surfaceGridChanged) { + m_renderer->updateSurfaceGridStatus(m_isSurfaceGridEnabled); + m_changeTracker.surfaceGridChanged = false; + } + + if (m_isDataDirty) { + m_renderer->updateDataModel(static_cast<QSurfaceDataProxy *>(m_data)); + m_isDataDirty = false; + } +} + +void Surface3DController::handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) +{ + Q_UNUSED(orientation) + Q_UNUSED(autoAdjust) + + adjustValueAxisRange(); +} + +void Surface3DController::handleAxisRangeChangedBySender(QObject *sender) +{ + scene()->setSlicingActive(false); + Abstract3DController::handleAxisRangeChangedBySender(sender); +} + +void Surface3DController::setSmoothSurface(bool enable) +{ + m_isSmoothSurfaceEnabled = enable; + m_changeTracker.smoothStatusChanged = true; + emitNeedRender(); +} + +bool Surface3DController::smoothSurface() +{ + return m_isSmoothSurfaceEnabled; +} + +void Surface3DController::setSurfaceGrid(bool enable) +{ + m_isSurfaceGridEnabled = enable; + m_changeTracker.surfaceGridChanged = true; + emitNeedRender(); +} + +bool Surface3DController::surfaceGrid() +{ + return m_isSurfaceGridEnabled; +} + +void Surface3DController::setGradient(const QLinearGradient &gradient) +{ + m_userDefinedGradient = gradient; + m_userDefinedGradient.setStart(1, 1000); + m_userDefinedGradient.setFinalStop(0, 0); + m_changeTracker.gradientColorChanged = true; + emitNeedRender(); +} + +QLinearGradient Surface3DController::gradient() const +{ + return m_userDefinedGradient; +} + +void Surface3DController::setGradientColorAt(qreal pos, const QColor &color) +{ + m_userDefinedGradient.setColorAt(pos, color); + m_changeTracker.gradientColorChanged = true; + emitNeedRender(); +} + +void Surface3DController::setSelectionMode(QDataVis::SelectionMode mode) +{ + if (!(mode == QDataVis::SelectionModeNone || mode == QDataVis::SelectionModeItem + || mode == QDataVis::SelectionModeSliceRow + || mode == QDataVis::SelectionModeSliceColumn)) { + qWarning("Unsupported selection mode."); + return; + } + // Disable zoom if selection mode changes + setSlicingActive(false); + Abstract3DController::setSelectionMode(mode); +} + + +void Surface3DController::setActiveDataProxy(QAbstractDataProxy *proxy) +{ + // Setting null proxy indicates default proxy + if (!proxy) { + proxy = new QSurfaceDataProxy; + proxy->d_ptr->setDefaultProxy(true); + } + + Q_ASSERT(proxy->type() == QAbstractDataProxy::DataTypeSurface); + + Abstract3DController::setActiveDataProxy(proxy); + + QSurfaceDataProxy *surfaceDataProxy = static_cast<QSurfaceDataProxy *>(m_data); + + QObject::connect(surfaceDataProxy, &QSurfaceDataProxy::arrayReset, + this, &Surface3DController::handleArrayReset); + + scene()->setSlicingActive(false); + adjustValueAxisRange(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Surface3DController::handleArrayReset() +{ + scene()->setSlicingActive(false); + adjustValueAxisRange(); + m_isDataDirty = true; + emitNeedRender(); +} + +void Surface3DController::adjustValueAxisRange() +{ + if (m_data) { + QVector3D minLimits; + QVector3D maxLimits; + static_cast<QSurfaceDataProxy *>(m_data)->dptr()->limitValues(minLimits, maxLimits); + Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisX); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (minLimits.x() != maxLimits.x()) + valueAxis->dptr()->setRange(minLimits.x(), maxLimits.x()); + else + valueAxis->dptr()->setRange(minLimits.x() - 1.0f, minLimits.x() + 1.0f); // Default to some valid range + } + + valueAxis = static_cast<Q3DValueAxis *>(m_axisY); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (minLimits.y() != maxLimits.y()) + valueAxis->dptr()->setRange(minLimits.y(), maxLimits.y()); + else + valueAxis->dptr()->setRange(minLimits.y() - 1.0f, minLimits.y() + 1.0f); // Default to some valid range + } + + valueAxis = static_cast<Q3DValueAxis *>(m_axisZ); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (minLimits.z() != maxLimits.z()) + valueAxis->dptr()->setRange(minLimits.z(), maxLimits.z()); + else + valueAxis->dptr()->setRange(minLimits.z() - 1.0f, minLimits.z() + 1.0f); // Default to some valid range + } + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/surface3dcontroller_p.h b/src/datavisualization/engine/surface3dcontroller_p.h new file mode 100644 index 00000000..0efece97 --- /dev/null +++ b/src/datavisualization/engine/surface3dcontroller_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef SURFACE3DCONTROLLER_P_H +#define SURFACE3DCONTROLLER_P_H + +#include "abstract3dcontroller_p.h" +#include "datavisualizationglobal_p.h" + +#include <QLinearGradient> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class Surface3DRenderer; + +struct Surface3DChangeBitField { + bool gradientColorChanged : 1; + bool smoothStatusChanged : 1; + bool surfaceGridChanged : 1; + + Surface3DChangeBitField() : + gradientColorChanged(true), + smoothStatusChanged(true), + surfaceGridChanged(true) + { + } +}; + +class QT_DATAVISUALIZATION_EXPORT Surface3DController : public Abstract3DController +{ + Q_OBJECT + +private: + Surface3DChangeBitField m_changeTracker; + + // Rendering + Surface3DRenderer *m_renderer; + bool m_isSmoothSurfaceEnabled; + bool m_isSurfaceGridEnabled; + QLinearGradient m_userDefinedGradient; + +public: + explicit Surface3DController(QRect rect); + ~Surface3DController(); + + void initializeOpenGL(); + virtual void synchDataToRenderer(); + + void setSmoothSurface(bool enable); + bool smoothSurface(); + + void setSurfaceGrid(bool enable); + bool surfaceGrid(); + + void setGradient(const QLinearGradient &gradient); + QLinearGradient gradient() const; + + void setGradientColorAt(qreal pos, const QColor &color); + + void setSelectionMode(QDataVis::SelectionMode mode); + + virtual void setActiveDataProxy(QAbstractDataProxy *proxy); + + virtual void handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust); + virtual void handleAxisRangeChangedBySender(QObject *sender); + +public slots: + void handleArrayReset(); + +signals: + void smoothStatusChanged(bool enable); + void surfaceGridChanged(bool enable); + void segmentCountChanged(GLint segmentCount, GLfloat step, GLfloat minimum); + +private: + void adjustValueAxisRange(); + + Q_DISABLE_COPY(Surface3DController) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // SURFACE3DCONTROLLER_P_H diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp new file mode 100644 index 00000000..a1dfc7e8 --- /dev/null +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -0,0 +1,2185 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "surface3dcontroller_p.h" +#include "surface3drenderer_p.h" +#include "q3dcamera.h" +#include "q3dcamera_p.h" +#include "shaderhelper_p.h" +#include "objecthelper_p.h" +#include "surfaceobject_p.h" +#include "texturehelper_p.h" +#include "selectionpointer_p.h" +#include "theme_p.h" +#include "utils_p.h" +#include "drawer_p.h" +#include "q3dlight.h" + +#include <QMatrix4x4> +#include <QMouseEvent> +#include <qmath.h> + +#include <QLinearGradient> +#include <QPainter> + +#include <QDebug> + +static const int ID_TO_RGBA_MASK = 0xff; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +//#define SHOW_DEPTH_TEXTURE_SCENE + +// TODO Uniform scaling is broken on surface +//#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values + +const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd. +const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background) +const GLfloat labelMargin = 0.05f; +const GLfloat backgroundBottom = 1.0f; +const GLfloat gridLineWidth = 0.005f; +const GLfloat sliceZScale = 0.1f; +const GLfloat surfaceGridYOffsetValue = 0.001f; +const GLfloat sliceUnits = 2.5f; +const int subViewDivider = 5; +// The second offset to opposite direction is double because same matrix is translated twice +const GLfloat surfaceGridYOffset[2] = {-surfaceGridYOffsetValue, 2.0f * surfaceGridYOffsetValue}; + +Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) + : Abstract3DRenderer(controller), + m_controller(controller), + m_labelStyle(QDataVis::LabelStyleFromTheme), + m_font(QFont(QStringLiteral("Arial"))), + m_isGridEnabled(true), + m_shader(0), + m_depthShader(0), + m_backgroundShader(0), + m_surfaceShader(0), + m_surfaceGridShader(0), + m_selectionShader(0), + m_labelShader(0), + m_heightNormalizer(0.0f), + m_scaleFactor(0.0f), + m_scaleX(0.0f), + m_scaleZ(0.0f), + m_scaleXWithBackground(0.0f), + m_scaleZWithBackground(0.0f), + m_surfaceScaleX(0.0f), + m_surfaceScaleZ(0.0f), + m_surfaceOffsetX(0.0f), + m_surfaceOffsetZ(0.0f), + m_minVisibleColumnValue(0.0f), + m_maxVisibleColumnValue(0.0f), + m_minVisibleRowValue(0.0f), + m_maxVisibleRowValue(0.0f), + m_visibleColumnRange(0.0f), + m_visibleRowRange(0.0f), + m_backgroundObj(0), + m_gridLineObj(0), + m_labelObj(0), + m_surfaceObj(0), + m_sliceSurfaceObj(0), + m_depthTexture(0), + m_depthFrameBuffer(0), + m_selectionFrameBuffer(0), + m_selectionDepthBuffer(0), + m_gradientTexture(0), + m_selectionTexture(0), + m_selectionResultTexture(0), + m_shadowQualityToShader(33.3f), + m_flatSupported(true), + m_selectionPointer(0), + m_selectionActive(false), + m_xFlipped(false), + m_zFlipped(false), + m_yFlipped(false), + m_sampleSpace(QRect(0, 0, 0, 0)), + m_shadowQualityMultiplier(3), + m_cachedSelectionId(0), + m_selectionModeChanged(false), + m_hasHeightAdjustmentChanged(true) +{ +#if !defined(QT_OPENGL_ES_2) + // Check if flat feature is supported + ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), + QStringLiteral(":/shaders/fragmentSurfaceFlat")); + if (!tester.testCompile()) { + m_flatSupported = false; + m_controller->setSmoothSurface(true); + } +#endif + + m_cachedSmoothSurface = m_controller->smoothSurface(); + updateSurfaceGridStatus(m_controller->surfaceGrid()); + + // Shadows are disabled for Q3DSurface in Tech Preview + updateShadowQuality(QDataVis::ShadowQualityNone); + + initializeOpenGLFunctions(); + initializeOpenGL(); +} + +Surface3DRenderer::~Surface3DRenderer() +{ + m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer); + m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer); + m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer); + + m_textureHelper->deleteTexture(&m_depthTexture); + m_textureHelper->deleteTexture(&m_gradientTexture); + m_textureHelper->deleteTexture(&m_selectionTexture); + m_textureHelper->deleteTexture(&m_selectionResultTexture); + + delete m_shader; + delete m_depthShader; + delete m_backgroundShader; + delete m_selectionShader; + delete m_surfaceShader; + delete m_surfaceGridShader; + delete m_labelShader; + + delete m_backgroundObj; + delete m_surfaceObj; + delete m_sliceSurfaceObj; + delete m_gridLineObj; + delete m_labelObj; + + delete m_selectionPointer; + + for (int i = 0; i < m_dataArray.size(); i++) + delete m_dataArray.at(i); + m_dataArray.clear(); + + for (int i = 0; i < m_sliceDataArray.size(); i++) + delete m_sliceDataArray.at(i); + m_sliceDataArray.clear(); +} + +void Surface3DRenderer::initializeOpenGL() +{ + Abstract3DRenderer::initializeOpenGL(); + + // Initialize shaders + handleShadowQualityChange(); + + initSurfaceShaders(); + + initLabelShaders(QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + +#if !defined(QT_OPENGL_ES_2) + // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api. + initDepthShader(); +#endif + + // Init selection shader + initSelectionShaders(); + + // Load grid line mesh + loadGridLineMesh(); + + // Load label mesh + loadLabelMesh(); + + // Resize in case we've missed resize events + // Resize calls initSelectionBuffer and initDepthBuffer, so they don't need to be called here + handleResize(); + + // Load background mesh (we need to be initialized first) + loadBackgroundMesh(); +} + +void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy) +{ + calculateSceneScalingFactors(); + + const QSurfaceDataArray &array = *dataProxy->array(); + + // Need minimum of 2x2 array to draw a surface + if (array.size() >= 2 && array.at(0)->size() >= 2) { + QRect sampleSpace = calculateSampleRect(array); + + bool dimensionChanged = false; + if (m_sampleSpace != sampleSpace) { + dimensionChanged = true; + m_sampleSpace = sampleSpace; + + for (int i = 0; i < m_dataArray.size(); i++) + delete m_dataArray.at(i); + m_dataArray.clear(); + } + + // TODO: Handle partial surface grids on the graph edges + if (sampleSpace.width() >= 2 && sampleSpace.height() >= 2) { + if (dimensionChanged) { + m_dataArray.reserve(sampleSpace.height()); + for (int i = 0; i < sampleSpace.height(); i++) + m_dataArray << new QSurfaceDataRow(sampleSpace.width()); + } + for (int i = 0; i < sampleSpace.height(); i++) { + for (int j = 0; j < sampleSpace.width(); j++) + (*(m_dataArray.at(i)))[j] = array.at(i + sampleSpace.y())->at(j + sampleSpace.x()); + } + + if (m_dataArray.size() > 0) { + if (!m_surfaceObj) + loadSurfaceObj(); + + // Note: Data setup can change samplespace (as min width/height is 1) + if (m_cachedSmoothSurface) { + m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), dimensionChanged); + } else { + m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), dimensionChanged); + } + + if (dimensionChanged) + updateSelectionTexture(); + } + } + } + + m_selectionActive = false; + m_cachedSelectionId = 0; + for (int i = 0; i < m_sliceDataArray.size(); i++) + delete m_sliceDataArray.at(i); + m_sliceDataArray.clear(); + + Abstract3DRenderer::updateDataModel(dataProxy); +} + +void Surface3DRenderer::updateSliceDataModel(int selectionId) +{ + int column = (selectionId - 1) % m_sampleSpace.width(); + int row = (selectionId - 1) / m_sampleSpace.width(); + + for (int i = 0; i < m_sliceDataArray.size(); i++) + delete m_sliceDataArray.at(i); + m_sliceDataArray.clear(); + + m_sliceDataArray.reserve(2); + QSurfaceDataRow *sliceRow; + + qreal adjust = (0.025 * m_heightNormalizer) / 2.0; + qreal stepDown = 2.0 * adjust; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + QSurfaceDataRow *src = m_dataArray.at(row); + sliceRow = new QSurfaceDataRow(src->size()); + for (int i = 0; i < sliceRow->size(); i++) + (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, -1.0)); + } else { + sliceRow = new QSurfaceDataRow(m_sampleSpace.height()); + for (int i = 0; i < m_sampleSpace.height(); i++) { + (*sliceRow)[i].setPosition(QVector3D(m_dataArray.at(i)->at(column).z(), + m_dataArray.at(i)->at(column).y() + adjust, + -1.0)); + } + } + + m_sliceDataArray << sliceRow; + + // Make a duplicate, so that we get a little bit depth + QSurfaceDataRow *duplicateRow = new QSurfaceDataRow(*sliceRow); + for (int i = 0; i < sliceRow->size(); i++) + (*sliceRow)[i].setPosition(QVector3D(sliceRow->at(i).x(), sliceRow->at(i).y() - stepDown, 1.0)); + + m_sliceDataArray << duplicateRow; + + QRect sliceRect(0, 0, sliceRow->size(), 2); + + if (sliceRow->size() > 0) { + if (!m_sliceSurfaceObj) + loadSliceSurfaceObj(); + + if (m_cachedSmoothSurface) { + m_sliceSurfaceObj->setUpSmoothData(m_sliceDataArray, sliceRect, m_heightNormalizer, + m_axisCacheY.min(), true); + } else { + m_sliceSurfaceObj->setUpData(m_sliceDataArray, sliceRect, m_heightNormalizer, + m_axisCacheY.min(), true); + } + } +} + +QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array) +{ + QRect sampleSpace; + + int rowCount = array.size(); + int columnCount = array.at(0)->size(); + + int i; + bool found; + float axisMinX = float(m_axisCacheX.min()); + float axisMaxX = float(m_axisCacheX.max()); + float axisMinZ = float(m_axisCacheZ.min()); + float axisMaxZ = float(m_axisCacheZ.max()); + + // Comparisons between float and double are not accurate, so fudge our comparison values + //a little to get all rows and columns into view that need to be visible. + const float fudgeFactor = 0.00001f; + float fudgedAxisXRange = (axisMaxX - axisMinX) * fudgeFactor; + float fudgedAxisZRange = (axisMaxZ - axisMinZ) * fudgeFactor; + axisMinX -= fudgedAxisXRange; + axisMinZ -= fudgedAxisZRange; + axisMaxX += fudgedAxisXRange; + axisMaxZ += fudgedAxisZRange; + + // m_minVisibleColumnValue + for (i = 0, found = false; i < columnCount; i++) { + if (array.at(0)->at(i).x() >= axisMinX) { + found = true; + break; + } + } + if (found) { + m_minVisibleColumnValue = array.at(0)->at(i).x(); + sampleSpace.setLeft(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; + } + + // m_maxVisibleColumnValue + for (i = columnCount - 1, found = false; i >= 0; i--) { + if (array.at(0)->at(i).x() <= axisMaxX) { + found = true; + break; + } + } + if (found) { + m_maxVisibleColumnValue = array.at(0)->at(i).x(); + sampleSpace.setRight(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; + } + + // m_minVisibleRowValue + for (i = 0, found = false; i < rowCount; i++) { + if (array.at(i)->at(0).z() >= axisMinZ) { + found = true; + break; + } + } + if (found) { + m_minVisibleRowValue = array.at(i)->at(0).z(); + sampleSpace.setTop(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; + } + + // m_maxVisibleRowValue + for (i = rowCount - 1, found = false; i >= 0; i--) { + if (array.at(i)->at(0).z() <= axisMaxZ) { + found = true; + break; + } + } + if (found) { + m_maxVisibleRowValue = array.at(i)->at(0).z(); + sampleSpace.setBottom(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; + } + + m_visibleColumnRange = m_maxVisibleColumnValue - m_minVisibleColumnValue; + m_visibleRowRange = m_maxVisibleRowValue - m_minVisibleRowValue; + m_surfaceScaleX = m_scaleX * m_visibleColumnRange / m_areaSize.width(); + m_surfaceScaleZ = m_scaleZ * m_visibleRowRange / m_areaSize.height(); + GLfloat axis2XCenterX = axisMinX + axisMaxX; + GLfloat axis2XCenterZ = axisMinZ + axisMaxZ; + GLfloat data2XCenterX = GLfloat(m_minVisibleColumnValue + m_maxVisibleColumnValue); + GLfloat data2XCenterZ = GLfloat(m_minVisibleRowValue + m_maxVisibleRowValue); + m_surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width(); + m_surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height(); + + return sampleSpace; +} + +void Surface3DRenderer::updateScene(Q3DScene *scene) +{ + // TODO: Move these to more suitable place e.g. controller should be controlling the viewports. + scene->setSecondarySubViewport(m_sliceViewPort); + scene->setPrimarySubViewport(m_mainViewPort); + + // Set initial camera position + // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later + if (m_hasHeightAdjustmentChanged) { + scene->activeCamera()->setBaseOrientation(QVector3D(0.0f, 0.0f, cameraDistance + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + // For now this is used just to make things once. Proper use will come + m_hasHeightAdjustmentChanged = false; + } + + scene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment); + scene->setLightPositionRelativeToCamera(defaultLightPos); + + if (m_selectionPointer) + m_selectionPointer->updateScene(scene); + + Abstract3DRenderer::updateScene(scene); +} + +void Surface3DRenderer::render(GLuint defaultFboHandle) +{ + bool slicingActivated = m_cachedScene->isSlicingActive(); + bool slicingChanged = m_cachedIsSlicingActivated != slicingActivated; + + updateSlicingActive(slicingActivated); + + // Handle GL state setup for FBO buffers and clearing of the render surface + Abstract3DRenderer::render(defaultFboHandle); + + // In slice mode; draw slice and render selection ball + if (m_cachedIsSlicingActivated && m_selectionPointer && m_selectionActive) { + drawSlicedScene(); + m_selectionPointer->render(defaultFboHandle); + } + + // Draw the surface scene + drawScene(defaultFboHandle); + + // Render selection ball if not in slice mode + if (!m_cachedIsSlicingActivated && m_selectionPointer && m_selectionActive) + m_selectionPointer->render(defaultFboHandle); + + // If slicing has been activated by this render pass, we need another render + // Also trigger another render always when slicing changes in general to ensure + // final draw is correct. + if (slicingActivated != m_cachedScene->isSlicingActive() || slicingChanged) + emit needRender(); +} + +void Surface3DRenderer::drawSlicedScene() +{ + QVector3D lightPos; + + // Specify viewport + glViewport(m_sliceViewPort.x(), m_sliceViewPort.y(), + m_sliceViewPort.width(), m_sliceViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + + GLfloat aspect = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height(); + projectionMatrix.ortho(-sliceUnits * aspect, sliceUnits * aspect, + -sliceUnits, sliceUnits, -1.0f, 14.0f); // 14.0 because of zComp + + // Set view matrix + QMatrix4x4 viewMatrix; + viewMatrix.lookAt(QVector3D(0.0f, 0.0f, zComp + 1.0f), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // Set light position + lightPos = m_cachedScene->activeLight()->position(); + + QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix; + + GLfloat scaleX = 0.0f; + GLfloat scaleXBackground = 0.0f; + GLfloat offset = 0.0f; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + scaleX = m_surfaceScaleX; + scaleXBackground = m_scaleXWithBackground; + offset = m_surfaceOffsetX; + } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { + scaleX = m_surfaceScaleZ; + scaleXBackground = m_scaleZWithBackground; + offset = -m_surfaceOffsetZ; + } + + if (m_surfaceObj) { + ShaderHelper *surfaceShader = m_shader; + surfaceShader->bind(); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(offset, 0.0f, zComp); + QVector3D scaling(scaleX, 1.0f, sliceZScale); + modelMatrix.scale(scaling); + itModelMatrix.scale(scaling); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + QVector3D color; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) + color = Utils::vectorFromColor(m_cachedTheme.m_highlightRowColor); + else + color = Utils::vectorFromColor(m_cachedTheme.m_highlightColumnColor); + + // Set shader bindings + surfaceShader->setUniformValue(surfaceShader->lightP(), lightPos); + surfaceShader->setUniformValue(surfaceShader->view(), viewMatrix); + surfaceShader->setUniformValue(surfaceShader->model(), modelMatrix); + surfaceShader->setUniformValue(surfaceShader->nModel(), itModelMatrix.inverted().transposed()); + surfaceShader->setUniformValue(surfaceShader->MVP(), MVPMatrix); + surfaceShader->setUniformValue(surfaceShader->color(), color); + surfaceShader->setUniformValue(surfaceShader->lightS(), 0.25f); + surfaceShader->setUniformValue(surfaceShader->ambientS(), + m_cachedTheme.m_ambientStrength * 2.0f); + + m_drawer->drawObject(surfaceShader, m_sliceSurfaceObj); + + surfaceShader->release(); + + // Draw surface grid + if (m_cachedSurfaceGridOn) { + m_surfaceGridShader->bind(); + + m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(), + Utils::vectorFromColor(m_cachedTheme.m_gridLine)); + // Draw the grid twice, with slight offset on Y axis to each direction + for (int i = 0; i < 2; i++) { + MVPMatrix.translate(0.0f, surfaceGridYOffset[i], 0.0f); + + m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), MVPMatrix); + m_drawer->drawSurfaceGrid(m_surfaceGridShader, m_sliceSurfaceObj); + } + m_surfaceGridShader->release(); + } + } + + // Disable textures + glDisable(GL_TEXTURE_2D); + + // lines to the back + if (m_cachedIsGridEnabled && m_heightNormalizer) { + ShaderHelper *lineShader = m_backgroundShader; + // Bind line shader + lineShader->bind(); + + if (m_axisCacheY.segmentCount() > 0) { + QVector3D gridLineScaleX(scaleXBackground, gridLineWidth, gridLineWidth); + + // Set unchanging shader bindings + QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine); + lineShader->setUniformValue(lineShader->lightP(), lightPos); + lineShader->setUniformValue(lineShader->view(), viewMatrix); + lineShader->setUniformValue(lineShader->color(), lineColor); + lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength * 2.0f); + lineShader->setUniformValue(lineShader->lightS(), 0.25f); + + // Back wall + GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer; + GLfloat linePos = -1.0f; + int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, linePos, zComp - sliceZScale); + + modelMatrix.scale(gridLineScaleX); + itModelMatrix.scale(gridLineScaleX); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + + linePos += lineStep; + } + } + + // Floor lines + QVector3D gridLineScaleZ(gridLineWidth, gridLineWidth, sliceZScale); + QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth); + + int lastSegment; + GLfloat lineStep; + GLfloat linePos; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor; + lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); + linePos = m_scaleX; + } else { + lineStep = -2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor; + lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); + linePos = m_scaleZ; + } + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(linePos, -backgroundMargin, zComp); + + modelMatrix.scale(gridLineScaleZ); + itModelMatrix.scale(gridLineScaleZ); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + + linePos += lineStep; + } + + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) + linePos = m_scaleX; + else + linePos = m_scaleZ; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(linePos, 0.0f, zComp - sliceZScale); + modelMatrix.scale(gridLineScaleY); + itModelMatrix.scale(gridLineScaleY); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + + linePos += lineStep; + } + + // Release line shader + lineShader->release(); + } + + // Draw axis labels + m_labelShader->bind(); + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + glCullFace(GL_BACK); + if (m_cachedLabelStyle > QDataVis::LabelStyleOpaque) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + // Y Labels to back wall + GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer; + GLfloat labelPos = -1.0f; + int labelNbr = 0; + + QVector3D positionComp(0.0f, 0.0f, zComp); + QVector3D rotation(0.0f, 0.0f, 0.0f); + QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, labelPos, zComp); + for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + if (m_axisCacheY.labelItems().size() > labelNbr) { + labelTrans.setY(labelPos); + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + positionComp, rotation, 0, m_cachedSelectionMode, m_labelShader, + m_labelObj, m_cachedScene->activeCamera(), + true, true, Drawer::LabelMid, Qt::AlignRight); + } + labelNbr++; + labelPos += posStep; + } + + // X Labels to ground + int countLabelItems; + int lastSegment; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor; + labelPos = -m_scaleX; + lastSegment = m_axisCacheX.segmentCount(); + countLabelItems = m_axisCacheX.labelItems().size(); + } else { + posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor; + labelPos = -m_scaleZ; + lastSegment = m_axisCacheZ.segmentCount(); + countLabelItems = m_axisCacheZ.labelItems().size(); + } + + labelNbr = 0; + positionComp.setY(backgroundMargin); + rotation.setZ(-45.0f); + labelTrans.setY(-backgroundMargin); + for (int segment = 0; segment <= lastSegment; segment++) { + if (countLabelItems > labelNbr) { + // Draw the label here + labelTrans.setX(labelPos); + + m_dummyRenderItem.setTranslation(labelTrans); + + LabelItem *axisLabelItem; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) + axisLabelItem = m_axisCacheX.labelItems().at(labelNbr); + else + axisLabelItem = m_axisCacheZ.labelItems().at(labelNbr); + + m_drawer->drawLabel(m_dummyRenderItem, *axisLabelItem, viewMatrix, projectionMatrix, + positionComp, rotation, 0, QDataVis::SelectionModeSliceRow, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), + false, false, Drawer::LabelBelow, Qt::AlignTop); + } + labelNbr++; + labelPos += posStep; + } + + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); + if (m_cachedLabelStyle > QDataVis::LabelStyleOpaque) + glDisable(GL_BLEND); + + // Release label shader + m_labelShader->release(); +} + +void Surface3DRenderer::drawScene(GLuint defaultFboHandle) +{ + GLfloat backgroundRotation = 0; + uint selectionId = 0; + + // Specify viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + // Set up projection matrix + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f); + + // Calculate view matrix + QMatrix4x4 viewMatrix = m_cachedScene->activeCamera()->viewMatrix(); + + QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix; + + // Calculate flipping indicators + if (viewMatrix.row(0).x() > 0) + m_zFlipped = false; + else + m_zFlipped = true; + if (viewMatrix.row(0).z() <= 0) + m_xFlipped = false; + else + m_xFlipped = true; + + // calculate background rotation based on view matrix rotation + if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() <= 0) + backgroundRotation = 270.0f; + else if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() > 0) + backgroundRotation = 180.0f; + else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() > 0) + backgroundRotation = 90.0f; + else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() <= 0) + backgroundRotation = 0.0f; + + QVector3D lightPos = m_cachedScene->activeLight()->position(); + + QMatrix4x4 depthViewMatrix; + QMatrix4x4 depthProjectionMatrix; + QMatrix4x4 depthProjectionViewMatrix; + + GLfloat adjustedLightStrength = m_cachedTheme.m_lightStrength / 10.0f; + + QVector3D surfaceScaler(m_surfaceScaleX, 1.0f, m_surfaceScaleZ); + QVector3D surfaceOffset(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ + zComp); + + // Draw depth buffer +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone && m_surfaceObj) { + // Render scene into a depth texture for using with shadow mapping + // Enable drawing to depth framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer); + glClear(GL_DEPTH_BUFFER_BIT); + + // Bind depth shader + m_depthShader->bind(); + + // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows. + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width() * m_shadowQualityMultiplier, + m_mainViewPort.height() * m_shadowQualityMultiplier); + + // Get the depth view matrix + // It may be possible to hack lightPos here if we want to make some tweaks to shadow + QVector3D depthLightPos = m_cachedScene->activeCamera()->calculatePositionRelativeToCamera( + QVector3D(0.0f, 0.0f, zComp), 0.0f, 1.5f / m_autoScaleAdjustment); + depthViewMatrix.lookAt(depthLightPos, QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + + // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? + // That causes the scene to be not drawn from above -> must be fixed + // qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3); + // Set the depth projection matrix +#ifndef USE_WIDER_SHADOWS + // Use this for perspective shadows + depthProjectionMatrix.perspective(10.0f, (GLfloat)m_mainViewPort.width() + / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f); +#else + // Use these for orthographic shadows + depthProjectionMatrix.ortho(-2.0f * 2.0f, 2.0f * 2.0f, + -2.0f, 2.0f, + 0.0f, 100.0f); +#endif + depthProjectionViewMatrix = depthProjectionMatrix * depthViewMatrix; + + glCullFace(GL_FRONT); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + modelMatrix.translate(surfaceOffset); + modelMatrix.scale(surfaceScaler); + + MVPMatrix = depthProjectionViewMatrix * modelMatrix; + + m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); + + // 1st attribute buffer : vertices + glEnableVertexAttribArray(m_depthShader->posAtt()); + glBindBuffer(GL_ARRAY_BUFFER, m_surfaceObj->vertexBuf()); + glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, + (void *)0); + + // Index buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_surfaceObj->elementBuf()); + + // Draw the triangles + glDrawElements(GL_TRIANGLES, m_surfaceObj->indexCount(), GL_UNSIGNED_SHORT, + (void *)0); + + // Free buffers + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableVertexAttribArray(m_depthShader->posAtt()); + + // Disable drawing to depth framebuffer (= enable drawing to screen) + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Release depth shader + m_depthShader->release(); + + // Revert to original viewport + glViewport(m_mainViewPort.x(), m_mainViewPort.y(), + m_mainViewPort.width(), m_mainViewPort.height()); + + // Reset culling to normal + glCullFace(GL_BACK); + +#if 0 // Use this if you want to see what is being drawn to the framebuffer + // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it) + { + m_labelShader->bind(); + glEnable(GL_TEXTURE_2D); + QMatrix4x4 modelMatrix; + QMatrix4x4 viewmatrix; + viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp), + QVector3D(0.0f, 0.0f, zComp), + QVector3D(0.0f, 1.0f, 0.0f)); + modelMatrix.translate(0.0, 0.0, zComp); + QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix; + m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix); + m_drawer->drawObject(m_labelShader, m_labelObj, m_depthTexture); + glDisable(GL_TEXTURE_2D); + m_labelShader->release(); + } +#endif + } +#endif + + bool selectionDirty = false; + + // Enable texturing + glEnable(GL_TEXTURE_2D); + + // Draw selection buffer + if (!m_cachedIsSlicingActivated && m_controller->inputState() == QDataVis::InputStateOnScene + && m_surfaceObj && m_cachedSelectionMode > QDataVis::SelectionModeNone) { + m_selectionShader->bind(); + glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer); + glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer + glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled + + glDisable(GL_CULL_FACE); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + + modelMatrix.translate(surfaceOffset); + modelMatrix.scale(surfaceScaler); + + MVPMatrix = projectionViewMatrix * modelMatrix; + + m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); + + m_drawer->drawObject(m_selectionShader, m_surfaceObj, m_selectionTexture); + + glEnable(GL_DITHER); + + QPoint point = m_controller->inputPosition(); + GLubyte pixel[4] = {0}; + glReadPixels(point.x(), m_cachedBoundingRect.height() - point.y(), 1, 1, + GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixel); + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle); + + // Release selection shader + m_selectionShader->release(); + + // Put the RGBA value back to uint +#if defined (Q_OS_ANDROID) + selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536; +#else + selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536 + pixel[3] * 16777216; +#endif + + selectionDirty = true; + } + + // Draw the surface + if (m_surfaceObj && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) { + m_surfaceShader->bind(); + + // For surface we can see climpses from underneath + glDisable(GL_CULL_FACE); + + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(surfaceOffset); + modelMatrix.scale(surfaceScaler); + itModelMatrix.scale(surfaceScaler); + +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionViewMatrix * modelMatrix; +#else + MVPMatrix = projectionViewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set shader bindings + m_surfaceShader->setUniformValue(m_surfaceShader->lightP(), lightPos); + m_surfaceShader->setUniformValue(m_surfaceShader->view(), viewMatrix); + m_surfaceShader->setUniformValue(m_surfaceShader->model(), modelMatrix); + m_surfaceShader->setUniformValue(m_surfaceShader->nModel(), + itModelMatrix.inverted().transposed()); + m_surfaceShader->setUniformValue(m_surfaceShader->MVP(), MVPMatrix); + m_surfaceShader->setUniformValue(m_surfaceShader->ambientS(), + m_cachedTheme.m_ambientStrength); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + m_surfaceShader->setUniformValue(m_surfaceShader->shadowQ(), m_shadowQualityToShader); + m_surfaceShader->setUniformValue(m_surfaceShader->depth(), depthMVPMatrix); + m_surfaceShader->setUniformValue(m_surfaceShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(m_surfaceShader, m_surfaceObj, m_gradientTexture, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_surfaceShader->setUniformValue(m_surfaceShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_surfaceShader, m_surfaceObj, m_gradientTexture); + } + + m_surfaceShader->release(); + + glEnable(GL_CULL_FACE); + + // Draw surface grid + if (m_cachedSurfaceGridOn) { + m_surfaceGridShader->bind(); + + m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(), + Utils::vectorFromColor(m_cachedTheme.m_gridLine)); + // Draw the grid twice, with slight offset on Y axis to each direction + for (int i = 0; i < 2; i++) { + MVPMatrix.translate(0.0f, surfaceGridYOffset[i], 0.0f); + + m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), MVPMatrix); + m_drawer->drawSurfaceGrid(m_surfaceGridShader, m_surfaceObj); + } + m_surfaceGridShader->release(); + } + } + + // Bind background shader + m_backgroundShader->bind(); + glCullFace(GL_BACK); + + // Draw background + if (m_cachedIsBackgroundEnabled && m_backgroundObj) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, 0.0f, zComp); + QVector3D bgScale(m_scaleXWithBackground, backgroundMargin, m_scaleZWithBackground); + modelMatrix.scale(bgScale); + itModelMatrix.scale(bgScale); + + // If we're viewing from below, background object must be flipped + if (m_yFlipped) { + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + modelMatrix.rotate(270.0f - backgroundRotation, 0.0f, 1.0f, 0.0f); + } else { + modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); + } + +#ifdef SHOW_DEPTH_TEXTURE_SCENE + MVPMatrix = depthProjectionViewMatrix * modelMatrix; +#else + MVPMatrix = projectionViewMatrix * modelMatrix; +#endif + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme.m_backgroundColor); + + // Set shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos); + m_backgroundShader->setUniformValue(m_backgroundShader->view(), viewMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->nModel(), + itModelMatrix.inverted().transposed()); + m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->color(), backgroundColor); + m_backgroundShader->setUniformValue(m_backgroundShader->ambientS(), + m_cachedTheme.m_ambientStrength * 2.0f); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->shadowQ(), + m_shadowQualityToShader); + m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_backgroundObj); + } + } + + // Release background shader + m_backgroundShader->release(); + + // Draw grid lines + QVector3D gridLineScaleX(m_scaleXWithBackground, gridLineWidth, gridLineWidth); + QVector3D gridLineScaleZ(gridLineWidth, gridLineWidth, m_scaleZWithBackground); + QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth); + + if (m_cachedIsGridEnabled && m_heightNormalizer) { + ShaderHelper *lineShader = m_backgroundShader; + // Bind line shader + lineShader->bind(); + + // Set unchanging shader bindings + QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme.m_gridLine); + lineShader->setUniformValue(lineShader->lightP(), lightPos); + lineShader->setUniformValue(lineShader->view(), viewMatrix); + lineShader->setUniformValue(lineShader->color(), lineColor); + lineShader->setUniformValue(lineShader->ambientS(), m_cachedTheme.m_ambientStrength); + + // Rows (= Z) + if (m_axisCacheZ.segmentCount() > 0) { + // Floor lines + GLfloat lineStep = 2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor; + GLfloat linePos = m_scaleZ + zComp; // Start line + int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_yFlipped) + modelMatrix.translate(0.0f, backgroundMargin, linePos); + else + modelMatrix.translate(0.0f, -backgroundMargin, linePos); + + modelMatrix.scale(gridLineScaleX); + itModelMatrix.scale(gridLineScaleX); + + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos -= lineStep; + } + + // Side wall lines + GLfloat lineXTrans = m_scaleXWithBackground; + linePos = m_scaleZ + zComp; // Start line + + if (!m_xFlipped) + lineXTrans = -lineXTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(lineXTrans, 0.0f, linePos); + modelMatrix.scale(gridLineScaleY); + itModelMatrix.scale(gridLineScaleY); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), + adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos -= lineStep; + } + } + + // Columns (= X) + if (m_axisCacheX.segmentCount() > 0) { + // Floor lines + GLfloat lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor; + GLfloat linePos = m_scaleX; + int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + if (m_yFlipped) + modelMatrix.translate(linePos, backgroundMargin, zComp); + else + modelMatrix.translate(linePos, -backgroundMargin, zComp); + + modelMatrix.scale(gridLineScaleZ); + itModelMatrix.scale(gridLineScaleZ); + + // If we're viewing from below, grid line object must be flipped + if (m_yFlipped) + modelMatrix.rotate(180.0f, 1.0, 0.0, 0.0); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + + // Back wall lines + GLfloat lineZTrans = m_scaleZWithBackground + zComp; + linePos = m_scaleX; + + if (!m_zFlipped) + lineZTrans = -lineZTrans + zComp + zComp; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(linePos, 0.0f, lineZTrans); + modelMatrix.scale(gridLineScaleY); + itModelMatrix.scale(gridLineScaleY); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + } + + // Horizontal wall lines + if (m_axisCacheY.segmentCount() > 0) { + // Back wall + GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer; + GLfloat linePos = -1.0f; + int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + + GLfloat lineZTrans = m_scaleZWithBackground + zComp; + + if (!m_zFlipped) + lineZTrans = -lineZTrans + zComp + zComp; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(0.0f, linePos, lineZTrans); + + modelMatrix.scale(gridLineScaleX); + itModelMatrix.scale(gridLineScaleX); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + + // Side wall + linePos = -1.0f; + lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + GLfloat lineXTrans = m_scaleXWithBackground; + + if (!m_xFlipped) + lineXTrans = -lineXTrans; + + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; + + modelMatrix.translate(lineXTrans, linePos, zComp); + + modelMatrix.scale(gridLineScaleZ); + itModelMatrix.scale(gridLineScaleZ); + + MVPMatrix = projectionViewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + + // Set the rest of the shader bindings + lineShader->setUniformValue(lineShader->model(), modelMatrix); + lineShader->setUniformValue(lineShader->nModel(), + itModelMatrix.inverted().transposed()); + lineShader->setUniformValue(lineShader->MVP(), MVPMatrix); + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + // Set shadow shader bindings + lineShader->setUniformValue(lineShader->shadowQ(), m_shadowQualityToShader); + lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix); + lineShader->setUniformValue(lineShader->lightS(), adjustedLightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture); + } else +#endif + { + // Set shadowless shader bindings + lineShader->setUniformValue(lineShader->lightS(), + m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(lineShader, m_gridLineObj); + } + linePos += lineStep; + } + } + + // Release line shader + lineShader->release(); + } + + // Draw axis labels + m_labelShader->bind(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Z Labels + QVector3D positionZComp(0.0f, 0.0f, zComp); + if (m_axisCacheZ.segmentCount() > 0) { + GLfloat posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor; + GLfloat labelPos = m_scaleZ + zComp; + int lastSegment = m_axisCacheZ.segmentCount(); + int labelNbr = 0; + GLfloat labelXTrans = m_scaleXWithBackground + labelMargin; + GLfloat labelYTrans = -backgroundMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 0.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + if (m_xFlipped) { + labelXTrans = -labelXTrans; + alignment = Qt::AlignLeft; + } + if (m_yFlipped) { + rotLabelZ += 180.0f; + rotLabelY += 180.0f; + labelYTrans = -labelYTrans; + } + QVector3D labelTrans = QVector3D(labelXTrans, + labelYTrans, + labelPos); + QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ); + + for (int segment = 0; segment <= lastSegment; segment++) { + if (m_axisCacheZ.labelItems().size() > labelNbr) { + labelTrans.setZ(labelPos); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + positionZComp, rotation, 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), + true, true, Drawer::LabelMid, alignment); + } + labelNbr++; + labelPos -= posStep; + } + } + // X Labels + if (m_axisCacheX.segmentCount() > 0) { + GLfloat posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor; + GLfloat labelPos = -m_scaleX; + int lastSegment = m_axisCacheX.segmentCount(); + + int labelNbr = 0; + GLfloat labelZTrans = m_scaleZWithBackground + labelMargin; + GLfloat labelYTrans = -backgroundMargin; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (m_xFlipped) + rotLabelY = -90.0f; + if (m_zFlipped) { + labelZTrans = -labelZTrans; + alignment = Qt::AlignRight; + } + if (m_yFlipped) { + rotLabelZ += 180.0f; + rotLabelY += 180.0f; + labelYTrans = -labelYTrans; + } + QVector3D labelTrans = QVector3D(labelPos, + labelYTrans, + labelZTrans + zComp); + QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ); + + for (int segment = 0; segment <= lastSegment; segment++) { + if (m_axisCacheX.labelItems().size() > labelNbr) { + // Draw the label here + labelTrans.setX(labelPos); + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + positionZComp, rotation, 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), + true, true, Drawer::LabelMid, alignment); + } + labelNbr++; + labelPos += posStep; + } + } + // Y Labels + if (m_axisCacheY.segmentCount() > 0) { + GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer; + GLfloat labelPos = -1.0f; + int labelNbr = 0; + GLfloat labelXTrans = m_scaleXWithBackground; + GLfloat labelZTrans = m_scaleZWithBackground; + + GLfloat labelMarginXTrans = labelMargin; + GLfloat labelMarginZTrans = labelMargin; + GLfloat rotLabelX = 0.0f; + GLfloat rotLabelY = -90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (!m_xFlipped) { + labelXTrans = -labelXTrans; + labelMarginXTrans = -labelMargin; + rotLabelY = 90.0f; + } + if (m_zFlipped) { + labelZTrans = -labelZTrans; + labelMarginZTrans = -labelMargin; + alignment = Qt::AlignRight; + } + + // Back wall + QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ); + + for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + if (m_axisCacheY.labelItems().size() > labelNbr) { + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + + // Side wall + QVector3D labelTrans = QVector3D(labelXTrans, labelPos, + labelZTrans + labelMarginZTrans + zComp); + if (m_xFlipped) + rotation.setY(-90.0f); + else + rotation.setY(90.0f); + if (m_zFlipped) + alignment = Qt::AlignRight; + else + alignment = Qt::AlignLeft; + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + positionZComp, rotation, 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), + true, true, Drawer::LabelMid, alignment); + + // Back wall + if (m_xFlipped) + alignment = Qt::AlignLeft; + else + alignment = Qt::AlignRight; + if (m_zFlipped) + rotation.setY(180.0f); + else + rotation.setY(0.0f); + + labelTrans = QVector3D(-labelXTrans - labelMarginXTrans, labelPos, + -labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + positionZComp, rotation, 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, m_cachedScene->activeCamera(), + true, true, Drawer::LabelMid, alignment); + } + labelNbr++; + labelPos += posStep; + } + } + + glDisable(GL_TEXTURE_2D); + + glDisable(GL_BLEND); + + // Release label shader + m_labelShader->release(); + + // Selection handling + if (m_selectionModeChanged || selectionDirty) { + if (selectionDirty) + m_cachedSelectionId = selectionId; + if (m_cachedSelectionMode == QDataVis::SelectionModeNone) { + m_cachedSelectionId = 0; + m_selectionActive = false; + } + if (m_cachedSelectionMode == QDataVis::SelectionModeItem) { + if (m_cachedSelectionId) + surfacePointSelected(m_cachedSelectionId); + else + m_selectionActive = false; + } + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow + || m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { + if (m_cachedSelectionId) { + updateSliceDataModel(m_cachedSelectionId); + m_cachedScene->setSlicingActive(true); + + surfacePointSelected(m_cachedSelectionId); + + emit needRender(); + } + } + + m_selectionModeChanged = false; + } + if (m_controller->inputState() == QDataVis::InputStateOnOverview) { + if (m_cachedIsSlicingActivated) { + m_cachedScene->setSlicingActive(false); + m_selectionActive = false; + m_cachedSelectionId = 0; + } + } +} + +void Surface3DRenderer::updateSurfaceGradient(const QLinearGradient &gradient) +{ + QImage image(QSize(1, 1000), QImage::Format_RGB32); + QPainter pmp(&image); + pmp.setBrush(QBrush(gradient)); + pmp.setPen(Qt::NoPen); + pmp.drawRect(0, 0, 1, 1000); + + if (m_gradientTexture) { + m_textureHelper->deleteTexture(&m_gradientTexture); + m_gradientTexture = 0; + } + + m_gradientTexture = m_textureHelper->create2DTexture(image, false, true); +} + +// This one needs to be called when the data size changes +void Surface3DRenderer::updateSelectionTexture() +{ + // Create the selection ID image. Each grid corner gets 2x2 pixel area of + // ID color so that each vertex (data point) has 4x4 pixel area of ID color + int idImageWidth = (m_sampleSpace.width() - 1) * 4; + int idImageHeight = (m_sampleSpace.height() - 1) * 4; + int stride = idImageWidth * 4 * sizeof(uchar); // 4 = number of color components (rgba) + + uchar *bits = new uchar[idImageWidth * idImageHeight * 4 * sizeof(uchar)]; + uint id = 1; + for (int i = 0; i < idImageHeight; i += 4) { + for (int j = 0; j < idImageWidth; j += 4) { + int p = (i * idImageWidth + j) * 4; + uchar r, g, b, a; + idToRGBA(id, &r, &g, &b, &a); + fillIdCorner(&bits[p], r, g, b, a, stride); + + idToRGBA(id + 1, &r, &g, &b, &a); + fillIdCorner(&bits[p + 8], r, g, b, a, stride); + + idToRGBA(id + m_sampleSpace.width(), &r, &g, &b, &a); + fillIdCorner(&bits[p + 2 * stride], r, g, b, a, stride); + + idToRGBA(id + m_sampleSpace.width() + 1, &r, &g, &b, &a); + fillIdCorner(&bits[p + 2 * stride + 8], r, g, b, a, stride); + + id++; + } + id++; + } + + // If old texture exists, delete it + if (m_selectionTexture) { + m_textureHelper->deleteTexture(&m_selectionTexture); + m_selectionTexture = 0; + } + + // Move the ID image (bits) to the texture + QImage image = QImage(bits, idImageWidth, idImageHeight, QImage::Format_RGB32); + m_selectionTexture = m_textureHelper->create2DTexture(image, false, false, false); + + // Release the temp bits allocation + delete[] bits; +} + +void Surface3DRenderer::initSelectionBuffer() +{ + // Create the result selection texture and buffers + if (m_selectionResultTexture) { + m_textureHelper->deleteTexture(&m_selectionResultTexture); + m_selectionResultTexture = 0; + } + + m_selectionResultTexture = m_textureHelper->createSelectionTexture(m_mainViewPort.size(), + m_selectionFrameBuffer, + m_selectionDepthBuffer); +} + +void Surface3DRenderer::fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride) +{ + p[0] = r; + p[1] = g; + p[2] = b; + p[3] = a; + p[4] = r; + p[5] = g; + p[6] = b; + p[7] = a; + p[stride + 0] = r; + p[stride + 1] = g; + p[stride + 2] = b; + p[stride + 3] = a; + p[stride + 4] = r; + p[stride + 5] = g; + p[stride + 6] = b; + p[stride + 7] = a; +} + +void Surface3DRenderer::idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a) +{ + *r = id & ID_TO_RGBA_MASK; + *g = (id >> 8) & ID_TO_RGBA_MASK; + *b = (id >> 16) & ID_TO_RGBA_MASK; + *a = (id >> 24) & ID_TO_RGBA_MASK; +} + +void Surface3DRenderer::updateTextures() +{ + updateSurfaceGradient(m_cachedTheme.m_surfaceGradient); +} + +void Surface3DRenderer::calculateSceneScalingFactors() +{ + // Calculate scene scaling and translation factors + m_heightNormalizer = GLfloat(m_axisCacheY.max() - m_axisCacheY.min()); + m_areaSize.setHeight(m_axisCacheZ.max() - m_axisCacheZ.min()); + m_areaSize.setWidth(m_axisCacheX.max() - m_axisCacheX.min()); + m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + m_scaleX = aspectRatio * m_areaSize.width() / m_scaleFactor; + m_scaleZ = aspectRatio * m_areaSize.height() / m_scaleFactor; + m_scaleXWithBackground = m_scaleX * backgroundMargin; + m_scaleZWithBackground = m_scaleZ * backgroundMargin; +#else // ..and this if we want uniform scaling based on largest dimension + m_scaleX = aspectRatio / m_scaleFactor; + m_scaleZ = aspectRatio / m_scaleFactor; + m_scaleXWithBackground = aspectRatio * backgroundMargin; + m_scaleZWithBackground = aspectRatio * backgroundMargin; +#endif +} + +bool Surface3DRenderer::updateSmoothStatus(bool enable) +{ + if (!enable && !m_flatSupported) { + qWarning() << "Warning: Flat qualifier not supported on your platform's GLSL language." + " Requires at least GLSL version 1.5."; + enable = true; + } + + bool changed = false; + if (enable != m_cachedSmoothSurface) { + m_cachedSmoothSurface = enable; + changed = true; + initSurfaceShaders(); + } + + // If no surface object created yet, don't try to update the object + if (m_surfaceObj && changed && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) { + if (m_cachedSmoothSurface) { + m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), true); + } else { + m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), true); + } + } + + return m_cachedSmoothSurface; +} + +void Surface3DRenderer::updateSelectionMode(QDataVis::SelectionMode mode) +{ + if (mode != m_cachedSelectionMode) + m_selectionModeChanged = true; + + Abstract3DRenderer::updateSelectionMode(mode); +} + +void Surface3DRenderer::updateSurfaceGridStatus(bool enable) +{ + m_cachedSurfaceGridOn = enable; +} + +void Surface3DRenderer::loadBackgroundMesh() +{ + if (m_backgroundObj) + delete m_backgroundObj; + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); + m_backgroundObj->load(); +} + +void Surface3DRenderer::loadSurfaceObj() +{ + if (m_surfaceObj) + delete m_surfaceObj; + m_surfaceObj = new SurfaceObject(); +} + +void Surface3DRenderer::loadSliceSurfaceObj() +{ + if (m_sliceSurfaceObj) + delete m_sliceSurfaceObj; + m_sliceSurfaceObj = new SurfaceObject(); +} + +void Surface3DRenderer::loadGridLineMesh() +{ + if (m_gridLineObj) + delete m_gridLineObj; + m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar")); + m_gridLineObj->load(); +} + +void Surface3DRenderer::handleResize() +{ + if (m_cachedBoundingRect.width() == 0 || m_cachedBoundingRect.height() == 0) + return; + + // Set view port + if (m_cachedIsSlicingActivated) { + m_mainViewPort = QRect(0, + m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / subViewDivider, + m_cachedBoundingRect.width() / subViewDivider, + m_cachedBoundingRect.height() / subViewDivider); + } else { + m_mainViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + } + m_sliceViewPort = QRect(0, 0, m_cachedBoundingRect.width(), m_cachedBoundingRect.height()); + + if (m_selectionPointer) { + if (m_cachedIsSlicingActivated) + m_selectionPointer->updateBoundingRect(m_sliceViewPort); + else + m_selectionPointer->updateBoundingRect(m_mainViewPort); + } + + Abstract3DRenderer::handleResize(); +} + +void Surface3DRenderer::surfacePointSelected(int id) +{ + int column = (id - 1) % m_sampleSpace.width(); + int row = (id - 1) / m_sampleSpace.width(); + + if (row < 0 || column < 0 || m_dataArray.size() < row || m_dataArray.at(row)->size() < column) + return; + + qreal value = qreal(m_dataArray.at(row)->at(column).y()); + + if (!m_selectionPointer) + m_selectionPointer = new SelectionPointer(m_drawer); + + QVector3D pos; + if (m_cachedSelectionMode == QDataVis::SelectionModeSliceRow) { + pos = m_sliceSurfaceObj->vertexAt(column, 0); + pos *= QVector3D(m_surfaceScaleX, 1.0f, 0.0f); + pos += QVector3D(m_surfaceOffsetX, 0.0f, 0.0f); + m_selectionPointer->updateBoundingRect(m_sliceViewPort); + m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); + } else if (m_cachedSelectionMode == QDataVis::SelectionModeSliceColumn) { + pos = m_sliceSurfaceObj->vertexAt(row, 0); + pos *= QVector3D(m_surfaceScaleZ, 1.0f, 0.0f); + pos += QVector3D(-m_surfaceOffsetZ, 0.0f, 0.0f); + m_selectionPointer->updateBoundingRect(m_sliceViewPort); + m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); + } else { + pos = m_surfaceObj->vertexAt(column, row); + pos *= QVector3D(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);; + pos += QVector3D(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ); + m_selectionPointer->updateBoundingRect(m_mainViewPort); + m_selectionPointer->updateSliceData(false, m_autoScaleAdjustment); + } + + m_selectionPointer->setPosition(pos); + m_selectionPointer->setLabel(createSelectionLabel(value, column, row)); + m_selectionPointer->updateScene(m_cachedScene); + + //Put the selection pointer flag active + m_selectionActive = true; +} + +QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row) +{ + QString labelText = itemLabelFormat(); + static const QString xTitleTag(QStringLiteral("@xTitle")); + static const QString yTitleTag(QStringLiteral("@yTitle")); + static const QString zTitleTag(QStringLiteral("@zTitle")); + static const QString xLabelTag(QStringLiteral("@xLabel")); + static const QString yLabelTag(QStringLiteral("@yLabel")); + static const QString zLabelTag(QStringLiteral("@zLabel")); + + labelText.replace(xTitleTag, m_axisCacheX.title()); + labelText.replace(yTitleTag, m_axisCacheY.title()); + labelText.replace(zTitleTag, m_axisCacheZ.title()); + + if (labelText.contains(xLabelTag)) { + QString labelFormat = m_axisCacheX.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, + m_dataArray.at(row)->at(column).x()); + labelText.replace(xLabelTag, valueLabelText); + } + if (labelText.contains(yLabelTag)) { + QString labelFormat = m_axisCacheY.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, value); + labelText.replace(yLabelTag, valueLabelText); + } + if (labelText.contains(zLabelTag)) { + QString labelFormat = m_axisCacheZ.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, + m_dataArray.at(row)->at(column).z()); + labelText.replace(zLabelTag, valueLabelText); + } + + return labelText; +} + +void Surface3DRenderer::loadMeshFile() +{ + qDebug() << __FUNCTION__ << "should we do something"; +} + +void Surface3DRenderer::updateShadowQuality(QDataVis::ShadowQuality quality) +{ + qWarning() << "Shadows have been disabled for Q3DSurface in technology preview"; + m_cachedShadowQuality = QDataVis::ShadowQualityNone; //quality; + switch (quality) { + case QDataVis::ShadowQualityLow: + m_shadowQualityToShader = 33.3f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualityMedium: + m_shadowQualityToShader = 100.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualityHigh: + m_shadowQualityToShader = 200.0f; + m_shadowQualityMultiplier = 5; + break; + case QDataVis::ShadowQualitySoftLow: + m_shadowQualityToShader = 5.0f; + m_shadowQualityMultiplier = 1; + break; + case QDataVis::ShadowQualitySoftMedium: + m_shadowQualityToShader = 10.0f; + m_shadowQualityMultiplier = 3; + break; + case QDataVis::ShadowQualitySoftHigh: + m_shadowQualityToShader = 15.0f; + m_shadowQualityMultiplier = 4; + break; + default: + m_shadowQualityToShader = 0.0f; + m_shadowQualityMultiplier = 1; + break; + } + +#if !defined(QT_OPENGL_ES_2) + updateDepthBuffer(); +#endif +} + +void Surface3DRenderer::updateSlicingActive(bool isSlicing) +{ + if (isSlicing == m_cachedIsSlicingActivated) + return; + + m_cachedIsSlicingActivated = isSlicing; + if (isSlicing) { + m_mainViewPort = QRect(0, m_cachedBoundingRect.height() - m_cachedBoundingRect.height() / subViewDivider, + m_cachedBoundingRect.width() / subViewDivider, m_cachedBoundingRect.height() / subViewDivider); + if (m_depthTexture) { + m_textureHelper->deleteTexture(&m_depthTexture); + m_depthTexture = 0; + } + } else { + m_mainViewPort = QRect(0, 0, this->m_cachedBoundingRect.width(), + this->m_cachedBoundingRect.height()); + initSelectionBuffer(); // We need to re-init selection buffer in case there has been a resize +#if !defined(QT_OPENGL_ES_2) + updateDepthBuffer(); // Re-init depth buffer as well +#endif + } +} + +void Surface3DRenderer::loadLabelMesh() +{ + if (m_labelObj) + delete m_labelObj; + m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label")); + m_labelObj->load(); +} + +void Surface3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_shader) + delete m_shader; + m_shader = new ShaderHelper(this, vertexShader, fragmentShader); + m_shader->initialize(); +} + +void Surface3DRenderer::initBackgroundShaders(const QString &vertexShader, + const QString &fragmentShader) +{ + if (m_backgroundShader) + delete m_backgroundShader; + m_backgroundShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_backgroundShader->initialize(); +} + +void Surface3DRenderer::initSelectionShaders() +{ + if (m_selectionShader) + delete m_selectionShader; + m_selectionShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"), + QStringLiteral(":/shaders/fragmentLabel")); + m_selectionShader->initialize(); +} + +void Surface3DRenderer::initSurfaceShaders() +{ + if (m_surfaceShader) + delete m_surfaceShader; + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedSmoothSurface) { + m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurface"), + QStringLiteral(":/shaders/fragmentSurface")); + } else { + m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), + QStringLiteral(":/shaders/fragmentSurfaceFlat")); + } +#else + m_surfaceShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurface"), + QStringLiteral(":/shaders/fragmentSurfaceES2")); +#endif + m_surfaceShader->initialize(); + + if (m_surfaceGridShader) + delete m_surfaceGridShader; + + m_surfaceGridShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceGrid"), + QStringLiteral(":/shaders/fragmentSurfaceGrid")); + + m_surfaceGridShader->initialize(); +} + +void Surface3DRenderer::initLabelShaders(const QString &vertexShader, const QString &fragmentShader) +{ + if (m_labelShader) + delete m_labelShader; + m_labelShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_labelShader->initialize(); +} + +#if !defined(QT_OPENGL_ES_2) +void Surface3DRenderer::initDepthShader() +{ + // TODO: Implement a depth shader for surface after technology preview + if (m_depthShader) + delete m_depthShader; + m_depthShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexDepth"), + QStringLiteral(":/shaders/fragmentDepth")); + m_depthShader->initialize(); +} + +void Surface3DRenderer::updateDepthBuffer() +{ + if (m_depthTexture) { + m_textureHelper->deleteTexture(&m_depthTexture); + m_depthTexture = 0; + } + + if (m_cachedShadowQuality > QDataVis::ShadowQualityNone) { + m_depthTexture = m_textureHelper->createDepthTexture(m_mainViewPort.size(), + m_depthFrameBuffer, + m_shadowQualityMultiplier); + if (!m_depthTexture) { + switch (m_cachedShadowQuality) { + case QDataVis::ShadowQualityHigh: + qWarning("Creating high quality shadows failed. Changing to medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityMedium); + updateShadowQuality(QDataVis::ShadowQualityMedium); + break; + case QDataVis::ShadowQualityMedium: + qWarning("Creating medium quality shadows failed. Changing to low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityLow); + updateShadowQuality(QDataVis::ShadowQualityLow); + break; + case QDataVis::ShadowQualityLow: + qWarning("Creating low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + case QDataVis::ShadowQualitySoftHigh: + qWarning("Creating soft high quality shadows failed. Changing to soft medium quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftMedium); + updateShadowQuality(QDataVis::ShadowQualitySoftMedium); + break; + case QDataVis::ShadowQualitySoftMedium: + qWarning("Creating soft medium quality shadows failed. Changing to soft low quality."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualitySoftLow); + updateShadowQuality(QDataVis::ShadowQualitySoftLow); + break; + case QDataVis::ShadowQualitySoftLow: + qWarning("Creating soft low quality shadows failed. Switching shadows off."); + (void)m_controller->setShadowQuality(QDataVis::ShadowQualityNone); + updateShadowQuality(QDataVis::ShadowQualityNone); + break; + default: + // You'll never get here + break; + } + } + } +} +#endif + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h new file mode 100644 index 00000000..e42e820a --- /dev/null +++ b/src/datavisualization/engine/surface3drenderer_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef SURFACE3DRENDERER_P_H +#define SURFACE3DRENDERER_P_H + +#include <QtCore/QSize> +#include <QtCore/QObject> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QFont> +#include <QLinearGradient> +#include <QWindow> + +#include "datavisualizationglobal_p.h" +#include "surface3dcontroller_p.h" +#include "abstract3drenderer_p.h" +#include "scatterrenderitem_p.h" +#include "qsurfacedataproxy.h" + +class QOpenGLShaderProgram; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class ShaderHelper; +class ObjectHelper; +class SurfaceObject; +class TextureHelper; +class Theme; +class Drawer; +class Q3DScene; +class SelectionPointer; + +class QT_DATAVISUALIZATION_EXPORT Surface3DRenderer : public Abstract3DRenderer +{ + Q_OBJECT + +public: + Surface3DController *m_controller; + + // Visual parameters + QRect m_boundingRect; + QDataVis::LabelStyle m_labelStyle; + QFont m_font; + bool m_isGridEnabled; + +private: + bool m_cachedIsSlicingActivated; + + // Internal attributes purely related to how the scene is drawn with GL. + QRect m_mainViewPort; + QRect m_sliceViewPort; + ShaderHelper *m_shader; + ShaderHelper *m_depthShader; + ShaderHelper *m_backgroundShader; + ShaderHelper *m_surfaceShader; + ShaderHelper *m_surfaceGridShader; + ShaderHelper *m_selectionShader; + ShaderHelper *m_labelShader; + GLfloat m_heightNormalizer; + GLfloat m_scaleFactor; + GLfloat m_scaleX; + GLfloat m_scaleZ; + GLfloat m_scaleXWithBackground; + GLfloat m_scaleZWithBackground; + GLfloat m_surfaceScaleX; + GLfloat m_surfaceScaleZ; + GLfloat m_surfaceOffsetX; + GLfloat m_surfaceOffsetZ; + GLfloat m_minVisibleColumnValue; + GLfloat m_maxVisibleColumnValue; + GLfloat m_minVisibleRowValue; + GLfloat m_maxVisibleRowValue; + GLfloat m_visibleColumnRange; + GLfloat m_visibleRowRange; + ObjectHelper *m_backgroundObj; + ObjectHelper *m_gridLineObj; + ObjectHelper *m_labelObj; + SurfaceObject *m_surfaceObj; + SurfaceObject *m_sliceSurfaceObj; + GLuint m_depthTexture; + GLuint m_depthFrameBuffer; + GLuint m_selectionFrameBuffer; + GLuint m_selectionDepthBuffer; + GLuint m_gradientTexture; + GLuint m_selectionTexture; + GLuint m_selectionResultTexture; + GLfloat m_shadowQualityToShader; + bool m_cachedSmoothSurface; + bool m_flatSupported; + bool m_cachedSurfaceGridOn; + SelectionPointer *m_selectionPointer; + bool m_selectionActive; + bool m_xFlipped; + bool m_zFlipped; + bool m_yFlipped; + AbstractRenderItem m_dummyRenderItem; + QSurfaceDataArray m_dataArray; + QSurfaceDataArray m_sliceDataArray; + QRect m_sampleSpace; + GLint m_shadowQualityMultiplier; + QSizeF m_areaSize; + uint m_cachedSelectionId; + bool m_selectionModeChanged; + bool m_hasHeightAdjustmentChanged; + +public: + explicit Surface3DRenderer(Surface3DController *controller); + ~Surface3DRenderer(); + + void updateDataModel(QSurfaceDataProxy *dataProxy); + void updateScene(Q3DScene *scene); + void drawSlicedScene(); + void render(GLuint defaultFboHandle = 0); + +protected: + void initializeOpenGL(); + virtual void loadMeshFile(); + +public slots: + bool updateSmoothStatus(bool enable); + void updateSurfaceGridStatus(bool enable); + void updateSurfaceGradient(const QLinearGradient &gradient); + void updateSlicingActive(bool isSlicing); + void updateSelectionMode(QDataVis::SelectionMode mode); + +private: + void updateSliceDataModel(int selectionId); + virtual void updateShadowQuality(QDataVis::ShadowQuality quality); + virtual void updateTextures(); + virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); + QRect calculateSampleRect(const QSurfaceDataArray &array); + void loadBackgroundMesh(); + void loadGridLineMesh(); + void loadLabelMesh(); + void loadSurfaceObj(); + void loadSliceSurfaceObj(); + void drawScene(GLuint defaultFboHandle); + void handleResize(); + void calculateSceneScalingFactors(); + void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader); + void initLabelShaders(const QString &vertexShader, const QString &fragmentShader); + void initSelectionShaders(); + void initSurfaceShaders(); + void initSelectionBuffer(); + void initDepthShader(); + void updateSelectionTexture(); + void idToRGBA(uint id, uchar *r, uchar *g, uchar *b, uchar *a); + void fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride); + void surfacePointSelected(int id); + QString createSelectionLabel(qreal value, int column, int row); +#if !defined(QT_OPENGL_ES_2) + void updateDepthBuffer(); +#endif + + Q_DISABLE_COPY(Surface3DRenderer) +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif // SURFACE3DRENDERER_P_H diff --git a/src/datavisualization/engine/theme.cpp b/src/datavisualization/engine/theme.cpp new file mode 100644 index 00000000..d9f2974a --- /dev/null +++ b/src/datavisualization/engine/theme.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "theme_p.h" + +#ifdef Q_OS_WIN +#include <windows.h> +#include <stdio.h> +#endif + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +Theme::Theme() + : m_baseColor(QColor(Qt::gray)), + m_heightColor(QColor(Qt::black)), + m_depthColor(QColor(Qt::black)), + m_backgroundColor(QColor(Qt::gray)), + m_windowColor(QColor(Qt::gray)), + m_textColor(QColor(Qt::white)), + m_textBackgroundColor(QColor(0x00, 0x00, 0x00, 0xa0)), + m_gridLine(QColor(Qt::black)), + m_highlightBarColor(QColor(Qt::red)), + m_highlightRowColor(QColor(Qt::darkRed)), + m_highlightColumnColor(QColor(Qt::darkMagenta)), + m_surfaceGradient(QLinearGradient(1, 1000, 0, 0)), + m_lightStrength(4.0f), + m_ambientStrength(0.3f), + m_highlightLightStrength(8.0f), + m_uniformColor(true), + m_labelBorders(false) +{ + // Default values for surface gradient +} + +Theme::~Theme() +{ +} + +QDataVis::Theme Theme::theme() +{ + return m_theme; +} + +void Theme::useTheme(QDataVis::Theme theme) +{ + m_theme = theme; + switch (theme) { + case QDataVis::ThemeQt: { + m_baseColor = QColor(QRgb(0x80c342)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0xffffff)); + m_windowColor = QColor(QRgb(0xffffff)); + m_textColor = QColor(QRgb(0x35322f)); + m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x99); + m_gridLine = QColor(QRgb(0xd7d6d5)); + m_highlightBarColor = QColor(QRgb(0x14aaff)); + m_highlightRowColor = QColor(QRgb(0x6400aa)); + m_highlightColumnColor = QColor(QRgb(0x6400aa)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = true; + m_labelBorders = true; + break; + } + case QDataVis::ThemePrimaryColors: { + m_baseColor = QColor(QRgb(0xffe400)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0xffffff)); + m_windowColor = QColor(QRgb(0xffffff)); + m_textColor = QColor(QRgb(0x000000)); + m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x99); + m_gridLine = QColor(QRgb(0xd7d6d5)); + m_highlightBarColor = QColor(QRgb(0x27beee)); + m_highlightRowColor = QColor(QRgb(0xee1414)); + m_highlightColumnColor = QColor(QRgb(0xee1414)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = true; + m_labelBorders = false; + break; + } + case QDataVis::ThemeDigia: { + m_baseColor = QColor(QRgb(0xcccccc)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0xffffff)); + m_windowColor = QColor(QRgb(0xffffff)); + m_textColor = QColor(QRgb(0x000000)); + m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x80); + m_gridLine = QColor(QRgb(0xd7d6d5)); + m_highlightBarColor = QColor(QRgb(0xfa0000)); + m_highlightRowColor = QColor(QRgb(0x555555)); + m_highlightColumnColor = QColor(QRgb(0x555555)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = false; + m_labelBorders = false; + break; + } + case QDataVis::ThemeStoneMoss: { + m_baseColor = QColor(QRgb(0xbeb32b)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0x4d4d4f)); + m_windowColor = QColor(QRgb(0x4d4d4f)); + m_textColor = QColor(QRgb(0xffffff)); + m_textBackgroundColor = QColor(0x4d, 0x4d, 0x4f, 0xcd); + m_gridLine = QColor(QRgb(0x3e3e40)); + m_highlightBarColor = QColor(QRgb(0xfbf6d6)); + m_highlightRowColor = QColor(QRgb(0x442f20)); + m_highlightColumnColor = QColor(QRgb(0x442f20)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = true; + m_labelBorders = true; + break; + } + case QDataVis::ThemeArmyBlue: { + m_baseColor = QColor(QRgb(0x495f76)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0xd5d6d7)); + m_windowColor = QColor(QRgb(0xd5d6d7)); + m_textColor = QColor(QRgb(0x000000)); + m_textBackgroundColor = QColor(0xd5, 0xd6, 0xd7, 0xcd); + m_gridLine = QColor(QRgb(0xaeadac)); + m_highlightBarColor = QColor(QRgb(0x2aa2f9)); + m_highlightRowColor = QColor(QRgb(0x103753)); + m_highlightColumnColor = QColor(QRgb(0x103753)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = false; + m_labelBorders = false; + break; + } + case QDataVis::ThemeRetro: { + m_baseColor = QColor(QRgb(0x533b23)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0xe9e2ce)); + m_windowColor = QColor(QRgb(0xe9e2ce)); + m_textColor = QColor(QRgb(0x000000)); + m_textBackgroundColor = QColor(0xe9, 0xe2, 0xce, 0xc0); + m_gridLine = QColor(QRgb(0xd0c0b0)); + m_highlightBarColor = QColor(QRgb(0x8ea317)); + m_highlightRowColor = QColor(QRgb(0xc25708)); + m_highlightColumnColor = QColor(QRgb(0xc25708)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = false; + m_labelBorders = false; + break; + } + case QDataVis::ThemeEbony: { + m_baseColor = QColor(QRgb(0xffffff)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0x000000)); + m_windowColor = QColor(QRgb(0x000000)); + m_textColor = QColor(QRgb(0xaeadac)); + m_textBackgroundColor = QColor(0x00, 0x00, 0x00, 0xcd); + m_gridLine = QColor(QRgb(0x35322f)); + m_highlightBarColor = QColor(QRgb(0xf5dc0d)); + m_highlightRowColor = QColor(QRgb(0xd72222)); + m_highlightColumnColor = QColor(QRgb(0xd72222)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = true; + m_labelBorders = false; + break; + } + case QDataVis::ThemeIsabelle: { + m_baseColor = QColor(QRgb(0xf9d900)); + //m_heightColor = QColor(QRgb(0x)); + //m_depthColor = QColor(QRgb(0x)); + m_backgroundColor = QColor(QRgb(0x000000)); + m_windowColor = QColor(QRgb(0x000000)); + m_textColor = QColor(QRgb(0xaeadac)); + m_textBackgroundColor = QColor(0x00, 0x00, 0x00, 0xc0); + m_gridLine = QColor(QRgb(0x35322f)); + m_highlightBarColor = QColor(QRgb(0xfff7cc)); + m_highlightRowColor = QColor(QRgb(0xde0a0a)); + m_highlightColumnColor = QColor(QRgb(0xde0a0a)); + m_lightStrength = 5.0f; + m_ambientStrength = 0.5f; + m_highlightLightStrength = 5.0f; + m_uniformColor = true; + m_labelBorders = false; + break; + } + default: + break; + } + if (m_uniformColor) { + m_surfaceGradient.setColorAt(0.0, m_baseColor); + } else { + m_surfaceGradient.setColorAt(0.0, QColor(m_baseColor.redF() * 0.7, + m_baseColor.greenF() * 0.7, + m_baseColor.blueF() * 0.7)); + } + m_surfaceGradient.setColorAt(1.0, m_baseColor); +} + +void Theme::setFromTheme(Theme &theme) +{ + m_theme = theme.m_theme; + m_baseColor = theme.m_baseColor; + m_heightColor = theme.m_heightColor; + m_depthColor = theme.m_depthColor; + m_backgroundColor = theme.m_backgroundColor; + m_windowColor = theme.m_windowColor; + m_textColor = theme.m_textColor; + m_textBackgroundColor = theme.m_textBackgroundColor; + m_gridLine = theme.m_gridLine; + m_highlightBarColor = theme.m_highlightBarColor; + m_highlightRowColor = theme.m_highlightRowColor; + m_highlightColumnColor = theme.m_highlightColumnColor; + m_surfaceGradient = theme.m_surfaceGradient; + m_lightStrength = theme.m_lightStrength; + m_ambientStrength = theme.m_ambientStrength; + m_highlightLightStrength = theme.m_highlightLightStrength; + m_uniformColor = theme.m_uniformColor; + m_labelBorders = theme.m_labelBorders; +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/theme_p.h b/src/datavisualization/engine/theme_p.h new file mode 100644 index 00000000..ec689f63 --- /dev/null +++ b/src/datavisualization/engine/theme_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef THEME_P_H +#define THEME_P_H + +#include "datavisualizationglobal_p.h" +#include "q3dbars.h" +#include <QLinearGradient> + +class QColor; + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class QT_DATAVISUALIZATION_EXPORT Theme +{ +public: + explicit Theme(); + ~Theme(); + + void useTheme(QDataVis::Theme theme); + QDataVis::Theme theme(); + void setFromTheme(Theme &theme); + +private: + friend class Abstract3DController; + friend class Abstract3DRenderer; + friend class Bars3DRenderer; + friend class Surface3DRenderer; + friend class Surface3DController; + friend class Scatter3DRenderer; + friend class SelectionPointer; + friend class Drawer; + + QDataVis::Theme m_theme; + QColor m_baseColor; + QColor m_heightColor; + QColor m_depthColor; + QColor m_backgroundColor; + QColor m_windowColor; + QColor m_textColor; + QColor m_textBackgroundColor; + QColor m_gridLine; + QColor m_highlightBarColor; + QColor m_highlightRowColor; + QColor m_highlightColumnColor; + QLinearGradient m_surfaceGradient; + float m_lightStrength; + float m_ambientStrength; + float m_highlightLightStrength; + bool m_uniformColor; + bool m_labelBorders; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif |