2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "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"
21 #ifndef _USE_MATH_DEFINES
22 #define _USE_MATH_DEFINES
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
;
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
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)
58 m_bIsFinished
= false;
59 m_bDrawNextImage
= false;
60 m_bTransitionImmediately
= false;
62 m_bCanMoveHorizontally
= false;
63 m_bCanMoveVertically
= false;
66 CSlideShowPic::~CSlideShowPic()
71 void CSlideShowPic::Close()
73 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
76 m_bIsFinished
= false;
77 m_bDrawNextImage
= false;
78 m_bTransitionImmediately
= false;
86 void CSlideShowPic::Reset(DISPLAY_EFFECT dispEffect
, TRANSITION_EFFECT transEffect
)
88 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
90 SetTexture_Internal(m_iSlideNumber
, std::move(m_pImage
), dispEffect
, transEffect
);
95 bool CSlideShowPic::DisplayEffectNeedChange(DISPLAY_EFFECT newDispEffect
) const
97 if (m_displayEffect
== newDispEffect
)
99 if (newDispEffect
== EFFECT_RANDOM
&& m_displayEffect
!= EFFECT_NONE
&& m_displayEffect
!= EFFECT_NO_TIMEOUT
)
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
);
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
);
122 m_bTransitionImmediately
= false;
123 m_iSlideNumber
= iSlideNumber
;
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();
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
;
145 m_displayEffect
= (DISPLAY_EFFECT
)((rand() % (EFFECT_RANDOM
- 1)) + 1);
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;
161 if (m_pImage
->GetOrientation() == 7)
162 { // rotate to 270 degrees
165 if (m_pImage
->GetOrientation() == 2)
166 { // rotate to 180 degrees
169 if (m_pImage
->GetOrientation() == 5)
170 { // rotate to 90 degrees
176 m_fPosX
= m_fPosY
= 0.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
;
194 m_fVelocityX
= -m_fPosX
* 2.0f
/ m_iTotalFrames
;
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
;
204 m_fVelocityY
= -m_fPosY
* 2.0f
/ m_iTotalFrames
;
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
)
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;
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
);
246 return m_iOriginalHeight
;
248 return m_iOriginalWidth
;
251 int CSlideShowPic::GetOriginalHeight()
253 int iAngle
= (int)(m_fAngle
/ 90.0f
+ 0.4f
);
255 return m_iOriginalWidth
;
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());
269 static CRect
GetRectangle(const float x
[4], const float y
[4])
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);
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
)
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
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
)
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.
326 for (i
= 0; i
< 10; i
++)
328 if (fabs(m_fZoomAmount
- zoomamount
[i
]) < 0.01f
* zoomamount
[i
])
330 m_fZoomAmount
= zoomamount
[i
];
334 m_bNoEffect
= (m_fZoomAmount
!= 1.0f
); // turn effect rendering back on.
336 m_transitionTemp
.type
= TRANSITION_NONE
;
340 if (m_transitionTemp
.type
== TRANSITION_ROTATE
)
341 m_fAngle
+= m_fTransitionAngle
;
342 if (m_transitionTemp
.type
== TRANSITION_ZOOM
)
343 m_fZoomAmount
+= m_fTransitionZoom
;
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;
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
)
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);
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
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
)
479 if ((!bFillScreen
&& fScreenWidth
*fPixelRatio
> fScreenHeight
*fSourceAR
) || (bFillScreen
&& fScreenWidth
*fPixelRatio
< fScreenHeight
*fSourceAR
))
480 fScaleNorm
= fScreenHeight
/ (m_fHeight
* fPixelRatio
);
482 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& m_displayEffect
!= EFFECT_NONE
&& fScreenRatio
< fSourceInvAR
* fComp
&& fSourceInvAR
< fScreenRatio
* fComp
)
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
;
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
)
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
;
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)
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
;
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
;
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
);
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
595 for (int i
= 0; i
< 4; i
++)
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
620 if (fabs(x
[1] - x
[0]) > fabs(x
[3] - x
[0]))
621 scale
= (sx
[1] - sx
[0]) / (x
[1] - x
[0]);
623 scale
= (sx
[3] - sx
[0]) / (x
[3] - x
[0]);
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
);
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;
666 void CSlideShowPic::Pause(bool bPause
)
668 if (!m_bDrawNextImage
)
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;
700 m_fAngle
+= fRotateAngle
;
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
;
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;
727 m_fZoomAmount
= fZoom
;
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
;
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
740 void CSlideShowPic::Move(float fDeltaX
, float fDeltaY
)
742 m_fZoomLeft
+= fDeltaX
;
743 m_fZoomTop
+= fDeltaY
;
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
);
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())))
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);
790 void CSlideShowPic::Render(float* x
, float* y
, CTexture
* pTexture
, UTILS::COLOR::Color color
)
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
);
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();
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
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]);
828 if (!UpdateVertexBuffer(vertex
))
831 ComPtr
<ID3D11DeviceContext
> pContext
= DX::DeviceResources::Get()->GetD3DContext();
833 unsigned stride
= sizeof(Vertex
);
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());
846 pTexture
->LoadToGPU();
847 pTexture
->BindToUnit(0);
849 glBlendFunc(GL_SRC_ALPHA
,GL_ONE_MINUS_SRC_ALPHA
);
852 renderSystem
->EnableShader(ShaderMethodGL::SM_TEXTURE
);
856 renderSystem
->EnableShader(ShaderMethodGL::SM_DEFAULT
);
859 float u1
= 0, u2
= 1, v1
= 0, v2
= 1;
862 u2
= (float)pTexture
->GetWidth() / pTexture
->GetTextureWidth();
863 v2
= (float)pTexture
->GetHeight() / pTexture
->GetTextureHeight();
867 GLubyte idx
[4] = {0, 1, 3, 2}; //determines order of the vertices
876 // Setup vertex position values
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());
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
);
956 renderSystem
->EnableGUIShader(ShaderMethodGLES::SM_DEFAULT
);
959 float u1
= 0, u2
= 1, v1
= 0, v2
= 1;
962 u2
= (float)pTexture
->GetWidth() / pTexture
->GetTextureWidth();
963 v2
= (float)pTexture
->GetHeight() / pTexture
->GetTextureHeight();
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
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();