[filesystem][SpecialProtocol] Removed assert from GetPath
[xbmc.git] / xbmc / windowing / GraphicContext.cpp
bloba5513fa1910831bd3488bac586bff6da2ebb0010
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 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());
39 else
40 m_origins.push(CPoint(x,y));
42 AddTransform(TransformMatrix::CreateTranslation(x, y));
45 void CGraphicContext::RestoreOrigin()
47 if (!m_origins.empty())
48 m_origins.pop();
49 RemoveTransform();
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
55 CPoint 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);
61 rect += origin;
62 if (!m_clipRegions.empty())
64 // intersect with original clip region
65 rect.Intersect(m_clipRegions.top());
68 if (rect.IsEmpty())
69 return false;
71 m_clipRegions.push(rect);
73 // here we could set the hardware clipping, if applicable
74 return true;
77 void CGraphicContext::RestoreClipRegion()
79 if (!m_clipRegions.empty())
80 m_clipRegions.pop();
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;
107 if (texture2)
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();
127 return clipRegion;
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();
162 m_transforms.pop();
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.
170 float x[4], y[4];
171 x[0] = x[3] = fx;
172 x[1] = x[2] = fx + fwidth;
173 y[0] = y[1] = fy;
174 y[2] = y[3] = fy + fheight;
175 float minX = (float)m_iScreenWidth;
176 float maxX = 0;
177 float minY = (float)m_iScreenHeight;
178 float maxY = 0;
179 for (int i = 0; i < 4; i++)
181 float z = 0;
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
203 return false;
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
216 return false;
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());
236 return true;
239 void CGraphicContext::RestoreViewPort()
241 if (m_viewStack.size() <= 1) return;
243 m_viewStack.pop();
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
252 CPoint res(point);
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;
268 return res;
271 CRect CGraphicContext::StereoCorrection(const CRect &rect) const
273 CRect res(StereoCorrection(rect.P1())
274 , StereoCorrection(rect.P2()));
275 return res;
278 void CGraphicContext::SetScissors(const CRect &rect)
280 m_scissors = 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
287 return m_scissors;
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)
300 CRect rect;
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;
306 return rect;
308 return m_videoRect;
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;
332 else
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);
356 else
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())
379 return true;
382 return false;
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);
392 else
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))
405 res = RES_DESKTOP;
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)
411 return;
414 if (res >= RES_DESKTOP)
416 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
417 m_bFullScreenRoot = true;
419 else
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);
446 #else
447 switched = CServiceBroker::GetWinSystem()->SetFullScreen(true, info_org, false);
448 #endif
450 else if (lastRes >= RES_DESKTOP )
451 switched = CServiceBroker::GetWinSystem()->SetFullScreen(false, info_org, false);
452 else
453 switched = CServiceBroker::GetWinSystem()->ResizeWindow(info_org.iWidth, info_org.iHeight, -1, -1);
455 if (switched)
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();
466 if (gui)
467 gui->GetWindowManager().SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
469 else
471 // Reset old state
472 m_iScreenWidth = origScreenWidth;
473 m_iScreenHeight = origScreenHeight;
474 m_fFPSOverride = origFPSOverride;
475 if (IsValidResolution(lastRes))
477 m_Resolution = lastRes;
479 else
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",
496 res);
497 res = RES_DESKTOP;
500 if (res >= RES_DESKTOP)
502 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = true;
503 m_bFullScreenRoot = true;
505 else
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;
532 m_Resolution = res;
533 m_fFPSOverride = 0;
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
551 return m_Resolution;
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)
564 overscan.left = 0;
565 overscan.top = 0;
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;
607 info.iBlanking = 0;
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;
621 info.iBlanking = 0;
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;
634 return info;
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;
681 fZoom -= 1.0f;
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;
693 if (matrix)
695 TransformMatrix guiScaler = TransformMatrix::CreateScaler(fToWidth / fFromWidth, fToHeight / fFromHeight, fToHeight / fFromHeight);
696 TransformMatrix guiOffset = TransformMatrix::CreateTranslation(fToPosX, fToPosY);
697 *matrix = guiOffset * guiScaler;
700 else
702 scaleX = scaleY = 1.0f;
703 if (matrix)
704 matrix->Reset();
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);
713 else
715 m_guiTransform.Reset();
718 // reset our origin and camera
719 while (!m_origins.empty())
720 m_origins.pop();
721 m_origins.push(CPoint(0, 0));
722 while (!m_cameras.empty())
723 m_cameras.pop();
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)
743 m_stereoView = view;
745 while(!m_viewStack.empty())
746 m_viewStack.pop();
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
794 CPoint cam(camera);
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;
801 m_cameras.push(cam);
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());
808 m_cameras.pop();
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)|
829 // | |
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;
836 float z = 0.0f;
837 ScaleFinalCoords(x1, y1, z);
838 CServiceBroker::GetRenderSystem()->Project(x1, y1, z);
840 z = 0.0f;
841 ScaleFinalCoords(x2, y2, z);
842 CServiceBroker::GetRenderSystem()->Project(x2, y2, z);
844 z = 0.0f;
845 ScaleFinalCoords(x3, y3, z);
846 CServiceBroker::GetRenderSystem()->Project(x3, y3, z);
848 z = 0.0f;
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;
886 return false;
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;
934 return 60.0f;
937 float CGraphicContext::GetDisplayLatency() const
939 float latency = CServiceBroker::GetWinSystem()->GetDisplayLatency();
940 if (latency < 0.0f)
942 // fallback
943 latency = (CServiceBroker::GetWinSystem()->NoOfBuffers() + 1) / GetFPS() * 1000.0f;
946 return latency;
949 bool CGraphicContext::IsFullScreenRoot () const
951 return m_bFullScreenRoot;
954 void CGraphicContext::ToggleFullScreen()
956 RESOLUTION uiRes;
958 if (m_bFullScreenRoot)
960 uiRes = RES_WINDOW;
962 else
964 if (CDisplaySettings::GetInstance().GetCurrentResolution() > RES_DESKTOP)
965 uiRes = CDisplaySettings::GetInstance().GetCurrentResolution();
966 else
967 uiRes = RES_DESKTOP;
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)
999 res.clear();
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;