[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / windowing / GraphicContext.cpp
blob888be5bf2809f3ff75f4b3d0e586b696190f542b
1 /*
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.
7 */
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"
29 #include <cassert>
30 #include <mutex>
32 using KODI::UTILS::COLOR::Color;
34 CGraphicContext::CGraphicContext() = default;
35 CGraphicContext::~CGraphicContext() = default;
37 void CGraphicContext::SetOrigin(float x, float y)
39 if (!m_origins.empty())
40 m_origins.push(CPoint(x,y) + m_origins.top());
41 else
42 m_origins.emplace(x, y);
44 AddTransform(TransformMatrix::CreateTranslation(x, y));
47 void CGraphicContext::RestoreOrigin()
49 if (!m_origins.empty())
50 m_origins.pop();
51 RemoveTransform();
54 // add a new clip region, intersecting with the previous clip region.
55 bool CGraphicContext::SetClipRegion(float x, float y, float w, float h)
56 { // transform from our origin
57 CPoint origin;
58 if (!m_origins.empty())
59 origin = m_origins.top();
61 // ok, now intersect with our old clip region
62 CRect rect(x, y, x + w, y + h);
63 rect += origin;
64 if (!m_clipRegions.empty())
66 // intersect with original clip region
67 rect.Intersect(m_clipRegions.top());
70 if (rect.IsEmpty())
71 return false;
73 m_clipRegions.push(rect);
75 // here we could set the hardware clipping, if applicable
76 return true;
79 void CGraphicContext::RestoreClipRegion()
81 if (!m_clipRegions.empty())
82 m_clipRegions.pop();
84 // here we could reset the hardware clipping, if applicable
87 void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
89 // this is the software clipping routine. If the graphics hardware is set to do the clipping
90 // (eg via SetClipPlane in D3D for instance) then this routine is unneeded.
91 if (!m_clipRegions.empty())
93 // take a copy of the vertex rectangle and intersect
94 // it with our clip region (moved to the same coordinate system)
95 CRect clipRegion(m_clipRegions.top());
96 if (!m_origins.empty())
97 clipRegion -= m_origins.top();
98 CRect original(vertex);
99 vertex.Intersect(clipRegion);
100 // and use the original to compute the texture coordinates
101 if (original != vertex)
103 float scaleX = texture.Width() / original.Width();
104 float scaleY = texture.Height() / original.Height();
105 texture.x1 += (vertex.x1 - original.x1) * scaleX;
106 texture.y1 += (vertex.y1 - original.y1) * scaleY;
107 texture.x2 += (vertex.x2 - original.x2) * scaleX;
108 texture.y2 += (vertex.y2 - original.y2) * scaleY;
109 if (texture2)
111 scaleX = texture2->Width() / original.Width();
112 scaleY = texture2->Height() / original.Height();
113 texture2->x1 += (vertex.x1 - original.x1) * scaleX;
114 texture2->y1 += (vertex.y1 - original.y1) * scaleY;
115 texture2->x2 += (vertex.x2 - original.x2) * scaleX;
116 texture2->y2 += (vertex.y2 - original.y2) * scaleY;
122 CRect CGraphicContext::GetClipRegion()
124 if (m_clipRegions.empty())
125 return CRect(0, 0, m_iScreenWidth, m_iScreenHeight);
126 CRect clipRegion(m_clipRegions.top());
127 if (!m_origins.empty())
128 clipRegion -= m_origins.top();
129 return clipRegion;
132 void CGraphicContext::AddGUITransform()
134 m_transforms.push(m_finalTransform);
135 m_finalTransform = m_guiTransform;
138 TransformMatrix CGraphicContext::AddTransform(const TransformMatrix &matrix)
140 m_transforms.push(m_finalTransform);
141 m_finalTransform.matrix *= matrix;
142 return m_finalTransform.matrix;
145 void CGraphicContext::SetTransform(const TransformMatrix &matrix)
147 m_transforms.push(m_finalTransform);
148 m_finalTransform.matrix = matrix;
151 void CGraphicContext::SetTransform(const TransformMatrix &matrix, float scaleX, float scaleY)
153 m_transforms.push(m_finalTransform);
154 m_finalTransform.matrix = matrix;
155 m_finalTransform.scaleX = scaleX;
156 m_finalTransform.scaleY = scaleY;
159 void CGraphicContext::RemoveTransform()
161 if (!m_transforms.empty())
163 m_finalTransform = m_transforms.top();
164 m_transforms.pop();
168 bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
170 // transform coordinates - we may have a rotation which changes the positioning of the
171 // minimal and maximal viewport extents. We currently go to the maximal extent.
172 float x[4], y[4];
173 x[0] = x[3] = fx;
174 x[1] = x[2] = fx + fwidth;
175 y[0] = y[1] = fy;
176 y[2] = y[3] = fy + fheight;
177 float minX = (float)m_iScreenWidth;
178 float maxX = 0;
179 float minY = (float)m_iScreenHeight;
180 float maxY = 0;
181 for (int i = 0; i < 4; i++)
183 float z = 0;
184 ScaleFinalCoords(x[i], y[i], z);
185 if (x[i] < minX) minX = x[i];
186 if (x[i] > maxX) maxX = x[i];
187 if (y[i] < minY) minY = y[i];
188 if (y[i] > maxY) maxY = y[i];
191 int newLeft = (int)(minX + 0.5f);
192 int newTop = (int)(minY + 0.5f);
193 int newRight = (int)(maxX + 0.5f);
194 int newBottom = (int)(maxY + 0.5f);
195 if (intersectPrevious)
197 CRect oldviewport = m_viewStack.top();
198 // do the intersection
199 int oldLeft = (int)oldviewport.x1;
200 int oldTop = (int)oldviewport.y1;
201 int oldRight = (int)oldviewport.x2;
202 int oldBottom = (int)oldviewport.y2;
203 if (newLeft >= oldRight || newTop >= oldBottom || newRight <= oldLeft || newBottom <= oldTop)
204 { // empty intersection - return false to indicate no rendering should occur
205 return false;
207 // ok, they intersect, do the intersection
208 if (newLeft < oldLeft) newLeft = oldLeft;
209 if (newTop < oldTop) newTop = oldTop;
210 if (newRight > oldRight) newRight = oldRight;
211 if (newBottom > oldBottom) newBottom = oldBottom;
213 // check range against screen size
214 if (newRight <= 0 || newBottom <= 0 ||
215 newTop >= m_iScreenHeight || newLeft >= m_iScreenWidth ||
216 newLeft >= newRight || newTop >= newBottom)
217 { // no intersection with the screen
218 return false;
220 // intersection with the screen
221 if (newLeft < 0) newLeft = 0;
222 if (newTop < 0) newTop = 0;
223 if (newRight > m_iScreenWidth) newRight = m_iScreenWidth;
224 if (newBottom > m_iScreenHeight) newBottom = m_iScreenHeight;
226 assert(newLeft < newRight);
227 assert(newTop < newBottom);
229 CRect newviewport((float)newLeft, (float)newTop, (float)newRight, (float)newBottom);
231 m_viewStack.push(newviewport);
233 newviewport = StereoCorrection(newviewport);
234 CServiceBroker::GetRenderSystem()->SetViewPort(newviewport);
237 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
238 return true;
241 void CGraphicContext::RestoreViewPort()
243 if (m_viewStack.size() <= 1) return;
245 m_viewStack.pop();
246 CRect viewport = StereoCorrection(m_viewStack.top());
247 CServiceBroker::GetRenderSystem()->SetViewPort(viewport);
249 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
252 CPoint CGraphicContext::StereoCorrection(const CPoint &point) const
254 CPoint res(point);
256 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
258 const RESOLUTION_INFO info = GetResInfo();
260 if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
261 res.y += info.iHeight + info.iBlanking;
263 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
265 const RESOLUTION_INFO info = GetResInfo();
267 if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
268 res.x += info.iWidth + info.iBlanking;
270 return res;
273 CRect CGraphicContext::StereoCorrection(const CRect &rect) const
275 CRect res(StereoCorrection(rect.P1())
276 , StereoCorrection(rect.P2()));
277 return res;
280 void CGraphicContext::SetScissors(const CRect &rect)
282 m_scissors = rect;
283 m_scissors.Intersect(CRect(0,0,(float)m_iScreenWidth, (float)m_iScreenHeight));
284 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors));
287 const CRect &CGraphicContext::GetScissors() const
289 return m_scissors;
292 void CGraphicContext::ResetScissors()
294 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
295 CServiceBroker::GetRenderSystem()->SetScissors(StereoCorrection(m_scissors));
298 const CRect CGraphicContext::GetViewWindow() const
300 if (m_bCalibrating || m_bFullScreenVideo)
302 CRect rect;
303 RESOLUTION_INFO info = GetResInfo();
304 rect.x1 = (float)info.Overscan.left;
305 rect.y1 = (float)info.Overscan.top;
306 rect.x2 = (float)info.Overscan.right;
307 rect.y2 = (float)info.Overscan.bottom;
308 return rect;
310 return m_videoRect;
313 void CGraphicContext::SetViewWindow(float left, float top, float right, float bottom)
315 m_videoRect.x1 = ScaleFinalXCoord(left, top);
316 m_videoRect.y1 = ScaleFinalYCoord(left, top);
317 m_videoRect.x2 = ScaleFinalXCoord(right, bottom);
318 m_videoRect.y2 = ScaleFinalYCoord(right, bottom);
321 void CGraphicContext::SetFullScreenVideo(bool bOnOff)
323 std::unique_lock<CCriticalSection> lock(*this);
325 m_bFullScreenVideo = bOnOff;
327 if (m_bFullScreenRoot)
329 bool bTriggerUpdateRes = false;
330 auto& components = CServiceBroker::GetAppComponents();
331 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
332 if (m_bFullScreenVideo)
333 bTriggerUpdateRes = true;
334 else
336 bool allowDesktopRes = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) == ADJUST_REFRESHRATE_ALWAYS;
337 if (!allowDesktopRes)
339 if (appPlayer->IsPlayingVideo())
340 bTriggerUpdateRes = true;
344 bool allowResolutionChangeOnStop = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_ON_START;
345 RESOLUTION targetResolutionOnStop = RES_DESKTOP;
346 if (bTriggerUpdateRes)
347 appPlayer->TriggerUpdateResolution();
348 else if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP)
350 targetResolutionOnStop = CDisplaySettings::GetInstance().GetCurrentResolution();
353 if (allowResolutionChangeOnStop && !bTriggerUpdateRes)
355 SetVideoResolution(targetResolutionOnStop, false);
358 else
359 SetVideoResolution(RES_WINDOW, false);
362 bool CGraphicContext::IsFullScreenVideo() const
364 return m_bFullScreenVideo;
367 bool CGraphicContext::IsCalibrating() const
369 return m_bCalibrating;
372 void CGraphicContext::SetCalibrating(bool bOnOff)
374 m_bCalibrating = bOnOff;
377 bool CGraphicContext::IsValidResolution(RESOLUTION res)
379 if (res >= RES_WINDOW && (size_t) res < CDisplaySettings::GetInstance().ResolutionInfoSize())
381 return true;
384 return false;
387 // call SetVideoResolutionInternal and ensure its done from mainthread
388 void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
390 if (CServiceBroker::GetAppMessenger()->IsProcessThread())
392 SetVideoResolutionInternal(res, forceUpdate);
394 else
396 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_SETVIDEORESOLUTION, res, forceUpdate ? 1 : 0);
400 void CGraphicContext::SetVideoResolutionInternal(RESOLUTION res, bool forceUpdate)
402 RESOLUTION lastRes = m_Resolution;
404 // If the user asked us to guess, go with desktop
405 if (!IsValidResolution(res))
407 res = RES_DESKTOP;
410 // If we are switching to the same resolution and same window/full-screen, no need to do anything
411 if (!forceUpdate && res == lastRes && m_bFullScreenRoot == CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen)
413 return;
416 if (res >= RES_DESKTOP)
418 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
419 m_bFullScreenRoot = true;
421 else
423 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
424 m_bFullScreenRoot = false;
427 std::unique_lock<CCriticalSection> lock(*this);
429 // FIXME Wayland windowing needs some way to "deny" resolution updates since what Kodi
430 // requests might not get actually set by the compositor.
431 // So in theory, m_iScreenWidth etc. would not need to be updated at all before the
432 // change is confirmed.
433 // But other windowing code expects these variables to be already set when
434 // SetFullScreen() is called, so set them anyway and remember the old values.
435 int origScreenWidth = m_iScreenWidth;
436 int origScreenHeight = m_iScreenHeight;
437 float origFPSOverride = m_fFPSOverride;
439 UpdateInternalStateWithResolution(res);
440 RESOLUTION_INFO info_org = CDisplaySettings::GetInstance().GetResolutionInfo(res);
442 bool switched = false;
443 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen)
445 #if defined (TARGET_DARWIN) || defined (TARGET_WINDOWS)
446 bool blankOtherDisplays = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS);
447 switched = CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org, blankOtherDisplays);
448 #else
449 switched = CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org, false);
450 #endif
452 else if (lastRes >= RES_DESKTOP )
453 switched = CServiceBroker::GetWinSystem()->SetFullScreen(false, info_org, false);
454 else
455 switched = CServiceBroker::GetWinSystem()->ResizeWindow(info_org.iWidth, info_org.iHeight, -1, -1);
457 if (switched)
459 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
461 // make sure all stereo stuff are correctly setup
462 SetStereoView(RENDER_STEREO_VIEW_OFF);
464 // update anyone that relies on sizing information
465 CServiceBroker::GetInputManager().SetMouseResolution(info_org.iWidth, info_org.iHeight, 1, 1);
467 CGUIComponent *gui = CServiceBroker::GetGUI();
468 if (gui)
469 gui->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
471 else
473 // Reset old state
474 m_iScreenWidth = origScreenWidth;
475 m_iScreenHeight = origScreenHeight;
476 m_fFPSOverride = origFPSOverride;
477 if (IsValidResolution(lastRes))
479 m_Resolution = lastRes;
481 else
483 // FIXME Resolution has become invalid
484 // This happens e.g. when switching monitors and the new monitor has fewer
485 // resolutions than the old one. Fall back to RES_DESKTOP and hope that
486 // the real resolution is set soon.
487 // Again, must be fixed as part of a greater refactor.
488 m_Resolution = RES_DESKTOP;
493 void CGraphicContext::ApplyVideoResolution(RESOLUTION res)
495 if (!IsValidResolution(res))
497 CLog::LogF(LOGWARNING, "Asked to apply invalid resolution {}, falling back to RES_DESKTOP",
498 res);
499 res = RES_DESKTOP;
502 if (res >= RES_DESKTOP)
504 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
505 m_bFullScreenRoot = true;
507 else
509 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
510 m_bFullScreenRoot = false;
513 std::unique_lock<CCriticalSection> lock(*this);
515 UpdateInternalStateWithResolution(res);
517 m_scissors.SetRect(0, 0, (float)m_iScreenWidth, (float)m_iScreenHeight);
519 // make sure all stereo stuff are correctly setup
520 SetStereoView(RENDER_STEREO_VIEW_OFF);
522 // update anyone that relies on sizing information
523 RESOLUTION_INFO info_org = CDisplaySettings::GetInstance().GetResolutionInfo(res);
524 CServiceBroker::GetInputManager().SetMouseResolution(info_org.iWidth, info_org.iHeight, 1, 1);
525 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
528 void CGraphicContext::UpdateInternalStateWithResolution(RESOLUTION res)
530 RESOLUTION_INFO info_mod = GetResInfo(res);
532 m_iScreenWidth = info_mod.iWidth;
533 m_iScreenHeight = info_mod.iHeight;
534 m_Resolution = res;
535 m_fFPSOverride = 0;
538 void CGraphicContext::ApplyModeChange(RESOLUTION res)
540 ApplyVideoResolution(res);
541 CServiceBroker::GetWinSystem()->FinishModeChange(res);
544 void CGraphicContext::ApplyWindowResize(int newWidth, int newHeight)
546 CServiceBroker::GetWinSystem()->SetWindowResolution(newWidth, newHeight);
547 ApplyVideoResolution(RES_WINDOW);
548 CServiceBroker::GetWinSystem()->FinishWindowResize(newWidth, newHeight);
551 RESOLUTION CGraphicContext::GetVideoResolution() const
553 return m_Resolution;
556 void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
558 res.Overscan.left = 0;
559 res.Overscan.top = 0;
560 res.Overscan.right = res.iWidth;
561 res.Overscan.bottom = res.iHeight;
564 void CGraphicContext::ResetOverscan(RESOLUTION res, OVERSCAN &overscan)
566 overscan.left = 0;
567 overscan.top = 0;
569 RESOLUTION_INFO info = GetResInfo(res);
570 overscan.right = info.iWidth;
571 overscan.bottom = info.iHeight;
574 void CGraphicContext::ResetScreenParameters(RESOLUTION res)
576 RESOLUTION_INFO& info = CDisplaySettings::GetInstance().GetResolutionInfo(res);
578 info.iSubtitles = info.iHeight;
579 info.fPixelRatio = 1.0f;
580 info.iScreenWidth = info.iWidth;
581 info.iScreenHeight = info.iHeight;
582 ResetOverscan(res, info.Overscan);
585 void CGraphicContext::Clear()
587 CServiceBroker::GetRenderSystem()->InvalidateColorBuffer();
590 void CGraphicContext::Clear(Color color)
592 CServiceBroker::GetRenderSystem()->ClearBuffers(color);
595 void CGraphicContext::CaptureStateBlock()
597 CServiceBroker::GetRenderSystem()->CaptureStateBlock();
600 void CGraphicContext::ApplyStateBlock()
602 CServiceBroker::GetRenderSystem()->ApplyStateBlock();
605 const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
607 RESOLUTION_INFO info = CDisplaySettings::GetInstance().GetResolutionInfo(res);
609 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
611 if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
613 info.fPixelRatio /= 2;
614 info.iBlanking = 0;
615 info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
617 info.iHeight = (info.iHeight - info.iBlanking) / 2;
618 info.Overscan.top /= 2;
619 info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2;
620 info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2;
623 if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
625 if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
627 info.fPixelRatio *= 2;
628 info.iBlanking = 0;
629 info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
631 info.iWidth = (info.iWidth - info.iBlanking) / 2;
632 info.Overscan.left /= 2;
633 info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2;
636 if (res == m_Resolution && m_fFPSOverride != 0)
638 info.fRefreshRate = m_fFPSOverride;
641 return info;
644 void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
646 RESOLUTION_INFO& curr = CDisplaySettings::GetInstance().GetResolutionInfo(res);
647 curr.Overscan = info.Overscan;
648 curr.iSubtitles = info.iSubtitles;
649 curr.fPixelRatio = info.fPixelRatio;
650 curr.guiInsets = info.guiInsets;
652 if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
654 curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking;
655 if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
656 curr.fPixelRatio /= 2.0f;
659 if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
661 curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking;
662 curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking;
663 if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
664 curr.fPixelRatio *= 2.0f;
668 const RESOLUTION_INFO CGraphicContext::GetResInfo() const
670 return GetResInfo(m_Resolution);
673 void CGraphicContext::GetGUIScaling(const RESOLUTION_INFO &res, float &scaleX, float &scaleY, TransformMatrix *matrix /* = NULL */)
675 if (m_Resolution != RES_INVALID)
677 // calculate necessary scalings
678 RESOLUTION_INFO info = GetResInfo();
679 float fFromWidth = (float)res.iWidth;
680 float fFromHeight = (float)res.iHeight;
681 auto fToPosX = info.Overscan.left + info.guiInsets.left;
682 auto fToPosY = info.Overscan.top + info.guiInsets.top;
683 auto fToWidth = info.Overscan.right - info.guiInsets.right - fToPosX;
684 auto fToHeight = info.Overscan.bottom - info.guiInsets.bottom - fToPosY;
686 float fZoom = (100 + CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_SKINZOOM)) * 0.01f;
688 fZoom -= 1.0f;
689 fToPosX -= fToWidth * fZoom * 0.5f;
690 fToWidth *= fZoom + 1.0f;
692 // adjust for aspect ratio as zoom is given in the vertical direction and we don't
693 // do aspect ratio corrections in the gui code
694 fZoom = fZoom / info.fPixelRatio;
695 fToPosY -= fToHeight * fZoom * 0.5f;
696 fToHeight *= fZoom + 1.0f;
698 scaleX = fFromWidth / fToWidth;
699 scaleY = fFromHeight / fToHeight;
700 if (matrix)
702 TransformMatrix guiScaler = TransformMatrix::CreateScaler(fToWidth / fFromWidth, fToHeight / fFromHeight, fToHeight / fFromHeight);
703 TransformMatrix guiOffset = TransformMatrix::CreateTranslation(fToPosX, fToPosY);
704 *matrix = guiOffset * guiScaler;
707 else
709 scaleX = scaleY = 1.0f;
710 if (matrix)
711 matrix->Reset();
715 void CGraphicContext::SetScalingResolution(const RESOLUTION_INFO &res, bool needsScaling)
717 m_windowResolution = res;
718 if (needsScaling && m_Resolution != RES_INVALID)
719 GetGUIScaling(res, m_guiTransform.scaleX, m_guiTransform.scaleY, &m_guiTransform.matrix);
720 else
722 m_guiTransform.Reset();
725 // reset our origin and camera
726 while (!m_origins.empty())
727 m_origins.pop();
728 m_origins.emplace(.0f, .0f);
729 while (!m_cameras.empty())
730 m_cameras.pop();
731 m_cameras.emplace(0.5f * m_iScreenWidth, 0.5f * m_iScreenHeight);
732 while (!m_stereoFactors.empty())
733 m_stereoFactors.pop();
734 m_stereoFactors.push(0.0f);
736 // and reset the final transform
737 m_finalTransform = m_guiTransform;
740 void CGraphicContext::SetRenderingResolution(const RESOLUTION_INFO &res, bool needsScaling)
742 std::unique_lock<CCriticalSection> lock(*this);
744 SetScalingResolution(res, needsScaling);
745 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
748 void CGraphicContext::SetStereoView(RENDER_STEREO_VIEW view)
750 m_stereoView = view;
752 while(!m_viewStack.empty())
753 m_viewStack.pop();
755 CRect viewport(0.0f, 0.0f, (float)m_iScreenWidth, (float)m_iScreenHeight);
757 m_viewStack.push(viewport);
759 viewport = StereoCorrection(viewport);
760 CServiceBroker::GetRenderSystem()->SetStereoMode(m_stereoMode, m_stereoView);
761 CServiceBroker::GetRenderSystem()->SetViewPort(viewport);
762 CServiceBroker::GetRenderSystem()->SetScissors(viewport);
765 void CGraphicContext::InvertFinalCoords(float &x, float &y) const
767 m_finalTransform.matrix.InverseTransformPosition(x, y);
770 float CGraphicContext::ScaleFinalXCoord(float x, float y) const
772 return m_finalTransform.matrix.TransformXCoord(x, y, 0);
775 float CGraphicContext::ScaleFinalYCoord(float x, float y) const
777 return m_finalTransform.matrix.TransformYCoord(x, y, 0);
780 float CGraphicContext::ScaleFinalZCoord(float x, float y) const
782 return m_finalTransform.matrix.TransformZCoord(x, y, 0);
785 void CGraphicContext::ScaleFinalCoords(float &x, float &y, float &z) const
787 m_finalTransform.matrix.TransformPosition(x, y, z);
790 float CGraphicContext::GetScalingPixelRatio() const
792 // assume the resolutions are different - we want to return the aspect ratio of the video resolution
793 // but only once it's been corrected for the skin -> screen coordinates scaling
794 return GetResInfo().fPixelRatio * (m_finalTransform.scaleY / m_finalTransform.scaleX);
797 void CGraphicContext::SetCameraPosition(const CPoint &camera)
799 // offset the camera from our current location (this is in XML coordinates) and scale it up to
800 // the screen resolution
801 CPoint cam(camera);
802 if (!m_origins.empty())
803 cam += m_origins.top();
805 cam.x *= (float)m_iScreenWidth / m_windowResolution.iWidth;
806 cam.y *= (float)m_iScreenHeight / m_windowResolution.iHeight;
808 m_cameras.push(cam);
809 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
812 void CGraphicContext::RestoreCameraPosition()
813 { // remove the top camera from the stack
814 assert(m_cameras.size());
815 m_cameras.pop();
816 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
819 void CGraphicContext::SetStereoFactor(float factor)
821 m_stereoFactors.push(factor);
822 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
825 void CGraphicContext::RestoreStereoFactor()
826 { // remove the top factor from the stack
827 assert(m_stereoFactors.size());
828 m_stereoFactors.pop();
829 UpdateCameraPosition(m_cameras.top(), m_stereoFactors.top());
832 float CGraphicContext::GetNormalizedDepth(uint32_t depth)
834 float normalizedDepth = static_cast<float>(depth);
835 normalizedDepth /= m_layer;
836 normalizedDepth = normalizedDepth * 2 - 1;
837 return normalizedDepth;
840 float CGraphicContext::GetTransformDepth(int32_t depthOffset)
842 float depth = static_cast<float>(m_finalTransform.matrix.depth + depthOffset);
843 depth /= m_layer;
844 depth = depth * 2 - 1;
845 return depth;
848 CRect CGraphicContext::GenerateAABB(const CRect &rect) const
850 // ------------------------
851 // |(x1, y1) (x2, y2)|
852 // | |
853 // |(x3, y3) (x4, y4)|
854 // ------------------------
856 float x1 = rect.x1, x2 = rect.x2, x3 = rect.x1, x4 = rect.x2;
857 float y1 = rect.y1, y2 = rect.y1, y3 = rect.y2, y4 = rect.y2;
859 float z = 0.0f;
860 ScaleFinalCoords(x1, y1, z);
861 CServiceBroker::GetRenderSystem()->Project(x1, y1, z);
863 z = 0.0f;
864 ScaleFinalCoords(x2, y2, z);
865 CServiceBroker::GetRenderSystem()->Project(x2, y2, z);
867 z = 0.0f;
868 ScaleFinalCoords(x3, y3, z);
869 CServiceBroker::GetRenderSystem()->Project(x3, y3, z);
871 z = 0.0f;
872 ScaleFinalCoords(x4, y4, z);
873 CServiceBroker::GetRenderSystem()->Project(x4, y4, z);
875 return CRect( std::min(std::min(std::min(x1, x2), x3), x4),
876 std::min(std::min(std::min(y1, y2), y3), y4),
877 std::max(std::max(std::max(x1, x2), x3), x4),
878 std::max(std::max(std::max(y1, y2), y3), y4));
881 // NOTE: This routine is currently called (twice) every time there is a <camera>
882 // tag in the skin. It actually only has to be called before we render
883 // something, so another option is to just save the camera coordinates
884 // and then have a routine called before every draw that checks whether
885 // the camera has changed, and if so, changes it. Similarly, it could set
886 // the world transform at that point as well (or even combine world + view
887 // to cut down on one setting)
888 void CGraphicContext::UpdateCameraPosition(const CPoint &camera, const float &factor)
890 float stereoFactor = 0.f;
891 if ( m_stereoMode != RENDER_STEREO_MODE_OFF
892 && m_stereoMode != RENDER_STEREO_MODE_MONO
893 && m_stereoView != RENDER_STEREO_VIEW_OFF)
895 RESOLUTION_INFO res = GetResInfo();
896 RESOLUTION_INFO desktop = GetResInfo(RES_DESKTOP);
897 float scaleRes = (static_cast<float>(res.iWidth) / static_cast<float>(desktop.iWidth));
898 float scaleX = static_cast<float>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_STEREOSTRENGTH)) * scaleRes;
899 stereoFactor = factor * (m_stereoView == RENDER_STEREO_VIEW_LEFT ? scaleX : -scaleX);
901 CServiceBroker::GetRenderSystem()->SetCameraPosition(camera, m_iScreenWidth, m_iScreenHeight, stereoFactor);
904 bool CGraphicContext::RectIsAngled(float x1, float y1, float x2, float y2) const
905 { // need only test 3 points, as they must be co-planer
906 if (m_finalTransform.matrix.TransformZCoord(x1, y1, 0)) return true;
907 if (m_finalTransform.matrix.TransformZCoord(x2, y2, 0)) return true;
908 if (m_finalTransform.matrix.TransformZCoord(x1, y2, 0)) return true;
909 return false;
912 const TransformMatrix &CGraphicContext::GetGUIMatrix() const
914 return m_finalTransform.matrix;
917 float CGraphicContext::GetGUIScaleX() const
919 return m_finalTransform.scaleX;
922 float CGraphicContext::GetGUIScaleY() const
924 return m_finalTransform.scaleY;
927 Color CGraphicContext::MergeAlpha(Color color) const
929 Color alpha = m_finalTransform.matrix.TransformAlpha((color >> 24) & 0xff);
930 if (alpha > 255) alpha = 255;
931 return ((alpha << 24) & 0xff000000) | (color & 0xffffff);
934 Color CGraphicContext::MergeColor(Color color) const
936 return m_finalTransform.matrix.TransformColor(color);
939 int CGraphicContext::GetWidth() const
941 return m_iScreenWidth;
944 int CGraphicContext::GetHeight() const
946 return m_iScreenHeight;
949 float CGraphicContext::GetFPS() const
951 if (m_Resolution != RES_INVALID)
953 RESOLUTION_INFO info = GetResInfo();
954 if (info.fRefreshRate > 0)
955 return info.fRefreshRate;
957 return 60.0f;
960 float CGraphicContext::GetDisplayLatency() const
962 float latency = CServiceBroker::GetWinSystem()->GetDisplayLatency();
963 if (latency < 0.0f)
965 // fallback
966 latency = (CServiceBroker::GetWinSystem()->NoOfBuffers() + 1) / GetFPS() * 1000.0f;
969 return latency;
972 bool CGraphicContext::IsFullScreenRoot () const
974 return m_bFullScreenRoot;
977 void CGraphicContext::ToggleFullScreen()
979 RESOLUTION uiRes;
981 if (m_bFullScreenRoot)
983 uiRes = RES_WINDOW;
985 else
987 if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP)
988 uiRes = CDisplaySettings::GetInstance().GetCurrentResolution();
989 else
990 uiRes = RES_DESKTOP;
993 CDisplaySettings::GetInstance().SetCurrentResolution(uiRes, true);
996 void CGraphicContext::SetMediaDir(const std::string &strMediaDir)
998 CServiceBroker::GetGUI()->GetTextureManager().SetTexturePath(strMediaDir);
999 m_strMediaDir = strMediaDir;
1002 const std::string& CGraphicContext::GetMediaDir() const
1004 return m_strMediaDir;
1008 void CGraphicContext::Flip(bool rendered, bool videoLayer)
1010 CServiceBroker::GetRenderSystem()->PresentRender(rendered, videoLayer);
1012 if(m_stereoMode != m_nextStereoMode)
1014 m_stereoMode = m_nextStereoMode;
1015 SetVideoResolution(GetVideoResolution(), true);
1016 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
1020 void CGraphicContext::GetAllowedResolutions(std::vector<RESOLUTION> &res)
1022 res.clear();
1024 res.push_back(RES_WINDOW);
1025 res.push_back(RES_DESKTOP);
1026 for (size_t r = (size_t) RES_CUSTOM; r < CDisplaySettings::GetInstance().ResolutionInfoSize(); r++)
1028 res.push_back((RESOLUTION) r);
1032 void CGraphicContext::SetRenderOrder(RENDER_ORDER renderOrder)
1034 m_renderOrder = renderOrder;
1035 if (renderOrder == RENDER_ORDER_ALL_BACK_TO_FRONT)
1036 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_OFF);
1037 else if (renderOrder == RENDER_ORDER_BACK_TO_FRONT)
1038 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_BACK_TO_FRONT);
1039 else if (renderOrder == RENDER_ORDER_FRONT_TO_BACK)
1040 CServiceBroker::GetRenderSystem()->SetDepthCulling(DEPTH_CULLING_FRONT_TO_BACK);
1043 uint32_t CGraphicContext::GetDepth(uint32_t addLayers)
1045 uint32_t layer = m_layer;
1046 m_layer += addLayers;
1047 return layer;
1050 void CGraphicContext::SetFPS(float fps)
1052 m_fFPSOverride = fps;