diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-10-25 17:54:56 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-11-02 09:54:56 +0000 |
commit | 3ddad604c29761f1069fe88b27e6f9d44c0dbe82 (patch) | |
tree | 4d600fde9849f9cc87180a469d84c64785cb53de | |
parent | 74e92c8d0d879dc0bc5bc3dd9612f7a65dbf349c (diff) |
Implement scene camera tab
The scene camera tab on the bottom dockable area provides a zoomable
pixel perfect view of the scene camera.
Task-number: QT3DS-709
Change-Id: I7d96464e8208b9e57a1bd980fc6b71656028e49a
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
22 files changed, 1042 insertions, 85 deletions
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp index 2b609ecf..0ebb5d90 100644 --- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp +++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp @@ -56,6 +56,7 @@ static QColor s_textColor; static QColor s_masterColor; static QColor s_disabledColor; static QColor s_dataInputColor; +static QColor s_matteColor; static QLinearGradient s_welcomeBackgroundGradient; static QColor s_timelineRowColorNormal; @@ -142,6 +143,7 @@ void CStudioPreferences::loadPreferences(const QString &filePath) s_masterColor = QColor("#5caa15"); s_disabledColor = QColor("#727476"); s_dataInputColor = QColor("#ff5102"); + s_matteColor = QColor("#222222"); s_welcomeBackgroundGradient = QLinearGradient(0.0, 0.0, 1.0, 0.0); s_welcomeBackgroundGradient.setColorAt(0.0, QColor("#343E55")); @@ -884,6 +886,11 @@ QColor CStudioPreferences::dataInputColor() return s_dataInputColor; } +QColor CStudioPreferences::matteColor() +{ + return s_matteColor; +} + QLinearGradient CStudioPreferences::welcomeBackgroundGradient() { return s_welcomeBackgroundGradient; diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h index 8f086a86..6bee5cbf 100644 --- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h +++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h @@ -169,6 +169,8 @@ public: static QColor masterColor(); static QColor disabledColor(); static QColor dataInputColor(); + static QColor matteColor(); + static QLinearGradient welcomeBackgroundGradient(); static QColor timelineRowColorNormal(); diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp index 4fe62850..824bce17 100644 --- a/src/Authoring/Studio/Application/StudioApp.cpp +++ b/src/Authoring/Studio/Application/StudioApp.cpp @@ -69,6 +69,7 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(res); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); SharedTools::QtSingleApplication guiApp(QStringLiteral("Qt3DStudio"), argc, argv); #if defined(Q_OS_MACOS) diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp index 8b7b5644..8c321dad 100644 --- a/src/Authoring/Studio/MainFrm.cpp +++ b/src/Authoring/Studio/MainFrm.cpp @@ -176,6 +176,7 @@ CMainFrame::CMainFrame() connect(m_ui->actionProject, &QAction::triggered, this, &CMainFrame::OnViewProject); connect(m_ui->actionSlide, &QAction::triggered, this, &CMainFrame::OnViewSlide); connect(m_ui->actionTimeline, &QAction::triggered, this, &CMainFrame::OnViewTimeline); + connect(m_ui->actionSceneCamera, &QAction::triggered, this, &CMainFrame::onViewSceneCamera); connect(m_ui->actionBounding_Boxes, &QAction::triggered, this, &CMainFrame::OnViewBoundingBoxes); connect(m_ui->actionPivot_Point, &QAction::triggered, this, &CMainFrame::OnViewPivotPoint); @@ -269,6 +270,7 @@ CMainFrame::CMainFrame() OnUpdateViewWireframe(); OnUpdateViewTooltips(); OnUpdateViewTimeline(); + onUpdateViewSceneCamera(); OnUpdateViewInspector(); OnUpdateViewAction(); OnUpdateViewBasicObjects(); @@ -1634,6 +1636,21 @@ void CMainFrame::OnUpdateViewTimeline() m_paletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_TIMELINE)); } +void CMainFrame::onViewSceneCamera() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_SCENECAMERA); + onUpdateViewSceneCamera(); +} + +void CMainFrame::onUpdateViewSceneCamera() +{ + const bool cameraVisible = m_paletteManager->IsControlVisible( + CPaletteManager::CONTROLTYPE_SCENECAMERA); + m_ui->actionSceneCamera->setChecked(cameraVisible); + g_StudioApp.getRenderer().setFullSizePreview(cameraVisible); + g_StudioApp.getRenderer().RequestRender(); +} + //============================================================================== /** * Called when the View Inspector Palette menu item is chosen. diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h index a51b4620..a4bcb30f 100644 --- a/src/Authoring/Studio/MainFrm.h +++ b/src/Authoring/Studio/MainFrm.h @@ -198,6 +198,8 @@ public: void OnUpdateViewSlide(); void OnViewTimeline(); void OnUpdateViewTimeline(); + void onViewSceneCamera(); + void onUpdateViewSceneCamera(); void OnEditCameraZoomExtent(); void OnEditCameraPan(); diff --git a/src/Authoring/Studio/MainFrm.ui b/src/Authoring/Studio/MainFrm.ui index 86f9c1d7..958f92eb 100644 --- a/src/Authoring/Studio/MainFrm.ui +++ b/src/Authoring/Studio/MainFrm.ui @@ -116,6 +116,7 @@ Project palette using Import functionality.</string> <addaction name="actionProject"/> <addaction name="actionSlide"/> <addaction name="actionTimeline"/> + <addaction name="actionSceneCamera"/> <addaction name="separator"/> <addaction name="actionBounding_Boxes"/> <addaction name="actionPivot_Point"/> @@ -1010,6 +1011,20 @@ Project palette using Import functionality.</string> <string>Disable Lighting from Scene Lights in Edit Views</string> </property> </action> + <action name="actionSceneCamera"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Scene Camera</string> + </property> + <property name="toolTip"> + <string>Scene Camera</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+F</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/src/Authoring/Studio/Palettes/PaletteManager.cpp b/src/Authoring/Studio/Palettes/PaletteManager.cpp index f6774060..bb6cf84d 100644 --- a/src/Authoring/Studio/Palettes/PaletteManager.cpp +++ b/src/Authoring/Studio/Palettes/PaletteManager.cpp @@ -44,6 +44,7 @@ #include "ProjectView.h" #include "TabOrderHandler.h" #include "StudioPreferences.h" +#include "scenecameraview.h" #include <QtWidgets/qdockwidget.h> #include <QtWidgets/qboxlayout.h> @@ -65,24 +66,24 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) inMainFrame->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); m_projectDock = new QDockWidget(QObject::tr("Project"), inMainFrame); - m_projectDock->setObjectName("project"); + m_projectDock->setObjectName(QStringLiteral("project")); m_projectDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); m_slideDock = new QDockWidget(QObject::tr("Slide"), inMainFrame); - m_slideDock->setObjectName("slide"); + m_slideDock->setObjectName(QStringLiteral("slide")); m_slideDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); // Slide palette has a fixed size hint auto slideView = new SlideView(m_slideDock); slideView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_slideDock->setWidget(slideView); inMainFrame->addDockWidget(Qt::LeftDockWidgetArea, m_slideDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_SLIDE, m_slideDock)); + m_ControlList.insert({CONTROLTYPE_SLIDE, m_slideDock}); QObject::connect(m_slideDock, &QDockWidget::dockLocationChanged, slideView, &SlideView::onDockLocationChange); m_basicObjectsDock = new QDockWidget(QObject::tr("Basic Objects"), inMainFrame); - m_basicObjectsDock->setObjectName("basic_objects"); + m_basicObjectsDock->setObjectName(QStringLiteral("basic_objects")); m_basicObjectsDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); // Basic objects palette has a fixed size hint @@ -91,10 +92,10 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) m_basicObjectsDock->setWidget(basicObjectsView); inMainFrame->addDockWidget(Qt::LeftDockWidgetArea, m_basicObjectsDock); inMainFrame->tabifyDockWidget(m_basicObjectsDock, m_slideDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_BASICOBJECTS, m_basicObjectsDock)); + m_ControlList.insert({CONTROLTYPE_BASICOBJECTS, m_basicObjectsDock}); m_timelineDock = new QDockWidget(QObject::tr("Timeline")); - m_timelineDock->setObjectName("timeline"); + m_timelineDock->setObjectName(QStringLiteral("timeline")); m_timelineDock->setAllowedAreas(Qt::BottomDockWidgetArea); // Give the preferred size as percentages of the mainframe size @@ -113,7 +114,20 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) m_timelineDock->setWidget(timeLineWidgetControl); inMainFrame->addDockWidget(Qt::BottomDockWidgetArea, m_timelineDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_TIMELINE, m_timelineDock)); + m_ControlList.insert({CONTROLTYPE_TIMELINE, m_timelineDock}); + + m_cameraDock = new QDockWidget(QObject::tr("Scene Camera")); + m_cameraDock->setObjectName(QStringLiteral("scenecamera")); + m_cameraDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::LeftDockWidgetArea + | Qt::RightDockWidgetArea); + + m_cameraWidget = new SceneCameraView(inMainFrame, m_cameraDock); + m_cameraWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + m_cameraDock->setWidget(m_cameraWidget); + inMainFrame->addDockWidget(Qt::BottomDockWidgetArea, m_cameraDock); + inMainFrame->tabifyDockWidget(m_timelineDock, m_cameraDock); + m_ControlList.insert({CONTROLTYPE_SCENECAMERA, m_cameraDock}); // Give the preferred size as percentages of the mainframe size m_projectView = new ProjectView(QSize(defaultRightDockWidth, defaultProjectHeight), @@ -121,10 +135,10 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) m_projectView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_projectDock->setWidget(m_projectView); inMainFrame->addDockWidget(Qt::RightDockWidgetArea, m_projectDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_PROJECT, m_projectDock)); + m_ControlList.insert({CONTROLTYPE_PROJECT, m_projectDock}); m_actionDock = new QDockWidget(QObject::tr("Action"), inMainFrame); - m_actionDock->setObjectName("action"); + m_actionDock->setObjectName(QStringLiteral("action")); m_actionDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); // Give the preferred size as percentages of the mainframe size @@ -134,10 +148,10 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) actionView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_actionDock->setWidget(actionView); inMainFrame->addDockWidget(Qt::RightDockWidgetArea, m_actionDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_ACTION, m_actionDock)); + m_ControlList.insert({CONTROLTYPE_ACTION, m_actionDock}); m_inspectorDock = new QDockWidget(QObject::tr("Inspector"), inMainFrame); - m_inspectorDock->setObjectName("inspector_control"); + m_inspectorDock->setObjectName(QStringLiteral("inspector_control")); m_inspectorDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); // Give the preferred size as percentages of the mainframe size @@ -148,7 +162,7 @@ CPaletteManager::CPaletteManager(CMainFrame *inMainFrame, QObject *parent) m_inspectorDock->setWidget(inspectorView); inMainFrame->addDockWidget(Qt::RightDockWidgetArea, m_inspectorDock); inMainFrame->tabifyDockWidget(m_inspectorDock, m_actionDock); - m_ControlList.insert(std::make_pair(CONTROLTYPE_INSPECTOR, m_inspectorDock)); + m_ControlList.insert({CONTROLTYPE_INSPECTOR, m_inspectorDock}); m_inspectorDock->raise(); @@ -280,5 +294,6 @@ void CPaletteManager::EnablePalettes() m_timelineDock->setEnabled(true); m_actionDock->setEnabled(true); m_inspectorDock->setEnabled(true); + m_cameraDock->setEnabled(true); } diff --git a/src/Authoring/Studio/Palettes/PaletteManager.h b/src/Authoring/Studio/Palettes/PaletteManager.h index 3d924e1c..0b061898 100644 --- a/src/Authoring/Studio/Palettes/PaletteManager.h +++ b/src/Authoring/Studio/Palettes/PaletteManager.h @@ -48,6 +48,7 @@ class TimeLineToolbar; class TimelineView; class ProjectView; class TimelineWidget; +class SceneCameraView; QT_FORWARD_DECLARE_CLASS(QDockWidget) @@ -59,20 +60,15 @@ class CPaletteManager : public QObject { Q_OBJECT public: - // Do NOT change the order/values of this enum, these - // values are stored in the registry enum EControlTypes { - CONTROLTYPE_NONE = 0, ///< - CONTROLTYPE_ACTION = 1, ///< - CONTROLTYPE_BASICOBJECTS = 3, ///< - CONTROLTYPE_INSPECTOR = 4, ///< - CONTROLTYPE_SLIDE = 6, ///< - CONTROLTYPE_TIMELINE = 7, ///< - CONTROLTYPE_PROJECT = 9, ///< - - CONTROLTYPE_MAXCONTROLS = 32, ///< the maximum number of palettes( a string of this length - ///is saved in the registry, changing this value will require - ///an upgrade process ) + CONTROLTYPE_NONE = 0, + CONTROLTYPE_ACTION, + CONTROLTYPE_BASICOBJECTS, + CONTROLTYPE_INSPECTOR, + CONTROLTYPE_SLIDE, + CONTROLTYPE_TIMELINE, + CONTROLTYPE_PROJECT, + CONTROLTYPE_SCENECAMERA, }; protected: @@ -89,10 +85,12 @@ protected: QDockWidget *m_timelineDock; QDockWidget *m_actionDock; QDockWidget *m_inspectorDock; + QDockWidget *m_cameraDock; TimelineView *m_timelineView; ProjectView *m_projectView = nullptr; TimelineWidget *m_timelineWidget; + SceneCameraView *m_cameraWidget; public: CPaletteManager(CMainFrame *inMainFrame, QObject *parent = nullptr); diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.cpp b/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.cpp new file mode 100644 index 00000000..e4ca5680 --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "Qt3DSCommonPrecompile.h" +#include "scenecameraglwidget.h" +#include "StudioApp.h" +#include "IStudioRenderer.h" +#include "WGLRenderContext.h" +#include "StudioPreferences.h" + +#include <QtGui/qopenglshaderprogram.h> +#include <QtGui/qopengltexture.h> +#include <QtGui/qopenglbuffer.h> +#include <QtGui/qopenglvertexarrayobject.h> + +const QVector4D defaultTextureOffset = QVector4D(0.0f, 0.0f, 1.0f, 1.0f); +const QVector2D defaultGeometryOffset = QVector2D(1.0f, 1.0f); + +SceneCameraGlWidget::SceneCameraGlWidget(QWidget *parent) + : QOpenGLWidget(parent) + , m_textureOffset(defaultTextureOffset) + , m_geometryOffset(defaultGeometryOffset) +{ + QSurfaceFormat format = CWGLRenderContext::selectSurfaceFormat(this); + format.setSamples(1); // We want pixel perfect view, not aliased one + setFormat(format); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +SceneCameraGlWidget::~SceneCameraGlWidget() +{ + cleanup(); +} + +void SceneCameraGlWidget::initializeGL() +{ + initializeOpenGLFunctions(); + QObject::connect(context(), &QOpenGLContext::aboutToBeDestroyed, + this, &SceneCameraGlWidget::cleanup); + + m_program = new QOpenGLShaderProgram(); + if (!m_program->addShaderFromSourceCode( + QOpenGLShader::Vertex, + "attribute highp vec2 aVertex;\n" + "attribute highp vec2 aUV;\n" + "uniform highp vec4 uTexOffset;\n" + "uniform highp vec4 uGeomOffset;\n" + "varying highp vec2 vUV;\n" + "void main(void)\n" + "{\n" + " gl_Position = vec4(uGeomOffset.xy + aVertex * uGeomOffset.zw, 0.0, 1.0);\n" + " vUV = vec2(uTexOffset.z * aUV.x + uTexOffset.x,\n" + " uTexOffset.w * aUV.y + uTexOffset.y);\n" + "}")) { + qWarning() << __FUNCTION__ << "Failed to add vertex shader for scene camera preview"; + return; + } + if (!m_program->addShaderFromSourceCode( + QOpenGLShader::Fragment, + "varying highp vec2 vUV;\n" + "uniform sampler2D uSampler;\n" + "void main(void) {\n" + " lowp vec4 oc = texture2D(uSampler, vUV);\n" + " gl_FragColor = vec4(oc);\n" + "}")) { + + qWarning() << __FUNCTION__ << "Failed to add fragment shader for scene camera preview"; + return; + } + if (!m_program->link()) { + qWarning() << __FUNCTION__ << "Failed to link program for scene camera preview"; + return; + } + if (!m_program->bind()) { + qWarning() << __FUNCTION__ << "Failed to bind program for scene camera preview"; + return; + } else { + GLint vertexAtt = GLint(m_program->attributeLocation("aVertex")); + GLint uvAtt = GLint(m_program->attributeLocation("aUV")); + m_uniformTextureOffset = GLint(m_program->uniformLocation("uTexOffset")); + m_uniformGeometryOffset = GLint(m_program->uniformLocation("uGeomOffset")); + m_program->setUniformValue("uSampler", 0); + + m_vao = new QOpenGLVertexArrayObject; + if (m_vao->create()) { + m_vao->bind(); + m_vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + if (m_vertexBuffer->create() && m_vertexBuffer->bind()) { + GLfloat vertexBuffer[] = {-1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f}; + m_vertexBuffer->allocate(vertexBuffer, 8 * sizeof(GLfloat)); + glEnableVertexAttribArray(vertexAtt); + glVertexAttribPointer(vertexAtt, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); + } else { + qWarning() << __FUNCTION__ + << "Failed to create/bind vertex buffer for scene camera preview"; + return; + } + m_uvBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + if (m_uvBuffer->create() && m_uvBuffer->bind()) { + GLfloat uvBuffer[] = {0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 1.0f, + 1.0f, 0.0f}; + m_uvBuffer->allocate(uvBuffer, 8 * sizeof(GLfloat)); + glEnableVertexAttribArray(uvAtt); + glVertexAttribPointer(uvAtt, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); + } else { + qWarning() << __FUNCTION__ + << "Failed to create/bind UV buffer for scene camera preview"; + return; + } + + m_vao->release(); + } else { + qWarning() << __FUNCTION__ << "Failed to create/bind vertex array object"; + return; + } + } + + const QColor matteColor = CStudioPreferences::matteColor(); + glClearColor(matteColor.redF(), matteColor.greenF(), matteColor.blueF(), 1.0f); +} + +void SceneCameraGlWidget::paintGL() +{ + Q3DStudio::IStudioRenderer &renderer(g_StudioApp.getRenderer()); + if (renderer.IsInitialized()) { + m_vao->bind(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + QSize fboSize; + qt3ds::QT3DSU32 textureId; + renderer.getFullSizePreviewFbo(fboSize, textureId); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, GLuint(textureId)); + + m_program->setUniformValueArray(m_uniformTextureOffset, &m_textureOffset, 1); + m_program->setUniformValueArray(m_uniformGeometryOffset, &m_geometryOffset, 1); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_vao->release(); + } +} + +void SceneCameraGlWidget::resizeGL(int, int) +{ + // We need to update immediately to avoid flicker + update(); +} + +void SceneCameraGlWidget::cleanup() +{ + makeCurrent(); + + delete m_program; + delete m_vertexBuffer; + delete m_uvBuffer; + delete m_vao; + m_program = nullptr; + m_vertexBuffer = nullptr; + m_uvBuffer = nullptr; + m_vao = nullptr; + m_uniformTextureOffset = 0; + m_uniformGeometryOffset = 0; + m_textureOffset = defaultTextureOffset; + m_geometryOffset = defaultGeometryOffset; + + doneCurrent(); +} diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.h b/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.h new file mode 100644 index 00000000..93becf19 --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecameraglwidget.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCENE_CAMERA_GLWIDGET_H +#define SCENE_CAMERA_GLWIDGET_H + +#include <QtWidgets/qopenglwidget.h> +#include <QtGui/qopenglfunctions.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector4d.h> + +QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) +QT_FORWARD_DECLARE_CLASS(QOpenGLBuffer) +QT_FORWARD_DECLARE_CLASS(QOpenGLVertexArrayObject) + +class SceneCameraGlWidget : public QOpenGLWidget, QOpenGLFunctions +{ + Q_OBJECT +public: + explicit SceneCameraGlWidget(QWidget *parent = nullptr); + ~SceneCameraGlWidget(); + + void setTextureOffset(const QVector4D &offset) { m_textureOffset = offset; } + void setGeometryOffset(const QVector4D &offset) { m_geometryOffset = offset; } + +protected: + void initializeGL() override; + void paintGL() override; + void resizeGL(int, int) override; + +private: + void cleanup(); + + QOpenGLShaderProgram *m_program = nullptr; + QOpenGLBuffer *m_vertexBuffer = nullptr; + QOpenGLBuffer *m_uvBuffer = nullptr; + QOpenGLVertexArrayObject *m_vao = nullptr; + GLint m_uniformTextureOffset = 0; + GLint m_uniformGeometryOffset = 0; + QVector4D m_textureOffset; + QVector4D m_geometryOffset; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.cpp b/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.cpp new file mode 100644 index 00000000..035e242c --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "Qt3DSCommonPrecompile.h" +#include "scenecamerascrollarea.h" +#include "scenecameraglwidget.h" +#include "Core.h" + +#include <QtWidgets/qscrollbar.h> +#include <QtGui/qevent.h> + +SceneCameraScrollArea::SceneCameraScrollArea(QWidget *parent) + : QAbstractScrollArea(parent) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + m_glWidget = new SceneCameraGlWidget(this); +} + +SceneCameraScrollArea::~SceneCameraScrollArea() +{ +} + +void SceneCameraScrollArea::setZoom(qreal zoom, const QPoint &zoomPoint) +{ + // Calculate the actual presentation point + qreal oldH = (horizontalScrollBar()->value() + zoomPoint.x()) / m_zoom; + qreal oldV = (verticalScrollBar()->value() + zoomPoint.y()) / m_zoom; + + m_zoom = zoom; + + recalculateScrollRanges(); + + // Move the scrollbars so that the actual presentation point stays in the same location + horizontalScrollBar()->setValue(qRound(oldH * m_zoom - zoomPoint.x())); + verticalScrollBar()->setValue(qRound(oldV * m_zoom - zoomPoint.y())); + + recalculateOffsets(); + + Q_EMIT needUpdate(); +} + +void SceneCameraScrollArea::setPresentationSize(const QSize &size) +{ + if (m_presentationSize != size) { + m_presentationSize = size; + recalculateScrollRanges(); + recalculateOffsets(); + } +} + +void SceneCameraScrollArea::recalculateScrollRanges() +{ + const QSizeF presSize = zoomedPresentationSize(); + + const QSize viewSize = viewport()->size(); + horizontalScrollBar()->setRange(0, int(presSize.width() - viewSize.width())); + verticalScrollBar()->setRange(0, int(presSize.height() - viewSize.height())); + horizontalScrollBar()->setPageStep(viewSize.width()); + verticalScrollBar()->setPageStep(viewSize.height()); +} + +void SceneCameraScrollArea::recalculateOffsets() +{ + // Texture offset vector contains normalized rect of the viewable area of the texture + const QSize viewSize = viewport()->size(); + const qreal fullWidth = qreal(horizontalScrollBar()->maximum() + viewSize.width()); + const qreal fullHeight = qreal(verticalScrollBar()->maximum() + viewSize.height()); + QVector4D textureOffset( + float(horizontalScrollBar()->value() / fullWidth), + float((verticalScrollBar()->maximum() - verticalScrollBar()->value()) / fullHeight), + float(viewSize.width() / fullWidth), float(viewSize.height() / fullHeight)); + + m_glWidget->setTextureOffset(textureOffset); + + // The geometry offset is adjusted to keep aspect ratio when view area is larger than + // zoomed width/height. Since the geometry of the quad is in range [-1, 1], the width/height of + // the offset is just a direct multiplier to the coordinate. + // XY contain the subpixel offset to ensure we don't get artifacts depending on pixel alignment. + const QSizeF presSize = zoomedPresentationSize(); + float subPixelX = 0.0f; + float subPixelY = 0.0f; + qreal normWidth = 1.0; + qreal normHeight = 1.0; + if (presSize.width() < fullWidth) { + qreal diffX = (fullWidth - qRound(presSize.width())) / 2.0; + subPixelX = float((diffX - qRound(diffX)) / fullWidth); + normWidth = presSize.width() / fullWidth; + } + if (presSize.height() < fullHeight) { + qreal diffY = (fullHeight - qRound(presSize.height())) / 2.0; + subPixelY = float((diffY - qRound(diffY)) / fullHeight); + normHeight = presSize.height() / fullHeight; + } + + QVector4D geometryOffset(subPixelX, subPixelY, float(normWidth), float(normHeight)); + m_glWidget->setGeometryOffset(geometryOffset); +} + +void SceneCameraScrollArea::scrollContentsBy(int, int) +{ + recalculateOffsets(); + Q_EMIT needUpdate(); +} + +void SceneCameraScrollArea::showEvent(QShowEvent *event) +{ + QAbstractScrollArea::showEvent(event); + + recalculateScrollRanges(); + recalculateOffsets(); + resizeGlWidget(); +} + +void SceneCameraScrollArea::resizeGlWidget() +{ + m_glWidget->resize(viewport()->size()); +} + +QSizeF SceneCameraScrollArea::zoomedPresentationSize() +{ + // Multiply QSize components separately to avoid rounding to integers + QSizeF size = QSizeF(m_presentationSize.width() * m_zoom, + m_presentationSize.height() * m_zoom); + return size; +} + +void SceneCameraScrollArea::resizeEvent(QResizeEvent *event) +{ + QAbstractScrollArea::resizeEvent(event); + + recalculateScrollRanges(); + recalculateOffsets(); + resizeGlWidget(); +} diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.h b/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.h new file mode 100644 index 00000000..682dc430 --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecamerascrollarea.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCENE_CAMERA_SCROLL_AREA +#define SCENE_CAMERA_SCROLL_AREA + +#include <QtWidgets/qabstractscrollarea.h> + +class SceneCameraGlWidget; + +class SceneCameraScrollArea : public QAbstractScrollArea +{ + Q_OBJECT + +public: + SceneCameraScrollArea(QWidget *parent = nullptr); + virtual ~SceneCameraScrollArea(); + + SceneCameraGlWidget *glWidget() const { return m_glWidget; } + + void setZoom(qreal zoom, const QPoint &zoomPoint); + void setPresentationSize(const QSize &size); + void recalculateScrollRanges(); + void recalculateOffsets(); + +Q_SIGNALS: + void needUpdate(); + +protected: + void resizeEvent(QResizeEvent *event) override; + void scrollContentsBy(int, int) override; + void showEvent(QShowEvent *event) override; + +private: + void resizeGlWidget(); + QSizeF zoomedPresentationSize(); + +protected: + SceneCameraGlWidget *m_glWidget = nullptr; + qreal m_zoom = 1.0; + QSize m_presentationSize; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.cpp b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.cpp new file mode 100644 index 00000000..56410dd9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scenecameraview.h" +#include "ui_scenecameraview.h" +#include "scenecameraglwidget.h" +#include "StudioApp.h" +#include "Core.h" +#include "StudioProjectSettings.h" +#include "MainFrm.h" +#include "PlayerWnd.h" +#include "MouseCursor.h" +#include "ResourceCache.h" + +#include <QtCore/qlocale.h> +#include <QtGui/qevent.h> +#include <QtWidgets/qscrollbar.h> + +const QPoint invalidMousePoint = QPoint(-999999, -999999); + +SceneCameraView::SceneCameraView(CMainFrame *mainFrame, QWidget *parent) : + QWidget(parent) + , m_ui(new Ui::SceneCameraView) + , m_mousePressPointLeft(invalidMousePoint) + , m_mousePressPointRight(invalidMousePoint) +{ + m_ui->setupUi(this); + + m_cursorPan = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_EDIT_CAMERA_PAN); + m_cursorZoom = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_EDIT_CAMERA_ZOOM); + + // Limit the preview framerate a bit to limit amount of updates when dragging the slider + m_updateTimer.setInterval(0); + m_updateTimer.setSingleShot(true); + + connect(m_ui->zoomSlider, &QSlider::valueChanged, + this, &SceneCameraView::handleSliderValueChange); + connect(mainFrame->GetPlayerWnd(), &CPlayerWnd::newFrame, + this, &SceneCameraView::requestUpdate); + connect(m_ui->scrollArea, &SceneCameraScrollArea::needUpdate, + this, &SceneCameraView::requestUpdate); + connect(&m_updateTimer, &QTimer::timeout, this, &SceneCameraView::doUpdate); +} + +SceneCameraView::~SceneCameraView() +{ + delete m_ui; +} + +void SceneCameraView::wheelEvent(QWheelEvent *e) +{ + m_zoomPoint = m_ui->scrollArea->viewport()->mapFrom(this, e->pos()); + m_ui->zoomSlider->setValue(m_ui->zoomSlider->value() + (e->angleDelta().y() / 60)); +} + +void SceneCameraView::resizeEvent(QResizeEvent *e) +{ + m_zoomPoint = m_ui->scrollArea->viewport()->geometry().center(); + + QWidget::resizeEvent(e); +} + +void SceneCameraView::mousePressEvent(QMouseEvent *e) +{ + // Panning can be done with left or middle button. Left is more natural and we don't need it + // for selection. Alt+middle pans in edit camera mode, so middle button is also supported for + // panning. + if (m_mousePressPointRight == invalidMousePoint + && (e->button() == Qt::LeftButton || e->button() == Qt::MidButton)) { + m_mousePressPointLeft = e->pos(); + m_mousePressScrollValues = QPoint(m_ui->scrollArea->horizontalScrollBar()->value(), + m_ui->scrollArea->verticalScrollBar()->value()); + setCursor(m_cursorPan); + } else if (m_mousePressPointLeft == invalidMousePoint && e->button() == Qt::RightButton) { + m_mousePressPointRight = e->pos(); + m_mousePressZoomValue = m_ui->zoomSlider->value(); + setCursor(m_cursorZoom); + } +} + +void SceneCameraView::mouseMoveEvent(QMouseEvent *e) +{ + if (m_mousePressPointLeft != invalidMousePoint) { + const QPoint delta = e->pos() - m_mousePressPointLeft; + m_ui->scrollArea->horizontalScrollBar()->setValue(m_mousePressScrollValues.x() - delta.x()); + m_ui->scrollArea->verticalScrollBar()->setValue(m_mousePressScrollValues.y() - delta.y()); + } + if (m_mousePressPointRight != invalidMousePoint) { + const qreal delta = qreal(e->pos().y() - m_mousePressPointRight.y()); + m_zoomPoint = m_mousePressPointRight; + m_ui->zoomSlider->setValue(m_mousePressZoomValue - delta / 2.0); + } +} + +void SceneCameraView::mouseReleaseEvent(QMouseEvent *e) +{ + if (m_mousePressPointLeft != invalidMousePoint + && e->button() == Qt::LeftButton || e->button() == Qt::MidButton) { + m_mousePressPointLeft = invalidMousePoint; + setCursor(Qt::ArrowCursor); + } else if (m_mousePressPointRight != invalidMousePoint) { + m_zoomPoint = m_ui->scrollArea->viewport()->geometry().center(); + m_mousePressPointRight = invalidMousePoint; + m_mousePressZoomValue = 0; + setCursor(Qt::ArrowCursor); + } +} + +void SceneCameraView::handleSliderValueChange() +{ + static const QString formatTemplate = tr("%1x"); + const qreal zoom = qreal(m_ui->zoomSlider->value()) / 10.0; + m_ui->slideValueLabel->setText(formatTemplate.arg(QLocale(QLocale::C).toString(zoom))); + m_ui->scrollArea->setZoom(zoom, m_zoomPoint); + m_zoomPoint = m_ui->scrollArea->viewport()->geometry().center(); +} + +void SceneCameraView::doUpdate() +{ + // There is no event for presentation size change, so update every frame to catch the change + m_ui->scrollArea->setPresentationSize( + g_StudioApp.GetCore()->GetStudioProjectSettings()->getPresentationSize()); + m_ui->scrollArea->glWidget()->update(); +} + +void SceneCameraView::requestUpdate() +{ + if (!m_updateTimer.isActive()) + m_updateTimer.start(); +} diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.h b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.h new file mode 100644 index 00000000..e2bfb05b --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCENECAMERAVIEW_H +#define SCENECAMERAVIEW_H + +#include <QtWidgets/qwidget.h> +#include <QtCore/qtimer.h> + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { +class SceneCameraView; +} +QT_END_NAMESPACE + +class CMainFrame; + +class SceneCameraView : public QWidget +{ + Q_OBJECT + +public: + explicit SceneCameraView(CMainFrame *mainFrame, QWidget *parent = 0); + ~SceneCameraView(); + +protected: + void wheelEvent(QWheelEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + +private: + void handleSliderValueChange(); + void doUpdate(); + void requestUpdate(); + + Ui::SceneCameraView *m_ui = nullptr; + + QTimer m_updateTimer; + QPoint m_zoomPoint; + QPoint m_mousePressPointLeft; + QPoint m_mousePressPointRight; + QPoint m_mousePressScrollValues; + int m_mousePressZoomValue = 0; + + QCursor m_cursorPan; + QCursor m_cursorZoom; +}; + +#endif // SCENECAMERAVIEW_H diff --git a/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.ui b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.ui new file mode 100644 index 00000000..73bd6e19 --- /dev/null +++ b/src/Authoring/Studio/Palettes/scenecamera/scenecameraview.ui @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SceneCameraView</class> + <widget class="QWidget" name="SceneCameraView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="SceneCameraScrollArea" name="scrollArea" native="true"/> + </item> + <item> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QSlider" name="zoomSlider"> + <property name="maximumSize"> + <size> + <width>300</width> + <height>16777215</height> + </size> + </property> + <property name="minimum"> + <number>10</number> + </property> + <property name="maximum"> + <number>200</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="slideValueLabel"> + <property name="text"> + <string>1.0</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>165</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>SceneCameraScrollArea</class> + <extends>QWidget</extends> + <header>scenecamerascrollarea.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro index 6f91c0b1..fa7978fe 100644 --- a/src/Authoring/Studio/Qt3DStudio.pro +++ b/src/Authoring/Studio/Qt3DStudio.pro @@ -37,6 +37,7 @@ INCLUDEPATH += \ Palettes/Timeline \ Palettes/TimelineGraphicsView \ Palettes/TimelineGraphicsView/ui \ + Palettes/scenecamera \ Render \ UI \ Utils \ @@ -217,7 +218,10 @@ HEADERS += \ Application/PresentationFile.h \ Palettes/Project/ChooseImagePropertyDlg.h \ Application/StudioTutorialPageIndicator.h \ - Palettes/Inspector/MaterialRefView.h + Palettes/Inspector/MaterialRefView.h \ + Palettes/scenecamera/scenecameraview.h \ + Palettes/scenecamera/scenecamerascrollarea.h \ + Palettes/scenecamera/scenecameraglwidget.h FORMS += \ MainFrm.ui \ @@ -236,7 +240,8 @@ FORMS += \ UI/GLVersionDlg.ui \ UI/StartupDlg.ui \ Palettes/Project/EditPresentationIdDlg.ui \ - Palettes/Project/ChooseImagePropertyDlg.ui + Palettes/Project/ChooseImagePropertyDlg.ui \ + Palettes/scenecamera/scenecameraview.ui SOURCES += \ Application/AboutDlg.cpp \ @@ -388,7 +393,10 @@ SOURCES += \ Application/PresentationFile.cpp \ Palettes/Project/ChooseImagePropertyDlg.cpp \ Application/StudioTutorialPageIndicator.cpp \ - Palettes/Inspector/MaterialRefView.cpp + Palettes/Inspector/MaterialRefView.cpp \ + Palettes/scenecamera/scenecameraview.cpp \ + Palettes/scenecamera/scenecamerascrollarea.cpp \ + Palettes/scenecamera/scenecameraglwidget.cpp RESOURCES += \ MainFrm.qrc \ diff --git a/src/Authoring/Studio/Render/IStudioRenderer.h b/src/Authoring/Studio/Render/IStudioRenderer.h index 9e8e1a8b..55214cc9 100644 --- a/src/Authoring/Studio/Render/IStudioRenderer.h +++ b/src/Authoring/Studio/Render/IStudioRenderer.h @@ -56,6 +56,7 @@ public: virtual void Initialize(QWidget *inWindow) = 0; virtual void SetViewRect(const QRect &inRect) = 0; + virtual void setFullSizePreview(bool enabled) = 0; virtual void GetEditCameraList(QStringList &outCameras) = 0; virtual void SetPolygonFillModeEnabled(bool inEnableFillMode) = 0; @@ -77,6 +78,7 @@ public: // synchronously render the content virtual void RenderNow() = 0; + virtual void getFullSizePreviewFbo(QSize &outFboDim, qt3ds::QT3DSU32 &outFboTexture) = 0; virtual void MakeContextCurrent() = 0; virtual void ReleaseContext() = 0; diff --git a/src/Authoring/Studio/Render/StudioRenderer.cpp b/src/Authoring/Studio/Render/StudioRenderer.cpp index a3850618..92860459 100644 --- a/src/Authoring/Studio/Render/StudioRenderer.cpp +++ b/src/Authoring/Studio/Render/StudioRenderer.cpp @@ -117,6 +117,7 @@ struct SRendererImpl : public IStudioRenderer, QHash<QString, StudioSubPresentation> m_subpresentations; QScopedPointer<Q3DSQmlStreamProxy> m_proxy; QMap<QString, int> m_initialFrameMap; + bool m_fullSizePreview = false; SRendererImpl() : m_Dispatch(*g_StudioApp.GetCore()->GetDispatch()) @@ -362,6 +363,12 @@ struct SRendererImpl : public IStudioRenderer, m_RenderContext->EndRender(); } } + + void setFullSizePreview(bool enabled) override + { + m_fullSizePreview = enabled; + } + // Request that this object renders. May be ignored if a transaction // is ongoing so we don't get multiple rendering per transaction. void RequestRender() override @@ -382,6 +389,25 @@ struct SRendererImpl : public IStudioRenderer, Render(); } + void getFullSizePreviewFbo(QSize &outFboDim, qt3ds::QT3DSU32 &outFboTexture) override + { + if (m_Translation) { + outFboDim = QSize(m_Translation->m_previewFullSizeFboDimensions.x, + m_Translation->m_previewFullSizeFboDimensions.y); + // The handle is a void * so first cast to size_t to avoid truncating pointer warning + if (m_Translation->m_previewFullSizeTexture) { + outFboTexture = static_cast<qt3ds::QT3DSU32>(reinterpret_cast<size_t>( + m_Translation->m_previewFullSizeTexture->GetTextureObjectHandle())); + } else { + outFboTexture = 0; + } + + } else { + outFboDim = QSize(0, 0); + outFboTexture = 0; + } + } + void MakeContextCurrent() override { m_RenderContext->BeginRender(); @@ -401,8 +427,9 @@ struct SRendererImpl : public IStudioRenderer, if (m_Translation) { preview = CStudioPreferences::showEditModePreview() && m_Translation->m_EditCameraEnabled - && !m_Translation->GetPreviewViewportDimensions().isZero(); - m_Translation->PreRender(preview); + && !m_Translation->GetPreviewViewportDimensions(false).isZero(); + m_Translation->PreRender(preview || m_fullSizePreview, + m_fullSizePreview && !preview); } NVRenderContext &theContext = m_RenderContext->GetRenderContext(); theContext.SetDepthWriteEnabled(true); @@ -410,12 +437,19 @@ struct SRendererImpl : public IStudioRenderer, qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); if (m_Translation) { - // draw scene preview view screen display area layer if (preview) { - m_Translation->Render(0, false, true, false); - m_Translation->PreRender(false); + // draw scene preview view screen display area layer + m_Translation->Render(0, false, true, false, false); + m_Translation->PreRender(m_fullSizePreview, m_fullSizePreview); + } + if (m_fullSizePreview) { + // We need separate full size preview for Scene camera tab even if we are + // rendering the scene normally, since we don't want the guides or widgets + m_Translation->Render(0, false, true, true, false); + m_Translation->PreRender(false, false); } - m_Translation->Render(m_PickResult.GetWidgetId(), m_GuidesEnabled, false, preview); + m_Translation->Render(m_PickResult.GetWidgetId(), m_GuidesEnabled, false, + m_fullSizePreview, preview); } m_RenderContext->EndRender(); diff --git a/src/Authoring/Studio/Render/StudioRendererTranslation.cpp b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp index 7ddaff39..81403ccc 100644 --- a/src/Authoring/Studio/Render/StudioRendererTranslation.cpp +++ b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp @@ -2058,27 +2058,30 @@ void STranslation::MarkDirty(qt3dsdm::Qt3DSDMInstanceHandle inInstance) RequestRender(); } -QT3DSVec2 STranslation::GetPreviewViewportDimensions() +QT3DSVec2 STranslation::GetPreviewViewportDimensions(bool fullSize) { CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); QSize thePresSize = theSettings->getPresentationSize(); - QT3DSVec2 vp(GetViewportDimensions()); - if (vp.x < m_previewViewportSize || vp.y < m_previewViewportSize) - return QT3DSVec2(0.0f); QT3DSVec2 ret(thePresSize.width(), thePresSize.height()); - const float aspect = ret.x / ret.y; - if (aspect > 1.0) { - ret.x = m_previewViewportSize; - ret.y = m_previewViewportSize / aspect; - } else { - ret.x = m_previewViewportSize * aspect; - ret.y = m_previewViewportSize; + if (!fullSize) { + QT3DSVec2 vp(GetViewportDimensions()); + if (vp.x < m_previewViewportSize || vp.y < m_previewViewportSize) { + ret = QT3DSVec2(0.0f); + } else { + const float aspect = ret.x / ret.y; + if (aspect > 1.0) { + ret.x = m_previewViewportSize; + ret.y = m_previewViewportSize / aspect; + } else { + ret.x = m_previewViewportSize * aspect; + ret.y = m_previewViewportSize; + } + } } - return ret; } -void STranslation::PreRender(bool scenePreviewPass) +void STranslation::PreRender(bool scenePreviewPass, bool fullSizePreview) { // Run through the entire asset graph and mark active or inactive if we have an // associated render representation. @@ -2094,12 +2097,15 @@ void STranslation::PreRender(bool scenePreviewPass) QT3DSVec2 theViewportDims(GetViewportDimensions()); if (scenePreviewPass) { m_Context.SetScaleMode(qt3ds::render::ScaleModes::FitSelected); - theViewportDims = GetPreviewViewportDimensions(); + theViewportDims = GetPreviewViewportDimensions(fullSizePreview); } else { m_Context.SetScaleMode(qt3ds::render::ScaleModes::ExactSize); } - m_Context.SetMatteColor(QT3DSVec4(.13f, .13f, .13f, 1.0f)); + static const QT3DSVec4 matteColor(CStudioPreferences::matteColor().redF(), + CStudioPreferences::matteColor().greenF(), + CStudioPreferences::matteColor().blueF(), 1.0f); + m_Context.SetMatteColor(matteColor); // Ensure the camera points where it should if (m_EditCameraEnabled && !scenePreviewPass) { m_EditCameraInfo.ApplyToCamera(m_EditCamera, theViewportDims); @@ -2351,14 +2357,14 @@ struct SVerticalGuideFactory : public IGuideElementFactory } }; -qt3ds::render::NVRenderRect STranslation::GetPreviewViewport() +qt3ds::render::NVRenderRect STranslation::GetPreviewViewport(bool fullSize) { - QT3DSVec2 vp = GetPreviewViewportDimensions(); + QT3DSVec2 vp = GetPreviewViewportDimensions(fullSize); return qt3ds::render::NVRenderRect(0, 0, vp.x, vp.y); } void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPass, - bool overlayPreview) + bool fullsizePreview, bool overlayPreview) { // For now, we just render. // Next step will be to get the bounding boxes and such setup. @@ -2372,39 +2378,47 @@ void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPa if (scenePreviewPass) { qt3ds::render::NVRenderContext &renderContext(m_Context.GetRenderContext()); - QT3DSVec2 previewDims(GetPreviewViewportDimensions()); - if (m_previewFboDimensions != previewDims) { - m_previewFboDimensions = previewDims; - if (m_previewFbo) - m_Context.GetResourceManager().Release(*m_previewFbo); - if (m_previewRenderBuffer) - m_Context.GetResourceManager().Release(*m_previewRenderBuffer); - if (m_previewTexture) - m_Context.GetResourceManager().Release(*m_previewTexture); - m_previewFbo = nullptr; - m_previewRenderBuffer = nullptr; - m_previewTexture = nullptr; + QT3DSVec2 previewDims(GetPreviewViewportDimensions(fullsizePreview)); + QT3DSVec2 &previewFboDimensions + = fullsizePreview ? m_previewFullSizeFboDimensions : m_previewFboDimensions; + NVScopedRefCounted<qt3ds::render::NVRenderFrameBuffer> &previewFbo + = fullsizePreview ? m_previewFullSizeFbo : m_previewFbo; + NVScopedRefCounted<qt3ds::render::NVRenderRenderBuffer> &previewRenderBuffer + = fullsizePreview ? m_previewFullSizeRenderBuffer : m_previewRenderBuffer; + NVScopedRefCounted<qt3ds::render::NVRenderTexture2D> &previewTexture + = fullsizePreview ? m_previewFullSizeTexture : m_previewTexture; + if (previewFboDimensions != previewDims) { + previewFboDimensions = previewDims; + if (previewFbo) + m_Context.GetResourceManager().Release(*previewFbo); + if (previewRenderBuffer) + m_Context.GetResourceManager().Release(*previewRenderBuffer); + if (previewTexture) + m_Context.GetResourceManager().Release(*previewTexture); + previewFbo = nullptr; + previewRenderBuffer = nullptr; + previewTexture = nullptr; } - if (!m_previewFbo) - m_previewFbo = m_Context.GetResourceManager().AllocateFrameBuffer(); - if (!m_previewTexture) { - m_previewTexture = renderContext.CreateTexture2D(); - m_previewTexture->SetTextureData(qt3ds::foundation::NVDataRef<qt3ds::QT3DSU8>(), + if (!previewFbo) + previewFbo = m_Context.GetResourceManager().AllocateFrameBuffer(); + if (!previewTexture) { + previewTexture = renderContext.CreateTexture2D(); + previewTexture->SetTextureData(qt3ds::foundation::NVDataRef<qt3ds::QT3DSU8>(), 0, previewDims.x, previewDims.y, qt3ds::render::NVRenderTextureFormats::RGBA8); - m_previewFbo->Attach( + previewFbo->Attach( qt3ds::render::NVRenderFrameBufferAttachments::Color0, - qt3ds::render::NVRenderTextureOrRenderBuffer(*m_previewTexture)); + qt3ds::render::NVRenderTextureOrRenderBuffer(*previewTexture)); } - if (!m_previewRenderBuffer) { - m_previewRenderBuffer = m_Context.GetResourceManager().AllocateRenderBuffer( + if (!previewRenderBuffer) { + previewRenderBuffer = m_Context.GetResourceManager().AllocateRenderBuffer( previewDims.x, previewDims.y, qt3ds::render::NVRenderRenderBufferFormats::Depth24); - m_previewFbo->Attach( + previewFbo->Attach( qt3ds::render::NVRenderFrameBufferAttachments::Depth, - qt3ds::render::NVRenderTextureOrRenderBuffer(*m_previewRenderBuffer)); + qt3ds::render::NVRenderTextureOrRenderBuffer(*previewRenderBuffer)); } - renderContext.SetRenderTarget(m_previewFbo); + renderContext.SetRenderTarget(previewFbo); } else { // Render the bounding boxes and extra widgets. // This is called *before* the render because these sort of appendages need to be added @@ -2573,12 +2587,12 @@ void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPa } Option<NVRenderRect> viewport = m_Context.GetRenderContext().GetViewport(); if (scenePreviewPass) { - m_Context.GetRenderContext().SetViewport(GetPreviewViewport()); + m_Context.GetRenderContext().SetViewport(GetPreviewViewport(fullsizePreview)); m_Context.SetSceneColor(Option<QT3DSVec4>()); } m_Scene->PrepareForRender(scenePreviewPass - ? GetPreviewViewportDimensions() + ? GetPreviewViewportDimensions(fullsizePreview) : GetViewportDimensions(), m_Context); m_Context.RunRenderTasks(); @@ -2596,7 +2610,7 @@ void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPa } m_Scene->Render(scenePreviewPass - ? GetPreviewViewportDimensions() + ? GetPreviewViewportDimensions(fullsizePreview) : GetViewportDimensions(), m_Context, SScene::DoNotClear); if (!scenePreviewPass && m_editModeCamerasAndLights.size() > 0) { @@ -2705,11 +2719,11 @@ void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPa if (overlayPreview) { // Draw the overlay framebuffer qt3ds::render::NVRenderContext &renderContext(m_Context.GetRenderContext()); - renderContext.SetViewport(GetPreviewViewport()); + renderContext.SetViewport(GetPreviewViewport(false)); qt3ds::render::SCamera camera; camera.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); camera.m_Flags.SetOrthographic(true); - QT3DSVec2 previewDims(GetPreviewViewportDimensions()); + QT3DSVec2 previewDims(GetPreviewViewportDimensions(false)); camera.CalculateGlobalVariables( render::NVRenderRectF(0, 0, previewDims.x, previewDims.y), previewDims); QT3DSMat44 theVP; @@ -2721,6 +2735,14 @@ void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPa m_Context.GetRenderer().RenderQuad(previewDims, theVP, *m_previewTexture); } + // Hack: For some reason, the m_previewFullSizeTexture is only valid later if it is + // actually drawn somewhere during the main render pass, so draw a dummy quad with it + if (!scenePreviewPass && m_previewFullSizeTexture) { + m_Context.GetRenderContext().SetViewport(NVRenderRect(0, 0, 0, 0)); + m_Context.GetRenderer().RenderQuad(QT3DSVec2(0.0f), QT3DSMat44(), + *m_previewFullSizeTexture); + } + if (scenePreviewPass) m_Context.GetRenderContext().SetRenderTarget(nullptr); diff --git a/src/Authoring/Studio/Render/StudioRendererTranslation.h b/src/Authoring/Studio/Render/StudioRendererTranslation.h index cabed632..5c9e1cd8 100644 --- a/src/Authoring/Studio/Render/StudioRendererTranslation.h +++ b/src/Authoring/Studio/Render/StudioRendererTranslation.h @@ -409,6 +409,11 @@ namespace studio { NVScopedRefCounted<qt3ds::render::NVRenderRenderBuffer> m_previewRenderBuffer; QT3DSVec2 m_previewFboDimensions; + NVScopedRefCounted<qt3ds::render::NVRenderTexture2D> m_previewFullSizeTexture; + NVScopedRefCounted<qt3ds::render::NVRenderFrameBuffer> m_previewFullSizeFbo; + NVScopedRefCounted<qt3ds::render::NVRenderRenderBuffer> m_previewFullSizeRenderBuffer; + QT3DSVec2 m_previewFullSizeFboDimensions; + STranslation(IStudioRenderer &inRenderer, IQt3DSRenderContext &inContext); void MarkBeginComponentSeconds(qt3dsdm::Qt3DSDMSlideHandle) { ++m_ComponentSecondsDepth; } @@ -491,8 +496,8 @@ namespace studio { void SetViewport(QT3DSF32 inWidth, QT3DSF32 inHeight) { m_Viewport = QT3DSVec2(inWidth, inHeight); } QT3DSVec2 GetViewportDimensions() { return m_Viewport; } - QT3DSVec2 GetPreviewViewportDimensions(); - qt3ds::render::NVRenderRect GetPreviewViewport(); + QT3DSVec2 GetPreviewViewportDimensions(bool fullSize); + qt3ds::render::NVRenderRect GetPreviewViewport(bool fullSize); void ClearDirtySet() { @@ -514,8 +519,9 @@ namespace studio { void DeactivateScan(SGraphObjectTranslator &inParent, qt3dsdm::Qt3DSDMInstanceHandle inAliasHandle = qt3dsdm::Qt3DSDMInstanceHandle()); - void PreRender(bool scenePreviewPass); - void Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPass, bool overlayPreview); + void PreRender(bool scenePreviewPass, bool fullSizePreview); + void Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPass, bool fullsizePreview, + bool overlayPreview); void EndRender(); void DoPrepareForDrag(SNode *inSelectedNode); void ResetWidgets(); diff --git a/src/Authoring/Studio/UI/PlayerWnd.cpp b/src/Authoring/Studio/UI/PlayerWnd.cpp index 5e1f0c51..a528cea1 100644 --- a/src/Authoring/Studio/UI/PlayerWnd.cpp +++ b/src/Authoring/Studio/UI/PlayerWnd.cpp @@ -242,6 +242,8 @@ void CPlayerWnd::paintGL() Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.getRenderer()); // Don't use request render here, this has to be synchronous inside paintGL theRenderer.RenderNow(); + + Q_EMIT newFrame(); } qreal CPlayerWnd::fixedDevicePixelRatio() const diff --git a/src/Authoring/Studio/UI/PlayerWnd.h b/src/Authoring/Studio/UI/PlayerWnd.h index 81eec6bc..de005220 100644 --- a/src/Authoring/Studio/UI/PlayerWnd.h +++ b/src/Authoring/Studio/UI/PlayerWnd.h @@ -50,6 +50,7 @@ public: ~CPlayerWnd(); void setContainerWnd(CPlayerContainerWnd *inSceneView); + CPlayerContainerWnd *containerWnd() const { return m_containerWnd; } QSize sizeHint() const override; @@ -70,6 +71,7 @@ protected: Q_SIGNALS: void dropReceived(); + void newFrame(); protected: void mouseMoveEvent(QMouseEvent *event) override; |