diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-06-05 12:00:24 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-06-05 12:03:16 +0300 |
commit | cfbfbea7d932f98c3f541bb4fc3e975ffb7a5658 (patch) | |
tree | bed376368e9611c751cf1dd75b85de2827d67325 /src/datavisualization/engine/abstract3drenderer.cpp | |
parent | 8435c15d224a4e9db0920ecd33c4bea3e70d83bf (diff) | |
parent | c51e0f83ef6dd9e85db6953995585ba0cafb35d7 (diff) |
Merge branch 'develop'
Change-Id: I3d06158cec5e54f69ff3d0606b7d1dfe1a8a2f70
Diffstat (limited to 'src/datavisualization/engine/abstract3drenderer.cpp')
-rw-r--r-- | src/datavisualization/engine/abstract3drenderer.cpp | 797 |
1 files changed, 712 insertions, 85 deletions
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 3122cf76..5d97a6ca 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -17,15 +17,13 @@ ****************************************************************************/ #include "abstract3drenderer_p.h" -#include "qvalue3daxis.h" #include "texturehelper_p.h" -#include "utils_p.h" -#include "q3dscene_p.h" #include "q3dcamera_p.h" -#include "q3dlight_p.h" -#include "qabstract3dseries_p.h" #include "q3dtheme_p.h" -#include "objecthelper_p.h" +#include "qvalue3daxisformatter_p.h" +#include "shaderhelper_p.h" +#include "qcustom3ditem_p.h" +#include "qcustom3dlabel_p.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -37,6 +35,7 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) m_cachedShadowQuality(QAbstract3DGraph::ShadowQualityMedium), m_autoScaleAdjustment(1.0f), m_cachedSelectionMode(QAbstract3DGraph::SelectionNone), + m_cachedOptimizationHint(QAbstract3DGraph::OptimizationDefault), m_textureHelper(0), m_cachedScene(new Q3DScene()), m_selectionDirty(true), @@ -45,12 +44,18 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) m_selectionLabelDirty(true), m_clickPending(false), m_clickedSeries(0), - m_selectionLabelItem(0) -#ifdef DISPLAY_RENDER_SPEED - , m_isFirstFrame(true), - m_numFrames(0) -#endif - + m_clickedType(QAbstract3DGraph::ElementNone), + m_selectionLabelItem(0), + m_visibleSeriesCount(0), + m_customItemShader(0), + m_useOrthoProjection(false), + m_xFlipped(false), + m_yFlipped(false), + m_zFlipped(false), + m_backgroundObj(0), + m_gridLineObj(0), + m_labelObj(0), + m_graphAspectRatio(2.0f) { QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Abstract3DRenderer::updateTextures); QObject::connect(this, &Abstract3DRenderer::needRender, controller, @@ -61,14 +66,30 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller) Abstract3DRenderer::~Abstract3DRenderer() { - for (int i = 0; i < m_visibleSeriesList.size(); i++) - m_visibleSeriesList[i].cleanup(m_textureHelper); - delete m_drawer; - delete m_textureHelper; delete m_cachedScene; delete m_cachedTheme; delete m_selectionLabelItem; + delete m_customItemShader; + + foreach (SeriesRenderCache *cache, m_renderCacheList) { + cache->cleanup(m_textureHelper); + delete cache; + } + m_renderCacheList.clear(); + + foreach (CustomRenderItem *item, m_customRenderCache) { + GLuint texture = item->texture(); + m_textureHelper->deleteTexture(&texture); + delete item; + } + m_customRenderCache.clear(); + + ObjectHelper::releaseObjectHelper(this, m_backgroundObj); + ObjectHelper::releaseObjectHelper(this, m_gridLineObj); + ObjectHelper::releaseObjectHelper(this, m_labelObj); + + delete m_textureHelper; } void Abstract3DRenderer::initializeOpenGL() @@ -95,23 +116,6 @@ void Abstract3DRenderer::initializeOpenGL() 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() << float(m_lastFrameTime.elapsed()) / float(m_numFrames) << "ms/frame (=" - << float(m_numFrames) << "fps)"; - m_numFrames = 0; - m_lastFrameTime.restart(); - } -#endif - if (defaultFboHandle) { glDepthMask(true); glEnable(GL_DEPTH_TEST); @@ -131,20 +135,12 @@ void Abstract3DRenderer::render(const GLuint defaultFboHandle) m_viewport.width(), m_viewport.height()); glEnable(GL_SCISSOR_TEST); - QVector3D clearColor = Utils::vectorFromColor(m_cachedTheme->windowColor()); + QVector4D clearColor = Utils::vectorFromColor(m_cachedTheme->windowColor()); glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); } -QString Abstract3DRenderer::generateValueLabel(const QString &format, float value) -{ - QString valueLabelFormat = format; - Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat); - QByteArray valueFormatArray = valueLabelFormat.toUtf8(); - return Utils::formatLabel(valueFormatArray, valueParamType, value); -} - void Abstract3DRenderer::updateSelectionState(SelectionState state) { m_selectionState = state; @@ -163,6 +159,15 @@ void Abstract3DRenderer::initGradientShaders(const QString &vertexShader, Q_UNUSED(fragmentShader) } +void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader, + const QString &fragmentShader) +{ + if (m_customItemShader) + delete m_customItemShader; + m_customItemShader = new ShaderHelper(this, vertexShader, fragmentShader); + m_customItemShader->initialize(); +} + void Abstract3DRenderer::updateTheme(Q3DTheme *theme) { // Synchronize the controller theme with renderer @@ -229,6 +234,8 @@ void Abstract3DRenderer::reInitShaders() QStringLiteral(":/shaders/fragmentShadowNoTex")); initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"), QStringLiteral(":/shaders/fragmentShadowNoTex")); + initCustomItemShaders(QStringLiteral(":/shaders/vertexShadow"), + QStringLiteral(":/shaders/fragmentShadow")); } else { initGradientShaders(QStringLiteral(":/shaders/vertex"), QStringLiteral(":/shaders/fragmentColorOnY")); @@ -236,6 +243,8 @@ void Abstract3DRenderer::reInitShaders() QStringLiteral(":/shaders/fragment")); initBackgroundShaders(QStringLiteral(":/shaders/vertex"), QStringLiteral(":/shaders/fragment")); + initCustomItemShaders(QStringLiteral(":/shaders/vertexTexture"), + QStringLiteral(":/shaders/fragmentTexture")); } #else initGradientShaders(QStringLiteral(":/shaders/vertex"), @@ -244,6 +253,8 @@ void Abstract3DRenderer::reInitShaders() QStringLiteral(":/shaders/fragmentES2")); initBackgroundShaders(QStringLiteral(":/shaders/vertex"), QStringLiteral(":/shaders/fragmentES2")); + initCustomItemShaders(QStringLiteral(":/shaders/vertexTexture"), + QStringLiteral(":/shaders/fragmentTextureES2")); #endif } @@ -266,18 +277,28 @@ void Abstract3DRenderer::updateSelectionMode(QAbstract3DGraph::SelectionFlags mo m_selectionDirty = true; } +void Abstract3DRenderer::updateAspectRatio(float ratio) +{ + m_graphAspectRatio = ratio; + calculateZoomLevel(); + m_cachedScene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment); + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setDataDirty(true); + updateCustomItemPositions(); +} + +void Abstract3DRenderer::updateOptimizationHint(QAbstract3DGraph::OptimizationHints hint) +{ + m_cachedOptimizationHint = hint; +} + void Abstract3DRenderer::handleResize() { if (m_primarySubViewport.width() == 0 || m_primarySubViewport.height() == 0) return; - // Calculate zoom level based on aspect ratio - GLfloat div; - GLfloat zoomAdjustment; - div = qMin(m_primarySubViewport.width(), m_primarySubViewport.height()); - zoomAdjustment = defaultRatio * ((m_primarySubViewport.width() / div) - / (m_primarySubViewport.height() / div)); - m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f + // Recalculate zoom + calculateZoomLevel(); // Re-init selection buffer initSelectionBuffer(); @@ -288,6 +309,18 @@ void Abstract3DRenderer::handleResize() #endif } +void Abstract3DRenderer::calculateZoomLevel() +{ + // Calculate zoom level based on aspect ratio + GLfloat div; + GLfloat zoomAdjustment; + div = qMin(m_primarySubViewport.width(), m_primarySubViewport.height()); + zoomAdjustment = 2.0f * defaultRatio + * ((m_primarySubViewport.width() / div) + / (m_primarySubViewport.height() / div)) / m_graphAspectRatio; + m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f +} + void Abstract3DRenderer::updateAxisType(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis::AxisType type) { @@ -312,18 +345,25 @@ void Abstract3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orient AxisRenderCache &cache = axisCacheForOrientation(orientation); cache.setMin(min); cache.setMax(max); + + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setDataDirty(true); + + updateCustomItemPositions(); } void Abstract3DRenderer::updateAxisSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count) { - axisCacheForOrientation(orientation).setSegmentCount(count); + AxisRenderCache &cache = axisCacheForOrientation(orientation); + cache.setSegmentCount(count); } void Abstract3DRenderer::updateAxisSubSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count) { - axisCacheForOrientation(orientation).setSubSegmentCount(count); + AxisRenderCache &cache = axisCacheForOrientation(orientation); + cache.setSubSegmentCount(count); } void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation, @@ -332,6 +372,67 @@ void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation axisCacheForOrientation(orientation).setLabelFormat(format); } +void Abstract3DRenderer::updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, + bool enable) +{ + axisCacheForOrientation(orientation).setReversed(enable); + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setDataDirty(true); + + updateCustomItemPositions(); +} + +void Abstract3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation, + QValue3DAxisFormatter *formatter) +{ + AxisRenderCache &cache = axisCacheForOrientation(orientation); + if (cache.ctrlFormatter() != formatter) { + delete cache.formatter(); + cache.setFormatter(formatter->createNewInstance()); + cache.setCtrlFormatter(formatter); + } + formatter->d_ptr->populateCopy(*(cache.formatter())); + cache.markPositionsDirty(); + + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setDataDirty(true); + + updateCustomItemPositions(); +} + +void Abstract3DRenderer::updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientation orientation, + float angle) +{ + AxisRenderCache &cache = axisCacheForOrientation(orientation); + if (cache.labelAutoRotation() != angle) + cache.setLabelAutoRotation(angle); +} + +void Abstract3DRenderer::updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientation orientation, + bool visible) +{ + AxisRenderCache &cache = axisCacheForOrientation(orientation); + if (cache.isTitleVisible() != visible) + cache.setTitleVisible(visible); +} + +void Abstract3DRenderer::updateAxisTitleFixed(QAbstract3DAxis::AxisOrientation orientation, + bool fixed) +{ + AxisRenderCache &cache = axisCacheForOrientation(orientation); + if (cache.isTitleFixed() != fixed) + cache.setTitleFixed(fixed); +} + +void Abstract3DRenderer::modifiedSeriesList(const QVector<QAbstract3DSeries *> &seriesList) +{ + foreach (QAbstract3DSeries *series, seriesList) { + SeriesRenderCache *cache = m_renderCacheList.value(series, 0); + if (cache) + cache->setDataDirty(true); + } +} + void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh) { // Default implementation does nothing. @@ -339,41 +440,84 @@ void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::M Q_UNUSED(mesh) } -void Abstract3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList, - bool updateVisibility) +void Abstract3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList) { - int visibleCount = 0; - if (updateVisibility) { - int oldSize = m_visibleSeriesList.size(); - foreach (QAbstract3DSeries *current, seriesList) { - if (current->isVisible()) - visibleCount++; - } + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setValid(false); - // Clean up series caches that are about to be permanently deleted. - // Can't just use cache destructor, as resize will call that to all items. - if (visibleCount < oldSize) { - for (int i = visibleCount; i < oldSize; i++) - m_visibleSeriesList[i].cleanup(m_textureHelper); + m_visibleSeriesCount = 0; + int seriesCount = seriesList.size(); + for (int i = 0; i < seriesCount; i++) { + QAbstract3DSeries *series = seriesList.at(i); + SeriesRenderCache *cache = m_renderCacheList.value(series); + bool newSeries = false; + if (!cache) { + cache = createNewCache(series); + m_renderCacheList[series] = cache; + newSeries = true; } + cache->setValid(true); + cache->populate(newSeries); + if (cache->isVisible()) + m_visibleSeriesCount++; + } + + // Remove non-valid objects from the cache list + foreach (SeriesRenderCache *cache, m_renderCacheList) { + if (!cache->isValid()) + cleanCache(cache); + } +} + +void Abstract3DRenderer::updateCustomData(const QList<QCustom3DItem *> &customItems) +{ + if (customItems.isEmpty() && m_customRenderCache.isEmpty()) + return; - if (visibleCount != oldSize) - m_visibleSeriesList.resize(visibleCount); + foreach (CustomRenderItem *item, m_customRenderCache) + item->setValid(false); - visibleCount = 0; + int itemCount = customItems.size(); + // Check custom item list for items that are not yet in render item cache + for (int i = 0; i < itemCount; i++) { + QCustom3DItem *item = customItems.at(i); + CustomRenderItem *renderItem = m_customRenderCache.value(item); + if (!renderItem) + renderItem = addCustomItem(item); + renderItem->setValid(true); + renderItem->setIndex(i); // always update index, as it must match the custom item index } - foreach (QAbstract3DSeries *current, seriesList) { - if (current->isVisible()) { - // Item selection label may need update - if (current->d_ptr->m_changeTracker.nameChanged - || current->d_ptr->m_changeTracker.itemLabelFormatChanged) { - m_selectionLabelDirty = true; - } - m_visibleSeriesList[visibleCount++].populate(current, this); + + // Check render item cache and remove items that are not in customItems list anymore + foreach (CustomRenderItem *renderItem, m_customRenderCache) { + if (!renderItem->isValid()) { + m_customRenderCache.remove(renderItem->itemPointer()); + GLuint texture = renderItem->texture(); + m_textureHelper->deleteTexture(&texture); + delete renderItem; } } } +void Abstract3DRenderer::updateCustomItems() +{ + // Check all items + foreach (CustomRenderItem *item, m_customRenderCache) + updateCustomItem(item); +} + +SeriesRenderCache *Abstract3DRenderer::createNewCache(QAbstract3DSeries *series) +{ + return new SeriesRenderCache(series, this); +} + +void Abstract3DRenderer::cleanCache(SeriesRenderCache *cache) +{ + m_renderCacheList.remove(cache->series()); + cache->cleanup(m_textureHelper); + delete cache; +} + AxisRenderCache &Abstract3DRenderer::axisCacheForOrientation( QAbstract3DAxis::AxisOrientation orientation) { @@ -428,26 +572,243 @@ void Abstract3DRenderer::lowerShadowQuality() updateShadowQuality(newQuality); } -void Abstract3DRenderer::generateBaseColorTexture(const QColor &color, GLuint *texture) +void Abstract3DRenderer::drawAxisTitleY(const QVector3D &sideLabelRotation, + const QVector3D &backLabelRotation, + const QVector3D &sideLabelTrans, + const QVector3D &backLabelTrans, + const QQuaternion &totalSideRotation, + const QQuaternion &totalBackRotation, + AbstractRenderItem &dummyItem, + const Q3DCamera *activeCamera, + float labelsMaxWidth, + const QMatrix4x4 &viewMatrix, + const QMatrix4x4 &projectionMatrix, + ShaderHelper *shader) { - if (*texture) { - m_textureHelper->deleteTexture(texture); - *texture = 0; + float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheY.titleItem().size().height(); + float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor)); + float yRotation; + QVector3D titleTrans; + QQuaternion totalRotation; + if (m_xFlipped == m_zFlipped) { + yRotation = backLabelRotation.y(); + titleTrans = backLabelTrans; + totalRotation = totalBackRotation; + } else { + yRotation = sideLabelRotation.y(); + titleTrans = sideLabelTrans; + totalRotation = totalSideRotation; + } + + QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation); + QVector3D titleOffsetVector = + offsetRotator.rotatedVector(QVector3D(-titleOffset, 0.0f, 0.0f)); + + QQuaternion titleRotation; + if (m_axisCacheY.isTitleFixed()) { + titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation) + * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, 90.0f); + } else { + titleRotation = totalRotation + * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, 90.0f); } + dummyItem.setTranslation(titleTrans + titleOffsetVector); + + m_drawer->drawLabel(dummyItem, m_axisCacheY.titleItem(), viewMatrix, + projectionMatrix, zeroVector, titleRotation, 0, + m_cachedSelectionMode, shader, m_labelObj, activeCamera, + true, true, Drawer::LabelMid, Qt::AlignBottom); +} +void Abstract3DRenderer::drawAxisTitleX(const QVector3D &labelRotation, + const QVector3D &labelTrans, + const QQuaternion &totalRotation, + AbstractRenderItem &dummyItem, + const Q3DCamera *activeCamera, + float labelsMaxWidth, + const QMatrix4x4 &viewMatrix, + const QMatrix4x4 &projectionMatrix, + ShaderHelper *shader) +{ + float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheX.titleItem().size().height(); + float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor)); + float zRotation = 0.0f; + float yRotation = 0.0f; + float xRotation = -90.0f + labelRotation.z(); + float offsetRotation = labelRotation.z(); + float extraRotation = -90.0f; + Qt::AlignmentFlag alignment = Qt::AlignTop; + if (m_yFlipped) { + alignment = Qt::AlignBottom; + if (m_zFlipped) { + zRotation = 180.0f; + titleOffset = -titleOffset; + if (m_xFlipped) { + offsetRotation = -offsetRotation; + extraRotation = -extraRotation; + } else { + xRotation = -90.0f - labelRotation.z(); + } + } else { + zRotation = 180.0f; + yRotation = 180.0f; + if (m_xFlipped) { + offsetRotation = -offsetRotation; + xRotation = -90.0f - labelRotation.z(); + } else { + extraRotation = -extraRotation; + } + } + } else { + if (m_zFlipped) { + titleOffset = -titleOffset; + if (m_xFlipped) { + yRotation = 180.0f; + offsetRotation = -offsetRotation; + } else { + yRotation = 180.0f; + xRotation = -90.0f - labelRotation.z(); + extraRotation = -extraRotation; + } + } else { + if (m_xFlipped) { + offsetRotation = -offsetRotation; + xRotation = -90.0f - labelRotation.z(); + extraRotation = -extraRotation; + } + } + } + + if (offsetRotation == 180.0f || offsetRotation == -180.0f) + offsetRotation = 0.0f; + QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, offsetRotation); + QVector3D titleOffsetVector = + offsetRotator.rotatedVector(QVector3D(0.0f, 0.0f, titleOffset)); + + QQuaternion titleRotation; + if (m_axisCacheX.isTitleFixed()) { + titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, zRotation) + * QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation) + * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, xRotation); + } else { + titleRotation = totalRotation + * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, extraRotation); + } + dummyItem.setTranslation(labelTrans + titleOffsetVector); + + m_drawer->drawLabel(dummyItem, m_axisCacheX.titleItem(), viewMatrix, + projectionMatrix, zeroVector, titleRotation, 0, + m_cachedSelectionMode, shader, m_labelObj, activeCamera, + true, true, Drawer::LabelMid, alignment); +} + +void Abstract3DRenderer::drawAxisTitleZ(const QVector3D &labelRotation, + const QVector3D &labelTrans, + const QQuaternion &totalRotation, + AbstractRenderItem &dummyItem, + const Q3DCamera *activeCamera, + float labelsMaxWidth, + const QMatrix4x4 &viewMatrix, + const QMatrix4x4 &projectionMatrix, + ShaderHelper *shader) +{ + float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheZ.titleItem().size().height(); + float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor)); + float zRotation = labelRotation.z(); + float yRotation = -90.0f; + float xRotation = -90.0f; + float extraRotation = 90.0f; + Qt::AlignmentFlag alignment = Qt::AlignTop; + if (m_yFlipped) { + alignment = Qt::AlignBottom; + xRotation = -xRotation; + if (m_zFlipped) { + if (m_xFlipped) { + titleOffset = -titleOffset; + zRotation = -zRotation; + extraRotation = -extraRotation; + } else { + zRotation = -zRotation; + yRotation = -yRotation; + } + } else { + if (m_xFlipped) { + titleOffset = -titleOffset; + } else { + extraRotation = -extraRotation; + yRotation = -yRotation; + } + } + } else { + if (m_zFlipped) { + zRotation = -zRotation; + if (m_xFlipped) { + titleOffset = -titleOffset; + } else { + extraRotation = -extraRotation; + yRotation = -yRotation; + } + } else { + if (m_xFlipped) { + titleOffset = -titleOffset; + extraRotation = -extraRotation; + } else { + yRotation = -yRotation; + } + } + } + + float offsetRotation = zRotation; + if (offsetRotation == 180.0f || offsetRotation == -180.0f) + offsetRotation = 0.0f; + QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, offsetRotation); + QVector3D titleOffsetVector = + offsetRotator.rotatedVector(QVector3D(titleOffset, 0.0f, 0.0f)); + + QQuaternion titleRotation; + if (m_axisCacheZ.isTitleFixed()) { + titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, zRotation) + * QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation) + * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, xRotation); + } else { + titleRotation = totalRotation + * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, extraRotation); + } + dummyItem.setTranslation(labelTrans + titleOffsetVector); + + m_drawer->drawLabel(dummyItem, m_axisCacheZ.titleItem(), viewMatrix, + projectionMatrix, zeroVector, titleRotation, 0, + m_cachedSelectionMode, shader, m_labelObj, activeCamera, + true, true, Drawer::LabelMid, alignment); +} + +void Abstract3DRenderer::loadGridLineMesh() +{ + ObjectHelper::resetObjectHelper(this, m_gridLineObj, + QStringLiteral(":/defaultMeshes/plane")); +} + +void Abstract3DRenderer::loadLabelMesh() +{ + ObjectHelper::resetObjectHelper(this, m_labelObj, + QStringLiteral(":/defaultMeshes/plane")); +} + + +void Abstract3DRenderer::generateBaseColorTexture(const QColor &color, GLuint *texture) +{ + m_textureHelper->deleteTexture(texture); *texture = m_textureHelper->createUniformTexture(color); } -void Abstract3DRenderer::fixGradientAndGenerateTexture(QLinearGradient *gradient, GLuint *gradientTexture) +void Abstract3DRenderer::fixGradientAndGenerateTexture(QLinearGradient *gradient, + GLuint *gradientTexture) { // Readjust start/stop to match gradient texture size gradient->setStart(qreal(gradientTextureWidth), qreal(gradientTextureHeight)); gradient->setFinalStop(0.0, 0.0); - if (*gradientTexture) { - m_textureHelper->deleteTexture(gradientTexture); - *gradientTexture = 0; - } + m_textureHelper->deleteTexture(gradientTexture); *gradientTexture = m_textureHelper->createGradientTexture(*gradient); } @@ -471,4 +832,270 @@ QString &Abstract3DRenderer::selectionLabel() return m_selectionLabel; } +QVector4D Abstract3DRenderer::indexToSelectionColor(GLint index) +{ + GLubyte idxRed = index & 0xff; + GLubyte idxGreen = (index & 0xff00) >> 8; + GLubyte idxBlue = (index & 0xff0000) >> 16; + + return QVector4D(idxRed, idxGreen, idxBlue, 0); +} + +CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) +{ + CustomRenderItem *newItem = new CustomRenderItem(); + newItem->setRenderer(this); + newItem->setItemPointer(item); // Store pointer for render item updates + newItem->setMesh(item->meshFile()); + QVector3D scaling = item->scaling(); + QImage textureImage = item->d_ptr->textureImage(); + bool facingCamera = false; + if (item->d_ptr->m_isLabelItem) { + QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item); + float pointSize = labelItem->font().pointSizeF(); + // Check do we have custom visuals or need to use theme + if (!labelItem->dptr()->m_customVisuals) { + // Recreate texture using theme + labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(), + m_cachedTheme->labelTextColor(), + m_cachedTheme->isLabelBackgroundEnabled(), + m_cachedTheme->isLabelBorderEnabled()); + pointSize = m_cachedTheme->font().pointSizeF(); + textureImage = item->d_ptr->textureImage(); + } + // Calculate scaling based on text (texture size), font size and asked scaling + float scaledFontSize = (0.05f + pointSize / 500.0f) / float(textureImage.height()); + scaling.setX(scaling.x() * textureImage.width() * scaledFontSize); + scaling.setY(scaling.y() * textureImage.height() * scaledFontSize); + // Check if facing camera + facingCamera = labelItem->isFacingCamera(); + } + newItem->setScaling(scaling); + newItem->setRotation(item->rotation()); + newItem->setPosition(item->position()); + newItem->setPositionAbsolute(item->isPositionAbsolute()); + newItem->setBlendNeeded(textureImage.hasAlphaChannel()); + GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true); + newItem->setTexture(texture); + item->d_ptr->clearTextureImage(); + QVector3D translation = convertPositionToTranslation(item->position(), + item->isPositionAbsolute()); + newItem->setTranslation(translation); + newItem->setVisible(item->isVisible()); + newItem->setShadowCasting(item->isShadowCasting()); + newItem->setFacingCamera(facingCamera); + m_customRenderCache.insert(item, newItem); + return newItem; +} + +void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) +{ + QCustom3DItem *item = renderItem->itemPointer(); + if (item->d_ptr->m_dirtyBits.meshDirty) { + renderItem->setMesh(item->meshFile()); + item->d_ptr->m_dirtyBits.meshDirty = false; + } + if (item->d_ptr->m_dirtyBits.scalingDirty) { + QVector3D scaling = item->scaling(); + // In case we have label item, we need to recreate texture for scaling adjustment + if (item->d_ptr->m_isLabelItem) { + QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item); + float pointSize = labelItem->font().pointSizeF(); + // Check do we have custom visuals or need to use theme + if (labelItem->dptr()->m_customVisuals) { + // Recreate texture + labelItem->dptr()->createTextureImage(); + } else { + // Recreate texture using theme + labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(), + m_cachedTheme->labelTextColor(), + m_cachedTheme->isLabelBackgroundEnabled(), + m_cachedTheme->isLabelBorderEnabled()); + pointSize = m_cachedTheme->font().pointSizeF(); + } + QImage textureImage = item->d_ptr->textureImage(); + // Calculate scaling based on text (texture size), font size and asked scaling + float scaledFontSize = (0.05f + pointSize / 500.0f) / float(textureImage.height()); + scaling.setX(scaling.x() * textureImage.width() * scaledFontSize); + scaling.setY(scaling.y() * textureImage.height() * scaledFontSize); + item->d_ptr->clearTextureImage(); + } + renderItem->setScaling(scaling); + item->d_ptr->m_dirtyBits.scalingDirty = false; + } + if (item->d_ptr->m_dirtyBits.rotationDirty) { + renderItem->setRotation(item->rotation()); + item->d_ptr->m_dirtyBits.rotationDirty = false; + } + if (item->d_ptr->m_dirtyBits.textureDirty) { + QImage textureImage = item->d_ptr->textureImage(); + if (item->d_ptr->m_isLabelItem) { + QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item); + // Check do we have custom visuals or need to use theme + if (!labelItem->dptr()->m_customVisuals) { + // Recreate texture using theme + labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(), + m_cachedTheme->labelTextColor(), + m_cachedTheme->isLabelBackgroundEnabled(), + m_cachedTheme->isLabelBorderEnabled()); + textureImage = item->d_ptr->textureImage(); + } + } + renderItem->setBlendNeeded(textureImage.hasAlphaChannel()); + GLuint oldTexture = renderItem->texture(); + m_textureHelper->deleteTexture(&oldTexture); + GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true); + renderItem->setTexture(texture); + item->d_ptr->clearTextureImage(); + item->d_ptr->m_dirtyBits.textureDirty = false; + } + if (item->d_ptr->m_dirtyBits.positionDirty || item->d_ptr->m_dirtyBits.positionAbsoluteDirty) { + renderItem->setPosition(item->position()); + renderItem->setPositionAbsolute(item->isPositionAbsolute()); + QVector3D translation = convertPositionToTranslation(item->position(), + item->isPositionAbsolute()); + renderItem->setTranslation(translation); + item->d_ptr->m_dirtyBits.positionDirty = false; + item->d_ptr->m_dirtyBits.positionAbsoluteDirty = false; + } + if (item->d_ptr->m_dirtyBits.visibleDirty) { + renderItem->setVisible(item->isVisible()); + item->d_ptr->m_dirtyBits.visibleDirty = false; + } + if (item->d_ptr->m_dirtyBits.shadowCastingDirty) { + renderItem->setShadowCasting(item->isShadowCasting()); + item->d_ptr->m_dirtyBits.shadowCastingDirty = false; + } + if (item->d_ptr->m_isLabelItem) { + QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item); + if (labelItem->dptr()->m_facingCameraDirty) { + renderItem->setFacingCamera(labelItem->isFacingCamera()); + labelItem->dptr()->m_facingCameraDirty = false; + } + } +} + +void Abstract3DRenderer::updateCustomItemPositions() +{ + foreach (CustomRenderItem *renderItem, m_customRenderCache) { + QVector3D translation = convertPositionToTranslation(renderItem->position(), + renderItem->isPositionAbsolute()); + renderItem->setTranslation(translation); + } +} + +void Abstract3DRenderer::drawCustomItems(RenderingState state, + ShaderHelper *shader, + const QMatrix4x4 &viewMatrix, + const QMatrix4x4 &projectionViewMatrix, + const QMatrix4x4 &depthProjectionViewMatrix, + GLuint depthTexture, + GLfloat shadowQuality) +{ + if (m_customRenderCache.isEmpty()) + return; + + if (RenderingNormal == state) { + shader->bind(); + shader->setUniformValue(shader->lightP(), m_cachedScene->activeLight()->position()); + shader->setUniformValue(shader->ambientS(), m_cachedTheme->ambientLightStrength()); + shader->setUniformValue(shader->lightColor(), + Utils::vectorFromColor(m_cachedTheme->lightColor())); + shader->setUniformValue(shader->view(), viewMatrix); + + glEnable(GL_TEXTURE_2D); + } + + // Draw custom items + foreach (CustomRenderItem *item, m_customRenderCache) { + // Check that the render item is visible, and skip drawing if not + if (!item->isVisible()) + continue; + + // Check if the render item is in data coordinates and not within axis ranges, and skip drawing if it is + if (!item->isPositionAbsolute() + && (item->position().x() < m_axisCacheX.min() + || item->position().x() > m_axisCacheX.max() + || item->position().z() < m_axisCacheZ.min() + || item->position().z() > m_axisCacheZ.max() + || item->position().y() < m_axisCacheY.min() + || item->position().y() > m_axisCacheY.max())) { + continue; + } + + QMatrix4x4 modelMatrix; + QMatrix4x4 itModelMatrix; + QMatrix4x4 MVPMatrix; + + QQuaternion rotation = item->rotation(); + // Check if the (label) item should be facing camera, and adjust rotation accordingly + if (item->isFacingCamera()) { + float camRotationX = m_cachedScene->activeCamera()->xRotation(); + float camRotationY = m_cachedScene->activeCamera()->yRotation(); + rotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, -camRotationX) + * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -camRotationY); + } + + modelMatrix.translate(item->translation()); + modelMatrix.rotate(rotation); + modelMatrix.scale(item->scaling()); + itModelMatrix.rotate(rotation); + if (!item->isFacingCamera()) + itModelMatrix.scale(item->scaling()); + MVPMatrix = projectionViewMatrix * modelMatrix; + + if (RenderingNormal == state) { + // Normal render + shader->setUniformValue(shader->model(), modelMatrix); + shader->setUniformValue(shader->MVP(), MVPMatrix); + shader->setUniformValue(shader->nModel(), itModelMatrix.inverted().transposed()); + + if (item->isBlendNeeded()) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + } else { + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); + } + +#if !defined(QT_OPENGL_ES_2) + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + shader->setUniformValue(shader->shadowQ(), shadowQuality); + shader->setUniformValue(shader->depth(), depthProjectionViewMatrix * modelMatrix); + shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength() / 10.0f); + m_drawer->drawObject(shader, item->mesh(), item->texture(), depthTexture); + } else +#else + Q_UNUSED(depthTexture) + Q_UNUSED(shadowQuality) +#endif + { + // Set shadowless shader bindings + shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength()); + m_drawer->drawObject(shader, item->mesh(), item->texture()); + } + } else if (RenderingSelection == state) { + // Selection render + shader->setUniformValue(shader->MVP(), MVPMatrix); + QVector4D itemColor = indexToSelectionColor(item->index()); + itemColor.setW(customItemAlpha); + itemColor /= 255.0f; + shader->setUniformValue(shader->color(), itemColor); + m_drawer->drawObject(shader, item->mesh()); + } else if (item->isShadowCasting()) { + // Depth render + shader->setUniformValue(shader->MVP(), depthProjectionViewMatrix * modelMatrix); + m_drawer->drawObject(shader, item->mesh()); + } + } + + if (RenderingNormal == state) { + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); + } +} + QT_END_NAMESPACE_DATAVISUALIZATION |