1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
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>
13 #include <QMouseEvent>
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
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
;
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
));
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
));
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
)
176 , m_renderContextCreated(false)
180 , m_supersamplingFactor(supersamplingFactor
)
181 , m_rotationMode(false)
183 , m_orbitModeEnabled(false)
188 , m_lastFrameTime(0.0f
)
189 , m_averageFrameTime(0.0f
)
190 , m_sceneDimensions(1.0f
, 1.0f
, 1.0f
)
191 , m_creatingRenderContext(false)
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())
201 gEnv
= m_env
; // Shhh!
203 CreateRenderContext();
205 m_camera
.reset(new CCamera());
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
));
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
)
246 Vec3
pos0(0,0,0), pos1(0,0,0);
247 if (!Camera()->Unproject(Vec3(float(x
), float(m_height
- y
), 0), pos0
))
251 if (!Camera()->Unproject(Vec3(float(x
), float(m_height
- y
), 1), pos1
))
256 Vec3 v
= (pos1
- pos0
);
257 v
= v
.GetNormalized();
264 QPoint
QViewport::ProjectToScreen(const Vec3
& wp
)
267 if (Camera()->Project(wp
, out
))
269 return QPoint((int)out
.x
,(int)out
.y
);
271 RestorePreviousContext();
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
)
297 m_creatingRenderContext
= true;
298 DestroyRenderContext();
299 HWND window
= (HWND
)QWidget::winId();
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;
324 m_creatingRenderContext
= 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)
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()
356 if (m_previousContexts
.empty())
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
);
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);
384 void QViewport::Serialize(IArchive
& ar
)
388 ar(m_state
->cameraTarget
, "cameraTarget", "Camera Target");
394 AutoBool(bool* value
)
408 void QViewport::Update()
410 int64 time
= m_env
->pSystem
->GetITimer()->GetAsyncTime().GetMilliSecondsAsInt64();
413 m_lastFrameTime
= (time
- m_lastTime
) * 0.001f
;
415 if (m_averageFrameTime
== 0.0f
)
416 m_averageFrameTime
= m_lastFrameTime
;
418 m_averageFrameTime
= 0.01f
* m_lastFrameTime
+ 0.99f
* m_averageFrameTime
;
420 if (m_env
->pRenderer
== 0 ||
421 m_env
->p3DEngine
== 0)
427 if (!m_width
|| !m_height
)
430 if (!m_renderContextCreated
)
436 AutoBool
updating(&m_updating
);
447 void QViewport::CaptureMouse()
452 void QViewport::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
)
471 float speedScale
= CalculateMoveSpeed(m_fastMode
, m_slowMode
);
473 if ((m_rotationMode
&& m_panMode
) /* || m_bInZoomMode*/)
475 if (!(m_settings
->camera
.transformRestraint
& eCameraTransformRestraint_Zoom
))
478 QuatT qt
= m_state
->cameraTarget
;
481 Vec3 ydir
= qt
.GetColumn1().GetNormalized();
483 pos
= pos
- 0.2f
* ydir
* (m_mousePressPos
.y() - point
.y()) * speedScale
;
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
));
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
));
511 if (!(m_settings
->camera
.transformRestraint
& eCameraTransformRestraint_Panning
))
514 QuatT qt
= m_state
->cameraTarget
;
515 Vec3 xdir
= qt
.GetColumn0().GetNormalized();
516 Vec3 zdir
= qt
.GetColumn2().GetNormalized();
519 pos
+= 0.0025f
* xdir
* (point
.x() - m_mousePressPos
.x()) * speedScale
+ 0.0025f
* zdir
* (m_mousePressPos
.y() - point
.y()) * speedScale
;
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
;
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
;
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
)
565 float deltaTime
= m_lastFrameTime
;
567 if (deltaTime
> 0.1f
)
570 QuatT qt
= m_state
->cameraTarget
;
571 Vec3 ydir
= qt
.GetColumn1().GetNormalized();
572 Vec3 xdir
= qt
.GetColumn0().GetNormalized();
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
)
617 CreateLookAt(m_state
->orbitTarget
, m_state
->orbitRadius
, qt
);
619 m_state
->cameraTarget
= qt
;
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
);
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
;
653 IEditorEventFromQViewportEvent(ev
, p
, evt
, flags
);
655 if (m_gizmoManager
.HandleMouseInput(m_pViewportAdapter
.get(), evt
, p
, flags
))
660 for (size_t i
= 0; i
< m_consumers
.size(); ++i
)
662 m_consumers
[i
]->OnViewportMouse(ev
);
669 void QViewport::PreRender()
672 rc
.camera
= m_camera
.get();
674 rc
.pAuxGeom
= m_pAuxGeom
;
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
);
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
)
720 if (qEvt
.type
== SMouseEvent::TYPE_MOVE
)
724 else if (qEvt
.type
== SMouseEvent::TYPE_PRESS
)
726 if (qEvt
.button
== SMouseEvent::BUTTON_LEFT
)
730 else if (qEvt
.button
== SMouseEvent::BUTTON_RIGHT
)
734 else if (qEvt
.button
== SMouseEvent::BUTTON_MIDDLE
)
739 else if (qEvt
.type
== SMouseEvent::TYPE_RELEASE
)
741 if (qEvt
.button
== SMouseEvent::BUTTON_LEFT
)
745 else if (qEvt
.button
== SMouseEvent::BUTTON_RIGHT
)
749 else if (qEvt
.button
== SMouseEvent::BUTTON_MIDDLE
)
758 ScopedBackup(IRenderAuxGeom
** pDCAuxGeomPtr
, IRenderAuxGeom
* pNewAuxGeom
)
760 ppDCAuxGeom
= pDCAuxGeomPtr
;
761 oldAuxGeom
= *pDCAuxGeomPtr
;
762 *pDCAuxGeomPtr
= pNewAuxGeom
;
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
);
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
);
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
);
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
);
848 col
.r
= uint8(d0
.x
* 255);
849 col
.g
= uint8(d0
.y
* 255);
850 col
.b
= uint8(d0
.z
* 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
);
861 rp
.pPrevMatrix
= &tm
;
864 rp
.dwFObjFlags
|= FOB_TRANS_MASK
;
867 rc
.camera
= m_camera
.get();
869 rc
.passInfo
= &passInfo
;
870 rc
.renderParams
= &rp
;
873 for (size_t i
= 0; i
< m_consumers
.size(); ++i
)
874 m_consumers
[i
]->OnViewportRender(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
);
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);
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
);
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).
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.
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
)
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
;
990 moveSpeed
*= m_settings
->camera
.fastMoveMultiplier
;
992 moveSpeed
*= m_settings
->camera
.slowMoveMultiplier
;
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
;
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
)
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());
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
);
1037 m_mousePressPos
= ev
->pos();
1039 // return prematurely if the viewport has processed the event
1045 if (m_orbitModeEnabled
&& (ev
->button() == Qt::LeftButton
))
1047 m_rotationMode
= false;
1050 QApplication::setOverrideCursor(Qt::BlankCursor
);
1054 if (ev
->button() == Qt::MiddleButton
)
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
)
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());
1078 QWidget::mouseReleaseEvent(ev
);
1080 if (ev
->button() == Qt::LeftButton
)
1082 m_orbitMode
= false;
1084 if (ev
->button() == Qt::MiddleButton
)
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();
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
;
1103 CameraMoved(qt
, false);
1106 void QViewport::mouseMoveEvent(QMouseEvent
* ev
)
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());
1114 m_fastMode
= (ev
->modifiers() & Qt::SHIFT
) != 0;
1115 m_slowMode
= (ev
->modifiers() & Qt::CTRL
) != 0;
1118 QWidget::mouseMoveEvent(ev
);
1121 void QViewport::keyPressEvent(QKeyEvent
* ev
)
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;
1130 QWidget::keyPressEvent(ev
);
1133 void QViewport::keyReleaseEvent(QKeyEvent
* ev
)
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;
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)
1156 m_env
->pSystem
->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RESIZE
, cx
, cy
);
1157 gEnv
->pRenderer
->ResizeContext(m_displayContextKey
, m_width
, m_height
);
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();
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());