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"
22 #ifndef _USE_MATH_DEFINES
23 #define _USE_MATH_DEFINES
28 #define IMMEDIATE_TRANSITION_TIME 20
30 #define PICTURE_MOVE_AMOUNT 0.02f
31 #define PICTURE_MOVE_AMOUNT_ANALOG 0.01f
32 #define PICTURE_VIEW_BOX_COLOR 0xffffff00 // YELLOW
33 #define PICTURE_VIEW_BOX_BACKGROUND 0xff000000 // BLACK
37 static float zoomamount
[10] = { 1.0f
, 1.2f
, 1.5f
, 2.0f
, 2.8f
, 4.0f
, 6.0f
, 9.0f
, 13.5f
, 20.0f
};
39 CSlideShowPic::CSlideShowPic() : m_pImage(nullptr)
42 m_bDrawNextImage
= false;
43 m_bTransitionImmediately
= false;
45 m_bCanMoveHorizontally
= false;
46 m_bCanMoveVertically
= false;
49 CSlideShowPic::~CSlideShowPic()
54 void CSlideShowPic::Close()
56 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
59 m_bDrawNextImage
= false;
60 m_bTransitionImmediately
= false;
65 void CSlideShowPic::Reset(DISPLAY_EFFECT dispEffect
, TRANSITION_EFFECT transEffect
)
67 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
69 SetTexture_Internal(m_iSlideNumber
, std::move(m_pImage
), dispEffect
, transEffect
);
74 bool CSlideShowPic::DisplayEffectNeedChange(DISPLAY_EFFECT newDispEffect
) const
76 if (m_displayEffect
== newDispEffect
)
78 if (newDispEffect
== EFFECT_RANDOM
&& m_displayEffect
!= EFFECT_NONE
&& m_displayEffect
!= EFFECT_NO_TIMEOUT
)
83 bool CSlideShowPic::IsFinished() const
85 return IsLoaded() && m_iCounter
>= m_transitionEnd
.start
+ m_transitionEnd
.length
;
88 bool CSlideShowPic::IsAnimating() const
90 return !IsFinished() &&
91 (m_displayEffect
!= EFFECT_NO_TIMEOUT
|| // Special snowflake, doesn't work without this
92 m_iCounter
< m_transitionStart
.length
|| // Inside start transition
93 m_iCounter
>= m_transitionEnd
.start
|| // Inside end transition
94 (m_iCounter
>= m_transitionTemp
.start
&&
95 m_iCounter
< m_transitionTemp
.start
+ m_transitionTemp
.length
)); // Inside display effect
98 void CSlideShowPic::SetTexture(int iSlideNumber
,
99 std::unique_ptr
<CTexture
> pTexture
,
100 DISPLAY_EFFECT dispEffect
,
101 TRANSITION_EFFECT transEffect
)
103 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
105 SetTexture_Internal(iSlideNumber
, std::move(pTexture
), dispEffect
, transEffect
);
108 void CSlideShowPic::SetTexture_Internal(int iSlideNumber
,
109 std::unique_ptr
<CTexture
> pTexture
,
110 DISPLAY_EFFECT dispEffect
,
111 TRANSITION_EFFECT transEffect
)
113 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
116 m_bTransitionImmediately
= false;
117 m_iSlideNumber
= iSlideNumber
;
120 m_pImage
= std::move(pTexture
);
121 m_fWidth
= static_cast<float>(m_pImage
->GetWidth());
122 m_fHeight
= static_cast<float>(m_pImage
->GetHeight());
123 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_HIGHQUALITYDOWNSCALING
))
124 { // activate mipmapping when high quality downscaling is 'on'
125 m_pImage
->SetMipmapping();
129 // initialize our transition effect
130 m_transitionStart
.type
= transEffect
;
131 m_transitionStart
.start
= 0;
133 // initialize our display effect
134 if (dispEffect
== EFFECT_RANDOM
)
136 if (((m_fWidth
/ m_fHeight
) > 1.9f
) || ((m_fHeight
/ m_fWidth
) > 1.9f
))
137 m_displayEffect
= EFFECT_PANORAMA
;
139 m_displayEffect
= (DISPLAY_EFFECT
)((rand() % (EFFECT_RANDOM
- 1)) + 1);
142 m_displayEffect
= dispEffect
;
144 // the +1's make sure it actually occurs
145 float fadeTime
= 0.2f
;
146 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
)
147 fadeTime
= std::min(0.2f
*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
), 3.0f
);
148 m_transitionStart
.length
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * fadeTime
); // transition time in frames
149 m_transitionEnd
.type
= transEffect
;
150 m_transitionEnd
.length
= m_transitionStart
.length
;
151 m_transitionTemp
.type
= TRANSITION_NONE
;
152 m_fTransitionAngle
= 0;
153 m_fTransitionZoom
= 0;
155 if (m_pImage
->GetOrientation() == 7)
156 { // rotate to 270 degrees
159 if (m_pImage
->GetOrientation() == 2)
160 { // rotate to 180 degrees
163 if (m_pImage
->GetOrientation() == 5)
164 { // rotate to 90 degrees
170 m_fPosX
= m_fPosY
= 0.0f
;
172 m_fVelocityX
= m_fVelocityY
= m_fVelocityZ
= 0.0f
;
173 int iFrames
= std::max((int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
)), 1);
174 if (m_displayEffect
== EFFECT_PANORAMA
)
176 RESOLUTION_INFO res
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
177 float fScreenWidth
= (float)res
.Overscan
.right
- res
.Overscan
.left
;
178 float fScreenHeight
= (float)res
.Overscan
.bottom
- res
.Overscan
.top
;
180 if (m_fWidth
> m_fHeight
)
182 iFrames
= (int)(iFrames
* (m_fWidth
- m_fHeight
) / m_fHeight
);
183 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
185 m_fPosX
= 0.5f
- (fScreenWidth
/ fScreenHeight
) * (m_fHeight
/ m_fWidth
) * 0.5f
;
188 m_fVelocityX
= -m_fPosX
* 2.0f
/ m_iTotalFrames
;
192 iFrames
= (int)(iFrames
* (m_fHeight
- (0.5f
* m_fWidth
)) / m_fWidth
);
193 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
195 m_fPosY
= 0.5f
- (fScreenHeight
/ fScreenWidth
) * (m_fWidth
/ m_fHeight
) * 0.5f
;
198 m_fVelocityY
= -m_fPosY
* 2.0f
/ m_iTotalFrames
;
203 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
205 if (m_displayEffect
== EFFECT_FLOAT
)
207 // Calculate start and end positions
208 // choose a random direction
209 float angle
= (rand() % 1000) / 1000.0f
* 2 * (float)M_PI
;
210 m_fPosX
= cos(angle
) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.00005f
;
211 m_fPosY
= sin(angle
) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.00005f
;
212 m_fVelocityX
= -m_fPosX
* 2.0f
/ m_iTotalFrames
;
213 m_fVelocityY
= -m_fPosY
* 2.0f
/ m_iTotalFrames
;
215 else if (m_displayEffect
== EFFECT_ZOOM
)
218 m_fVelocityZ
= 0.0001f
* CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowZoomAmount
;
222 m_transitionEnd
.start
= m_transitionStart
.length
+ iFrames
;
224 m_bDrawNextImage
= false;
228 void CSlideShowPic::SetOriginalSize(int iOriginalWidth
, int iOriginalHeight
, bool bFullSize
)
230 m_iOriginalWidth
= iOriginalWidth
;
231 m_iOriginalHeight
= iOriginalHeight
;
232 m_bFullSize
= bFullSize
;
235 int CSlideShowPic::GetOriginalWidth()
237 int iAngle
= (int)(m_fAngle
/ 90.0f
+ 0.4f
);
239 return m_iOriginalHeight
;
241 return m_iOriginalWidth
;
244 int CSlideShowPic::GetOriginalHeight()
246 int iAngle
= (int)(m_fAngle
/ 90.0f
+ 0.4f
);
248 return m_iOriginalWidth
;
250 return m_iOriginalHeight
;
253 void CSlideShowPic::UpdateTexture(std::unique_ptr
<CTexture
> pTexture
)
255 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
256 m_pImage
= std::move(pTexture
);
257 m_fWidth
= static_cast<float>(m_pImage
->GetWidth());
258 m_fHeight
= static_cast<float>(m_pImage
->GetHeight());
262 static CRect
GetRectangle(const float x
[4], const float y
[4])
265 rect
.x1
= *std::min_element(x
, x
+4);
266 rect
.y1
= *std::min_element(y
, y
+4);
267 rect
.x2
= *std::max_element(x
, x
+4);
268 rect
.y2
= *std::max_element(y
, y
+4);
272 void CSlideShowPic::UpdateVertices(float cur_x
[4], float cur_y
[4], const float new_x
[4], const float new_y
[4], CDirtyRegionList
&dirtyregions
)
274 const size_t count
= sizeof(float)*4;
275 if(memcmp(cur_x
, new_x
, count
)
276 || memcmp(cur_y
, new_y
, count
)
279 dirtyregions
.emplace_back(GetRectangle(cur_x
, cur_y
));
280 dirtyregions
.emplace_back(GetRectangle(new_x
, new_y
));
281 memcpy(cur_x
, new_x
, count
);
282 memcpy(cur_y
, new_y
, count
);
286 void CSlideShowPic::Process(unsigned int currentTime
, CDirtyRegionList
&dirtyregions
)
288 if (!m_pImage
|| !m_bIsLoaded
|| IsFinished())
293 bool bPaused
= m_bPause
| (m_fZoomAmount
!= 1.0f
);
294 // check if we're doing a temporary effect (such as rotate + zoom)
295 if (m_transitionTemp
.type
!= TRANSITION_NONE
)
298 if (m_iCounter
>= m_transitionTemp
.start
)
300 if (m_iCounter
>= m_transitionTemp
.start
+ m_transitionTemp
.length
)
301 { // we're finished this transition
302 if (m_transitionTemp
.type
== TRANSITION_ZOOM
)
303 { // correct for any introduced inaccuracies.
305 for (i
= 0; i
< 10; i
++)
307 if (fabs(m_fZoomAmount
- zoomamount
[i
]) < 0.01f
* zoomamount
[i
])
309 m_fZoomAmount
= zoomamount
[i
];
313 m_bNoEffect
= (m_fZoomAmount
!= 1.0f
); // turn effect rendering back on.
315 m_transitionTemp
.type
= TRANSITION_NONE
;
319 if (m_transitionTemp
.type
== TRANSITION_ROTATE
)
320 m_fAngle
+= m_fTransitionAngle
;
321 if (m_transitionTemp
.type
== TRANSITION_ZOOM
)
322 m_fZoomAmount
+= m_fTransitionZoom
;
327 if (!m_bNoEffect
&& !bPaused
)
329 if (m_displayEffect
== EFFECT_PANORAMA
)
331 m_fPosX
+= m_fVelocityX
;
332 m_fPosY
+= m_fVelocityY
;
334 else if (m_displayEffect
== EFFECT_FLOAT
)
336 m_fPosX
+= m_fVelocityX
;
337 m_fPosY
+= m_fVelocityY
;
338 float fMoveAmount
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.0001f
;
339 if (m_fPosX
> fMoveAmount
)
341 m_fPosX
= fMoveAmount
;
342 m_fVelocityX
= -m_fVelocityX
;
344 if (m_fPosX
< -fMoveAmount
)
346 m_fPosX
= -fMoveAmount
;
347 m_fVelocityX
= -m_fVelocityX
;
349 if (m_fPosY
> fMoveAmount
)
351 m_fPosY
= fMoveAmount
;
352 m_fVelocityY
= -m_fVelocityY
;
354 if (m_fPosY
< -fMoveAmount
)
356 m_fPosY
= -fMoveAmount
;
357 m_fVelocityY
= -m_fVelocityY
;
360 else if (m_displayEffect
== EFFECT_ZOOM
)
362 m_fPosZ
+= m_fVelocityZ
;
363 /* if (m_fPosZ > 1.0f + 0.01f*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount"))
365 m_fPosZ = 1.0f + 0.01f * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount");
366 m_fVelocityZ = -m_fVelocityZ;
371 m_fVelocityZ = -m_fVelocityZ;
375 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& bPaused
&& !m_bTransitionImmediately
)
376 { // paused - increment the last transition start time
377 m_transitionEnd
.start
++;
379 if (m_iCounter
>= m_transitionEnd
.start
)
380 m_bDrawNextImage
= true;
383 /* this really annoying. there's non-stop logging when viewing a pic outside of the slideshow
384 if (m_displayEffect == EFFECT_NO_TIMEOUT)
385 CLog::Log(LOGDEBUG, "Incrementing counter ({}) while not in slideshow (startlength={},endstart={},endlength={})", m_iCounter, m_transitionStart.length, m_transitionEnd.start, m_transitionEnd.length);
390 RESOLUTION_INFO info
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
392 // calculate where we should render (and how large it should be)
393 // calculate aspect ratio correction factor
394 float fOffsetX
= (float)info
.Overscan
.left
;
395 float fOffsetY
= (float)info
.Overscan
.top
;
396 float fScreenWidth
= (float)info
.Overscan
.right
- info
.Overscan
.left
;
397 float fScreenHeight
= (float)info
.Overscan
.bottom
- info
.Overscan
.top
;
398 float fPixelRatio
= info
.fPixelRatio
;
400 // Rotate the image as needed
403 float si
= sin(m_fAngle
/ 180.0f
* static_cast<float>(M_PI
));
404 float co
= cos(m_fAngle
/ 180.0f
* static_cast<float>(M_PI
));
405 x
[0] = -m_fWidth
* co
+ m_fHeight
* si
;
406 y
[0] = -m_fWidth
* si
- m_fHeight
* co
;
407 x
[1] = m_fWidth
* co
+ m_fHeight
* si
;
408 y
[1] = m_fWidth
* si
- m_fHeight
* co
;
409 x
[2] = m_fWidth
* co
- m_fHeight
* si
;
410 y
[2] = m_fWidth
* si
+ m_fHeight
* co
;
411 x
[3] = -m_fWidth
* co
- m_fHeight
* si
;
412 y
[3] = -m_fWidth
* si
+ m_fHeight
* co
;
414 // calculate our scale amounts
415 float fSourceAR
= m_fWidth
/ m_fHeight
;
416 float fSourceInvAR
= 1 / fSourceAR
;
417 float fAR
= si
* si
* (fSourceInvAR
- fSourceAR
) + fSourceAR
;
419 //float fOutputFrameAR = fAR / fPixelRatio;
421 float fScaleNorm
= fScreenWidth
/ m_fWidth
;
422 float fScaleInv
= fScreenWidth
/ m_fHeight
;
424 bool bFillScreen
= false;
425 float fComp
= 1.0f
+ 0.01f
* CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowBlackBarCompensation
;
426 float fScreenRatio
= fScreenWidth
/ fScreenHeight
* fPixelRatio
;
427 // work out if we should be compensating the zoom to minimize blackbars
428 // we should compute this based on the % of black bars on screen perhaps??
429 //! @todo change m_displayEffect != EFFECT_NO_TIMEOUT to whether we're running the slideshow
430 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& m_displayEffect
!= EFFECT_NONE
&& fScreenRatio
< fSourceAR
* fComp
&& fSourceAR
< fScreenRatio
* fComp
)
432 if ((!bFillScreen
&& fScreenWidth
*fPixelRatio
> fScreenHeight
*fSourceAR
) || (bFillScreen
&& fScreenWidth
*fPixelRatio
< fScreenHeight
*fSourceAR
))
433 fScaleNorm
= fScreenHeight
/ (m_fHeight
* fPixelRatio
);
435 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& m_displayEffect
!= EFFECT_NONE
&& fScreenRatio
< fSourceInvAR
* fComp
&& fSourceInvAR
< fScreenRatio
* fComp
)
437 if ((!bFillScreen
&& fScreenWidth
*fPixelRatio
> fScreenHeight
*fSourceInvAR
) || (bFillScreen
&& fScreenWidth
*fPixelRatio
< fScreenHeight
*fSourceInvAR
))
438 fScaleInv
= fScreenHeight
/ (m_fWidth
* fPixelRatio
);
440 float fScale
= si
* si
* (fScaleInv
- fScaleNorm
) + fScaleNorm
;
441 // scale if we need to due to the effect we're using
442 if (m_displayEffect
== EFFECT_PANORAMA
)
444 if (m_fWidth
> m_fHeight
)
445 fScale
*= m_fWidth
/ fScreenWidth
* fScreenHeight
/ m_fHeight
;
447 fScale
*= m_fHeight
/ fScreenHeight
* fScreenWidth
/ m_fWidth
;
449 if (m_displayEffect
== EFFECT_FLOAT
)
450 fScale
*= (1.0f
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.0001f
);
451 if (m_displayEffect
== EFFECT_ZOOM
)
454 fScale
*= m_fZoomAmount
;
456 // calculate the resultant coordinates
457 for (int i
= 0; i
< 4; i
++)
459 x
[i
] *= fScale
* 0.5f
; // as the offsets x[] and y[] are from center
460 y
[i
] *= fScale
* fPixelRatio
* 0.5f
;
462 x
[i
] += 0.5f
* fScreenWidth
+ fOffsetX
;
463 y
[i
] += 0.5f
* fScreenHeight
+ fOffsetY
;
465 // shift if we're zooming
466 if (m_fZoomAmount
> 1)
472 for (int i
= 1; i
< 4; i
++)
474 if (x
[i
] < minx
) minx
= x
[i
];
475 if (x
[i
] > maxx
) maxx
= x
[i
];
476 if (y
[i
] < miny
) miny
= y
[i
];
477 if (y
[i
] > maxy
) maxy
= y
[i
];
479 float w
= maxx
- minx
;
480 float h
= maxy
- miny
;
481 m_bCanMoveHorizontally
= (w
>= fScreenWidth
);
482 m_bCanMoveVertically
= (h
>= fScreenHeight
);
483 if (w
>= fScreenWidth
)
484 { // must have no black bars
485 if (minx
+ m_fZoomLeft
*w
> fOffsetX
)
486 m_fZoomLeft
= (fOffsetX
- minx
) / w
;
487 if (maxx
+ m_fZoomLeft
*w
< fOffsetX
+ fScreenWidth
)
488 m_fZoomLeft
= (fScreenWidth
+ fOffsetX
- maxx
) / w
;
490 i
+= w
* m_fZoomLeft
;
492 if (h
>= fScreenHeight
)
493 { // must have no black bars
494 if (miny
+ m_fZoomTop
*h
> fOffsetY
)
495 m_fZoomTop
= (fOffsetY
- miny
) / h
;
496 if (maxy
+ m_fZoomTop
*h
< fOffsetY
+ fScreenHeight
)
497 m_fZoomTop
= (fScreenHeight
+ fOffsetY
- maxy
) / h
;
502 // add offset from display effects
503 for (int i
= 0; i
< 4; i
++)
505 x
[i
] += m_fPosX
* m_fWidth
* fScale
;
506 y
[i
] += m_fPosY
* m_fHeight
* fScale
;
509 UpdateVertices(m_ax
, m_ay
, x
, y
, dirtyregions
);
511 // now render the image in the top right corner if we're zooming
512 if (m_fZoomAmount
== 1 || m_bIsComic
)
514 const float empty
[4] = {};
515 UpdateVertices(m_bx
, m_by
, empty
, empty
, dirtyregions
);
516 UpdateVertices(m_sx
, m_sy
, empty
, empty
, dirtyregions
);
517 UpdateVertices(m_ox
, m_oy
, empty
, empty
, dirtyregions
);
523 sx
[0] = -m_fWidth
* co
+ m_fHeight
* si
;
524 sy
[0] = -m_fWidth
* si
- m_fHeight
* co
;
525 sx
[1] = m_fWidth
* co
+ m_fHeight
* si
;
526 sy
[1] = m_fWidth
* si
- m_fHeight
* co
;
527 sx
[2] = m_fWidth
* co
- m_fHeight
* si
;
528 sy
[2] = m_fWidth
* si
+ m_fHeight
* co
;
529 sx
[3] = -m_fWidth
* co
- m_fHeight
* si
;
530 sy
[3] = -m_fWidth
* si
+ m_fHeight
* co
;
531 // convert to the appropriate scale
532 float fSmallArea
= fScreenWidth
* fScreenHeight
/ 50;
533 float fSmallWidth
= sqrt(fSmallArea
* fAR
/ fPixelRatio
); // fAR*height = width, so total area*far = width*width
534 float fSmallHeight
= fSmallArea
/ fSmallWidth
;
535 float fSmallX
= fOffsetX
+ fScreenWidth
* 0.95f
- fSmallWidth
* 0.5f
;
536 float fSmallY
= fOffsetY
+ fScreenHeight
* 0.05f
+ fSmallHeight
* 0.5f
;
537 fScaleNorm
= fSmallWidth
/ m_fWidth
;
538 fScaleInv
= fSmallWidth
/ m_fHeight
;
539 fScale
= si
* si
* (fScaleInv
- fScaleNorm
) + fScaleNorm
;
540 for (int i
= 0; i
< 4; i
++)
542 sx
[i
] *= fScale
* 0.5f
;
543 sy
[i
] *= fScale
* fPixelRatio
* 0.5f
;
545 // calculate a black border
548 for (int i
= 0; i
< 4; i
++)
564 fSmallX
-= fSmallWidth
* 0.5f
;
565 fSmallY
-= fSmallHeight
* 0.5f
;
567 UpdateVertices(m_bx
, m_by
, bx
, by
, dirtyregions
);
568 UpdateVertices(m_sx
, m_sy
, sx
, sy
, dirtyregions
);
570 // now we must render the wireframe image of the view window
571 // work out the direction of the top of pic vector
573 if (fabs(x
[1] - x
[0]) > fabs(x
[3] - x
[0]))
574 scale
= (sx
[1] - sx
[0]) / (x
[1] - x
[0]);
576 scale
= (sx
[3] - sx
[0]) / (x
[3] - x
[0]);
579 ox
[0] = (fOffsetX
- x
[0]) * scale
+ sx
[0];
580 oy
[0] = (fOffsetY
- y
[0]) * scale
+ sy
[0];
581 ox
[1] = (fOffsetX
+ fScreenWidth
- x
[0]) * scale
+ sx
[0];
582 oy
[1] = (fOffsetY
- y
[0]) * scale
+ sy
[0];
583 ox
[2] = (fOffsetX
+ fScreenWidth
- x
[0]) * scale
+ sx
[0];
584 oy
[2] = (fOffsetY
+ fScreenHeight
- y
[0]) * scale
+ sy
[0];
585 ox
[3] = (fOffsetX
- x
[0]) * scale
+ sx
[0];
586 oy
[3] = (fOffsetY
+ fScreenHeight
- y
[0]) * scale
+ sy
[0];
587 // crop to within the range of our piccy
588 for (int i
= 0; i
< 4; i
++)
590 if (ox
[i
] < fSmallX
) ox
[i
] = fSmallX
;
591 if (ox
[i
] > fSmallX
+ fSmallWidth
) ox
[i
] = fSmallX
+ fSmallWidth
;
592 if (oy
[i
] < fSmallY
) oy
[i
] = fSmallY
;
593 if (oy
[i
] > fSmallY
+ fSmallHeight
) oy
[i
] = fSmallY
+ fSmallHeight
;
596 UpdateVertices(m_ox
, m_oy
, ox
, oy
, dirtyregions
);
600 void CSlideShowPic::Keep()
602 // this is called if we need to keep the current pic on screen
603 // to wait for the next pic to load
604 if (!m_bDrawNextImage
) return ; // don't need to keep pic
605 // hold off the start of the next frame
606 m_transitionEnd
.start
= m_iCounter
;
609 bool CSlideShowPic::StartTransition()
611 // this is called if we need to start transitioning immediately to the new picture
612 if (m_bDrawNextImage
) return false; // don't need to do anything as we are already transitioning
613 // decrease the number of display frame
614 m_transitionEnd
.start
= m_iCounter
;
615 m_bTransitionImmediately
= true;
619 void CSlideShowPic::Pause(bool bPause
)
621 if (!m_bDrawNextImage
)
625 void CSlideShowPic::SetInSlideshow(bool slideshow
)
627 if (slideshow
&& m_displayEffect
== EFFECT_NO_TIMEOUT
)
628 m_displayEffect
= EFFECT_NONE
;
631 int CSlideShowPic::GetTransitionTime(int iType
) const
633 if (iType
== 0) // start transition
634 return m_transitionStart
.length
;
635 else // iType == 1 // end transition
636 return m_transitionEnd
.length
;
639 void CSlideShowPic::SetTransitionTime(int iType
, int iTime
)
641 if (iType
== 0) // start transition
642 m_transitionStart
.length
= iTime
;
643 else // iType == 1 // end transition
644 m_transitionEnd
.length
= iTime
;
647 void CSlideShowPic::Rotate(float fRotateAngle
, bool immediate
/* = false */)
649 if (m_bDrawNextImage
) return;
650 if (m_transitionTemp
.type
== TRANSITION_ZOOM
) return;
653 m_fAngle
+= fRotateAngle
;
657 // if there is a rotation ongoing already
658 // add the new angle to the old destination angle
659 if (m_transitionTemp
.type
== TRANSITION_ROTATE
&&
660 m_transitionTemp
.start
+ m_transitionTemp
.length
> m_iCounter
)
662 int remainder
= m_transitionTemp
.start
+ m_transitionTemp
.length
- m_iCounter
;
663 fRotateAngle
+= m_fTransitionAngle
* remainder
;
666 m_transitionTemp
.type
= TRANSITION_ROTATE
;
667 m_transitionTemp
.start
= m_iCounter
;
668 m_transitionTemp
.length
= IMMEDIATE_TRANSITION_TIME
;
669 m_fTransitionAngle
= fRotateAngle
/ (float)m_transitionTemp
.length
;
671 m_transitionEnd
.start
= m_iCounter
+ m_transitionStart
.length
+ (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
));
674 void CSlideShowPic::Zoom(float fZoom
, bool immediate
/* = false */)
676 if (m_bDrawNextImage
) return;
677 if (m_transitionTemp
.type
== TRANSITION_ROTATE
) return;
680 m_fZoomAmount
= fZoom
;
683 m_transitionTemp
.type
= TRANSITION_ZOOM
;
684 m_transitionTemp
.start
= m_iCounter
;
685 m_transitionTemp
.length
= IMMEDIATE_TRANSITION_TIME
;
686 m_fTransitionZoom
= (fZoom
- m_fZoomAmount
) / (float)m_transitionTemp
.length
;
688 m_transitionEnd
.start
= m_iCounter
+ m_transitionStart
.length
+ (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
));
689 // turn off the render effects until we're back down to normal zoom
693 void CSlideShowPic::UpdateAlpha()
695 assert(m_iCounter
>= 0);
697 UTILS::COLOR::Color alpha
= m_alpha
;
699 if (m_iCounter
< m_transitionStart
.length
)
700 { // do start transition
701 switch (m_transitionStart
.type
)
704 // fade in at 1x speed
706 static_cast<UTILS::COLOR::Color
>(static_cast<float>(m_iCounter
+ 1) /
707 static_cast<float>(m_transitionStart
.length
) * 255.0f
);
710 // fade in at 2x speed, then keep solid
711 alpha
= std::min(static_cast<UTILS::COLOR::Color
>(
712 static_cast<float>(m_iCounter
+ 1) /
713 static_cast<float>(m_transitionStart
.length
) * 255.0f
* 2),
714 UTILS::COLOR::Color
{255});
717 alpha
= 255; // opaque
721 if (m_iCounter
>= m_transitionEnd
.start
)
722 { // do end transition
723 switch (m_transitionEnd
.type
)
726 // fade in at 1x speed
727 alpha
= 255 - static_cast<UTILS::COLOR::Color
>(
728 static_cast<float>(m_iCounter
- m_transitionEnd
.start
+ 1) /
729 static_cast<float>(m_transitionEnd
.length
) * 255.0f
);
732 // fade in at 2x speed, then keep solid
733 alpha
= std::min(static_cast<UTILS::COLOR::Color
>(
734 static_cast<float>(m_transitionEnd
.length
- m_iCounter
+
735 m_transitionEnd
.start
+ 1) /
736 static_cast<float>(m_transitionEnd
.length
) * 255.0f
* 2),
737 UTILS::COLOR::Color
{255});
740 alpha
= 255; // opaque
744 if (alpha
!= m_alpha
)
751 void CSlideShowPic::Move(float fDeltaX
, float fDeltaY
)
753 m_fZoomLeft
+= fDeltaX
;
754 m_fZoomTop
+= fDeltaY
;
756 // m_transitionEnd.start = m_iCounter + m_transitionStart.length + (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME));
759 void CSlideShowPic::Render()
761 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
762 RENDER_ORDER_FRONT_TO_BACK
)
764 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
766 Render(m_ax
, m_ay
, m_pImage
.get(), (m_alpha
<< 24) | 0xFFFFFF);
768 // now render the image in the top right corner if we're zooming
769 if (m_fZoomAmount
== 1.0f
|| m_bIsComic
) return ;
771 Render(m_bx
, m_by
, NULL
, PICTURE_VIEW_BOX_BACKGROUND
);
772 Render(m_sx
, m_sy
, m_pImage
.get(), 0xFFFFFFFF);
773 Render(m_ox
, m_oy
, NULL
, PICTURE_VIEW_BOX_COLOR
);