2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GraphicContext.h"
11 #include "ServiceBroker.h"
12 #include "WinSystem.h"
13 #include "application/ApplicationComponents.h"
14 #include "application/ApplicationPlayer.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIWindowManager.h"
17 #include "guilib/TextureManager.h"
18 #include "guilib/gui3d.h"
19 #include "input/InputManager.h"
20 #include "messaging/ApplicationMessenger.h"
21 #include "rendering/RenderSystem.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/DisplaySettings.h"
24 #include "settings/Settings.h"
25 #include "settings/SettingsComponent.h"
26 #include "settings/lib/Setting.h"
27 #include "utils/log.h"
32 CGraphicContext::CGraphicContext() = default;
33 CGraphicContext::~CGraphicContext() = default;
35 void CGraphicContext::SetOrigin(float x
, float y
)
37 if (!m_origins
.empty())
38 m_origins
.push(CPoint(x
,y
) + m_origins
.top());
40 m_origins
.push(CPoint(x
,y
));
42 AddTransform(TransformMatrix::CreateTranslation(x
, y
));
45 void CGraphicContext::RestoreOrigin()
47 if (!m_origins
.empty())
52 // add a new clip region, intersecting with the previous clip region.
53 bool CGraphicContext::SetClipRegion(float x
, float y
, float w
, float h
)
54 { // transform from our origin
56 if (!m_origins
.empty())
57 origin
= m_origins
.top();
59 // ok, now intersect with our old clip region
60 CRect
rect(x
, y
, x
+ w
, y
+ h
);
62 if (!m_clipRegions
.empty())
64 // intersect with original clip region
65 rect
.Intersect(m_clipRegions
.top());
71 m_clipRegions
.push(rect
);
73 // here we could set the hardware clipping, if applicable
77 void CGraphicContext::RestoreClipRegion()
79 if (!m_clipRegions
.empty())
82 // here we could reset the hardware clipping, if applicable
85 void CGraphicContext::ClipRect(CRect
&vertex
, CRect
&texture
, CRect
*texture2
)
87 // this is the software clipping routine. If the graphics hardware is set to do the clipping
88 // (eg via SetClipPlane in D3D for instance) then this routine is unneeded.
89 if (!m_clipRegions
.empty())
91 // take a copy of the vertex rectangle and intersect
92 // it with our clip region (moved to the same coordinate system)
93 CRect
clipRegion(m_clipRegions
.top());
94 if (!m_origins
.empty())
95 clipRegion
-= m_origins
.top();
96 CRect
original(vertex
);
97 vertex
.Intersect(clipRegion
);
98 // and use the original to compute the texture coordinates
99 if (original
!= vertex
)
101 float scaleX
= texture
.Width() / original
.Width();
102 float scaleY
= texture
.Height() / original
.Height();
103 texture
.x1
+= (vertex
.x1
- original
.x1
) * scaleX
;
104 texture
.y1
+= (vertex
.y1
- original
.y1
) * scaleY
;
105 texture
.x2
+= (vertex
.x2
- original
.x2
) * scaleX
;
106 texture
.y2
+= (vertex
.y2
- original
.y2
) * scaleY
;
109 scaleX
= texture2
->Width() / original
.Width();
110 scaleY
= texture2
->Height() / original
.Height();
111 texture2
->x1
+= (vertex
.x1
- original
.x1
) * scaleX
;
112 texture2
->y1
+= (vertex
.y1
- original
.y1
) * scaleY
;
113 texture2
->x2
+= (vertex
.x2
- original
.x2
) * scaleX
;
114 texture2
->y2
+= (vertex
.y2
- original
.y2
) * scaleY
;
120 CRect
CGraphicContext::GetClipRegion()
122 if (m_clipRegions
.empty())
123 return CRect(0, 0, m_iScreenWidth
, m_iScreenHeight
);
124 CRect
clipRegion(m_clipRegions
.top());
125 if (!m_origins
.empty())
126 clipRegion
-= m_origins
.top();
130 void CGraphicContext::AddGUITransform()
132 m_transforms
.push(m_finalTransform
);
133 m_finalTransform
= m_guiTransform
;
136 TransformMatrix
CGraphicContext::AddTransform(const TransformMatrix
&matrix
)
138 m_transforms
.push(m_finalTransform
);
139 m_finalTransform
.matrix
*= matrix
;
140 return m_finalTransform
.matrix
;
143 void CGraphicContext::SetTransform(const TransformMatrix
&matrix
)
145 m_transforms
.push(m_finalTransform
);
146 m_finalTransform
.matrix
= matrix
;
149 void CGraphicContext::SetTransform(const TransformMatrix
&matrix
, float scaleX
, float scaleY
)
151 m_transforms
.push(m_finalTransform
);
152 m_finalTransform
.matrix
= matrix
;
153 m_finalTransform
.scaleX
= scaleX
;
154 m_finalTransform
.scaleY
= scaleY
;
157 void CGraphicContext::RemoveTransform()
159 if (!m_transforms
.empty())
161 m_finalTransform
= m_transforms
.top();
166 bool CGraphicContext::SetViewPort(float fx
, float fy
, float fwidth
, float fheight
, bool intersectPrevious
/* = false */)
168 // transform coordinates - we may have a rotation which changes the positioning of the
169 // minimal and maximal viewport extents. We currently go to the maximal extent.
172 x
[1] = x
[2] = fx
+ fwidth
;
174 y
[2] = y
[3] = fy
+ fheight
;
175 float minX
= (float)m_iScreenWidth
;
177 float minY
= (float)m_iScreenHeight
;
179 for (int i
= 0; i
< 4; i
++)
182 ScaleFinalCoords(x
[i
], y
[i
], z
);
183 if (x
[i
] < minX
) minX
= x
[i
];
184 if (x
[i
] > maxX
) maxX
= x
[i
];
185 if (y
[i
] < minY
) minY
= y
[i
];
186 if (y
[i
] > maxY
) maxY
= y
[i
];
189 int newLeft
= (int)(minX
+ 0.5f
);
190 int newTop
= (int)(minY
+ 0.5f
);
191 int newRight
= (int)(maxX
+ 0.5f
);
192 int newBottom
= (int)(maxY
+ 0.5f
);
193 if (intersectPrevious
)
195 CRect oldviewport
= m_viewStack
.top();
196 // do the intersection
197 int oldLeft
= (int)oldviewport
.x1
;
198 int oldTop
= (int)oldviewport
.y1
;
199 int oldRight
= (int)oldviewport
.x2
;
200 int oldBottom
= (int)oldviewport
.y2
;
201 if (newLeft
>= oldRight
|| newTop
>= oldBottom
|| newRight
<= oldLeft
|| newBottom
<= oldTop
)
202 { // empty intersection - return false to indicate no rendering should occur
205 // ok, they intersect, do the intersection
206 if (newLeft
< oldLeft
) newLeft
= oldLeft
;
207 if (newTop
< oldTop
) newTop
= oldTop
;
208 if (newRight
> oldRight
) newRight
= oldRight
;
209 if (newBottom
> oldBottom
) newBottom
= oldBottom
;
211 // check range against screen size
212 if (newRight
<= 0 || newBottom
<= 0 ||
213 newTop
>= m_iScreenHeight
|| newLeft
>= m_iScreenWidth
||
214 newLeft
>= newRight
|| newTop
>= newBottom
)
215 { // no intersection with the screen
218 // intersection with the screen
219 if (newLeft
< 0) newLeft
= 0;
220 if (newTop
< 0) newTop
= 0;
221 if (newRight
> m_iScreenWidth
) newRight
= m_iScreenWidth
;
222 if (newBottom
> m_iScreenHeight
) newBottom
= m_iScreenHeight
;
224 assert(newLeft
< newRight
);
225 assert(newTop
< newBottom
);
227 CRect
newviewport((float)newLeft
, (float)newTop
, (float)newRight
, (float)newBottom
);
229 m_viewStack
.push(newviewport
);
231 newviewport
= StereoCorrection(newviewport
);
232 CServiceBroker::GetRenderSystem()->SetViewPort(newviewport
);
235 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
239 void CGraphicContext::RestoreViewPort()
241 if (m_viewStack
.size() <= 1) return;
244 CRect viewport
= StereoCorrection(m_viewStack
.top());
245 CServiceBroker::GetRenderSystem()->SetViewPort(viewport
);
247 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
250 CPoint
CGraphicContext::StereoCorrection(const CPoint
&point
) const
254 if(m_stereoMode
== RENDER_STEREO_MODE_SPLIT_HORIZONTAL
)
256 const RESOLUTION_INFO info
= GetResInfo();
258 if(m_stereoView
== RENDER_STEREO_VIEW_RIGHT
)
259 res
.y
+= info
.iHeight
+ info
.iBlanking
;
261 if(m_stereoMode
== RENDER_STEREO_MODE_SPLIT_VERTICAL
)
263 const RESOLUTION_INFO info
= GetResInfo();
265 if(m_stereoView
== RENDER_STEREO_VIEW_RIGHT
)
266 res
.x
+= info
.iWidth
+ info
.iBlanking
;
271 CRect
CGraphicContext::StereoCorrection(const CRect
&rect
) const
273 CRect
res(StereoCorrection(rect
.P1())
274 , StereoCorrection(rect
.P2()));
278 void CGraphicContext::SetScissors(const CRect
&rect
)
281 m_scissors
.Intersect(CRect(0,0,(float)m_iScreenWidth
, (float)m_iScreenHeight
));
282 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors
));
285 const CRect
&CGraphicContext::GetScissors() const
290 void CGraphicContext::ResetScissors()
292 m_scissors
.SetRect(0, 0, (float)m_iScreenWidth
, (float)m_iScreenHeight
);
293 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors
));
296 const CRect
CGraphicContext::GetViewWindow() const
298 if (m_bCalibrating
|| m_bFullScreenVideo
)
301 RESOLUTION_INFO info
= GetResInfo();
302 rect
.x1
= (float)info
.Overscan
.left
;
303 rect
.y1
= (float)info
.Overscan
.top
;
304 rect
.x2
= (float)info
.Overscan
.right
;
305 rect
.y2
= (float)info
.Overscan
.bottom
;
311 void CGraphicContext::SetViewWindow(float left
, float top
, float right
, float bottom
)
313 m_videoRect
.x1
= ScaleFinalXCoord(left
, top
);
314 m_videoRect
.y1
= ScaleFinalYCoord(left
, top
);
315 m_videoRect
.x2
= ScaleFinalXCoord(right
, bottom
);
316 m_videoRect
.y2
= ScaleFinalYCoord(right
, bottom
);
319 void CGraphicContext::SetFullScreenVideo(bool bOnOff
)
321 std::unique_lock
<CCriticalSection
> lock(*this);
323 m_bFullScreenVideo
= bOnOff
;
325 if (m_bFullScreenRoot
)
327 bool bTriggerUpdateRes
= false;
328 auto& components
= CServiceBroker::GetAppComponents();
329 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
330 if (m_bFullScreenVideo
)
331 bTriggerUpdateRes
= true;
334 bool allowDesktopRes
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE
) == ADJUST_REFRESHRATE_ALWAYS
;
335 if (!allowDesktopRes
)
337 if (appPlayer
->IsPlayingVideo())
338 bTriggerUpdateRes
= true;
342 bool allowResolutionChangeOnStop
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE
) != ADJUST_REFRESHRATE_ON_START
;
343 RESOLUTION targetResolutionOnStop
= RES_DESKTOP
;
344 if (bTriggerUpdateRes
)
345 appPlayer
->TriggerUpdateResolution();
346 else if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP
)
348 targetResolutionOnStop
= CDisplaySettings::GetInstance().GetCurrentResolution();
351 if (allowResolutionChangeOnStop
&& !bTriggerUpdateRes
)
353 SetVideoResolution(targetResolutionOnStop
, false);
357 SetVideoResolution(RES_WINDOW
, false);
360 bool CGraphicContext::IsFullScreenVideo() const
362 return m_bFullScreenVideo
;
365 bool CGraphicContext::IsCalibrating() const
367 return m_bCalibrating
;
370 void CGraphicContext::SetCalibrating(bool bOnOff
)
372 m_bCalibrating
= bOnOff
;
375 bool CGraphicContext::IsValidResolution(RESOLUTION res
)
377 if (res
>= RES_WINDOW
&& (size_t) res
< CDisplaySettings::GetInstance().ResolutionInfoSize())
385 // call SetVideoResolutionInternal and ensure its done from mainthread
386 void CGraphicContext::SetVideoResolution(RESOLUTION res
, bool forceUpdate
)
388 if (CServiceBroker::GetAppMessenger()->IsProcessThread())
390 SetVideoResolutionInternal(res
, forceUpdate
);
394 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_SETVIDEORESOLUTION
, res
, forceUpdate
? 1 : 0);
398 void CGraphicContext::SetVideoResolutionInternal(RESOLUTION res
, bool forceUpdate
)
400 RESOLUTION lastRes
= m_Resolution
;
402 // If the user asked us to guess, go with desktop
403 if (!IsValidResolution(res
))
408 // If we are switching to the same resolution and same window/full-screen, no need to do anything
409 if (!forceUpdate
&& res
== lastRes
&& m_bFullScreenRoot
== CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
)
414 if (res
>= RES_DESKTOP
)
416 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
= true;
417 m_bFullScreenRoot
= true;
421 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
= false;
422 m_bFullScreenRoot
= false;
425 std::unique_lock
<CCriticalSection
> lock(*this);
427 // FIXME Wayland windowing needs some way to "deny" resolution updates since what Kodi
428 // requests might not get actually set by the compositor.
429 // So in theory, m_iScreenWidth etc. would not need to be updated at all before the
430 // change is confirmed.
431 // But other windowing code expects these variables to be already set when
432 // SetFullScreen() is called, so set them anyway and remember the old values.
433 int origScreenWidth
= m_iScreenWidth
;
434 int origScreenHeight
= m_iScreenHeight
;
435 float origFPSOverride
= m_fFPSOverride
;
437 UpdateInternalStateWithResolution(res
);
438 RESOLUTION_INFO info_org
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
440 bool switched
= false;
441 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
)
443 #if defined (TARGET_DARWIN) || defined (TARGET_WINDOWS)
444 bool blankOtherDisplays
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS
);
445 switched
= CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org
, blankOtherDisplays
);
447 switched
= CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org
, false);
450 else if (lastRes
>= RES_DESKTOP
)
451 switched
= CServiceBroker::GetWinSystem()->SetFullScreen(false, info_org
, false);
453 switched
= CServiceBroker::GetWinSystem()->ResizeWindow(info_org
.iWidth
, info_org
.iHeight
, -1, -1);
457 m_scissors
.SetRect(0, 0, (float)m_iScreenWidth
, (float)m_iScreenHeight
);
459 // make sure all stereo stuff are correctly setup
460 SetStereoView(RENDER_STEREO_VIEW_OFF
);
462 // update anyone that relies on sizing information
463 CServiceBroker::GetInputManager().SetMouseResolution(info_org
.iWidth
, info_org
.iHeight
, 1, 1);
465 CGUIComponent
*gui
= CServiceBroker::GetGUI();
467 gui
->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_WINDOW_RESIZE
);
472 m_iScreenWidth
= origScreenWidth
;
473 m_iScreenHeight
= origScreenHeight
;
474 m_fFPSOverride
= origFPSOverride
;
475 if (IsValidResolution(lastRes
))
477 m_Resolution
= lastRes
;
481 // FIXME Resolution has become invalid
482 // This happens e.g. when switching monitors and the new monitor has fewer
483 // resolutions than the old one. Fall back to RES_DESKTOP and hope that
484 // the real resolution is set soon.
485 // Again, must be fixed as part of a greater refactor.
486 m_Resolution
= RES_DESKTOP
;
491 void CGraphicContext::ApplyVideoResolution(RESOLUTION res
)
493 if (!IsValidResolution(res
))
495 CLog::LogF(LOGWARNING
, "Asked to apply invalid resolution {}, falling back to RES_DESKTOP",
500 if (res
>= RES_DESKTOP
)
502 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
= true;
503 m_bFullScreenRoot
= true;
507 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen
= false;
508 m_bFullScreenRoot
= false;
511 std::unique_lock
<CCriticalSection
> lock(*this);
513 UpdateInternalStateWithResolution(res
);
515 m_scissors
.SetRect(0, 0, (float)m_iScreenWidth
, (float)m_iScreenHeight
);
517 // make sure all stereo stuff are correctly setup
518 SetStereoView(RENDER_STEREO_VIEW_OFF
);
520 // update anyone that relies on sizing information
521 RESOLUTION_INFO info_org
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
522 CServiceBroker::GetInputManager().SetMouseResolution(info_org
.iWidth
, info_org
.iHeight
, 1, 1);
523 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_WINDOW_RESIZE
);
526 void CGraphicContext::UpdateInternalStateWithResolution(RESOLUTION res
)
528 RESOLUTION_INFO info_mod
= GetResInfo(res
);
530 m_iScreenWidth
= info_mod
.iWidth
;
531 m_iScreenHeight
= info_mod
.iHeight
;
536 void CGraphicContext::ApplyModeChange(RESOLUTION res
)
538 ApplyVideoResolution(res
);
539 CServiceBroker::GetWinSystem()->FinishModeChange(res
);
542 void CGraphicContext::ApplyWindowResize(int newWidth
, int newHeight
)
544 CServiceBroker::GetWinSystem()->SetWindowResolution(newWidth
, newHeight
);
545 ApplyVideoResolution(RES_WINDOW
);
546 CServiceBroker::GetWinSystem()->FinishWindowResize(newWidth
, newHeight
);
549 RESOLUTION
CGraphicContext::GetVideoResolution() const
554 void CGraphicContext::ResetOverscan(RESOLUTION_INFO
&res
)
556 res
.Overscan
.left
= 0;
557 res
.Overscan
.top
= 0;
558 res
.Overscan
.right
= res
.iWidth
;
559 res
.Overscan
.bottom
= res
.iHeight
;
562 void CGraphicContext::ResetOverscan(RESOLUTION res
, OVERSCAN
&overscan
)
567 RESOLUTION_INFO info
= GetResInfo(res
);
568 overscan
.right
= info
.iWidth
;
569 overscan
.bottom
= info
.iHeight
;
572 void CGraphicContext::ResetScreenParameters(RESOLUTION res
)
574 RESOLUTION_INFO
& info
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
576 info
.iSubtitles
= info
.iHeight
;
577 info
.fPixelRatio
= 1.0f
;
578 info
.iScreenWidth
= info
.iWidth
;
579 info
.iScreenHeight
= info
.iHeight
;
580 ResetOverscan(res
, info
.Overscan
);
583 void CGraphicContext::Clear(UTILS::COLOR::Color color
)
585 CServiceBroker::GetRenderSystem()->ClearBuffers(color
);
588 void CGraphicContext::CaptureStateBlock()
590 CServiceBroker::GetRenderSystem()->CaptureStateBlock();
593 void CGraphicContext::ApplyStateBlock()
595 CServiceBroker::GetRenderSystem()->ApplyStateBlock();
598 const RESOLUTION_INFO
CGraphicContext::GetResInfo(RESOLUTION res
) const
600 RESOLUTION_INFO info
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
602 if(m_stereoMode
== RENDER_STEREO_MODE_SPLIT_HORIZONTAL
)
604 if((info
.dwFlags
& D3DPRESENTFLAG_MODE3DTB
) == 0)
606 info
.fPixelRatio
/= 2;
608 info
.dwFlags
|= D3DPRESENTFLAG_MODE3DTB
;
610 info
.iHeight
= (info
.iHeight
- info
.iBlanking
) / 2;
611 info
.Overscan
.top
/= 2;
612 info
.Overscan
.bottom
= (info
.Overscan
.bottom
- info
.iBlanking
) / 2;
613 info
.iSubtitles
= (info
.iSubtitles
- info
.iBlanking
) / 2;
616 if(m_stereoMode
== RENDER_STEREO_MODE_SPLIT_VERTICAL
)
618 if((info
.dwFlags
& D3DPRESENTFLAG_MODE3DSBS
) == 0)
620 info
.fPixelRatio
*= 2;
622 info
.dwFlags
|= D3DPRESENTFLAG_MODE3DSBS
;
624 info
.iWidth
= (info
.iWidth
- info
.iBlanking
) / 2;
625 info
.Overscan
.left
/= 2;
626 info
.Overscan
.right
= (info
.Overscan
.right
- info
.iBlanking
) / 2;
629 if (res
== m_Resolution
&& m_fFPSOverride
!= 0)
631 info
.fRefreshRate
= m_fFPSOverride
;
637 void CGraphicContext::SetResInfo(RESOLUTION res
, const RESOLUTION_INFO
& info
)
639 RESOLUTION_INFO
& curr
= CDisplaySettings::GetInstance().GetResolutionInfo(res
);
640 curr
.Overscan
= info
.Overscan
;
641 curr
.iSubtitles
= info
.iSubtitles
;
642 curr
.fPixelRatio
= info
.fPixelRatio
;
643 curr
.guiInsets
= info
.guiInsets
;
645 if(info
.dwFlags
& D3DPRESENTFLAG_MODE3DSBS
)
647 curr
.Overscan
.right
= info
.Overscan
.right
* 2 + info
.iBlanking
;
648 if((curr
.dwFlags
& D3DPRESENTFLAG_MODE3DSBS
) == 0)
649 curr
.fPixelRatio
/= 2.0f
;
652 if(info
.dwFlags
& D3DPRESENTFLAG_MODE3DTB
)
654 curr
.Overscan
.bottom
= info
.Overscan
.bottom
* 2 + info
.iBlanking
;
655 curr
.iSubtitles
= info
.iSubtitles
* 2 + info
.iBlanking
;
656 if((curr
.dwFlags
& D3DPRESENTFLAG_MODE3DTB
) == 0)
657 curr
.fPixelRatio
*= 2.0f
;
661 const RESOLUTION_INFO
CGraphicContext::GetResInfo() const
663 return GetResInfo(m_Resolution
);
666 void CGraphicContext::GetGUIScaling(const RESOLUTION_INFO
&res
, float &scaleX
, float &scaleY
, TransformMatrix
*matrix
/* = NULL */)
668 if (m_Resolution
!= RES_INVALID
)
670 // calculate necessary scalings
671 RESOLUTION_INFO info
= GetResInfo();
672 float fFromWidth
= (float)res
.iWidth
;
673 float fFromHeight
= (float)res
.iHeight
;
674 auto fToPosX
= info
.Overscan
.left
+ info
.guiInsets
.left
;
675 auto fToPosY
= info
.Overscan
.top
+ info
.guiInsets
.top
;
676 auto fToWidth
= info
.Overscan
.right
- info
.guiInsets
.right
- fToPosX
;
677 auto fToHeight
= info
.Overscan
.bottom
- info
.guiInsets
.bottom
- fToPosY
;
679 float fZoom
= (100 + CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_SKINZOOM
)) * 0.01f
;
682 fToPosX
-= fToWidth
* fZoom
* 0.5f
;
683 fToWidth
*= fZoom
+ 1.0f
;
685 // adjust for aspect ratio as zoom is given in the vertical direction and we don't
686 // do aspect ratio corrections in the gui code
687 fZoom
= fZoom
/ info
.fPixelRatio
;
688 fToPosY
-= fToHeight
* fZoom
* 0.5f
;
689 fToHeight
*= fZoom
+ 1.0f
;
691 scaleX
= fFromWidth
/ fToWidth
;
692 scaleY
= fFromHeight
/ fToHeight
;
695 TransformMatrix guiScaler
= TransformMatrix::CreateScaler(fToWidth
/ fFromWidth
, fToHeight
/ fFromHeight
, fToHeight
/ fFromHeight
);
696 TransformMatrix guiOffset
= TransformMatrix::CreateTranslation(fToPosX
, fToPosY
);
697 *matrix
= guiOffset
* guiScaler
;
702 scaleX
= scaleY
= 1.0f
;
708 void CGraphicContext::SetScalingResolution(const RESOLUTION_INFO
&res
, bool needsScaling
)
710 m_windowResolution
= res
;
711 if (needsScaling
&& m_Resolution
!= RES_INVALID
)
712 GetGUIScaling(res
, m_guiTransform
.scaleX
, m_guiTransform
.scaleY
, &m_guiTransform
.matrix
);
715 m_guiTransform
.Reset();
718 // reset our origin and camera
719 while (!m_origins
.empty())
721 m_origins
.push(CPoint(0, 0));
722 while (!m_cameras
.empty())
724 m_cameras
.push(CPoint(0.5f
*m_iScreenWidth
, 0.5f
*m_iScreenHeight
));
725 while (!m_stereoFactors
.empty())
726 m_stereoFactors
.pop();
727 m_stereoFactors
.push(0.0f
);
729 // and reset the final transform
730 m_finalTransform
= m_guiTransform
;
733 void CGraphicContext::SetRenderingResolution(const RESOLUTION_INFO
&res
, bool needsScaling
)
735 std::unique_lock
<CCriticalSection
> lock(*this);
737 SetScalingResolution(res
, needsScaling
);
738 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
741 void CGraphicContext::SetStereoView(RENDER_STEREO_VIEW view
)
745 while(!m_viewStack
.empty())
748 CRect
viewport(0.0f
, 0.0f
, (float)m_iScreenWidth
, (float)m_iScreenHeight
);
750 m_viewStack
.push(viewport
);
752 viewport
= StereoCorrection(viewport
);
753 CServiceBroker::GetRenderSystem()->SetStereoMode(m_stereoMode
, m_stereoView
);
754 CServiceBroker::GetRenderSystem()->SetViewPort(viewport
);
755 CServiceBroker::GetRenderSystem()->SetScissors(viewport
);
758 void CGraphicContext::InvertFinalCoords(float &x
, float &y
) const
760 m_finalTransform
.matrix
.InverseTransformPosition(x
, y
);
763 float CGraphicContext::ScaleFinalXCoord(float x
, float y
) const
765 return m_finalTransform
.matrix
.TransformXCoord(x
, y
, 0);
768 float CGraphicContext::ScaleFinalYCoord(float x
, float y
) const
770 return m_finalTransform
.matrix
.TransformYCoord(x
, y
, 0);
773 float CGraphicContext::ScaleFinalZCoord(float x
, float y
) const
775 return m_finalTransform
.matrix
.TransformZCoord(x
, y
, 0);
778 void CGraphicContext::ScaleFinalCoords(float &x
, float &y
, float &z
) const
780 m_finalTransform
.matrix
.TransformPosition(x
, y
, z
);
783 float CGraphicContext::GetScalingPixelRatio() const
785 // assume the resolutions are different - we want to return the aspect ratio of the video resolution
786 // but only once it's been corrected for the skin -> screen coordinates scaling
787 return GetResInfo().fPixelRatio
* (m_finalTransform
.scaleY
/ m_finalTransform
.scaleX
);
790 void CGraphicContext::SetCameraPosition(const CPoint
&camera
)
792 // offset the camera from our current location (this is in XML coordinates) and scale it up to
793 // the screen resolution
795 if (!m_origins
.empty())
796 cam
+= m_origins
.top();
798 cam
.x
*= (float)m_iScreenWidth
/ m_windowResolution
.iWidth
;
799 cam
.y
*= (float)m_iScreenHeight
/ m_windowResolution
.iHeight
;
802 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
805 void CGraphicContext::RestoreCameraPosition()
806 { // remove the top camera from the stack
807 assert(m_cameras
.size());
809 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
812 void CGraphicContext::SetStereoFactor(float factor
)
814 m_stereoFactors
.push(factor
);
815 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
818 void CGraphicContext::RestoreStereoFactor()
819 { // remove the top factor from the stack
820 assert(m_stereoFactors
.size());
821 m_stereoFactors
.pop();
822 UpdateCameraPosition(m_cameras
.top(), m_stereoFactors
.top());
825 CRect
CGraphicContext::GenerateAABB(const CRect
&rect
) const
827 // ------------------------
828 // |(x1, y1) (x2, y2)|
830 // |(x3, y3) (x4, y4)|
831 // ------------------------
833 float x1
= rect
.x1
, x2
= rect
.x2
, x3
= rect
.x1
, x4
= rect
.x2
;
834 float y1
= rect
.y1
, y2
= rect
.y1
, y3
= rect
.y2
, y4
= rect
.y2
;
837 ScaleFinalCoords(x1
, y1
, z
);
838 CServiceBroker::GetRenderSystem()->Project(x1
, y1
, z
);
841 ScaleFinalCoords(x2
, y2
, z
);
842 CServiceBroker::GetRenderSystem()->Project(x2
, y2
, z
);
845 ScaleFinalCoords(x3
, y3
, z
);
846 CServiceBroker::GetRenderSystem()->Project(x3
, y3
, z
);
849 ScaleFinalCoords(x4
, y4
, z
);
850 CServiceBroker::GetRenderSystem()->Project(x4
, y4
, z
);
852 return CRect( std::min(std::min(std::min(x1
, x2
), x3
), x4
),
853 std::min(std::min(std::min(y1
, y2
), y3
), y4
),
854 std::max(std::max(std::max(x1
, x2
), x3
), x4
),
855 std::max(std::max(std::max(y1
, y2
), y3
), y4
));
858 // NOTE: This routine is currently called (twice) every time there is a <camera>
859 // tag in the skin. It actually only has to be called before we render
860 // something, so another option is to just save the camera coordinates
861 // and then have a routine called before every draw that checks whether
862 // the camera has changed, and if so, changes it. Similarly, it could set
863 // the world transform at that point as well (or even combine world + view
864 // to cut down on one setting)
865 void CGraphicContext::UpdateCameraPosition(const CPoint
&camera
, const float &factor
)
867 float stereoFactor
= 0.f
;
868 if ( m_stereoMode
!= RENDER_STEREO_MODE_OFF
869 && m_stereoMode
!= RENDER_STEREO_MODE_MONO
870 && m_stereoView
!= RENDER_STEREO_VIEW_OFF
)
872 RESOLUTION_INFO res
= GetResInfo();
873 RESOLUTION_INFO desktop
= GetResInfo(RES_DESKTOP
);
874 float scaleRes
= (static_cast<float>(res
.iWidth
) / static_cast<float>(desktop
.iWidth
));
875 float scaleX
= static_cast<float>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_STEREOSTRENGTH
)) * scaleRes
;
876 stereoFactor
= factor
* (m_stereoView
== RENDER_STEREO_VIEW_LEFT
? scaleX
: -scaleX
);
878 CServiceBroker::GetRenderSystem()->SetCameraPosition(camera
, m_iScreenWidth
, m_iScreenHeight
, stereoFactor
);
881 bool CGraphicContext::RectIsAngled(float x1
, float y1
, float x2
, float y2
) const
882 { // need only test 3 points, as they must be co-planer
883 if (m_finalTransform
.matrix
.TransformZCoord(x1
, y1
, 0)) return true;
884 if (m_finalTransform
.matrix
.TransformZCoord(x2
, y2
, 0)) return true;
885 if (m_finalTransform
.matrix
.TransformZCoord(x1
, y2
, 0)) return true;
889 const TransformMatrix
&CGraphicContext::GetGUIMatrix() const
891 return m_finalTransform
.matrix
;
894 float CGraphicContext::GetGUIScaleX() const
896 return m_finalTransform
.scaleX
;
899 float CGraphicContext::GetGUIScaleY() const
901 return m_finalTransform
.scaleY
;
904 UTILS::COLOR::Color
CGraphicContext::MergeAlpha(UTILS::COLOR::Color color
) const
906 UTILS::COLOR::Color alpha
= m_finalTransform
.matrix
.TransformAlpha((color
>> 24) & 0xff);
907 if (alpha
> 255) alpha
= 255;
908 return ((alpha
<< 24) & 0xff000000) | (color
& 0xffffff);
911 UTILS::COLOR::Color
CGraphicContext::MergeColor(UTILS::COLOR::Color color
) const
913 return m_finalTransform
.matrix
.TransformColor(color
);
916 int CGraphicContext::GetWidth() const
918 return m_iScreenWidth
;
921 int CGraphicContext::GetHeight() const
923 return m_iScreenHeight
;
926 float CGraphicContext::GetFPS() const
928 if (m_Resolution
!= RES_INVALID
)
930 RESOLUTION_INFO info
= GetResInfo();
931 if (info
.fRefreshRate
> 0)
932 return info
.fRefreshRate
;
937 float CGraphicContext::GetDisplayLatency() const
939 float latency
= CServiceBroker::GetWinSystem()->GetDisplayLatency();
943 latency
= (CServiceBroker::GetWinSystem()->NoOfBuffers() + 1) / GetFPS() * 1000.0f
;
949 bool CGraphicContext::IsFullScreenRoot () const
951 return m_bFullScreenRoot
;
954 void CGraphicContext::ToggleFullScreen()
958 if (m_bFullScreenRoot
)
964 if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP
)
965 uiRes
= CDisplaySettings::GetInstance().GetCurrentResolution();
970 CDisplaySettings::GetInstance().SetCurrentResolution(uiRes
, true);
973 void CGraphicContext::SetMediaDir(const std::string
&strMediaDir
)
975 CServiceBroker::GetGUI()->GetTextureManager().SetTexturePath(strMediaDir
);
976 m_strMediaDir
= strMediaDir
;
979 const std::string
& CGraphicContext::GetMediaDir() const
981 return m_strMediaDir
;
985 void CGraphicContext::Flip(bool rendered
, bool videoLayer
)
987 CServiceBroker::GetRenderSystem()->PresentRender(rendered
, videoLayer
);
989 if(m_stereoMode
!= m_nextStereoMode
)
991 m_stereoMode
= m_nextStereoMode
;
992 SetVideoResolution(GetVideoResolution(), true);
993 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_RENDERER_RESET
);
997 void CGraphicContext::GetAllowedResolutions(std::vector
<RESOLUTION
> &res
)
1001 res
.push_back(RES_WINDOW
);
1002 res
.push_back(RES_DESKTOP
);
1003 for (size_t r
= (size_t) RES_CUSTOM
; r
< CDisplaySettings::GetInstance().ResolutionInfoSize(); r
++)
1005 res
.push_back((RESOLUTION
) r
);
1009 void CGraphicContext::SetFPS(float fps
)
1011 m_fFPSOverride
= fps
;