[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / pictures / SlideShowPicture.cpp
blob63ec8b9343248e9a66a482bfaba2151094aef19c
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 "SlideShowPicture.h"
11 #include "ServiceBroker.h"
12 #include "guilib/Texture.h"
13 #include "settings/AdvancedSettings.h"
14 #include "settings/Settings.h"
15 #include "settings/SettingsComponent.h"
16 #include "windowing/GraphicContext.h"
17 #include "windowing/WinSystem.h"
19 #include <mutex>
21 #ifndef _USE_MATH_DEFINES
22 #define _USE_MATH_DEFINES
23 #endif
24 #include <math.h>
26 #if defined(HAS_GL)
27 #include "rendering/gl/RenderSystemGL.h"
28 #include "utils/GLUtils.h"
29 #elif defined(HAS_GLES)
30 #include "rendering/gles/RenderSystemGLES.h"
31 #include "utils/GLUtils.h"
32 #elif defined(TARGET_WINDOWS)
33 #include "guilib/TextureDX.h"
34 #include "rendering/dx/DeviceResources.h"
35 #include "rendering/dx/RenderContext.h"
37 #include <DirectXMath.h>
38 using namespace DirectX;
39 using namespace Microsoft::WRL;
40 #endif
42 #include <cstddef>
44 #define IMMEDIATE_TRANSITION_TIME 20
46 #define PICTURE_MOVE_AMOUNT 0.02f
47 #define PICTURE_MOVE_AMOUNT_ANALOG 0.01f
48 #define PICTURE_VIEW_BOX_COLOR 0xffffff00 // YELLOW
49 #define PICTURE_VIEW_BOX_BACKGROUND 0xff000000 // BLACK
51 #define FPS 25
53 static float zoomamount[10] = { 1.0f, 1.2f, 1.5f, 2.0f, 2.8f, 4.0f, 6.0f, 9.0f, 13.5f, 20.0f };
55 CSlideShowPic::CSlideShowPic() : m_pImage(nullptr)
57 m_bIsLoaded = false;
58 m_bIsFinished = false;
59 m_bDrawNextImage = false;
60 m_bTransitionImmediately = false;
62 m_bCanMoveHorizontally = false;
63 m_bCanMoveVertically = false;
66 CSlideShowPic::~CSlideShowPic()
68 Close();
71 void CSlideShowPic::Close()
73 std::unique_lock<CCriticalSection> lock(m_textureAccess);
74 m_pImage.reset();
75 m_bIsLoaded = false;
76 m_bIsFinished = false;
77 m_bDrawNextImage = false;
78 m_bTransitionImmediately = false;
79 m_bIsDirty = true;
80 m_alpha = 0;
81 #ifdef HAS_DX
82 m_vb = nullptr;
83 #endif
86 void CSlideShowPic::Reset(DISPLAY_EFFECT dispEffect, TRANSITION_EFFECT transEffect)
88 std::unique_lock<CCriticalSection> lock(m_textureAccess);
89 if (m_pImage)
90 SetTexture_Internal(m_iSlideNumber, std::move(m_pImage), dispEffect, transEffect);
91 else
92 Close();
95 bool CSlideShowPic::DisplayEffectNeedChange(DISPLAY_EFFECT newDispEffect) const
97 if (m_displayEffect == newDispEffect)
98 return false;
99 if (newDispEffect == EFFECT_RANDOM && m_displayEffect != EFFECT_NONE && m_displayEffect != EFFECT_NO_TIMEOUT)
100 return false;
101 return true;
104 void CSlideShowPic::SetTexture(int iSlideNumber,
105 std::unique_ptr<CTexture> pTexture,
106 DISPLAY_EFFECT dispEffect,
107 TRANSITION_EFFECT transEffect)
109 std::unique_lock<CCriticalSection> lock(m_textureAccess);
110 Close();
111 SetTexture_Internal(iSlideNumber, std::move(pTexture), dispEffect, transEffect);
114 void CSlideShowPic::SetTexture_Internal(int iSlideNumber,
115 std::unique_ptr<CTexture> pTexture,
116 DISPLAY_EFFECT dispEffect,
117 TRANSITION_EFFECT transEffect)
119 std::unique_lock<CCriticalSection> lock(m_textureAccess);
120 m_bPause = false;
121 m_bNoEffect = false;
122 m_bTransitionImmediately = false;
123 m_iSlideNumber = iSlideNumber;
125 m_bIsDirty = true;
126 m_pImage = std::move(pTexture);
127 m_fWidth = static_cast<float>(m_pImage->GetWidth());
128 m_fHeight = static_cast<float>(m_pImage->GetHeight());
129 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_HIGHQUALITYDOWNSCALING))
130 { // activate mipmapping when high quality downscaling is 'on'
131 m_pImage->SetMipmapping();
133 // reset our counter
134 m_iCounter = 0;
135 // initialize our transition effect
136 m_transitionStart.type = transEffect;
137 m_transitionStart.start = 0;
139 // initialize our display effect
140 if (dispEffect == EFFECT_RANDOM)
142 if (((m_fWidth / m_fHeight) > 1.9f) || ((m_fHeight / m_fWidth) > 1.9f))
143 m_displayEffect = EFFECT_PANORAMA;
144 else
145 m_displayEffect = (DISPLAY_EFFECT)((rand() % (EFFECT_RANDOM - 1)) + 1);
147 else
148 m_displayEffect = dispEffect;
150 // the +1's make sure it actually occurs
151 float fadeTime = 0.2f;
152 if (m_displayEffect != EFFECT_NO_TIMEOUT)
153 fadeTime = std::min(0.2f*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME), 3.0f);
154 m_transitionStart.length = (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * fadeTime); // transition time in frames
155 m_transitionEnd.type = transEffect;
156 m_transitionEnd.length = m_transitionStart.length;
157 m_transitionTemp.type = TRANSITION_NONE;
158 m_fTransitionAngle = 0;
159 m_fTransitionZoom = 0;
160 m_fAngle = 0.0f;
161 if (m_pImage->GetOrientation() == 7)
162 { // rotate to 270 degrees
163 m_fAngle = 270.0f;
165 if (m_pImage->GetOrientation() == 2)
166 { // rotate to 180 degrees
167 m_fAngle = 180.0f;
169 if (m_pImage->GetOrientation() == 5)
170 { // rotate to 90 degrees
171 m_fAngle = 90.0f;
173 m_fZoomAmount = 1;
174 m_fZoomLeft = 0;
175 m_fZoomTop = 0;
176 m_fPosX = m_fPosY = 0.0f;
177 m_fPosZ = 1.0f;
178 m_fVelocityX = m_fVelocityY = m_fVelocityZ = 0.0f;
179 int iFrames = std::max((int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME)), 1);
180 if (m_displayEffect == EFFECT_PANORAMA)
182 RESOLUTION_INFO res = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
183 float fScreenWidth = (float)res.Overscan.right - res.Overscan.left;
184 float fScreenHeight = (float)res.Overscan.bottom - res.Overscan.top;
186 if (m_fWidth > m_fHeight)
188 iFrames = (int)(iFrames * (m_fWidth - m_fHeight) / m_fHeight);
189 m_iTotalFrames = m_transitionStart.length + m_transitionEnd.length + iFrames;
191 m_fPosX = 0.5f - (fScreenWidth / fScreenHeight) * (m_fHeight / m_fWidth) * 0.5f;
192 if (rand() % 2)
193 m_fPosX = -m_fPosX;
194 m_fVelocityX = -m_fPosX * 2.0f / m_iTotalFrames;
196 else
198 iFrames = (int)(iFrames * (m_fHeight - (0.5f * m_fWidth)) / m_fWidth);
199 m_iTotalFrames = m_transitionStart.length + m_transitionEnd.length + iFrames;
201 m_fPosY = 0.5f - (fScreenHeight / fScreenWidth) * (m_fWidth / m_fHeight) * 0.5f;
202 if (rand() % 2)
203 m_fPosY = -m_fPosY;
204 m_fVelocityY = -m_fPosY * 2.0f / m_iTotalFrames;
207 else
209 m_iTotalFrames = m_transitionStart.length + m_transitionEnd.length + iFrames;
211 if (m_displayEffect == EFFECT_FLOAT)
213 // Calculate start and end positions
214 // choose a random direction
215 float angle = (rand() % 1000) / 1000.0f * 2 * (float)M_PI;
216 m_fPosX = cos(angle) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount * m_iTotalFrames * 0.00005f;
217 m_fPosY = sin(angle) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount * m_iTotalFrames * 0.00005f;
218 m_fVelocityX = -m_fPosX * 2.0f / m_iTotalFrames;
219 m_fVelocityY = -m_fPosY * 2.0f / m_iTotalFrames;
221 else if (m_displayEffect == EFFECT_ZOOM)
223 m_fPosZ = 1.0f;
224 m_fVelocityZ = 0.0001f * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowZoomAmount;
228 m_transitionEnd.start = m_transitionStart.length + iFrames;
230 m_bIsFinished = false;
231 m_bDrawNextImage = false;
232 m_bIsLoaded = true;
235 void CSlideShowPic::SetOriginalSize(int iOriginalWidth, int iOriginalHeight, bool bFullSize)
237 m_iOriginalWidth = iOriginalWidth;
238 m_iOriginalHeight = iOriginalHeight;
239 m_bFullSize = bFullSize;
242 int CSlideShowPic::GetOriginalWidth()
244 int iAngle = (int)(m_fAngle / 90.0f + 0.4f);
245 if (iAngle % 2)
246 return m_iOriginalHeight;
247 else
248 return m_iOriginalWidth;
251 int CSlideShowPic::GetOriginalHeight()
253 int iAngle = (int)(m_fAngle / 90.0f + 0.4f);
254 if (iAngle % 2)
255 return m_iOriginalWidth;
256 else
257 return m_iOriginalHeight;
260 void CSlideShowPic::UpdateTexture(std::unique_ptr<CTexture> pTexture)
262 std::unique_lock<CCriticalSection> lock(m_textureAccess);
263 m_pImage = std::move(pTexture);
264 m_fWidth = static_cast<float>(m_pImage->GetWidth());
265 m_fHeight = static_cast<float>(m_pImage->GetHeight());
266 m_bIsDirty = true;
269 static CRect GetRectangle(const float x[4], const float y[4])
271 CRect rect;
272 rect.x1 = *std::min_element(x, x+4);
273 rect.y1 = *std::min_element(y, y+4);
274 rect.x2 = *std::max_element(x, x+4);
275 rect.y2 = *std::max_element(y, y+4);
276 return rect;
279 void CSlideShowPic::UpdateVertices(float cur_x[4], float cur_y[4], const float new_x[4], const float new_y[4], CDirtyRegionList &dirtyregions)
281 const size_t count = sizeof(float)*4;
282 if(memcmp(cur_x, new_x, count)
283 || memcmp(cur_y, new_y, count)
284 || m_bIsDirty)
286 dirtyregions.push_back(CDirtyRegion(GetRectangle(cur_x, cur_y)));
287 dirtyregions.push_back(CDirtyRegion(GetRectangle(new_x, new_y)));
288 memcpy(cur_x, new_x, count);
289 memcpy(cur_y, new_y, count);
293 void CSlideShowPic::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
295 if (!m_pImage || !m_bIsLoaded || m_bIsFinished) return ;
296 UTILS::COLOR::Color alpha = m_alpha;
297 if (m_iCounter <= m_transitionStart.length)
298 { // do start transition
299 if (m_transitionStart.type == CROSSFADE)
300 { // fade in at 1x speed
301 alpha = (UTILS::COLOR::Color)((float)m_iCounter / (float)m_transitionStart.length * 255.0f);
303 else if (m_transitionStart.type == FADEIN_FADEOUT)
304 { // fade in at 2x speed, then keep solid
305 alpha =
306 (UTILS::COLOR::Color)((float)m_iCounter / (float)m_transitionStart.length * 255.0f * 2);
307 if (alpha > 255) alpha = 255;
309 else // m_transitionEffect == TRANSITION_NONE
311 alpha = 0xFF; // opaque
314 bool bPaused = m_bPause | (m_fZoomAmount != 1.0f);
315 // check if we're doing a temporary effect (such as rotate + zoom)
316 if (m_transitionTemp.type != TRANSITION_NONE)
318 bPaused = true;
319 if (m_iCounter >= m_transitionTemp.start)
321 if (m_iCounter >= m_transitionTemp.start + m_transitionTemp.length)
322 { // we're finished this transition
323 if (m_transitionTemp.type == TRANSITION_ZOOM)
324 { // correct for any introduced inaccuracies.
325 int i;
326 for (i = 0; i < 10; i++)
328 if (fabs(m_fZoomAmount - zoomamount[i]) < 0.01f * zoomamount[i])
330 m_fZoomAmount = zoomamount[i];
331 break;
334 m_bNoEffect = (m_fZoomAmount != 1.0f); // turn effect rendering back on.
336 m_transitionTemp.type = TRANSITION_NONE;
338 else
340 if (m_transitionTemp.type == TRANSITION_ROTATE)
341 m_fAngle += m_fTransitionAngle;
342 if (m_transitionTemp.type == TRANSITION_ZOOM)
343 m_fZoomAmount += m_fTransitionZoom;
347 // now just display
348 if (!m_bNoEffect && !bPaused)
350 if (m_displayEffect == EFFECT_PANORAMA)
352 m_fPosX += m_fVelocityX;
353 m_fPosY += m_fVelocityY;
355 else if (m_displayEffect == EFFECT_FLOAT)
357 m_fPosX += m_fVelocityX;
358 m_fPosY += m_fVelocityY;
359 float fMoveAmount = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount * m_iTotalFrames * 0.0001f;
360 if (m_fPosX > fMoveAmount)
362 m_fPosX = fMoveAmount;
363 m_fVelocityX = -m_fVelocityX;
365 if (m_fPosX < -fMoveAmount)
367 m_fPosX = -fMoveAmount;
368 m_fVelocityX = -m_fVelocityX;
370 if (m_fPosY > fMoveAmount)
372 m_fPosY = fMoveAmount;
373 m_fVelocityY = -m_fVelocityY;
375 if (m_fPosY < -fMoveAmount)
377 m_fPosY = -fMoveAmount;
378 m_fVelocityY = -m_fVelocityY;
381 else if (m_displayEffect == EFFECT_ZOOM)
383 m_fPosZ += m_fVelocityZ;
384 /* if (m_fPosZ > 1.0f + 0.01f*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount"))
386 m_fPosZ = 1.0f + 0.01f * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount");
387 m_fVelocityZ = -m_fVelocityZ;
389 if (m_fPosZ < 1.0f)
391 m_fPosZ = 1.0f;
392 m_fVelocityZ = -m_fVelocityZ;
396 if (m_displayEffect != EFFECT_NO_TIMEOUT && bPaused && !m_bTransitionImmediately)
397 { // paused - increment the last transition start time
398 m_transitionEnd.start++;
400 if (m_iCounter >= m_transitionEnd.start)
401 { // do end transition
402 // CLog::Log(LOGDEBUG,"Transitioning");
403 m_bDrawNextImage = true;
404 if (m_transitionEnd.type == CROSSFADE)
405 { // fade out at 1x speed
406 alpha = 255 - (UTILS::COLOR::Color)((float)(m_iCounter - m_transitionEnd.start) /
407 (float)m_transitionEnd.length * 255.0f);
409 else if (m_transitionEnd.type == FADEIN_FADEOUT)
410 { // keep solid, then fade out at 2x speed
411 alpha = (UTILS::COLOR::Color)(
412 (float)(m_transitionEnd.length - m_iCounter + m_transitionEnd.start) /
413 (float)m_transitionEnd.length * 255.0f * 2);
414 if (alpha > 255) alpha = 255;
416 else // m_transitionEffect == TRANSITION_NONE
418 alpha = 0xFF; // opaque
421 if (alpha != m_alpha)
423 m_alpha = alpha;
424 m_bIsDirty = true;
426 if (m_displayEffect != EFFECT_NO_TIMEOUT || m_iCounter < m_transitionStart.length || m_iCounter >= m_transitionEnd.start || (m_iCounter >= m_transitionTemp.start && m_iCounter < m_transitionTemp.start + m_transitionTemp.length))
428 /* this really annoying. there's non-stop logging when viewing a pic outside of the slideshow
429 if (m_displayEffect == EFFECT_NO_TIMEOUT)
430 CLog::Log(LOGDEBUG, "Incrementing counter ({}) while not in slideshow (startlength={},endstart={},endlength={})", m_iCounter, m_transitionStart.length, m_transitionEnd.start, m_transitionEnd.length);
432 m_iCounter++;
434 if (m_iCounter > m_transitionEnd.start + m_transitionEnd.length)
435 m_bIsFinished = true;
437 RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
439 // calculate where we should render (and how large it should be)
440 // calculate aspect ratio correction factor
441 float fOffsetX = (float)info.Overscan.left;
442 float fOffsetY = (float)info.Overscan.top;
443 float fScreenWidth = (float)info.Overscan.right - info.Overscan.left;
444 float fScreenHeight = (float)info.Overscan.bottom - info.Overscan.top;
445 float fPixelRatio = info.fPixelRatio;
447 // Rotate the image as needed
448 float x[4];
449 float y[4];
450 float si = sin(m_fAngle / 180.0f * static_cast<float>(M_PI));
451 float co = cos(m_fAngle / 180.0f * static_cast<float>(M_PI));
452 x[0] = -m_fWidth * co + m_fHeight * si;
453 y[0] = -m_fWidth * si - m_fHeight * co;
454 x[1] = m_fWidth * co + m_fHeight * si;
455 y[1] = m_fWidth * si - m_fHeight * co;
456 x[2] = m_fWidth * co - m_fHeight * si;
457 y[2] = m_fWidth * si + m_fHeight * co;
458 x[3] = -m_fWidth * co - m_fHeight * si;
459 y[3] = -m_fWidth * si + m_fHeight * co;
461 // calculate our scale amounts
462 float fSourceAR = m_fWidth / m_fHeight;
463 float fSourceInvAR = 1 / fSourceAR;
464 float fAR = si * si * (fSourceInvAR - fSourceAR) + fSourceAR;
466 //float fOutputFrameAR = fAR / fPixelRatio;
468 float fScaleNorm = fScreenWidth / m_fWidth;
469 float fScaleInv = fScreenWidth / m_fHeight;
471 bool bFillScreen = false;
472 float fComp = 1.0f + 0.01f * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowBlackBarCompensation;
473 float fScreenRatio = fScreenWidth / fScreenHeight * fPixelRatio;
474 // work out if we should be compensating the zoom to minimize blackbars
475 // we should compute this based on the % of black bars on screen perhaps??
476 //! @todo change m_displayEffect != EFFECT_NO_TIMEOUT to whether we're running the slideshow
477 if (m_displayEffect != EFFECT_NO_TIMEOUT && m_displayEffect != EFFECT_NONE && fScreenRatio < fSourceAR * fComp && fSourceAR < fScreenRatio * fComp)
478 bFillScreen = true;
479 if ((!bFillScreen && fScreenWidth*fPixelRatio > fScreenHeight*fSourceAR) || (bFillScreen && fScreenWidth*fPixelRatio < fScreenHeight*fSourceAR))
480 fScaleNorm = fScreenHeight / (m_fHeight * fPixelRatio);
481 bFillScreen = false;
482 if (m_displayEffect != EFFECT_NO_TIMEOUT && m_displayEffect != EFFECT_NONE && fScreenRatio < fSourceInvAR * fComp && fSourceInvAR < fScreenRatio * fComp)
483 bFillScreen = true;
484 if ((!bFillScreen && fScreenWidth*fPixelRatio > fScreenHeight*fSourceInvAR) || (bFillScreen && fScreenWidth*fPixelRatio < fScreenHeight*fSourceInvAR))
485 fScaleInv = fScreenHeight / (m_fWidth * fPixelRatio);
487 float fScale = si * si * (fScaleInv - fScaleNorm) + fScaleNorm;
488 // scale if we need to due to the effect we're using
489 if (m_displayEffect == EFFECT_PANORAMA)
491 if (m_fWidth > m_fHeight)
492 fScale *= m_fWidth / fScreenWidth * fScreenHeight / m_fHeight;
493 else
494 fScale *= m_fHeight / fScreenHeight * fScreenWidth / m_fWidth;
496 if (m_displayEffect == EFFECT_FLOAT)
497 fScale *= (1.0f + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount * m_iTotalFrames * 0.0001f);
498 if (m_displayEffect == EFFECT_ZOOM)
499 fScale *= m_fPosZ;
500 // zoom image
501 fScale *= m_fZoomAmount;
503 // calculate the resultant coordinates
504 for (int i = 0; i < 4; i++)
506 x[i] *= fScale * 0.5f; // as the offsets x[] and y[] are from center
507 y[i] *= fScale * fPixelRatio * 0.5f;
508 // center it
509 x[i] += 0.5f * fScreenWidth + fOffsetX;
510 y[i] += 0.5f * fScreenHeight + fOffsetY;
512 // shift if we're zooming
513 if (m_fZoomAmount > 1)
515 float minx = x[0];
516 float maxx = x[0];
517 float miny = y[0];
518 float maxy = y[0];
519 for (int i = 1; i < 4; i++)
521 if (x[i] < minx) minx = x[i];
522 if (x[i] > maxx) maxx = x[i];
523 if (y[i] < miny) miny = y[i];
524 if (y[i] > maxy) maxy = y[i];
526 float w = maxx - minx;
527 float h = maxy - miny;
528 m_bCanMoveHorizontally = (w >= fScreenWidth);
529 m_bCanMoveVertically = (h >= fScreenHeight);
530 if (w >= fScreenWidth)
531 { // must have no black bars
532 if (minx + m_fZoomLeft*w > fOffsetX)
533 m_fZoomLeft = (fOffsetX - minx) / w;
534 if (maxx + m_fZoomLeft*w < fOffsetX + fScreenWidth)
535 m_fZoomLeft = (fScreenWidth + fOffsetX - maxx) / w;
536 for (float& i : x)
537 i += w * m_fZoomLeft;
539 if (h >= fScreenHeight)
540 { // must have no black bars
541 if (miny + m_fZoomTop*h > fOffsetY)
542 m_fZoomTop = (fOffsetY - miny) / h;
543 if (maxy + m_fZoomTop*h < fOffsetY + fScreenHeight)
544 m_fZoomTop = (fScreenHeight + fOffsetY - maxy) / h;
545 for (float& i : y)
546 i += m_fZoomTop * h;
549 // add offset from display effects
550 for (int i = 0; i < 4; i++)
552 x[i] += m_fPosX * m_fWidth * fScale;
553 y[i] += m_fPosY * m_fHeight * fScale;
556 UpdateVertices(m_ax, m_ay, x, y, dirtyregions);
558 // now render the image in the top right corner if we're zooming
559 if (m_fZoomAmount == 1 || m_bIsComic)
561 const float empty[4] = {};
562 UpdateVertices(m_bx, m_by, empty, empty, dirtyregions);
563 UpdateVertices(m_sx, m_sy, empty, empty, dirtyregions);
564 UpdateVertices(m_ox, m_oy, empty, empty, dirtyregions);
565 m_bIsDirty = false;
566 return;
569 float sx[4], sy[4];
570 sx[0] = -m_fWidth * co + m_fHeight * si;
571 sy[0] = -m_fWidth * si - m_fHeight * co;
572 sx[1] = m_fWidth * co + m_fHeight * si;
573 sy[1] = m_fWidth * si - m_fHeight * co;
574 sx[2] = m_fWidth * co - m_fHeight * si;
575 sy[2] = m_fWidth * si + m_fHeight * co;
576 sx[3] = -m_fWidth * co - m_fHeight * si;
577 sy[3] = -m_fWidth * si + m_fHeight * co;
578 // convert to the appropriate scale
579 float fSmallArea = fScreenWidth * fScreenHeight / 50;
580 float fSmallWidth = sqrt(fSmallArea * fAR / fPixelRatio); // fAR*height = width, so total area*far = width*width
581 float fSmallHeight = fSmallArea / fSmallWidth;
582 float fSmallX = fOffsetX + fScreenWidth * 0.95f - fSmallWidth * 0.5f;
583 float fSmallY = fOffsetY + fScreenHeight * 0.05f + fSmallHeight * 0.5f;
584 fScaleNorm = fSmallWidth / m_fWidth;
585 fScaleInv = fSmallWidth / m_fHeight;
586 fScale = si * si * (fScaleInv - fScaleNorm) + fScaleNorm;
587 for (int i = 0; i < 4; i++)
589 sx[i] *= fScale * 0.5f;
590 sy[i] *= fScale * fPixelRatio * 0.5f;
592 // calculate a black border
593 float bx[4];
594 float by[4];
595 for (int i = 0; i < 4; i++)
597 if (sx[i] > 0)
598 bx[i] = sx[i] + 1;
599 else
600 bx[i] = sx[i] - 1;
601 if (sy[i] > 0)
602 by[i] = sy[i] + 1;
603 else
604 by[i] = sy[i] - 1;
605 sx[i] += fSmallX;
606 sy[i] += fSmallY;
607 bx[i] += fSmallX;
608 by[i] += fSmallY;
611 fSmallX -= fSmallWidth * 0.5f;
612 fSmallY -= fSmallHeight * 0.5f;
614 UpdateVertices(m_bx, m_by, bx, by, dirtyregions);
615 UpdateVertices(m_sx, m_sy, sx, sy, dirtyregions);
617 // now we must render the wireframe image of the view window
618 // work out the direction of the top of pic vector
619 float scale;
620 if (fabs(x[1] - x[0]) > fabs(x[3] - x[0]))
621 scale = (sx[1] - sx[0]) / (x[1] - x[0]);
622 else
623 scale = (sx[3] - sx[0]) / (x[3] - x[0]);
624 float ox[4];
625 float oy[4];
626 ox[0] = (fOffsetX - x[0]) * scale + sx[0];
627 oy[0] = (fOffsetY - y[0]) * scale + sy[0];
628 ox[1] = (fOffsetX + fScreenWidth - x[0]) * scale + sx[0];
629 oy[1] = (fOffsetY - y[0]) * scale + sy[0];
630 ox[2] = (fOffsetX + fScreenWidth - x[0]) * scale + sx[0];
631 oy[2] = (fOffsetY + fScreenHeight - y[0]) * scale + sy[0];
632 ox[3] = (fOffsetX - x[0]) * scale + sx[0];
633 oy[3] = (fOffsetY + fScreenHeight - y[0]) * scale + sy[0];
634 // crop to within the range of our piccy
635 for (int i = 0; i < 4; i++)
637 if (ox[i] < fSmallX) ox[i] = fSmallX;
638 if (ox[i] > fSmallX + fSmallWidth) ox[i] = fSmallX + fSmallWidth;
639 if (oy[i] < fSmallY) oy[i] = fSmallY;
640 if (oy[i] > fSmallY + fSmallHeight) oy[i] = fSmallY + fSmallHeight;
643 UpdateVertices(m_ox, m_oy, ox, oy, dirtyregions);
644 m_bIsDirty = false;
647 void CSlideShowPic::Keep()
649 // this is called if we need to keep the current pic on screen
650 // to wait for the next pic to load
651 if (!m_bDrawNextImage) return ; // don't need to keep pic
652 // hold off the start of the next frame
653 m_transitionEnd.start = m_iCounter;
656 bool CSlideShowPic::StartTransition()
658 // this is called if we need to start transitioning immediately to the new picture
659 if (m_bDrawNextImage) return false; // don't need to do anything as we are already transitioning
660 // decrease the number of display frame
661 m_transitionEnd.start = m_iCounter;
662 m_bTransitionImmediately = true;
663 return true;
666 void CSlideShowPic::Pause(bool bPause)
668 if (!m_bDrawNextImage)
669 m_bPause = bPause;
672 void CSlideShowPic::SetInSlideshow(bool slideshow)
674 if (slideshow && m_displayEffect == EFFECT_NO_TIMEOUT)
675 m_displayEffect = EFFECT_NONE;
678 int CSlideShowPic::GetTransitionTime(int iType) const
680 if (iType == 0) // start transition
681 return m_transitionStart.length;
682 else // iType == 1 // end transition
683 return m_transitionEnd.length;
686 void CSlideShowPic::SetTransitionTime(int iType, int iTime)
688 if (iType == 0) // start transition
689 m_transitionStart.length = iTime;
690 else // iType == 1 // end transition
691 m_transitionEnd.length = iTime;
694 void CSlideShowPic::Rotate(float fRotateAngle, bool immediate /* = false */)
696 if (m_bDrawNextImage) return;
697 if (m_transitionTemp.type == TRANSITION_ZOOM) return;
698 if (immediate)
700 m_fAngle += fRotateAngle;
701 return;
704 // if there is a rotation ongoing already
705 // add the new angle to the old destination angle
706 if (m_transitionTemp.type == TRANSITION_ROTATE &&
707 m_transitionTemp.start + m_transitionTemp.length > m_iCounter)
709 int remainder = m_transitionTemp.start + m_transitionTemp.length - m_iCounter;
710 fRotateAngle += m_fTransitionAngle * remainder;
713 m_transitionTemp.type = TRANSITION_ROTATE;
714 m_transitionTemp.start = m_iCounter;
715 m_transitionTemp.length = IMMEDIATE_TRANSITION_TIME;
716 m_fTransitionAngle = fRotateAngle / (float)m_transitionTemp.length;
717 // reset the timer
718 m_transitionEnd.start = m_iCounter + m_transitionStart.length + (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME));
721 void CSlideShowPic::Zoom(float fZoom, bool immediate /* = false */)
723 if (m_bDrawNextImage) return;
724 if (m_transitionTemp.type == TRANSITION_ROTATE) return;
725 if (immediate)
727 m_fZoomAmount = fZoom;
728 return;
730 m_transitionTemp.type = TRANSITION_ZOOM;
731 m_transitionTemp.start = m_iCounter;
732 m_transitionTemp.length = IMMEDIATE_TRANSITION_TIME;
733 m_fTransitionZoom = (fZoom - m_fZoomAmount) / (float)m_transitionTemp.length;
734 // reset the timer
735 m_transitionEnd.start = m_iCounter + m_transitionStart.length + (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME));
736 // turn off the render effects until we're back down to normal zoom
737 m_bNoEffect = true;
740 void CSlideShowPic::Move(float fDeltaX, float fDeltaY)
742 m_fZoomLeft += fDeltaX;
743 m_fZoomTop += fDeltaY;
744 // reset the timer
745 // m_transitionEnd.start = m_iCounter + m_transitionStart.length + (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME));
748 void CSlideShowPic::Render()
750 std::unique_lock<CCriticalSection> lock(m_textureAccess);
752 Render(m_ax, m_ay, m_pImage.get(), (m_alpha << 24) | 0xFFFFFF);
754 // now render the image in the top right corner if we're zooming
755 if (m_fZoomAmount == 1.0f || m_bIsComic) return ;
757 Render(m_bx, m_by, NULL, PICTURE_VIEW_BOX_BACKGROUND);
758 Render(m_sx, m_sy, m_pImage.get(), 0xFFFFFFFF);
759 Render(m_ox, m_oy, NULL, PICTURE_VIEW_BOX_COLOR);
762 #ifdef HAS_DX
763 bool CSlideShowPic::UpdateVertexBuffer(Vertex* vertices)
765 if (!m_vb) // create new
767 CD3D11_BUFFER_DESC desc(sizeof(Vertex) * 5, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
768 D3D11_SUBRESOURCE_DATA initData = {};
769 initData.pSysMem = vertices;
770 initData.SysMemPitch = sizeof(Vertex) * 5;
771 if (SUCCEEDED(DX::DeviceResources::Get()->GetD3DDevice()->CreateBuffer(&desc, &initData, m_vb.ReleaseAndGetAddressOf())))
772 return true;
774 else // update
776 ID3D11DeviceContext* pContext = DX::DeviceResources::Get()->GetD3DContext();
777 D3D11_MAPPED_SUBRESOURCE res;
778 if (SUCCEEDED(pContext->Map(m_vb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &res)))
780 memcpy(res.pData, vertices, sizeof(Vertex) * 5);
781 pContext->Unmap(m_vb.Get(), 0);
782 return true;
786 return false;
788 #endif
790 void CSlideShowPic::Render(float* x, float* y, CTexture* pTexture, UTILS::COLOR::Color color)
792 #ifdef HAS_DX
793 Vertex vertex[5];
794 for (int i = 0; i < 4; i++)
796 vertex[i].pos = XMFLOAT3( x[i], y[i], 0);
797 CD3DHelper::XMStoreColor(&vertex[i].color, color);
798 vertex[i].texCoord = XMFLOAT2(0.0f, 0.0f);
799 vertex[i].texCoord2 = XMFLOAT2(0.0f, 0.0f);
802 if (pTexture)
804 vertex[1].texCoord.x = vertex[2].texCoord.x = (float) pTexture->GetWidth() / pTexture->GetTextureWidth();
805 vertex[2].texCoord.y = vertex[3].texCoord.y = (float) pTexture->GetHeight() / pTexture->GetTextureHeight();
807 else
809 vertex[1].texCoord.x = vertex[2].texCoord.x = 1.0f;
810 vertex[2].texCoord.y = vertex[3].texCoord.y = 1.0f;
812 vertex[4] = vertex[0]; // Not used when pTexture != NULL
814 CGUIShaderDX* pGUIShader = DX::Windowing()->GetGUIShader();
815 pGUIShader->Begin(SHADER_METHOD_RENDER_TEXTURE_BLEND);
817 // Set state to render the image
818 if (pTexture)
820 pTexture->LoadToGPU();
821 CDXTexture* dxTexture = reinterpret_cast<CDXTexture*>(pTexture);
822 ID3D11ShaderResourceView* shaderRes = dxTexture->GetShaderResource();
823 pGUIShader->SetShaderViews(1, &shaderRes);
824 pGUIShader->DrawQuad(vertex[0], vertex[1], vertex[2], vertex[3]);
826 else
828 if (!UpdateVertexBuffer(vertex))
829 return;
831 ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetD3DContext();
833 unsigned stride = sizeof(Vertex);
834 unsigned offset = 0;
835 pContext->IASetVertexBuffers(0, 1, m_vb.GetAddressOf(), &stride, &offset);
836 pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
838 pGUIShader->Draw(5, 0);
839 pGUIShader->RestoreBuffers();
842 #elif defined(HAS_GL)
843 CRenderSystemGL *renderSystem = dynamic_cast<CRenderSystemGL*>(CServiceBroker::GetRenderSystem());
844 if (pTexture)
846 pTexture->LoadToGPU();
847 pTexture->BindToUnit(0);
849 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
850 glEnable(GL_BLEND);
852 renderSystem->EnableShader(ShaderMethodGL::SM_TEXTURE);
854 else
856 renderSystem->EnableShader(ShaderMethodGL::SM_DEFAULT);
859 float u1 = 0, u2 = 1, v1 = 0, v2 = 1;
860 if (pTexture)
862 u2 = (float)pTexture->GetWidth() / pTexture->GetTextureWidth();
863 v2 = (float)pTexture->GetHeight() / pTexture->GetTextureHeight();
866 GLubyte colour[4];
867 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of the vertices
868 GLuint vertexVBO;
869 GLuint indexVBO;
870 struct PackedVertex
872 float x, y, z;
873 float u1, v1;
874 } vertex[4];
876 // Setup vertex position values
877 vertex[0].x = x[0];
878 vertex[0].y = y[0];
879 vertex[0].z = 0;
880 vertex[0].u1 = u1;
881 vertex[0].v1 = v1;
883 vertex[1].x = x[1];
884 vertex[1].y = y[1];
885 vertex[1].z = 0;
886 vertex[1].u1 = u2;
887 vertex[1].v1 = v1;
889 vertex[2].x = x[2];
890 vertex[2].y = y[2];
891 vertex[2].z = 0;
892 vertex[2].u1 = u2;
893 vertex[2].v1 = v2;
895 vertex[3].x = x[3];
896 vertex[3].y = y[3];
897 vertex[3].z = 0;
898 vertex[3].u1 = u1;
899 vertex[3].v1 = v2;
901 GLint posLoc = renderSystem->ShaderGetPos();
902 GLint tex0Loc = renderSystem->ShaderGetCoord0();
903 GLint uniColLoc= renderSystem->ShaderGetUniCol();
905 glGenBuffers(1, &vertexVBO);
906 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
907 glBufferData(GL_ARRAY_BUFFER, sizeof(PackedVertex)*4, &vertex[0], GL_STATIC_DRAW);
909 glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, sizeof(PackedVertex),
910 reinterpret_cast<const GLvoid*>(offsetof(PackedVertex, x)));
911 glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, 0, sizeof(PackedVertex),
912 reinterpret_cast<const GLvoid*>(offsetof(PackedVertex, u1)));
914 glEnableVertexAttribArray(posLoc);
915 glEnableVertexAttribArray(tex0Loc);
917 // Setup Colour values
918 colour[0] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::R, color);
919 colour[1] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::G, color);
920 colour[2] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::B, color);
921 colour[3] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::A, color);
923 glUniform4f(uniColLoc,(colour[0] / 255.0f), (colour[1] / 255.0f),
924 (colour[2] / 255.0f), (colour[3] / 255.0f));
926 glGenBuffers(1, &indexVBO);
927 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
928 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte)*4, idx, GL_STATIC_DRAW);
930 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0);
932 glDisableVertexAttribArray(posLoc);
933 glDisableVertexAttribArray(tex0Loc);
935 glBindBuffer(GL_ARRAY_BUFFER, 0);
936 glDeleteBuffers(1, &vertexVBO);
937 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
938 glDeleteBuffers(1, &indexVBO);
940 renderSystem->DisableShader();
942 #elif defined(HAS_GLES)
943 CRenderSystemGLES *renderSystem = dynamic_cast<CRenderSystemGLES*>(CServiceBroker::GetRenderSystem());
944 if (pTexture)
946 pTexture->LoadToGPU();
947 pTexture->BindToUnit(0);
949 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
950 glEnable(GL_BLEND); // Turn Blending On
952 renderSystem->EnableGUIShader(ShaderMethodGLES::SM_TEXTURE);
954 else
956 renderSystem->EnableGUIShader(ShaderMethodGLES::SM_DEFAULT);
959 float u1 = 0, u2 = 1, v1 = 0, v2 = 1;
960 if (pTexture)
962 u2 = (float)pTexture->GetWidth() / pTexture->GetTextureWidth();
963 v2 = (float)pTexture->GetHeight() / pTexture->GetTextureHeight();
966 GLubyte col[4];
967 GLfloat ver[4][3];
968 GLfloat tex[4][2];
969 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
971 GLint posLoc = renderSystem->GUIShaderGetPos();
972 GLint tex0Loc = renderSystem->GUIShaderGetCoord0();
973 GLint uniColLoc= renderSystem->GUIShaderGetUniCol();
975 glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, ver);
976 glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, 0, 0, tex);
978 glEnableVertexAttribArray(posLoc);
979 glEnableVertexAttribArray(tex0Loc);
981 // Setup Colour values
982 col[0] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::R, color);
983 col[1] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::G, color);
984 col[2] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::B, color);
985 col[3] = KODI::UTILS::GL::GetChannelFromARGB(KODI::UTILS::GL::ColorChannel::A, color);
987 if (CServiceBroker::GetWinSystem()->UseLimitedColor())
989 col[0] = (235 - 16) * col[0] / 255 + 16;
990 col[1] = (235 - 16) * col[1] / 255 + 16;
991 col[2] = (235 - 16) * col[2] / 255 + 16;
994 for (int i=0; i<4; i++)
996 // Setup vertex position values
997 ver[i][0] = x[i];
998 ver[i][1] = y[i];
999 ver[i][2] = 0.0f;
1001 // Setup texture coordinates
1002 tex[0][0] = tex[3][0] = u1;
1003 tex[0][1] = tex[1][1] = v1;
1004 tex[1][0] = tex[2][0] = u2;
1005 tex[2][1] = tex[3][1] = v2;
1007 glUniform4f(uniColLoc,(col[0] / 255.0f), (col[1] / 255.0f), (col[2] / 255.0f), (col[3] / 255.0f));
1008 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1010 glDisableVertexAttribArray(posLoc);
1011 glDisableVertexAttribArray(tex0Loc);
1013 renderSystem->DisableGUIShader();
1015 #endif