summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Render/StudioRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Render/StudioRenderer.cpp')
-rw-r--r--src/Authoring/Studio/Render/StudioRenderer.cpp883
1 files changed, 883 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Render/StudioRenderer.cpp b/src/Authoring/Studio/Render/StudioRenderer.cpp
new file mode 100644
index 00000000..960cc1b6
--- /dev/null
+++ b/src/Authoring/Studio/Render/StudioRenderer.cpp
@@ -0,0 +1,883 @@
+/****************************************************************************
+**
+** Copyright (C) 2006 NVIDIA Corporation.
+** Copyright (C) 2017 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 "stdafx.h"
+#include "StudioRendererImpl.h"
+#include "StudioRendererTranslation.h"
+#include "StudioPreferences.h"
+#include "HotKeys.h"
+#include "StudioUtils.h"
+
+#include <QDebug>
+
+#ifdef _WIN32
+#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+#endif
+using namespace uic::studio;
+
+namespace {
+
+const QT3DSU32 g_WheelFactor = 10; // the wheel zoom factor
+
+struct SEditCameraDefinition
+{
+ EditCameraTypes::Enum m_Type;
+ // Directional cameras have a direction they point
+ QT3DSVec3 m_Direction; // not normalized
+ QString m_Name;
+};
+
+SEditCameraDefinition g_EditCameraDefinitions[] = {
+ { EditCameraTypes::Perspective, QT3DSVec3(1, -1, -1), QObject::tr("Perspective View") },
+ { EditCameraTypes::Orthographic, QT3DSVec3(1, -1, -1), QObject::tr("Orthographic View") },
+ { EditCameraTypes::Directional, QT3DSVec3(0, -1, 0), QObject::tr("Top View") },
+ { EditCameraTypes::Directional, QT3DSVec3(0, 1, 0), QObject::tr("Bottom View") },
+ { EditCameraTypes::Directional, QT3DSVec3(1, 0, 0), QObject::tr("Left View") },
+ { EditCameraTypes::Directional, QT3DSVec3(-1, 0, 0), QObject::tr("Right View") },
+ { EditCameraTypes::Directional, QT3DSVec3(0, 0, -1), QObject::tr("Front View") },
+ { EditCameraTypes::Directional, QT3DSVec3(0, 0, 1), QObject::tr("Back View") },
+};
+QT3DSU32 g_NumEditCameras = sizeof(g_EditCameraDefinitions) / sizeof(*g_EditCameraDefinitions);
+
+struct SRendererImpl : public IStudioRenderer,
+ public IDataModelListener,
+ public IReloadListener,
+ public CPresentationChangeListener,
+ public CSceneDragListener,
+ public CToolbarChangeListener
+{
+ typedef eastl::vector<Option<SEditCameraPersistentInformation>> TEditCameraInfoList;
+ std::shared_ptr<CWGLRenderContext> m_RenderContext;
+ NVScopedRefCounted<IUICRenderContext> m_UICContext;
+ QRect m_Rect;
+ CDispatch &m_Dispatch;
+ CDoc &m_Doc;
+ std::shared_ptr<STranslation> m_Translation;
+ CPt m_MouseDownPoint;
+ CPt m_PreviousMousePoint;
+ bool m_HasPresentation;
+ bool m_Closed;
+ CUpdateableDocumentEditor m_UpdatableEditor;
+ MovementTypes::Enum m_LastDragToolMode;
+ bool m_MaybeDragStart;
+ TEditCameraInfoList m_EditCameraInformation;
+ QT3DSI32 m_EditCameraIndex;
+ SEditCameraPersistentInformation m_MouseDownCameraInformation;
+ SStudioPickValue m_PickResult;
+ bool m_RenderRequested;
+ int m_LastToolMode;
+ bool m_GuidesEnabled;
+ UICDM::TSignalConnectionPtr m_SelectionSignal;
+
+ SRendererImpl()
+ : m_Dispatch(*g_StudioApp.GetCore()->GetDispatch())
+ , m_Doc(*g_StudioApp.GetCore()->GetDoc())
+ , m_HasPresentation(false)
+ , m_Closed(false)
+ , m_UpdatableEditor(m_Doc)
+ , m_LastDragToolMode(MovementTypes::Unknown)
+ , m_MaybeDragStart(false)
+ , m_EditCameraIndex(-1)
+ , m_RenderRequested(false)
+ , m_LastToolMode(0)
+ , m_GuidesEnabled(true)
+ {
+ m_Dispatch.AddReloadListener(this);
+ m_Dispatch.AddDataModelListener(this);
+ m_Dispatch.AddPresentationChangeListener(this);
+ m_SelectionSignal =
+ m_Dispatch.ConnectSelectionChange(std::bind(&SRendererImpl::OnSelectionChange, this));
+ m_Dispatch.AddSceneDragListener(this);
+ m_Dispatch.AddToolbarChangeListener(this);
+ }
+ ~SRendererImpl()
+ {
+ Close();
+ m_Dispatch.RemoveDataModelListener(this);
+ m_Dispatch.RemovePresentationChangeListener(this);
+ m_Dispatch.RemoveSceneDragListener(this);
+ m_Dispatch.RemoveToolbarChangeListener(this);
+ }
+
+ // IDocSceneGraph
+ QT3DSVec3 GetIntendedPosition(UICDM::CUICDMInstanceHandle inHandle, CPt inPoint) override
+ {
+ if (m_Translation)
+ return m_Translation->GetIntendedPosition(inHandle, inPoint);
+
+ return QT3DSVec3(0, 0, 0);
+ }
+
+ ITextRenderer *GetTextRenderer() override
+ {
+ if (m_UICContext.mPtr)
+ return m_UICContext->GetTextRenderer();
+ return NULL;
+ }
+ // The buffer manager may not be available
+ IBufferManager *GetBufferManager() override
+ {
+ if (m_UICContext.mPtr)
+ return &m_UICContext->GetBufferManager();
+ return NULL;
+ }
+
+ IPathManager *GetPathManager() override
+ {
+ if (m_UICContext.mPtr)
+ return &m_UICContext->GetPathManager();
+ return NULL;
+ }
+
+ qt3ds::foundation::IStringTable *GetRenderStringTable() override
+ {
+ if (m_UICContext.mPtr)
+ return &m_UICContext->GetStringTable();
+ return NULL;
+ }
+
+ bool IsInitialized() override { return m_UICContext.mPtr != NULL; }
+
+ void Initialize(QWidget *inWindow) override
+ {
+ if (m_Closed)
+ return;
+ QT3DS_ASSERT(!m_RenderContext);
+ QT3DS_ASSERT(m_UICContext.mPtr == NULL);
+ try {
+ m_RenderContext = std::make_shared<CWGLRenderContext>(inWindow);
+
+ Q3DStudio::CString theResourcePath = Q3DStudio::CString::fromQString(resourcePath());
+ NVScopedRefCounted<uic::render::IUICRenderContextCore> theCore =
+ uic::render::IUICRenderContextCore::Create(
+ m_RenderContext->GetRenderContext().GetFoundation(),
+ m_RenderContext->GetRenderContext().GetStringTable());
+
+ // Create text renderer
+ uic::render::ITextRendererCore &theTextRenderer(
+ uic::render::ITextRendererCore::CreateQtTextRenderer(
+ m_RenderContext->GetRenderContext().GetFoundation(),
+ m_RenderContext->GetRenderContext().GetStringTable()));
+ theCore->SetTextRendererCore(theTextRenderer);
+
+ m_UICContext = theCore->CreateRenderContext(
+ m_RenderContext->GetRenderContext(),
+ m_RenderContext->GetRenderContext().GetStringTable().RegisterStr(
+ theResourcePath.c_str()));
+
+ // Allow the artist to interact with the top level objects alone.
+ m_UICContext->GetRenderer().PickRenderPlugins(false);
+
+ SetupTextRenderer();
+
+ m_UICContext->SetAuthoringMode(true);
+
+ InitializePointerTags(m_UICContext->GetStringTable());
+ SetViewRect(m_Rect);
+#ifdef KDAB_TEMPORARILY_REMOVE
+ // KDAB_TODO the below call asserts on windows
+ m_RenderContext->GetRenderContext().SetClearColor(QT3DSVec4(0, 0, 0, 1));
+#endif
+ if (m_HasPresentation)
+ CreateTranslator();
+
+ // Notify that renderer has been initialized
+ m_Dispatch.FireOnRendererInitialized();
+ } catch (...) {
+ m_UICContext = nullptr;
+ m_RenderContext = std::shared_ptr<CWGLRenderContext>();
+ throw;
+ }
+ }
+
+ void SetViewRect(const QRect &inRect) override
+ {
+ if (m_RenderContext)
+ m_RenderContext->resized();
+
+ m_Rect = inRect;
+ if (IsInitialized()) {
+ m_RenderContext->BeginRender();
+ NVRenderContext &theContext = m_RenderContext->GetRenderContext();
+ theContext.SetViewport(qt3ds::render::NVRenderRect(0, 0, inRect.width(),
+ inRect.height()));
+ SetTranslationViewport();
+ m_RenderContext->EndRender();
+ }
+ }
+ // 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
+ {
+ if (m_RenderContext)
+ m_RenderContext->requestRender();
+ }
+
+ void RenderRequestedRender()
+ {
+ if (m_RenderRequested) {
+ m_RenderContext->requestRender();
+ }
+ }
+
+ void RenderNow() override
+ {
+ Render();
+ }
+
+ void MakeContextCurrent() override
+ {
+ m_RenderContext->BeginRender();
+ }
+
+ void ReleaseContext()
+ {
+ m_RenderContext->EndRender();
+ }
+
+ void Render()
+ {
+ m_RenderRequested = false;
+ if (!m_Closed && IsInitialized()) {
+ m_RenderContext->BeginRender();
+ if (m_Translation)
+ m_Translation->PreRender();
+ NVRenderContext &theContext = m_RenderContext->GetRenderContext();
+ theContext.SetDepthWriteEnabled(true);
+ theContext.Clear(qt3ds::render::NVRenderClearFlags(
+ qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth));
+ if (m_Translation) {
+ m_Translation->Render(m_PickResult.GetWidgetId(), m_GuidesEnabled);
+ }
+ m_RenderContext->EndRender();
+ }
+ }
+ void GetEditCameraList(QStringList &outCameras) override
+ {
+ outCameras.clear();
+ for (QT3DSU32 idx = 0; idx < g_NumEditCameras; ++idx)
+ outCameras.push_back(g_EditCameraDefinitions[idx].m_Name);
+ }
+ void SetEnableEditLight(bool inEnableLight) override
+ {
+ CStudioPreferences::SetEditViewFillMode(inEnableLight);
+ if (m_Translation)
+ m_Translation->m_EditLightEnabled = inEnableLight;
+ RequestRender();
+ }
+
+ bool DoesEditCameraSupportRotation(QT3DSI32 inIndex) override
+ {
+ if (inIndex >= 0 && inIndex < (QT3DSI32)g_NumEditCameras)
+ return g_EditCameraDefinitions[inIndex].m_Type != EditCameraTypes::Directional;
+ return false;
+ }
+
+ bool AreGuidesEnabled() const override { return m_GuidesEnabled; }
+
+ void SetGuidesEnabled(bool val) override { m_GuidesEnabled = val; }
+
+ bool AreGuidesEditable() const override { return m_Doc.IsValid() ? m_Doc.GetDocumentReader().AreGuidesEditable() : false; }
+
+ void SetGuidesEditable(bool val) override { if (m_Doc.IsValid()) m_Doc.GetDocumentReader().SetGuidesEditable(val); }
+
+ // Setting the camera to -1 disables the edit cameras
+ // So setting the camera to 0- (numcameras - 1) will set change the active
+ // edit camera.
+ void SetEditCamera(QT3DSI32 inIndex) override
+ {
+ QT3DSI32 oldIndex = m_EditCameraIndex;
+ m_EditCameraIndex = NVMin(inIndex, (QT3DSI32)g_NumEditCameras);
+ // save the old edit camera information
+ if (oldIndex != m_EditCameraIndex && m_Translation && m_Translation->m_EditCameraEnabled) {
+ while (m_EditCameraInformation.size() <= (QT3DSU32)oldIndex)
+ m_EditCameraInformation.push_back(Empty());
+
+ m_EditCameraInformation[oldIndex] = m_Translation->m_EditCameraInfo;
+ }
+
+ ApplyEditCameraIndex();
+ RequestRender();
+ }
+
+ QT3DSI32 GetEditCamera() const override
+ {
+ if (m_EditCameraIndex >= 0 && m_EditCameraIndex < (QT3DSI32)g_NumEditCameras)
+ return m_EditCameraIndex;
+ return -1;
+ }
+
+ bool IsEditLightEnabled() const override
+ {
+ return GetEditCamera() >= 0 && CStudioPreferences::GetEditViewFillMode();
+ }
+
+ void EditCameraZoomToFit() override
+ {
+ UICDM::CUICDMInstanceHandle theInstance = m_Doc.GetSelectedInstance();
+ if (!m_Translation || m_Translation->m_EditCameraEnabled == false)
+ return;
+ // If we aren't pointed at a node then bounce up the asset graph till we are.
+ while (theInstance.Valid() && m_Translation->GetOrCreateTranslator(theInstance)
+ && GraphObjectTypes::IsNodeType(
+ m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type)
+ == false) {
+ theInstance = m_Translation->m_AssetGraph.GetParent(theInstance);
+ }
+ // If we still aren't pointed at a node then use the active layer.
+ if (theInstance.Valid() == false
+ || m_Translation->GetOrCreateTranslator(theInstance) == nullptr
+ || GraphObjectTypes::IsNodeType(
+ m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type)
+ == false)
+ theInstance = m_Doc.GetActiveLayer();
+
+ // If we *still* aren't pointed at a node then bail.
+ if (m_Translation->GetOrCreateTranslator(theInstance) == nullptr
+ || GraphObjectTypes::IsNodeType(
+ m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type)
+ == false)
+ return;
+
+ SNode &theNode = static_cast<SNode &>(
+ m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject());
+ qt3ds::NVBounds3 theBounds;
+ theBounds.setEmpty();
+ if (theNode.m_Type == GraphObjectTypes::Layer) {
+ SNode *theEditLayer = m_Translation->GetEditCameraLayer();
+ if (theEditLayer) {
+ for (SNode *theChild = theEditLayer->m_FirstChild; theChild;
+ theChild = theChild->m_NextSibling) {
+ qt3ds::NVBounds3 childBounds = theChild->GetBounds(
+ m_UICContext->GetBufferManager(), m_UICContext->GetPathManager());
+ if (childBounds.isEmpty() == false) {
+ childBounds.transform(theChild->m_GlobalTransform);
+ theBounds.include(childBounds);
+ }
+ }
+ }
+ } else
+ theBounds =
+ theNode.GetBounds(m_UICContext->GetBufferManager(), m_UICContext->GetPathManager());
+ QT3DSVec3 theCenter = theNode.m_GlobalTransform.transform(theBounds.getCenter());
+ // Center the edit camera so that it points directly at the bounds center point
+ m_Translation->m_EditCameraInfo.m_Position = theCenter;
+ // Now we need to adjust the camera's zoom such that the view frustum contains the bounding
+ // box.
+ // But to do that I need to figure out what the view frustum is at -600 units from the near
+ // clip plane
+
+ QT3DSVec3 theExtents = theBounds.getExtents();
+ // get the largest extent and then some addition so things fit nicely in the viewport.
+ QT3DSF32 theMaxPossibleRadius = theExtents.magnitude();
+ // easiest case, the viewport dimensions map directly to the
+ m_Translation->m_EditCameraInfo.m_ViewRadius = theMaxPossibleRadius;
+ RequestRender();
+ }
+
+ // This must be safe to call from multiple places
+ void Close() override
+ {
+ m_Closed = true;
+ m_Translation = std::shared_ptr<STranslation>();
+ m_UICContext = nullptr;
+ m_RenderContext = std::shared_ptr<CWGLRenderContext>();
+ }
+
+ // Data model listener
+
+ // Fired before a large group of notifications come out so views can
+ // only refresh their view once.
+ void OnBeginDataModelNotifications() override {}
+ // Fired after a large gruop of notifications (onInstancePropertyChanged, etc) come out
+ // so views can be careful about refreshing their data and there view
+ void OnEndDataModelNotifications() override { Render(); }
+
+ // Fired during 3d drag or mouse move events (or keyframe drag) or likewise
+ // events so that views that need to update based on the new data can.
+ void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override
+ {
+ if (m_Translation) {
+ m_Translation->MarkDirty(inInstance);
+ // Pass to translation system
+ Render();
+ }
+ }
+ // Same thing, but fired when more than one instance is being refreshed.
+ void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance,
+ long inInstanceCount) override
+ {
+ // Pass to translation system
+ if (m_Translation) {
+ m_Translation->MarkDirty(inInstance, inInstanceCount);
+ // Pass to translation system
+ Render();
+ }
+ Render();
+ }
+
+ void OnReloadEffectInstance(UICDM::CUICDMInstanceHandle inInstance) override
+ {
+ if (m_Translation)
+ m_Translation->ReleaseEffect(inInstance);
+ }
+
+ void ApplyEditCameraIndex()
+ {
+ if (!m_Translation)
+ return;
+ if (m_EditCameraIndex < 0 || m_EditCameraIndex >= (QT3DSI32)g_NumEditCameras)
+ m_Translation->m_EditCameraEnabled = false;
+ else {
+ const SEditCameraDefinition &theDefinition(g_EditCameraDefinitions[m_EditCameraIndex]);
+
+ while ((size_t)m_EditCameraIndex >= m_EditCameraInformation.size())
+ m_EditCameraInformation.push_back(Empty());
+
+ Option<SEditCameraPersistentInformation> &theCameraInfo =
+ m_EditCameraInformation[m_EditCameraIndex];
+
+ if (!theCameraInfo.hasValue()) {
+ theCameraInfo = SEditCameraPersistentInformation();
+ // TODO - consider resizing clip planes to scene so we use the depth buffer more
+ // accurately
+ // or consider requesting a larger depth buffer from the windowing system.
+ // Setup the camera
+ theCameraInfo->m_Direction = theDefinition.m_Direction;
+ theCameraInfo->m_CameraType = theDefinition.m_Type;
+ }
+
+ m_Translation->m_EditCameraEnabled = true;
+ m_Translation->m_EditCameraInfo = theCameraInfo;
+ }
+ }
+
+ void SetTranslationViewport()
+ {
+ if (m_Translation) {
+ m_Translation->SetViewport(QT3DSF32(m_Rect.right() - m_Rect.left()),
+ QT3DSF32(m_Rect.bottom() - m_Rect.top()));
+ }
+ }
+
+ void CreateTranslator()
+ {
+ if (!m_Translation) {
+ if (m_UICContext.mPtr) {
+ m_Translation = std::make_shared<STranslation>(std::ref(*this),
+ std::ref(*m_UICContext.mPtr));
+ m_Translation->m_EditLightEnabled = CStudioPreferences::GetEditViewFillMode();
+ ApplyEditCameraIndex();
+ SetTranslationViewport();
+ }
+ }
+ }
+
+ void SetupTextRenderer()
+ {
+ if (m_UICContext.mPtr && m_UICContext->GetTextRenderer()) {
+ m_UICContext->GetTextRenderer()->ClearProjectFontDirectories();
+ Q3DStudio::CString theDocDir = m_Doc.GetDocumentDirectory();
+ if (theDocDir.Length()) {
+ // Add the installed font folders from the res dir.
+ Q3DStudio::CString thePath(Q3DStudio::CString::fromQString(
+ resourcePath() + QStringLiteral("/Font")));
+ m_UICContext->GetTextRenderer()->AddSystemFontDirectory(
+ m_UICContext->GetStringTable().RegisterStr(thePath.c_str()));
+ m_UICContext->GetTextRenderer()->AddProjectFontDirectory(
+ m_UICContext->GetStringTable().RegisterStr(theDocDir.c_str()));
+ }
+ }
+ }
+
+ //==========================================================================
+ /**
+ * New presentation is being created.
+ */
+ void OnNewPresentation() override
+ {
+ OnClosingPresentation();
+ m_HasPresentation = true;
+ // Reset edit camera information.
+ m_EditCameraInformation.clear();
+ // Rebuild translation
+ CreateTranslator();
+ SetupTextRenderer();
+ RequestRender();
+ }
+
+ //==========================================================================
+ /**
+ * The current presentation is being closed.
+ */
+ void OnClosingPresentation() override
+ {
+ // Destroy translation
+ m_Translation = std::shared_ptr<STranslation>();
+ m_HasPresentation = false;
+ }
+
+ void OnSelectionChange() { RequestRender(); }
+
+ UICDM::CUICDMInstanceHandle GetAnchorPointFromPick(SPathPick &inPick)
+ {
+ return m_Translation->GetAnchorPoint(inPick);
+ }
+
+ //==========================================================================
+ // CSceneDragListener
+ //==========================================================================
+ void OnSceneMouseDown(SceneDragSenderType::Enum inSenderType, QPoint inPoint, int) override
+ {
+ if (m_Translation == NULL)
+ return;
+
+ inPoint.setX(inPoint.x() * devicePixelRatio());
+ inPoint.setY(inPoint.y() * devicePixelRatio());
+
+ m_PickResult = SStudioPickValue();
+ TranslationSelectMode::Enum theSelectMode = TranslationSelectMode::Group;
+ switch (g_StudioApp.GetSelectMode()) {
+ case STUDIO_SELECTMODE_ENTITY:
+ theSelectMode = TranslationSelectMode::Single;
+ break;
+ case STUDIO_SELECTMODE_GROUP:
+ theSelectMode = TranslationSelectMode::Group;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ if (inSenderType == SceneDragSenderType::SceneWindow
+ && m_Translation->GetPickArea(inPoint) == PickTargetAreas::Presentation) {
+ m_RenderContext->BeginRender();
+ m_PickResult = m_Translation->Pick(inPoint, theSelectMode);
+ m_RenderContext->EndRender();
+ // If we definitely did not pick a widget.
+ if (m_PickResult.getType() == StudioPickValueTypes::Instance) {
+ UICDM::CUICDMInstanceHandle theHandle(m_PickResult.getData<CUICDMInstanceHandle>());
+
+ if (theHandle != m_Doc.GetSelectedInstance())
+ m_Doc.SelectUICDMObject(theHandle);
+ } else if (m_PickResult.getType() == StudioPickValueTypes::Guide)
+ m_Doc.NotifySelectionChanged(m_PickResult.getData<UICDM::CUICDMGuideHandle>());
+ else if (m_PickResult.getType() == StudioPickValueTypes::Path) {
+ SPathPick thePick = m_PickResult.getData<SPathPick>();
+ UICDM::CUICDMInstanceHandle theAnchorHandle =
+ m_Translation->GetAnchorPoint(thePick);
+ if (theAnchorHandle.Valid() && theAnchorHandle != m_Doc.GetSelectedInstance()) {
+ m_Doc.SelectUICDMObject(theAnchorHandle);
+ }
+ }
+ RequestRender();
+ } else {
+ qt3ds::foundation::Option<UICDM::SGuideInfo> pickResult =
+ m_Translation->PickRulers(inPoint);
+ if (pickResult.hasValue() == false)
+ m_Translation->PrepareForDrag();
+ else {
+ Q3DStudio::IDocumentEditor &docEditor(
+ m_UpdatableEditor.EnsureEditor(L"Create Guide", __FILE__, __LINE__));
+ CUICDMGuideHandle newGuide = docEditor.CreateGuide(*pickResult);
+ m_PickResult = SStudioPickValue(newGuide);
+ m_Doc.NotifySelectionChanged(newGuide);
+ }
+ }
+ m_LastDragToolMode = MovementTypes::Unknown;
+ m_MaybeDragStart = true;
+ m_MouseDownPoint = inPoint;
+ m_PreviousMousePoint = inPoint;
+ m_MouseDownCameraInformation = m_Translation->m_EditCameraInfo;
+ m_LastToolMode = g_StudioApp.GetToolMode();
+ }
+
+ void OnSceneMouseDrag(SceneDragSenderType::Enum, QPoint inPoint, int inToolMode,
+ int inFlags) override
+ {
+ if (m_Translation == NULL)
+ return;
+
+ inPoint.setX(inPoint.x() * devicePixelRatio());
+ inPoint.setY(inPoint.y() * devicePixelRatio());
+
+ if (m_MaybeDragStart) {
+ // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental
+ // moves
+ CPt theDragDistance = inPoint - m_MouseDownPoint;
+ if (m_PickResult.getType() == StudioPickValueTypes::Widget
+ || inToolMode != STUDIO_TOOLMODE_SCALE) {
+ if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y
+ <= 25)
+ return;
+ } else {
+ if (abs(theDragDistance.y) <= 5)
+ return;
+ }
+ }
+
+ m_MaybeDragStart = false;
+
+ // If the tool mode changes then we throw out the last widget pick if there was one.
+ if (m_LastToolMode != inToolMode)
+ m_PickResult = SStudioPickValue();
+ m_LastToolMode = inToolMode;
+
+ // General dragging
+ if (m_PickResult.getType() == StudioPickValueTypes::Instance
+ || m_PickResult.getType()
+ == StudioPickValueTypes::UnknownValueType) // matte drag and widget drag
+ {
+ // Not sure what right-click drag does in the scene.
+ bool isEditCamera = m_Translation->m_EditCameraEnabled;
+ int theCameraToolMode = isEditCamera ? (inToolMode & (STUDIO_CAMERATOOL_MASK)) : 0;
+ bool rightClick = (inFlags & CHotKeys::MOUSE_RBUTTON) != 0;
+
+ if (theCameraToolMode == 0) {
+ if (m_Doc.GetDocumentReader().IsInstance(m_Doc.GetSelectedInstance())) {
+ bool rightClick = (inFlags & CHotKeys::MOUSE_RBUTTON) != 0;
+ MovementTypes::Enum theMovement(MovementTypes::Unknown);
+
+ switch (inToolMode) {
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ case STUDIO_TOOLMODE_MOVE:
+ if (rightClick)
+ theMovement = MovementTypes::TranslateAlongCameraDirection;
+ else
+ theMovement = MovementTypes::Translate;
+ break;
+ case STUDIO_TOOLMODE_SCALE:
+ if (rightClick)
+ theMovement = MovementTypes::ScaleZ;
+ else
+ theMovement = MovementTypes::Scale;
+ break;
+ case STUDIO_TOOLMODE_ROTATE:
+ if (rightClick)
+ theMovement = MovementTypes::RotationAboutCameraDirection;
+ else
+ theMovement = MovementTypes::Rotation;
+ break;
+ }
+
+ if (theMovement != MovementTypes::Unknown) {
+ bool theLockToAxis = (inFlags & CHotKeys::MODIFIER_SHIFT) != 0;
+
+ if (m_LastDragToolMode != MovementTypes::Unknown
+ && theMovement != m_LastDragToolMode) {
+ m_UpdatableEditor.RollbackEditor();
+ m_MouseDownPoint = inPoint;
+ }
+
+ m_LastDragToolMode = theMovement;
+
+ switch (theMovement) {
+ case MovementTypes::TranslateAlongCameraDirection:
+ m_Translation->TranslateSelectedInstanceAlongCameraDirection(
+ m_MouseDownPoint, inPoint, m_UpdatableEditor);
+ break;
+ case MovementTypes::Translate:
+ m_Translation->TranslateSelectedInstance(
+ m_MouseDownPoint, inPoint, m_UpdatableEditor, theLockToAxis);
+ break;
+ case MovementTypes::ScaleZ:
+ m_Translation->ScaleSelectedInstanceZ(m_MouseDownPoint, inPoint,
+ m_UpdatableEditor);
+ break;
+ case MovementTypes::Scale:
+ m_Translation->ScaleSelectedInstance(m_MouseDownPoint, inPoint,
+ m_UpdatableEditor);
+ break;
+ case MovementTypes::Rotation:
+ m_Translation->RotateSelectedInstance(m_MouseDownPoint,
+ m_PreviousMousePoint, inPoint,
+ m_UpdatableEditor, theLockToAxis);
+ break;
+ case MovementTypes::RotationAboutCameraDirection:
+ m_Translation->RotateSelectedInstanceAboutCameraDirectionVector(
+ m_PreviousMousePoint, inPoint, m_UpdatableEditor);
+ break;
+ }
+ }
+ }
+ } else {
+ QT3DSF32 theXDistance = static_cast<QT3DSF32>(inPoint.x() - m_MouseDownPoint.x);
+ QT3DSF32 theYDistance = static_cast<QT3DSF32>(inPoint.y() - m_MouseDownPoint.y);
+ QT3DSF32 theSubsetXDistance = static_cast<QT3DSF32>(inPoint.x() - m_PreviousMousePoint.x);
+ QT3DSF32 theSubsetYDistance = static_cast<QT3DSF32>(inPoint.y() - m_PreviousMousePoint.y);
+
+ // Edit cameras are not implemented.
+ switch (theCameraToolMode) {
+ case STUDIO_TOOLMODE_CAMERA_PAN: {
+ QT3DSVec3 theXAxis =
+ m_Translation->m_EditCamera.m_GlobalTransform.column0.getXYZ();
+ QT3DSVec3 theYAxis =
+ m_Translation->m_EditCamera.m_GlobalTransform.column1.getXYZ();
+ QT3DSVec3 theXChange = -1.0f * theXAxis * theXDistance;
+ QT3DSVec3 theYChange = theYAxis * theYDistance;
+ QT3DSVec3 theDiff = theXChange + theYChange;
+ m_Translation->m_EditCameraInfo.m_Position =
+ m_MouseDownCameraInformation.m_Position + theDiff;
+ RequestRender();
+ } break;
+ case STUDIO_TOOLMODE_CAMERA_ZOOM: {
+ QT3DSF32 theMultiplier = 1.0f + theSubsetYDistance / 40.0f;
+ m_Translation->m_EditCameraInfo.m_ViewRadius =
+ NVMax(.0001f, m_Translation->m_EditCameraInfo.m_ViewRadius * theMultiplier);
+ RequestRender();
+ } break;
+ case STUDIO_TOOLMODE_CAMERA_ROTATE: {
+ if (m_Translation->m_EditCameraInfo.SupportsRotation()) {
+ if (rightClick == false) {
+ QT3DSVec3 theXAxis = QT3DSVec3(1, 0, 0);
+ QT3DSVec3 theYAxis = QT3DSVec3(0, 1, 0);
+ // Rotate about the center; we will just rotation the direction vector.
+ QT3DSQuat theXRotation(-1.0f * theSubsetXDistance * g_RotationScaleFactor
+ / 20.0f,
+ theYAxis);
+ QT3DSQuat theYRotation(-1.0f * theSubsetYDistance * g_RotationScaleFactor
+ / 20.0f,
+ theXAxis);
+ m_Translation->m_EditCameraInfo.m_Rotation =
+ m_MouseDownCameraInformation.m_Rotation
+ * (theXRotation * theYRotation);
+ } else {
+ QT3DSVec3 theZAxis = QT3DSVec3(0, 0, 1);
+ QT3DSQuat theZRotation(
+ -1.0f * theYDistance * g_RotationScaleFactor / 20.0f, theZAxis);
+ m_Translation->m_EditCameraInfo.m_Rotation =
+ m_MouseDownCameraInformation.m_Rotation * theZRotation;
+ }
+ // Rotations need to be incremental and relative else things don't rotate
+ // intuitively.
+ m_MouseDownCameraInformation.m_Rotation =
+ m_Translation->m_EditCameraInfo.m_Rotation;
+ RequestRender();
+ }
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ } // if ( m_PickResult.m_WidgetId.hasValue() == false )
+
+ // We need to do widget-specific dragging.
+ else if (m_PickResult.getType() == StudioPickValueTypes::Widget) {
+ m_Translation->PerformWidgetDrag(m_PickResult.GetWidgetId(), m_MouseDownPoint,
+ m_PreviousMousePoint, inPoint, m_UpdatableEditor);
+ } else if (m_PickResult.getType() == StudioPickValueTypes::Guide) {
+ m_Translation->PerformGuideDrag(m_PickResult.getData<CUICDMGuideHandle>(), inPoint,
+ m_UpdatableEditor);
+ } else if (m_PickResult.getType() == StudioPickValueTypes::Path) {
+ SPathPick thePick = m_PickResult.getData<SPathPick>();
+ m_Translation->PerformPathDrag(thePick, m_MouseDownPoint, m_PreviousMousePoint, inPoint,
+ m_UpdatableEditor);
+ }
+ m_PreviousMousePoint = inPoint;
+ }
+
+ void OnSceneMouseUp(SceneDragSenderType::Enum) override
+ {
+ m_MaybeDragStart = false;
+ CUICDMGuideHandle theSelectedGuide;
+ if (m_PickResult.getType() == StudioPickValueTypes::Guide) {
+ theSelectedGuide = m_PickResult.getData<CUICDMGuideHandle>();
+ m_Translation->CheckGuideInPresentationRect(theSelectedGuide, m_UpdatableEditor);
+ }
+ m_UpdatableEditor.CommitEditor();
+ m_PickResult = SStudioPickValue();
+ if (m_Translation)
+ m_Translation->EndDrag();
+ if (theSelectedGuide.GetHandleValue()) {
+ // Get rid of selection if things aren't editable.
+ if (m_Doc.GetDocumentReader().AreGuidesEditable())
+ m_Doc.NotifySelectionChanged(theSelectedGuide);
+ else
+ m_Doc.NotifySelectionChanged();
+ }
+ RequestRender();
+ }
+
+ void OnSceneMouseDblClick(SceneDragSenderType::Enum inSenderType, QPoint inPoint) override
+ {
+ if (inSenderType == SceneDragSenderType::SceneWindow && m_Translation) {
+ inPoint.setX(inPoint.x() * devicePixelRatio());
+ inPoint.setY(inPoint.y() * devicePixelRatio());
+ m_RenderContext->BeginRender();
+ SStudioPickValue theResult(
+ m_Translation->Pick(inPoint, TranslationSelectMode::NestedComponentSingle));
+ m_RenderContext->EndRender();
+
+ if (theResult.getType() == StudioPickValueTypes::Instance)
+ m_Doc.SelectAndNavigateToUICDMObject(theResult.getData<CUICDMInstanceHandle>());
+ else if (theResult.getType() == StudioPickValueTypes::Path) {
+ SPathPick thePickValue = theResult.getData<SPathPick>();
+ UICDM::CUICDMInstanceHandle theAnchorHandle =
+ m_Translation->GetAnchorPoint(thePickValue);
+ if (theAnchorHandle.Valid() && theAnchorHandle != m_Doc.GetSelectedInstance()) {
+ m_Doc.SelectUICDMObject(theAnchorHandle);
+ }
+ }
+ }
+ }
+
+ void OnSceneMouseWheel(SceneDragSenderType::Enum inSenderType, short inDelta,
+ int inToolMode) override
+ {
+ ASSERT(inSenderType == SceneDragSenderType::Matte);
+ if (inToolMode == STUDIO_TOOLMODE_CAMERA_ZOOM && m_Translation) {
+ QT3DSF32 theMultiplier = 1.0f - inDelta / static_cast<QT3DSF32>(120 * g_WheelFactor);
+ m_Translation->m_EditCameraInfo.m_ViewRadius =
+ NVMax(.0001f, m_Translation->m_EditCameraInfo.m_ViewRadius * theMultiplier);
+ RequestRender();
+ }
+ }
+
+ void OnNudge(ENudgeDirection inNudgeDirection, int inToolMode, int inFlags) override
+ {
+ if (m_Translation)
+ m_Translation->OnNudge(inNudgeDirection, inToolMode, inFlags, m_UpdatableEditor);
+ }
+
+ void OnNudgeDone() override
+ {
+ if (m_Translation)
+ m_Translation->OnNudgeFinished();
+ m_UpdatableEditor.CommitEditor();
+ }
+
+ void OnToolbarChange() override { RequestRender(); }
+};
+}
+
+std::shared_ptr<IStudioRenderer> IStudioRenderer::CreateStudioRenderer()
+{
+ return std::make_shared<SRendererImpl>();
+}