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 using KODI::UTILS::COLOR::Color
;
41 CSlideShowPic::CSlideShowPic() : m_pImage(nullptr)
44 m_bDrawNextImage
= false;
45 m_bTransitionImmediately
= false;
47 m_bCanMoveHorizontally
= false;
48 m_bCanMoveVertically
= false;
51 CSlideShowPic::~CSlideShowPic()
56 void CSlideShowPic::Close()
58 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
61 m_bDrawNextImage
= false;
62 m_bTransitionImmediately
= false;
67 void CSlideShowPic::Reset(DISPLAY_EFFECT dispEffect
, TRANSITION_EFFECT transEffect
)
69 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
71 SetTexture_Internal(m_iSlideNumber
, std::move(m_pImage
), dispEffect
, transEffect
);
76 bool CSlideShowPic::DisplayEffectNeedChange(DISPLAY_EFFECT newDispEffect
) const
78 if (m_displayEffect
== newDispEffect
)
80 if (newDispEffect
== EFFECT_RANDOM
&& m_displayEffect
!= EFFECT_NONE
&& m_displayEffect
!= EFFECT_NO_TIMEOUT
)
85 bool CSlideShowPic::IsFinished() const
87 return IsLoaded() && m_iCounter
>= m_transitionEnd
.start
+ m_transitionEnd
.length
;
90 bool CSlideShowPic::IsAnimating() const
92 return !IsFinished() &&
93 (m_displayEffect
!= EFFECT_NO_TIMEOUT
|| // Special snowflake, doesn't work without this
94 m_iCounter
< m_transitionStart
.length
|| // Inside start transition
95 m_iCounter
>= m_transitionEnd
.start
|| // Inside end transition
96 (m_iCounter
>= m_transitionTemp
.start
&&
97 m_iCounter
< m_transitionTemp
.start
+ m_transitionTemp
.length
)); // Inside display effect
100 void CSlideShowPic::SetTexture(int iSlideNumber
,
101 std::unique_ptr
<CTexture
> pTexture
,
102 DISPLAY_EFFECT dispEffect
,
103 TRANSITION_EFFECT transEffect
)
105 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
107 SetTexture_Internal(iSlideNumber
, std::move(pTexture
), dispEffect
, transEffect
);
110 void CSlideShowPic::SetTexture_Internal(int iSlideNumber
,
111 std::unique_ptr
<CTexture
> pTexture
,
112 DISPLAY_EFFECT dispEffect
,
113 TRANSITION_EFFECT transEffect
)
115 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
118 m_bTransitionImmediately
= false;
119 m_iSlideNumber
= iSlideNumber
;
122 m_pImage
= std::move(pTexture
);
123 m_fWidth
= static_cast<float>(m_pImage
->GetWidth());
124 m_fHeight
= static_cast<float>(m_pImage
->GetHeight());
125 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_HIGHQUALITYDOWNSCALING
))
126 { // activate mipmapping when high quality downscaling is 'on'
127 m_pImage
->SetMipmapping();
131 // initialize our transition effect
132 m_transitionStart
.type
= transEffect
;
133 m_transitionStart
.start
= 0;
135 // initialize our display effect
136 if (dispEffect
== EFFECT_RANDOM
)
138 if (((m_fWidth
/ m_fHeight
) > 1.9f
) || ((m_fHeight
/ m_fWidth
) > 1.9f
))
139 m_displayEffect
= EFFECT_PANORAMA
;
141 m_displayEffect
= (DISPLAY_EFFECT
)((rand() % (EFFECT_RANDOM
- 1)) + 1);
144 m_displayEffect
= dispEffect
;
146 // the +1's make sure it actually occurs
147 float fadeTime
= 0.2f
;
148 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
)
149 fadeTime
= std::min(0.2f
*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
), 3.0f
);
150 m_transitionStart
.length
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * fadeTime
); // transition time in frames
151 m_transitionEnd
.type
= transEffect
;
152 m_transitionEnd
.length
= m_transitionStart
.length
;
153 m_transitionTemp
.type
= TRANSITION_NONE
;
154 m_fTransitionAngle
= 0;
155 m_fTransitionZoom
= 0;
157 if (m_pImage
->GetOrientation() == 7)
158 { // rotate to 270 degrees
161 if (m_pImage
->GetOrientation() == 2)
162 { // rotate to 180 degrees
165 if (m_pImage
->GetOrientation() == 5)
166 { // rotate to 90 degrees
172 m_fPosX
= m_fPosY
= 0.0f
;
174 m_fVelocityX
= m_fVelocityY
= m_fVelocityZ
= 0.0f
;
175 int iFrames
= std::max((int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
)), 1);
176 if (m_displayEffect
== EFFECT_PANORAMA
)
178 RESOLUTION_INFO res
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
179 float fScreenWidth
= (float)res
.Overscan
.right
- res
.Overscan
.left
;
180 float fScreenHeight
= (float)res
.Overscan
.bottom
- res
.Overscan
.top
;
182 if (m_fWidth
> m_fHeight
)
184 iFrames
= (int)(iFrames
* (m_fWidth
- m_fHeight
) / m_fHeight
);
185 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
187 m_fPosX
= 0.5f
- (fScreenWidth
/ fScreenHeight
) * (m_fHeight
/ m_fWidth
) * 0.5f
;
190 m_fVelocityX
= -m_fPosX
* 2.0f
/ m_iTotalFrames
;
194 iFrames
= (int)(iFrames
* (m_fHeight
- (0.5f
* m_fWidth
)) / m_fWidth
);
195 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
197 m_fPosY
= 0.5f
- (fScreenHeight
/ fScreenWidth
) * (m_fWidth
/ m_fHeight
) * 0.5f
;
200 m_fVelocityY
= -m_fPosY
* 2.0f
/ m_iTotalFrames
;
205 m_iTotalFrames
= m_transitionStart
.length
+ m_transitionEnd
.length
+ iFrames
;
207 if (m_displayEffect
== EFFECT_FLOAT
)
209 // Calculate start and end positions
210 // choose a random direction
211 float angle
= (rand() % 1000) / 1000.0f
* 2 * (float)M_PI
;
212 m_fPosX
= cos(angle
) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.00005f
;
213 m_fPosY
= sin(angle
) * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.00005f
;
214 m_fVelocityX
= -m_fPosX
* 2.0f
/ m_iTotalFrames
;
215 m_fVelocityY
= -m_fPosY
* 2.0f
/ m_iTotalFrames
;
217 else if (m_displayEffect
== EFFECT_ZOOM
)
220 m_fVelocityZ
= 0.0001f
* CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowZoomAmount
;
224 m_transitionEnd
.start
= m_transitionStart
.length
+ iFrames
;
226 m_bDrawNextImage
= false;
230 void CSlideShowPic::SetOriginalSize(int iOriginalWidth
, int iOriginalHeight
, bool bFullSize
)
232 m_iOriginalWidth
= iOriginalWidth
;
233 m_iOriginalHeight
= iOriginalHeight
;
234 m_bFullSize
= bFullSize
;
237 int CSlideShowPic::GetOriginalWidth()
239 int iAngle
= (int)(m_fAngle
/ 90.0f
+ 0.4f
);
241 return m_iOriginalHeight
;
243 return m_iOriginalWidth
;
246 int CSlideShowPic::GetOriginalHeight()
248 int iAngle
= (int)(m_fAngle
/ 90.0f
+ 0.4f
);
250 return m_iOriginalWidth
;
252 return m_iOriginalHeight
;
255 void CSlideShowPic::UpdateTexture(std::unique_ptr
<CTexture
> pTexture
)
257 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
258 m_pImage
= std::move(pTexture
);
259 m_fWidth
= static_cast<float>(m_pImage
->GetWidth());
260 m_fHeight
= static_cast<float>(m_pImage
->GetHeight());
264 static CRect
GetRectangle(const float x
[4], const float y
[4])
267 rect
.x1
= *std::min_element(x
, x
+4);
268 rect
.y1
= *std::min_element(y
, y
+4);
269 rect
.x2
= *std::max_element(x
, x
+4);
270 rect
.y2
= *std::max_element(y
, y
+4);
274 void CSlideShowPic::UpdateVertices(float cur_x
[4], float cur_y
[4], const float new_x
[4], const float new_y
[4], CDirtyRegionList
&dirtyregions
)
276 const size_t count
= sizeof(float)*4;
277 if(memcmp(cur_x
, new_x
, count
)
278 || memcmp(cur_y
, new_y
, count
)
281 dirtyregions
.emplace_back(GetRectangle(cur_x
, cur_y
));
282 dirtyregions
.emplace_back(GetRectangle(new_x
, new_y
));
283 memcpy(cur_x
, new_x
, count
);
284 memcpy(cur_y
, new_y
, count
);
288 void CSlideShowPic::Process(unsigned int currentTime
, CDirtyRegionList
&dirtyregions
)
290 if (!m_pImage
|| !m_bIsLoaded
|| IsFinished())
295 bool bPaused
= m_bPause
| (m_fZoomAmount
!= 1.0f
);
296 // check if we're doing a temporary effect (such as rotate + zoom)
297 if (m_transitionTemp
.type
!= TRANSITION_NONE
)
300 if (m_iCounter
>= m_transitionTemp
.start
)
302 if (m_iCounter
>= m_transitionTemp
.start
+ m_transitionTemp
.length
)
303 { // we're finished this transition
304 if (m_transitionTemp
.type
== TRANSITION_ZOOM
)
305 { // correct for any introduced inaccuracies.
307 for (i
= 0; i
< 10; i
++)
309 if (fabs(m_fZoomAmount
- zoomamount
[i
]) < 0.01f
* zoomamount
[i
])
311 m_fZoomAmount
= zoomamount
[i
];
315 m_bNoEffect
= (m_fZoomAmount
!= 1.0f
); // turn effect rendering back on.
317 m_transitionTemp
.type
= TRANSITION_NONE
;
321 if (m_transitionTemp
.type
== TRANSITION_ROTATE
)
322 m_fAngle
+= m_fTransitionAngle
;
323 if (m_transitionTemp
.type
== TRANSITION_ZOOM
)
324 m_fZoomAmount
+= m_fTransitionZoom
;
329 if (!m_bNoEffect
&& !bPaused
)
331 if (m_displayEffect
== EFFECT_PANORAMA
)
333 m_fPosX
+= m_fVelocityX
;
334 m_fPosY
+= m_fVelocityY
;
336 else if (m_displayEffect
== EFFECT_FLOAT
)
338 m_fPosX
+= m_fVelocityX
;
339 m_fPosY
+= m_fVelocityY
;
340 float fMoveAmount
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.0001f
;
341 if (m_fPosX
> fMoveAmount
)
343 m_fPosX
= fMoveAmount
;
344 m_fVelocityX
= -m_fVelocityX
;
346 if (m_fPosX
< -fMoveAmount
)
348 m_fPosX
= -fMoveAmount
;
349 m_fVelocityX
= -m_fVelocityX
;
351 if (m_fPosY
> fMoveAmount
)
353 m_fPosY
= fMoveAmount
;
354 m_fVelocityY
= -m_fVelocityY
;
356 if (m_fPosY
< -fMoveAmount
)
358 m_fPosY
= -fMoveAmount
;
359 m_fVelocityY
= -m_fVelocityY
;
362 else if (m_displayEffect
== EFFECT_ZOOM
)
364 m_fPosZ
+= m_fVelocityZ
;
365 /* if (m_fPosZ > 1.0f + 0.01f*CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount"))
367 m_fPosZ = 1.0f + 0.01f * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("Slideshow.ZoomAmount");
368 m_fVelocityZ = -m_fVelocityZ;
373 m_fVelocityZ = -m_fVelocityZ;
377 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& bPaused
&& !m_bTransitionImmediately
)
378 { // paused - increment the last transition start time
379 m_transitionEnd
.start
++;
381 if (m_iCounter
>= m_transitionEnd
.start
)
382 m_bDrawNextImage
= true;
385 /* this really annoying. there's non-stop logging when viewing a pic outside of the slideshow
386 if (m_displayEffect == EFFECT_NO_TIMEOUT)
387 CLog::Log(LOGDEBUG, "Incrementing counter ({}) while not in slideshow (startlength={},endstart={},endlength={})", m_iCounter, m_transitionStart.length, m_transitionEnd.start, m_transitionEnd.length);
392 RESOLUTION_INFO info
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
394 // calculate where we should render (and how large it should be)
395 // calculate aspect ratio correction factor
396 float fOffsetX
= (float)info
.Overscan
.left
;
397 float fOffsetY
= (float)info
.Overscan
.top
;
398 float fScreenWidth
= (float)info
.Overscan
.right
- info
.Overscan
.left
;
399 float fScreenHeight
= (float)info
.Overscan
.bottom
- info
.Overscan
.top
;
400 float fPixelRatio
= info
.fPixelRatio
;
402 // Rotate the image as needed
405 float si
= sin(m_fAngle
/ 180.0f
* static_cast<float>(M_PI
));
406 float co
= cos(m_fAngle
/ 180.0f
* static_cast<float>(M_PI
));
407 x
[0] = -m_fWidth
* co
+ m_fHeight
* si
;
408 y
[0] = -m_fWidth
* si
- m_fHeight
* co
;
409 x
[1] = m_fWidth
* co
+ m_fHeight
* si
;
410 y
[1] = m_fWidth
* si
- m_fHeight
* co
;
411 x
[2] = m_fWidth
* co
- m_fHeight
* si
;
412 y
[2] = m_fWidth
* si
+ m_fHeight
* co
;
413 x
[3] = -m_fWidth
* co
- m_fHeight
* si
;
414 y
[3] = -m_fWidth
* si
+ m_fHeight
* co
;
416 // calculate our scale amounts
417 float fSourceAR
= m_fWidth
/ m_fHeight
;
418 float fSourceInvAR
= 1 / fSourceAR
;
419 float fAR
= si
* si
* (fSourceInvAR
- fSourceAR
) + fSourceAR
;
421 //float fOutputFrameAR = fAR / fPixelRatio;
423 float fScaleNorm
= fScreenWidth
/ m_fWidth
;
424 float fScaleInv
= fScreenWidth
/ m_fHeight
;
426 bool bFillScreen
= false;
427 float fComp
= 1.0f
+ 0.01f
* CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowBlackBarCompensation
;
428 float fScreenRatio
= fScreenWidth
/ fScreenHeight
* fPixelRatio
;
429 // work out if we should be compensating the zoom to minimize blackbars
430 // we should compute this based on the % of black bars on screen perhaps??
431 //! @todo change m_displayEffect != EFFECT_NO_TIMEOUT to whether we're running the slideshow
432 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& m_displayEffect
!= EFFECT_NONE
&& fScreenRatio
< fSourceAR
* fComp
&& fSourceAR
< fScreenRatio
* fComp
)
434 if ((!bFillScreen
&& fScreenWidth
*fPixelRatio
> fScreenHeight
*fSourceAR
) || (bFillScreen
&& fScreenWidth
*fPixelRatio
< fScreenHeight
*fSourceAR
))
435 fScaleNorm
= fScreenHeight
/ (m_fHeight
* fPixelRatio
);
437 if (m_displayEffect
!= EFFECT_NO_TIMEOUT
&& m_displayEffect
!= EFFECT_NONE
&& fScreenRatio
< fSourceInvAR
* fComp
&& fSourceInvAR
< fScreenRatio
* fComp
)
439 if ((!bFillScreen
&& fScreenWidth
*fPixelRatio
> fScreenHeight
*fSourceInvAR
) || (bFillScreen
&& fScreenWidth
*fPixelRatio
< fScreenHeight
*fSourceInvAR
))
440 fScaleInv
= fScreenHeight
/ (m_fWidth
* fPixelRatio
);
442 float fScale
= si
* si
* (fScaleInv
- fScaleNorm
) + fScaleNorm
;
443 // scale if we need to due to the effect we're using
444 if (m_displayEffect
== EFFECT_PANORAMA
)
446 if (m_fWidth
> m_fHeight
)
447 fScale
*= m_fWidth
/ fScreenWidth
* fScreenHeight
/ m_fHeight
;
449 fScale
*= m_fHeight
/ fScreenHeight
* fScreenWidth
/ m_fWidth
;
451 if (m_displayEffect
== EFFECT_FLOAT
)
452 fScale
*= (1.0f
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowPanAmount
* m_iTotalFrames
* 0.0001f
);
453 if (m_displayEffect
== EFFECT_ZOOM
)
456 fScale
*= m_fZoomAmount
;
458 // calculate the resultant coordinates
459 for (int i
= 0; i
< 4; i
++)
461 x
[i
] *= fScale
* 0.5f
; // as the offsets x[] and y[] are from center
462 y
[i
] *= fScale
* fPixelRatio
* 0.5f
;
464 x
[i
] += 0.5f
* fScreenWidth
+ fOffsetX
;
465 y
[i
] += 0.5f
* fScreenHeight
+ fOffsetY
;
467 // shift if we're zooming
468 if (m_fZoomAmount
> 1)
474 for (int i
= 1; i
< 4; i
++)
476 if (x
[i
] < minx
) minx
= x
[i
];
477 if (x
[i
] > maxx
) maxx
= x
[i
];
478 if (y
[i
] < miny
) miny
= y
[i
];
479 if (y
[i
] > maxy
) maxy
= y
[i
];
481 float w
= maxx
- minx
;
482 float h
= maxy
- miny
;
483 m_bCanMoveHorizontally
= (w
>= fScreenWidth
);
484 m_bCanMoveVertically
= (h
>= fScreenHeight
);
485 if (w
>= fScreenWidth
)
486 { // must have no black bars
487 if (minx
+ m_fZoomLeft
*w
> fOffsetX
)
488 m_fZoomLeft
= (fOffsetX
- minx
) / w
;
489 if (maxx
+ m_fZoomLeft
*w
< fOffsetX
+ fScreenWidth
)
490 m_fZoomLeft
= (fScreenWidth
+ fOffsetX
- maxx
) / w
;
492 i
+= w
* m_fZoomLeft
;
494 if (h
>= fScreenHeight
)
495 { // must have no black bars
496 if (miny
+ m_fZoomTop
*h
> fOffsetY
)
497 m_fZoomTop
= (fOffsetY
- miny
) / h
;
498 if (maxy
+ m_fZoomTop
*h
< fOffsetY
+ fScreenHeight
)
499 m_fZoomTop
= (fScreenHeight
+ fOffsetY
- maxy
) / h
;
504 // add offset from display effects
505 for (int i
= 0; i
< 4; i
++)
507 x
[i
] += m_fPosX
* m_fWidth
* fScale
;
508 y
[i
] += m_fPosY
* m_fHeight
* fScale
;
511 UpdateVertices(m_ax
, m_ay
, x
, y
, dirtyregions
);
513 // now render the image in the top right corner if we're zooming
514 if (m_fZoomAmount
== 1 || m_bIsComic
)
516 const float empty
[4] = {};
517 UpdateVertices(m_bx
, m_by
, empty
, empty
, dirtyregions
);
518 UpdateVertices(m_sx
, m_sy
, empty
, empty
, dirtyregions
);
519 UpdateVertices(m_ox
, m_oy
, empty
, empty
, dirtyregions
);
525 sx
[0] = -m_fWidth
* co
+ m_fHeight
* si
;
526 sy
[0] = -m_fWidth
* si
- m_fHeight
* co
;
527 sx
[1] = m_fWidth
* co
+ m_fHeight
* si
;
528 sy
[1] = m_fWidth
* si
- m_fHeight
* co
;
529 sx
[2] = m_fWidth
* co
- m_fHeight
* si
;
530 sy
[2] = m_fWidth
* si
+ m_fHeight
* co
;
531 sx
[3] = -m_fWidth
* co
- m_fHeight
* si
;
532 sy
[3] = -m_fWidth
* si
+ m_fHeight
* co
;
533 // convert to the appropriate scale
534 float fSmallArea
= fScreenWidth
* fScreenHeight
/ 50;
535 float fSmallWidth
= sqrt(fSmallArea
* fAR
/ fPixelRatio
); // fAR*height = width, so total area*far = width*width
536 float fSmallHeight
= fSmallArea
/ fSmallWidth
;
537 float fSmallX
= fOffsetX
+ fScreenWidth
* 0.95f
- fSmallWidth
* 0.5f
;
538 float fSmallY
= fOffsetY
+ fScreenHeight
* 0.05f
+ fSmallHeight
* 0.5f
;
539 fScaleNorm
= fSmallWidth
/ m_fWidth
;
540 fScaleInv
= fSmallWidth
/ m_fHeight
;
541 fScale
= si
* si
* (fScaleInv
- fScaleNorm
) + fScaleNorm
;
542 for (int i
= 0; i
< 4; i
++)
544 sx
[i
] *= fScale
* 0.5f
;
545 sy
[i
] *= fScale
* fPixelRatio
* 0.5f
;
547 // calculate a black border
550 for (int i
= 0; i
< 4; i
++)
566 fSmallX
-= fSmallWidth
* 0.5f
;
567 fSmallY
-= fSmallHeight
* 0.5f
;
569 UpdateVertices(m_bx
, m_by
, bx
, by
, dirtyregions
);
570 UpdateVertices(m_sx
, m_sy
, sx
, sy
, dirtyregions
);
572 // now we must render the wireframe image of the view window
573 // work out the direction of the top of pic vector
575 if (fabs(x
[1] - x
[0]) > fabs(x
[3] - x
[0]))
576 scale
= (sx
[1] - sx
[0]) / (x
[1] - x
[0]);
578 scale
= (sx
[3] - sx
[0]) / (x
[3] - x
[0]);
581 ox
[0] = (fOffsetX
- x
[0]) * scale
+ sx
[0];
582 oy
[0] = (fOffsetY
- y
[0]) * scale
+ sy
[0];
583 ox
[1] = (fOffsetX
+ fScreenWidth
- x
[0]) * scale
+ sx
[0];
584 oy
[1] = (fOffsetY
- y
[0]) * scale
+ sy
[0];
585 ox
[2] = (fOffsetX
+ fScreenWidth
- x
[0]) * scale
+ sx
[0];
586 oy
[2] = (fOffsetY
+ fScreenHeight
- y
[0]) * scale
+ sy
[0];
587 ox
[3] = (fOffsetX
- x
[0]) * scale
+ sx
[0];
588 oy
[3] = (fOffsetY
+ fScreenHeight
- y
[0]) * scale
+ sy
[0];
589 // crop to within the range of our piccy
590 for (int i
= 0; i
< 4; i
++)
592 if (ox
[i
] < fSmallX
) ox
[i
] = fSmallX
;
593 if (ox
[i
] > fSmallX
+ fSmallWidth
) ox
[i
] = fSmallX
+ fSmallWidth
;
594 if (oy
[i
] < fSmallY
) oy
[i
] = fSmallY
;
595 if (oy
[i
] > fSmallY
+ fSmallHeight
) oy
[i
] = fSmallY
+ fSmallHeight
;
598 UpdateVertices(m_ox
, m_oy
, ox
, oy
, dirtyregions
);
602 void CSlideShowPic::Keep()
604 // this is called if we need to keep the current pic on screen
605 // to wait for the next pic to load
606 if (!m_bDrawNextImage
) return ; // don't need to keep pic
607 // hold off the start of the next frame
608 m_transitionEnd
.start
= m_iCounter
;
611 bool CSlideShowPic::StartTransition()
613 // this is called if we need to start transitioning immediately to the new picture
614 if (m_bDrawNextImage
) return false; // don't need to do anything as we are already transitioning
615 // decrease the number of display frame
616 m_transitionEnd
.start
= m_iCounter
;
617 m_bTransitionImmediately
= true;
621 void CSlideShowPic::Pause(bool bPause
)
623 if (!m_bDrawNextImage
)
627 void CSlideShowPic::SetInSlideshow(bool slideshow
)
629 if (slideshow
&& m_displayEffect
== EFFECT_NO_TIMEOUT
)
630 m_displayEffect
= EFFECT_NONE
;
633 int CSlideShowPic::GetTransitionTime(int iType
) const
635 if (iType
== 0) // start transition
636 return m_transitionStart
.length
;
637 else // iType == 1 // end transition
638 return m_transitionEnd
.length
;
641 void CSlideShowPic::SetTransitionTime(int iType
, int iTime
)
643 if (iType
== 0) // start transition
644 m_transitionStart
.length
= iTime
;
645 else // iType == 1 // end transition
646 m_transitionEnd
.length
= iTime
;
649 void CSlideShowPic::Rotate(float fRotateAngle
, bool immediate
/* = false */)
651 if (m_bDrawNextImage
) return;
652 if (m_transitionTemp
.type
== TRANSITION_ZOOM
) return;
655 m_fAngle
+= fRotateAngle
;
659 // if there is a rotation ongoing already
660 // add the new angle to the old destination angle
661 if (m_transitionTemp
.type
== TRANSITION_ROTATE
&&
662 m_transitionTemp
.start
+ m_transitionTemp
.length
> m_iCounter
)
664 int remainder
= m_transitionTemp
.start
+ m_transitionTemp
.length
- m_iCounter
;
665 fRotateAngle
+= m_fTransitionAngle
* remainder
;
668 m_transitionTemp
.type
= TRANSITION_ROTATE
;
669 m_transitionTemp
.start
= m_iCounter
;
670 m_transitionTemp
.length
= IMMEDIATE_TRANSITION_TIME
;
671 m_fTransitionAngle
= fRotateAngle
/ (float)m_transitionTemp
.length
;
673 m_transitionEnd
.start
= m_iCounter
+ m_transitionStart
.length
+ (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
));
676 void CSlideShowPic::Zoom(float fZoom
, bool immediate
/* = false */)
678 if (m_bDrawNextImage
) return;
679 if (m_transitionTemp
.type
== TRANSITION_ROTATE
) return;
682 m_fZoomAmount
= fZoom
;
685 m_transitionTemp
.type
= TRANSITION_ZOOM
;
686 m_transitionTemp
.start
= m_iCounter
;
687 m_transitionTemp
.length
= IMMEDIATE_TRANSITION_TIME
;
688 m_fTransitionZoom
= (fZoom
- m_fZoomAmount
) / (float)m_transitionTemp
.length
;
690 m_transitionEnd
.start
= m_iCounter
+ m_transitionStart
.length
+ (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME
));
691 // turn off the render effects until we're back down to normal zoom
695 void CSlideShowPic::UpdateAlpha()
697 assert(m_iCounter
>= 0);
699 Color alpha
= m_alpha
;
701 if (m_iCounter
< m_transitionStart
.length
)
702 { // do start transition
703 switch (m_transitionStart
.type
)
706 // fade in at 1x speed
707 alpha
= static_cast<Color
>(static_cast<float>(m_iCounter
+ 1) /
708 static_cast<float>(m_transitionStart
.length
) * 255.0f
);
711 // fade in at 2x speed, then keep solid
713 std::min(static_cast<Color
>(static_cast<float>(m_iCounter
+ 1) /
714 static_cast<float>(m_transitionStart
.length
) * 255.0f
* 2),
718 alpha
= 255; // opaque
722 if (m_iCounter
>= m_transitionEnd
.start
)
723 { // do end transition
724 switch (m_transitionEnd
.type
)
727 // fade in at 1x speed
729 255 - static_cast<Color
>(static_cast<float>(m_iCounter
- m_transitionEnd
.start
+ 1) /
730 static_cast<float>(m_transitionEnd
.length
) * 255.0f
);
733 // fade in at 2x speed, then keep solid
735 std::min(static_cast<Color
>(static_cast<float>(m_transitionEnd
.length
- m_iCounter
+
736 m_transitionEnd
.start
+ 1) /
737 static_cast<float>(m_transitionEnd
.length
) * 255.0f
* 2),
741 alpha
= 255; // opaque
745 if (alpha
!= m_alpha
)
752 void CSlideShowPic::Move(float fDeltaX
, float fDeltaY
)
754 m_fZoomLeft
+= fDeltaX
;
755 m_fZoomTop
+= fDeltaY
;
757 // m_transitionEnd.start = m_iCounter + m_transitionStart.length + (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS() * CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SLIDESHOW_STAYTIME));
760 void CSlideShowPic::Render()
762 if (CServiceBroker::GetWinSystem()->GetGfxContext().GetRenderOrder() ==
763 RENDER_ORDER_FRONT_TO_BACK
)
765 std::unique_lock
<CCriticalSection
> lock(m_textureAccess
);
767 Render(m_ax
, m_ay
, m_pImage
.get(), (m_alpha
<< 24) | 0xFFFFFF);
769 // now render the image in the top right corner if we're zooming
770 if (m_fZoomAmount
== 1.0f
|| m_bIsComic
) return ;
772 Render(m_bx
, m_by
, NULL
, PICTURE_VIEW_BOX_BACKGROUND
);
773 Render(m_sx
, m_sy
, m_pImage
.get(), 0xFFFFFFFF);
774 Render(m_ox
, m_oy
, NULL
, PICTURE_VIEW_BOX_COLOR
);