!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / Sandbox / Plugins / EditorCommon / QViewport.cpp
blobaabe4a656184030076d9f1c190d5b17b592e3049
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "stdafx.h"
5 #include <CryMath/Cry_Camera.h>
6 #include <CryRenderer/IRenderer.h>
7 #include <CryRenderer/IRenderAuxGeom.h>
8 #include <CrySystem/ITimer.h>
9 #include <Cry3DEngine/I3DEngine.h>
10 #include <CryPhysics/IPhysicsDebugRenderer.h>
11 #include <IEditor.h>
13 #include <QMouseEvent>
15 #include "QtUtil.h"
16 #include "QViewport.h"
17 #include "QViewportEvents.h"
18 #include "QViewportConsumer.h"
19 #include "QViewportSettings.h"
20 #include "Serialization.h"
21 #include <QApplication>
23 #include "ViewportInteraction.h"
24 #include "RenderLock.h"
26 SERIALIZATION_ENUM_BEGIN(ECameraTransformRestraint, "CameraTransformRestraint")
27 SERIALIZATION_ENUM(eCameraTransformRestraint_Rotation, "Rotation", "Rotation")
28 SERIALIZATION_ENUM(eCameraTransformRestraint_Panning, "Panning", "Panning")
29 SERIALIZATION_ENUM(eCameraTransformRestraint_Zoom, "Zoom", "Zoom")
30 SERIALIZATION_ENUM_END()
32 struct QViewport::SPreviousContext
34 CCamera systemCamera;
35 int width;
36 int height;
37 HWND window;
38 bool mainViewport;
41 #pragma warning(disable: 4355) // 'this' : used in base member initializer list)
43 void QViewport::CreateGridLine(ColorB col, const float alpha, const float alphaFalloff, const float slide, const float halfSlide, const float maxSlide, const Vec3& stepDir, const Vec3& orthoDir)
45 const SViewportState& state = *m_state;
46 const SViewportGridSettings& gridSettings = m_settings->grid;
48 ColorB colEnd = col;
50 float weight = 1.0f - (slide / halfSlide);
51 if (slide > halfSlide)
52 weight = (slide - halfSlide) / halfSlide;
54 float orthoWeight = 1.0f;
56 if (gridSettings.circular)
58 float invWeight = 1.0f - weight;
59 orthoWeight = sqrtf((invWeight * 2) - (invWeight * invWeight));
61 else
62 orthoWeight = 1.0f;
64 col.a = (1.0f - (weight * (1.0f - alphaFalloff))) * alpha;
65 colEnd.a = alphaFalloff * alpha;
67 Vec3 orthoStep = state.gridOrigin.q * (orthoDir * halfSlide * orthoWeight);
69 Vec3 point = state.gridOrigin * (-(stepDir * halfSlide) + (stepDir * slide));
70 Vec3 points[3] = {
71 point,
72 point - orthoStep,
73 point + orthoStep
76 const uint32 cPacked = col.pack_argb8888();
77 const uint32 cEndPacked = colEnd.pack_argb8888();
78 m_gridLineVertices.push_back(points[0]); m_gridLineVerticesColor.push_back(cPacked);
79 m_gridLineVertices.push_back(points[1]); m_gridLineVerticesColor.push_back(cEndPacked);
80 m_gridLineVertices.push_back(points[0]); m_gridLineVerticesColor.push_back(cPacked);
81 m_gridLineVertices.push_back(points[2]); m_gridLineVerticesColor.push_back(cEndPacked);
84 void QViewport::CreateGridLines(const uint count, const uint interStepCount, const Vec3& stepDir, const float stepSize, const Vec3& orthoDir, const float offset)
86 const SViewportGridSettings& gridSettings = m_settings->grid;
88 const uint countHalf = count / 2;
89 Vec3 step = stepDir * stepSize;
90 Vec3 orthoStep = orthoDir * countHalf;
91 Vec3 maxStep = step * countHalf;// + stepDir*fabs(offset);
92 const float maxStepLen = count * stepSize;
93 const float halfStepLen = countHalf * stepSize;
95 float interStepSize = interStepCount > 0 ? (stepSize / interStepCount) : stepSize;
96 const float alphaMulMain = (float)gridSettings.mainColor.a;
97 const float alphaMulInter = (float)gridSettings.middleColor.a;
98 const float alphaFalloff = 1.0f - (gridSettings.alphaFalloff / 100.0f);
99 float orthoWeight = 1.0f;
101 for (int i = 0; i < count + 2; i++)
103 float pointSlide = i * stepSize + offset;
104 if (pointSlide > 0.0f && pointSlide < maxStepLen)
105 CreateGridLine(gridSettings.mainColor, alphaMulMain, alphaFalloff, pointSlide, halfStepLen, maxStepLen, stepDir, orthoDir);
107 for (int d = 1; d < interStepCount; d++)
109 float interSlide = ((i - 1) * stepSize) + offset + (d * interStepSize);
110 if (interSlide > 0.0f && interSlide < maxStepLen)
111 CreateGridLine(gridSettings.middleColor, alphaMulInter, alphaFalloff, interSlide, halfStepLen, maxStepLen, stepDir, orthoDir);
116 void QViewport::DrawGrid()
118 const SViewportGridSettings& gridSettings = m_settings->grid;
120 const uint count = gridSettings.count * 2;
121 const float gridSize = gridSettings.spacing * gridSettings.count * 2.0f;
122 const float stepSize = gridSize / count;
124 m_gridLineVertices.clear();
125 m_gridLineVerticesColor.clear();
126 CreateGridLines(count, gridSettings.interCount, Vec3(1.0f, 0.0f, 0.0f), stepSize, Vec3(0.0f, 1.0f, 0.0f), m_state->gridCellOffset.x);
127 CreateGridLines(count, gridSettings.interCount, Vec3(0.0f, 1.0f, 0.0f), stepSize, Vec3(1.0f, 0.0f, 0.0f), m_state->gridCellOffset.y);
129 m_pAuxGeom->DrawLines( &m_gridLineVertices[0], &m_gridLineVerticesColor[0], (uint32)m_gridLineVertices.size() );
132 void QViewport::DrawOrigin(const ColorB& col)
134 IRenderAuxGeom* aux = m_pAuxGeom;
136 const float scale = 0.3f;
137 const float lineWidth = 4.0f;
138 aux->DrawLine(Vec3(-scale, 0, 0), col, Vec3(0, 0, 0), col, lineWidth);
139 aux->DrawLine(Vec3(0, -scale, 0), col, Vec3(0, 0, 0), col, lineWidth);
140 aux->DrawLine(Vec3(0, 0, -scale), col, Vec3(0, 0, 0), col, lineWidth);
141 const ColorB cx(255, 0, 0, 255);
142 const ColorB cy(0, 255, 0, 255);
143 const ColorB cz(0, 0, 255, 255);
144 aux->DrawLine(Vec3(0, 0, 0), cx, Vec3(scale, 0, 0), cx, lineWidth);
145 aux->DrawLine(Vec3(0, 0, 0), cy, Vec3(0, scale, 0), cy, lineWidth);
146 aux->DrawLine(Vec3(0, 0, 0), cz, Vec3(0, 0, scale), cz, lineWidth);
149 void QViewport::DrawOrigin(const int left, const int top, const float scale, const Matrix34 cameraTM)
151 IRenderAuxGeom* aux = m_pAuxGeom;
153 Vec3 originPos = Vec3(left, top, 0);
154 Quat originRot = Quat(0.707107f, 0.707107f, 0, 0) * Quat(cameraTM).GetInverted();
155 Vec3 x = originPos + originRot * Vec3(1, 0, 0) * scale;
156 Vec3 y = originPos + originRot * Vec3(0, 1, 0) * scale;
157 Vec3 z = originPos + originRot * Vec3(0, 0, 1) * scale;
158 ColorF xCol(1, 0, 0);
159 ColorF yCol(0, 1, 0);
160 ColorF zCol(0, 0, 1);
161 const float lineWidth = 2.0f;
163 aux->DrawLine(originPos, xCol, x, xCol, lineWidth);
164 aux->DrawLine(originPos, yCol, y, yCol, lineWidth);
165 aux->DrawLine(originPos, zCol, z, zCol, lineWidth);
168 struct QViewport::SPrivate
170 SRenderLight m_VPLight0;
174 QViewport::QViewport(SSystemGlobalEnvironment* env, QWidget* parent, int supersamplingFactor)
175 : QWidget(parent)
176 , m_renderContextCreated(false)
177 , m_updating(false)
178 , m_width(0)
179 , m_height(0)
180 , m_supersamplingFactor(supersamplingFactor)
181 , m_rotationMode(false)
182 , m_panMode(false)
183 , m_orbitModeEnabled(false)
184 , m_orbitMode(false)
185 , m_fastMode(false)
186 , m_slowMode(false)
187 , m_lastTime(0)
188 , m_lastFrameTime(0.0f)
189 , m_averageFrameTime(0.0f)
190 , m_sceneDimensions(1.0f, 1.0f, 1.0f)
191 , m_creatingRenderContext(false)
192 , m_env(env)
193 , m_cameraSmoothPosRate(0)
194 , m_cameraSmoothRotRate(0)
195 , m_settings(new SViewportSettings())
196 , m_state(new SViewportState())
197 , m_mouseMovementsSinceLastFrame(0)
198 , m_private(new SPrivate())
200 if (!gEnv)
201 gEnv = m_env; // Shhh!
203 CreateRenderContext();
205 m_camera.reset(new CCamera());
206 ResetCamera();
208 m_mousePressPos = QCursor::pos();
210 UpdateBackgroundColor();
212 setUpdatesEnabled(false);
213 setAttribute(Qt::WA_PaintOnScreen);
214 setMouseTracking(true);
215 m_LightRotationRadian = 0;
217 m_pViewportAdapter.reset(new CDisplayViewportAdapter(this));
220 QViewport::~QViewport()
222 DestroyRenderContext();
225 void QViewport::UpdateBackgroundColor()
227 QPalette pal(palette());
228 pal.setColor(QPalette::Background, QColor(m_settings->background.topColor.r,
229 m_settings->background.topColor.g,
230 m_settings->background.topColor.b,
231 m_settings->background.topColor.a));
232 setPalette(pal);
233 setAutoFillBackground(true);
236 void QViewport::SetOrbitMode(bool orbitMode)
238 m_orbitModeEnabled = orbitMode;
241 bool QViewport::ScreenToWorldRay(Ray* ray, int x, int y)
243 if (!m_env->pRenderer)
244 return false;
246 Vec3 pos0(0,0,0), pos1(0,0,0);
247 if (!Camera()->Unproject(Vec3(float(x), float(m_height - y), 0), pos0))
249 return false;
251 if (!Camera()->Unproject(Vec3(float(x), float(m_height - y), 1), pos1))
253 return false;
256 Vec3 v = (pos1 - pos0);
257 v = v.GetNormalized();
259 ray->origin = pos0;
260 ray->direction = v;
261 return true;
264 QPoint QViewport::ProjectToScreen(const Vec3& wp)
266 Vec3 out(0, 0, 0);
267 if (Camera()->Project(wp, out))
269 return QPoint((int)out.x,(int)out.y);
271 RestorePreviousContext();
273 return QPoint(0, 0);
276 void QViewport::LookAt(const Vec3& target, float radius, bool snap)
278 QuatT cameraTarget = m_state->cameraTarget;
279 CreateLookAt(target, radius, cameraTarget);
280 CameraMoved(cameraTarget, snap);
283 int QViewport::Width() const
285 return QtUtil::PixelScale(this, rect().width());
288 int QViewport::Height() const
290 return QtUtil::PixelScale(this, rect().height());
293 bool QViewport::CreateRenderContext()
295 if (m_creatingRenderContext)
296 return false;
297 m_creatingRenderContext = true;
298 DestroyRenderContext();
299 HWND window = (HWND)QWidget::winId();
301 // Create context.
302 if (window && m_env->pRenderer && !m_renderContextCreated)
304 IRenderer::SDisplayContextDescription desc;
306 desc.handle = window;
307 desc.type = IRenderer::eViewportType_Secondary;
308 desc.clearColor = ColorF(m_settings->background.topColor);
309 desc.renderFlags = FRT_CLEAR | FRT_OVERLAY_DEPTH;
310 desc.superSamplingFactor.x = m_supersamplingFactor;
311 desc.superSamplingFactor.y = m_supersamplingFactor;
312 desc.screenResolution.x = m_width;
313 desc.screenResolution.y = m_height;
315 m_displayContextKey = gEnv->pRenderer->CreateContext(desc);
317 m_renderContextCreated = true;
318 m_creatingRenderContext = false;
320 SetCurrentContext();
321 return true;
324 m_creatingRenderContext = false;
325 return false;
328 void QViewport::DestroyRenderContext()
330 // Destroy render context.
331 if (m_env->pRenderer && m_renderContextCreated)
333 // Do not delete primary context.
334 if (m_displayContextKey != static_cast<HWND>(m_env->pRenderer->GetHWND()))
335 m_env->pRenderer->DeleteContext(m_displayContextKey);
337 m_renderContextCreated = false;
341 void QViewport::SetCurrentContext()
343 if (m_camera.get() == 0)
344 return;
346 SPreviousContext previous;
347 previous.systemCamera = m_env->pSystem->GetViewCamera();
348 m_env->pSystem->SetViewCamera(*m_camera);
349 m_previousContexts.push_back(previous);
352 void QViewport::RestorePreviousContext()
354 if (!m_camera.get())
355 return;
356 if (m_previousContexts.empty())
358 ASSERT(0);
359 return;
361 SPreviousContext x = m_previousContexts.back();
362 m_previousContexts.pop_back();
363 m_env->pSystem->SetViewCamera(x.systemCamera);
366 void QViewport::InitDisplayContext(HWND hWnd)
368 CRY_PROFILE_FUNCTION(PROFILE_EDITOR);
370 // Draw all objects.
371 SDisplayContextKey displayContextKey;
372 displayContextKey.key.emplace<HWND>(hWnd);
373 DisplayContext& dctx = m_displayContext;
374 dctx.SetDisplayContext(displayContextKey);
375 dctx.SetView(m_pViewportAdapter.get());
376 dctx.SetCamera(m_camera.get());
377 dctx.renderer = m_env->pRenderer;
378 dctx.engine = m_env->p3DEngine;
379 dctx.box.min = Vec3(-100000, -100000, -100000);
380 dctx.box.max = Vec3(100000, 100000, 100000);
381 dctx.flags = 0;
384 void QViewport::Serialize(IArchive& ar)
386 if (!ar.isEdit())
388 ar(m_state->cameraTarget, "cameraTarget", "Camera Target");
392 struct AutoBool
394 AutoBool(bool* value)
395 : m_value(value)
397 * m_value = true;
400 ~AutoBool()
402 * m_value = false;
405 bool* m_value;
408 void QViewport::Update()
410 int64 time = m_env->pSystem->GetITimer()->GetAsyncTime().GetMilliSecondsAsInt64();
411 if (m_lastTime == 0)
412 m_lastTime = time;
413 m_lastFrameTime = (time - m_lastTime) * 0.001f;
414 m_lastTime = time;
415 if (m_averageFrameTime == 0.0f)
416 m_averageFrameTime = m_lastFrameTime;
417 else
418 m_averageFrameTime = 0.01f * m_lastFrameTime + 0.99f * m_averageFrameTime;
420 if (m_env->pRenderer == 0 ||
421 m_env->p3DEngine == 0)
422 return;
424 if (!isVisible())
425 return;
427 if (!m_width || !m_height)
428 return;
430 if (!m_renderContextCreated)
431 return;
433 if (m_updating)
434 return;
436 AutoBool updating(&m_updating);
438 if (hasFocus())
440 ProcessMouse();
441 ProcessKeys();
444 RenderInternal();
447 void QViewport::CaptureMouse()
449 grabMouse();
452 void QViewport::ReleaseMouse()
454 releaseMouse();
457 void QViewport::SetForegroundUpdateMode(bool foregroundUpdate)
459 //m_timer->setInterval(foregroundUpdate ? 2 : 50);
462 void QViewport::ProcessMouse()
464 QPoint point = mapFromGlobal(QCursor::pos());
466 if (point == m_mousePressPos)
468 return;
471 float speedScale = CalculateMoveSpeed(m_fastMode, m_slowMode);
473 if ((m_rotationMode && m_panMode) /* || m_bInZoomMode*/)
475 if (!(m_settings->camera.transformRestraint & eCameraTransformRestraint_Zoom))
477 // Zoom.
478 QuatT qt = m_state->cameraTarget;
479 Vec3 xdir(0, 0, 0);
481 Vec3 ydir = qt.GetColumn1().GetNormalized();
482 Vec3 pos = qt.t;
483 pos = pos - 0.2f * ydir * (m_mousePressPos.y() - point.y()) * speedScale;
484 qt.t = pos;
485 CameraMoved(qt, false);
487 QCursor::setPos(mapToGlobal(m_mousePressPos));
490 else if (m_rotationMode)
492 if (!(m_settings->camera.transformRestraint & eCameraTransformRestraint_Rotation))
494 Ang3 angles(-point.y() + m_mousePressPos.y(), 0, -point.x() + m_mousePressPos.x());
495 angles = angles * 0.001f * m_settings->camera.rotationSpeed;
497 QuatT qt = m_state->cameraTarget;
498 Ang3 ypr = CCamera::CreateAnglesYPR(Matrix33(qt.q));
499 ypr.x += angles.z;
500 ypr.y += angles.x;
501 ypr.y = clamp_tpl(ypr.y, -1.5f, 1.5f);
503 qt.q = Quat(CCamera::CreateOrientationYPR(ypr));
504 CameraMoved(qt, false);
506 QCursor::setPos(mapToGlobal(m_mousePressPos));
509 else if (m_panMode)
511 if (!(m_settings->camera.transformRestraint & eCameraTransformRestraint_Panning))
513 // Slide.
514 QuatT qt = m_state->cameraTarget;
515 Vec3 xdir = qt.GetColumn0().GetNormalized();
516 Vec3 zdir = qt.GetColumn2().GetNormalized();
518 Vec3 pos = qt.t;
519 pos += 0.0025f * xdir * (point.x() - m_mousePressPos.x()) * speedScale + 0.0025f * zdir * (m_mousePressPos.y() - point.y()) * speedScale;
520 qt.t = pos;
521 CameraMoved(qt, false);
523 QCursor::setPos(mapToGlobal(m_mousePressPos));
526 else if (m_orbitMode)
528 // Rotate around orbit target.
529 QuatT cameraTarget = m_state->cameraTarget;
530 Vec3 at = cameraTarget.t - m_state->orbitTarget;
531 float distanceFromTarget = at.GetLength();
532 if (distanceFromTarget > 0.001f)
534 at /= distanceFromTarget;
536 else
538 at = Vec3(0.0f, m_state->orbitRadius, 0.0f);
539 distanceFromTarget = m_state->orbitRadius;
542 Vec3 up = Vec3(0.0f, 0.0f, 1.0f);
543 const Vec3 right = at.Cross(up).GetNormalized();
544 up = right.Cross(at).GetNormalized();
546 Ang3 angles = CCamera::CreateAnglesYPR(Matrix33::CreateFromVectors(right, at, up));
547 const Ang3 delta = Ang3(-point.y() + m_mousePressPos.y(), 0.0f, -point.x() + m_mousePressPos.x()) * 0.002f * m_settings->camera.rotationSpeed;
548 angles.x += delta.z;
549 angles.y -= delta.x;
550 angles.y = clamp_tpl(angles.y, -1.5f, 1.5f);
552 cameraTarget.t = m_state->orbitTarget + CCamera::CreateOrientationYPR(angles).TransformVector(Vec3(0.0f, distanceFromTarget, 0.0f));
554 CameraMoved(cameraTarget, true);
556 QCursor::setPos(mapToGlobal(m_mousePressPos));
560 void QViewport::ProcessKeys()
562 if (!m_renderContextCreated)
563 return;
565 float deltaTime = m_lastFrameTime;
567 if (deltaTime > 0.1f)
568 deltaTime = 0.1f;
570 QuatT qt = m_state->cameraTarget;
571 Vec3 ydir = qt.GetColumn1().GetNormalized();
572 Vec3 xdir = qt.GetColumn0().GetNormalized();
573 Vec3 pos = qt.t;
575 float moveSpeed = CalculateMoveSpeed(m_fastMode, m_slowMode);
576 float moveBackForthSpeed = CalculateMoveSpeed(m_fastMode, m_slowMode, true);
577 bool hasPressedKey = false;
579 if (ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Forward))
581 hasPressedKey = true;
582 qt.t = qt.t + deltaTime * moveBackForthSpeed * ydir;
583 CameraMoved(qt, false);
586 if (ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Backward))
588 hasPressedKey = true;
589 qt.t = qt.t - deltaTime * moveBackForthSpeed * ydir;
590 CameraMoved(qt, false);
593 if (!m_orbitMode && ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Left))
595 hasPressedKey = true;
596 qt.t = qt.t - deltaTime * moveSpeed * xdir;
597 CameraMoved(qt, false);
600 if (!m_orbitMode && ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Right))
602 hasPressedKey = true;
603 qt.t = qt.t + deltaTime * moveSpeed * xdir;
604 CameraMoved(qt, false);
607 if (QGuiApplication::mouseButtons() & (Qt::LeftButton | Qt::RightButton))
609 hasPressedKey = true;
613 void QViewport::CameraMoved(QuatT qt, bool snap)
615 if (m_orbitMode)
617 CreateLookAt(m_state->orbitTarget, m_state->orbitRadius, qt);
619 m_state->cameraTarget = qt;
620 if (snap)
622 m_state->lastCameraTarget = qt;
624 SignalCameraMoved(qt);
627 void QViewport::OnKeyEvent(const SKeyEvent& ev)
629 for (size_t i = 0; i < m_consumers.size(); ++i)
630 m_consumers[i]->OnViewportKey(ev);
631 SignalKey(ev);
634 bool QViewport::OnMouseEvent(const SMouseEvent& ev)
636 if (ev.type == SMouseEvent::TYPE_MOVE)
638 // Make sure we don't process more than one mouse event per frame, so we don't
639 // end up consuming all the "idle" time
640 ++m_mouseMovementsSinceLastFrame;
642 if (m_mouseMovementsSinceLastFrame > 1)
644 // we can't discard all movement events, the last one should be delivered.
645 m_pendingMouseMoveEvent = ev;
646 return false;
650 CPoint p;
651 EMouseEvent evt;
652 int flags;
653 IEditorEventFromQViewportEvent(ev, p, evt, flags);
655 if (m_gizmoManager.HandleMouseInput(m_pViewportAdapter.get(), evt, p, flags))
657 return true;
660 for (size_t i = 0; i < m_consumers.size(); ++i)
662 m_consumers[i]->OnViewportMouse(ev);
664 SignalMouse(ev);
666 return false;
669 void QViewport::PreRender()
671 SRenderContext rc;
672 rc.camera = m_camera.get();
673 rc.viewport = this;
674 rc.pAuxGeom = m_pAuxGeom;
676 SignalPreRender(rc);
678 const float fov = DEG2RAD(m_settings->camera.fov);
679 const float fTime = m_env->pTimer->GetFrameTime();
680 float lastRotWeight = 0.0f;
682 QuatT targetTM = m_state->cameraTarget;
683 QuatT currentTM = m_state->lastCameraTarget;
685 if ((targetTM.t - currentTM.t).len() > 0.0001f)
686 SmoothCD(currentTM.t, m_cameraSmoothPosRate, fTime, targetTM.t, m_settings->camera.smoothPos);
687 else
688 m_cameraSmoothPosRate = Vec3(0);
690 SmoothCD(lastRotWeight, m_cameraSmoothRotRate, fTime, 1.0f, m_settings->camera.smoothRot);
692 if (lastRotWeight >= 1.0f)
693 m_cameraSmoothRotRate = 0.0f;
695 currentTM = QuatT(Quat::CreateNlerp(currentTM.q, targetTM.q, lastRotWeight), currentTM.t);
697 m_state->lastCameraParentFrame = m_state->cameraParentFrame;
698 m_state->lastCameraTarget = currentTM;
700 m_camera->SetFrustum(m_width, m_height, fov, m_settings->camera.nearClip, m_env->p3DEngine->GetMaxViewDistance());
701 m_camera->SetMatrix(Matrix34(m_state->cameraParentFrame * currentTM));
704 // TODO: Either move it somewhere reusable or completely remove IEditor or QViewport style events
705 void QViewport::IEditorEventFromQViewportEvent(const SMouseEvent& qEvt, CPoint& p, EMouseEvent& evt, int& flags)
707 p.x = qEvt.x;
708 p.y = qEvt.y;
709 flags = 0;
711 if (qEvt.control)
713 flags |= MK_CONTROL;
715 if (qEvt.shift)
717 flags |= MK_SHIFT;
720 if (qEvt.type == SMouseEvent::TYPE_MOVE)
722 evt = eMouseMove;
724 else if (qEvt.type == SMouseEvent::TYPE_PRESS)
726 if (qEvt.button == SMouseEvent::BUTTON_LEFT)
728 evt = eMouseLDown;
730 else if (qEvt.button == SMouseEvent::BUTTON_RIGHT)
732 evt = eMouseRDown;
734 else if (qEvt.button == SMouseEvent::BUTTON_MIDDLE)
736 evt = eMouseMDown;
739 else if (qEvt.type == SMouseEvent::TYPE_RELEASE)
741 if (qEvt.button == SMouseEvent::BUTTON_LEFT)
743 evt = eMouseLUp;
745 else if (qEvt.button == SMouseEvent::BUTTON_RIGHT)
747 evt = eMouseRUp;
749 else if (qEvt.button == SMouseEvent::BUTTON_MIDDLE)
751 evt = eMouseMUp;
756 struct ScopedBackup
758 ScopedBackup(IRenderAuxGeom** pDCAuxGeomPtr, IRenderAuxGeom* pNewAuxGeom)
760 ppDCAuxGeom = pDCAuxGeomPtr;
761 oldAuxGeom = *pDCAuxGeomPtr;
762 *pDCAuxGeomPtr = pNewAuxGeom;
764 ~ScopedBackup()
766 *ppDCAuxGeom = oldAuxGeom;
769 IRenderAuxGeom** ppDCAuxGeom;
770 IRenderAuxGeom* oldAuxGeom;
773 void QViewport::Render()
775 DisplayContext& dc = m_displayContext;
776 ScopedBackup(&m_displayContext.pRenderAuxGeom, m_pAuxGeom);
778 IRenderAuxGeom* aux = m_pAuxGeom;
779 SAuxGeomRenderFlags oldFlags = aux->GetRenderFlags();
781 dc.SetState(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeBack | e_DepthWriteOff | e_DepthTestOn);
783 // wireframe mode
784 CScopedWireFrameMode scopedWireFrame(m_env->pRenderer, m_settings->rendering.wireframe ? R_WIREFRAME_MODE : R_SOLID_MODE);
786 SRenderingPassInfo passInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(*m_camera, SRenderingPassInfo::DEFAULT_FLAGS, true, dc.GetDisplayContextKey());
788 if (m_settings->background.useGradient)
790 Vec3 frustumVertices[8];
791 aux->GetCamera().GetFrustumVertices(frustumVertices);
792 Vec3 lt = Vec3::CreateLerp(frustumVertices[0], frustumVertices[4], 0.10f);
793 Vec3 lb = Vec3::CreateLerp(frustumVertices[1], frustumVertices[5], 0.10f);
794 Vec3 rb = Vec3::CreateLerp(frustumVertices[2], frustumVertices[6], 0.10f);
795 Vec3 rt = Vec3::CreateLerp(frustumVertices[3], frustumVertices[7], 0.10f);
796 aux->SetRenderFlags(e_Mode3D | e_AlphaNone | e_FillModeSolid | e_CullModeNone | e_DepthWriteOff | e_DepthTestOn);
797 ColorB topColor = m_settings->background.topColor;
798 ColorB bottomColor = m_settings->background.bottomColor;
800 // convert colors from sRGB to linear to render the gradation to HDR render target instead of back buffer.
801 ColorF tempColor = ColorF(topColor.r, topColor.g, topColor.b) / 255.0f;
802 tempColor.srgb2rgb();
803 topColor = ColorB(tempColor);
804 tempColor = ColorF(bottomColor.r, bottomColor.g, bottomColor.b) / 255.0f;
805 tempColor.srgb2rgb();
806 bottomColor = ColorB(tempColor);
808 aux->DrawTriangle(lt, topColor, rt, topColor, rb, bottomColor);
809 aux->DrawTriangle(lb, bottomColor, rb, bottomColor, lt, topColor);
812 m_env->pRenderer->EF_StartEf(passInfo);
814 SRendParams rp;
815 rp.AmbientColor.r = m_settings->lighting.m_ambientColor.r / 255.0f * m_settings->lighting.m_brightness;
816 rp.AmbientColor.g = m_settings->lighting.m_ambientColor.g / 255.0f * m_settings->lighting.m_brightness;
817 rp.AmbientColor.b = m_settings->lighting.m_ambientColor.b / 255.0f * m_settings->lighting.m_brightness;
819 //---------------------------------------------------------------------------------------
820 //---- directional light -------------------------------------------------------------
821 //---------------------------------------------------------------------------------------
823 if (m_settings->lighting.m_useLightRotation)
824 m_LightRotationRadian += m_averageFrameTime;
825 if (m_LightRotationRadian > gf_PI)
826 m_LightRotationRadian = -gf_PI;
828 Matrix33 LightRot33 = Matrix33::CreateRotationZ(m_LightRotationRadian);
830 f32 lightMultiplier = m_settings->lighting.m_lightMultiplier;
831 f32 lightSpecMultiplier = m_settings->lighting.m_lightSpecMultiplier;
832 f32 lightRadius = 400;
834 f32 lightOrbit = 15.0f;
835 Vec3 LPos0 = Vec3(-lightOrbit, lightOrbit, lightOrbit / 2);
836 m_private->m_VPLight0.SetPosition(LightRot33 * LPos0);
838 Vec3 d0;
839 d0.x = f32(m_settings->lighting.m_directionalLightColor.r) / 255.0f;
840 d0.y = f32(m_settings->lighting.m_directionalLightColor.g) / 255.0f;
841 d0.z = f32(m_settings->lighting.m_directionalLightColor.b) / 255.0f;
842 m_private->m_VPLight0.m_Flags |= DLF_POINT;
843 m_private->m_VPLight0.SetLightColor(ColorF(d0.x * lightMultiplier, d0.y * lightMultiplier, d0.z * lightMultiplier, 0));
844 m_private->m_VPLight0.SetSpecularMult(lightSpecMultiplier);
845 m_private->m_VPLight0.SetRadius(lightRadius);
847 ColorB col;
848 col.r = uint8(d0.x * 255);
849 col.g = uint8(d0.y * 255);
850 col.b = uint8(d0.z * 255);
851 col.a = 255;
852 aux->DrawSphere(m_private->m_VPLight0.m_Origin, 0.4f, col);
854 m_private->m_VPLight0.m_Flags = DLF_SUN | DLF_DIRECTIONAL;
855 m_env->pRenderer->EF_ADDDlight(&m_private->m_VPLight0, passInfo);
857 //---------------------------------------------------------------------------------------
859 Matrix34 tm(IDENTITY);
860 rp.pMatrix = &tm;
861 rp.pPrevMatrix = &tm;
863 rp.dwFObjFlags = 0;
864 rp.dwFObjFlags |= FOB_TRANS_MASK;
866 SRenderContext rc;
867 rc.camera = m_camera.get();
868 rc.viewport = this;
869 rc.passInfo = &passInfo;
870 rc.renderParams = &rp;
871 rc.pAuxGeom = aux;
873 for (size_t i = 0; i < m_consumers.size(); ++i)
874 m_consumers[i]->OnViewportRender(rc);
875 SignalRender(rc);
877 m_gizmoManager.Display(dc);
879 m_env->pSystem->GetIPhysicsDebugRenderer()->Flush(m_lastFrameTime);
880 m_env->pRenderer->EF_EndEf3D(SHDF_ALLOWHDR | SHDF_SECONDARY_VIEWPORT, -1, -1, passInfo);
882 if (m_settings->grid.showGrid)
884 aux->SetRenderFlags(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeNone | e_DepthWriteOff | e_DepthTestOn);
885 DrawGrid();
888 if (m_settings->grid.origin)
890 aux->SetRenderFlags(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeNone | e_DepthWriteOff | e_DepthTestOn);
891 DrawOrigin(m_settings->grid.originColor);
894 if (m_settings->camera.showViewportOrientation)
896 aux->SetRenderFlags(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeNone | e_DepthWriteOn | e_DepthTestOn);
897 aux->SetOrthographicProjection(true, 0.0f, m_width, m_height, 0.0f);
898 DrawOrigin(50, m_height - 50, 20.0f, m_camera->GetMatrix());
899 aux->SetOrthographicProjection(false);
902 aux->Submit();
903 aux->SetRenderFlags(oldFlags);
905 if ((m_settings->rendering.fps == true) && (m_averageFrameTime != 0.0f))
907 IRenderAuxText::Draw2dLabel(12.0f, 12.0f, 1.25f, ColorF(1, 1, 1, 1), false, "FPS: %.2f", 1.0f / m_averageFrameTime);
910 if (m_mouseMovementsSinceLastFrame > 1)
912 m_mouseMovementsSinceLastFrame = 0;
914 // Make sure we deliver at least last mouse movement event
915 OnMouseEvent(m_pendingMouseMoveEvent);
919 void QViewport::RenderInternal()
921 // lock while we are rendering to prevent any recursive rendering across the application
922 if (CScopedRenderLock lock = CScopedRenderLock())
924 const HWND hWnd = reinterpret_cast<HWND>(QWidget::winId());
925 SDisplayContextKey displayContextKey;
926 displayContextKey.key.emplace<HWND>(hWnd);
928 SetCurrentContext();
930 // Configures Aux to draw to the current display-context
931 InitDisplayContext(hWnd);
933 // Request for a new aux geometry to capture aux commands in the current viewport
934 CCamera camera = *m_camera;
935 m_pAuxGeom = gEnv->pRenderer->GetOrCreateIRenderAuxGeom(&camera);
937 m_env->pSystem->RenderBegin(displayContextKey);
939 // Sets the current viewport's aux geometry display context
940 m_pAuxGeom->SetCurrentDisplayContext(displayContextKey);
942 // Do the pre-rendering. This call updates the member camera (applying transformation to the camera).
943 PreRender();
944 camera = *m_camera;
946 // PreRender touches the camera, so we need to submit the aux geometries drawn with the old camera
947 gEnv->pRenderer->SubmitAuxGeom(m_pAuxGeom, false);
949 // Get an Aux geometry using newly updated camera
950 // In addition set the default aux camera
951 m_pAuxGeom = gEnv->pRenderer->GetOrCreateIRenderAuxGeom(&camera);
952 gEnv->pRenderer->UpdateAuxDefaultCamera(*m_camera);
954 // Do the actual render call for the viewport.
955 Render();
957 // Submit the current viewport's aux geometry and make it null to completely pass the ownership to renderer
958 gEnv->pRenderer->SubmitAuxGeom(m_pAuxGeom, false);
959 m_pAuxGeom = nullptr;
961 bool renderStats = false;
962 m_env->pSystem->RenderEnd(renderStats);
964 RestorePreviousContext();
968 void QViewport::ResetCamera()
970 *m_state = SViewportState();
971 m_camera->SetMatrix(Matrix34(m_state->cameraTarget));
974 void QViewport::SetSettings(const SViewportSettings& settings)
976 *m_settings = settings;
979 void QViewport::SetState(const SViewportState& state)
981 *m_state = state;
984 float QViewport::CalculateMoveSpeed(bool shiftPressed, bool ctrlPressed, bool bBackForth) const
986 float maxDimension = max(0.1f, max(m_sceneDimensions.x, max(m_sceneDimensions.y, m_sceneDimensions.z)));
987 float moveSpeed = max(0.01f, bBackForth && m_settings->camera.bIndependentBackForthSpeed ? m_settings->camera.moveBackForthSpeed : m_settings->camera.moveSpeed) * maxDimension;
989 if (shiftPressed)
990 moveSpeed *= m_settings->camera.fastMoveMultiplier;
991 if (ctrlPressed)
992 moveSpeed *= m_settings->camera.slowMoveMultiplier;
994 return moveSpeed;
997 void QViewport::CreateLookAt(const Vec3& target, float radius, QuatT& cameraTarget) const
999 Vec3 at = target - cameraTarget.t;
1000 float distanceFromTarget = at.GetLength();
1001 if (distanceFromTarget > 0.001f)
1003 at /= distanceFromTarget;
1005 else
1007 at = Vec3(0.0f, 1.0f, 0.0f);
1008 distanceFromTarget = 0.0f;
1011 if (distanceFromTarget < radius)
1013 cameraTarget.t = target - (at * radius);
1016 Vec3 up = Vec3(0.0f, 0.0f, 1.0f);
1017 const Vec3 right = at.Cross(up).GetNormalized();
1018 up = right.Cross(at).GetNormalized();
1019 cameraTarget.q = Quat(Matrix33::CreateFromVectors(right, at, up));
1022 void QViewport::mousePressEvent(QMouseEvent* ev)
1024 SMouseEvent me;
1025 me.type = SMouseEvent::TYPE_PRESS;
1026 me.button = SMouseEvent::EButton(ev->button());
1027 me.x = QtUtil::PixelScale(this, ev->x());
1028 me.y = QtUtil::PixelScale(this, ev->y());
1029 me.viewport = this;
1030 me.shift = (ev->modifiers() & Qt::SHIFT) != 0;
1031 me.control = (ev->modifiers() & Qt::CTRL) != 0;
1032 bool bAccepted = OnMouseEvent(me);
1034 QWidget::mousePressEvent(ev);
1035 setFocus();
1037 m_mousePressPos = ev->pos();
1039 // return prematurely if the viewport has processed the event
1040 if (bAccepted)
1042 return;
1045 if (m_orbitModeEnabled && (ev->button() == Qt::LeftButton))
1047 m_rotationMode = false;
1048 m_panMode = false;
1049 m_orbitMode = true;
1050 QApplication::setOverrideCursor(Qt::BlankCursor);
1052 else
1054 if (ev->button() == Qt::MiddleButton)
1056 m_panMode = true;
1057 QApplication::setOverrideCursor(Qt::BlankCursor);
1059 if (ev->button() == Qt::RightButton)
1061 m_rotationMode = true;
1062 QApplication::setOverrideCursor(Qt::BlankCursor);
1067 void QViewport::mouseReleaseEvent(QMouseEvent* ev)
1070 SMouseEvent me;
1071 me.type = SMouseEvent::TYPE_RELEASE;
1072 me.button = SMouseEvent::EButton(ev->button());
1073 me.x = QtUtil::PixelScale(this, ev->x());
1074 me.y = QtUtil::PixelScale(this, ev->y());
1075 me.viewport = this;
1076 OnMouseEvent(me);
1078 QWidget::mouseReleaseEvent(ev);
1080 if (ev->button() == Qt::LeftButton)
1082 m_orbitMode = false;
1084 if (ev->button() == Qt::MiddleButton)
1086 m_panMode = false;
1088 if (ev->button() == Qt::RightButton)
1090 m_rotationMode = false;
1092 QApplication::restoreOverrideCursor();
1095 void QViewport::wheelEvent(QWheelEvent* ev)
1097 QuatT qt = m_state->cameraTarget;
1098 Vec3 ydir = qt.GetColumn1().GetNormalized();
1099 Vec3 pos = qt.t;
1100 const float wheelSpeed = m_settings->camera.zoomSpeed * (m_fastMode ? m_settings->camera.fastMoveMultiplier : 1.0f) * (m_slowMode ? m_settings->camera.slowMoveMultiplier : 1.0f);
1101 pos += 0.01f * ydir * ev->delta() * wheelSpeed;
1102 qt.t = pos;
1103 CameraMoved(qt, false);
1106 void QViewport::mouseMoveEvent(QMouseEvent* ev)
1108 SMouseEvent me;
1109 me.type = SMouseEvent::TYPE_MOVE;
1110 me.button = SMouseEvent::EButton(ev->button());
1111 me.x = QtUtil::PixelScale(this, ev->x());
1112 me.y = QtUtil::PixelScale(this, ev->y());
1113 me.viewport = this;
1114 m_fastMode = (ev->modifiers() & Qt::SHIFT) != 0;
1115 m_slowMode = (ev->modifiers() & Qt::CTRL) != 0;
1116 OnMouseEvent(me);
1118 QWidget::mouseMoveEvent(ev);
1121 void QViewport::keyPressEvent(QKeyEvent* ev)
1123 SKeyEvent event;
1124 event.type = SKeyEvent::TYPE_PRESS;
1125 event.key = ev->key() | ev->modifiers();
1126 m_fastMode = (ev->modifiers() & Qt::SHIFT) != 0;
1127 m_slowMode = (ev->modifiers() & Qt::CTRL) != 0;
1128 OnKeyEvent(event);
1130 QWidget::keyPressEvent(ev);
1133 void QViewport::keyReleaseEvent(QKeyEvent* ev)
1135 SKeyEvent event;
1136 event.type = SKeyEvent::TYPE_RELEASE;
1137 event.key = ev->key() | ev->modifiers();
1138 m_fastMode = (ev->modifiers() & Qt::SHIFT) != 0;
1139 m_slowMode = (ev->modifiers() & Qt::CTRL) != 0;
1140 OnKeyEvent(event);
1141 QWidget::keyReleaseEvent(ev);
1144 void QViewport::resizeEvent(QResizeEvent* ev)
1146 QWidget::resizeEvent(ev);
1148 int cx = ev->size().width() * devicePixelRatioF();
1149 int cy = ev->size().height() * devicePixelRatioF();
1150 if (cx == 0 || cy == 0)
1151 return;
1153 m_width = cx;
1154 m_height = cy;
1156 m_env->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RESIZE, cx, cy);
1157 gEnv->pRenderer->ResizeContext(m_displayContextKey, m_width, m_height);
1159 SignalUpdate();
1162 void QViewport::moveEvent(QMoveEvent* ev)
1164 QWidget::moveEvent(ev);
1166 m_env->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_MOVE, QtUtil::PixelScale(this, ev->pos().x()), QtUtil::PixelScale(this, ev->pos().y()));
1169 bool QViewport::event(QEvent* ev)
1171 bool result = QWidget::event(ev);
1173 if (ev->type() == QEvent::WinIdChange)
1175 CreateRenderContext();
1178 return result;
1181 void QViewport::paintEvent(QPaintEvent* ev)
1183 QWidget::paintEvent(ev);
1186 bool QViewport::winEvent(MSG* message, long* result)
1188 return QWidget::nativeEvent("windows_generic_MSG", message, result);
1191 void QViewport::AddConsumer(QViewportConsumer* consumer)
1193 RemoveConsumer(consumer);
1194 m_consumers.push_back(consumer);
1197 void QViewport::RemoveConsumer(QViewportConsumer* consumer)
1199 m_consumers.erase(std::remove(m_consumers.begin(), m_consumers.end(), consumer), m_consumers.end());