[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pictures / SlideShowPicture.cpp
blobb66c27520e533ce6d31d785f4af3dd0818ab935d
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 <cassert>
20 #include <mutex>
22 #ifndef _USE_MATH_DEFINES
23 #define _USE_MATH_DEFINES
24 #endif
25 #include <cstddef>
26 #include <math.h>
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
35 #define FPS 25
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)
41 m_bIsLoaded = false;
42 m_bDrawNextImage = false;
43 m_bTransitionImmediately = false;
45 m_bCanMoveHorizontally = false;
46 m_bCanMoveVertically = false;
49 CSlideShowPic::~CSlideShowPic()
51 Close();
54 void CSlideShowPic::Close()
56 std::unique_lock<CCriticalSection> lock(m_textureAccess);
57 m_pImage.reset();
58 m_bIsLoaded = false;
59 m_bDrawNextImage = false;
60 m_bTransitionImmediately = false;
61 m_bIsDirty = true;
62 m_alpha = 0;
65 void CSlideShowPic::Reset(DISPLAY_EFFECT dispEffect, TRANSITION_EFFECT transEffect)
67 std::unique_lock<CCriticalSection> lock(m_textureAccess);
68 if (m_pImage)
69 SetTexture_Internal(m_iSlideNumber, std::move(m_pImage), dispEffect, transEffect);
70 else
71 Close();
74 bool CSlideShowPic::DisplayEffectNeedChange(DISPLAY_EFFECT newDispEffect) const
76 if (m_displayEffect == newDispEffect)
77 return false;
78 if (newDispEffect == EFFECT_RANDOM && m_displayEffect != EFFECT_NONE && m_displayEffect != EFFECT_NO_TIMEOUT)
79 return false;
80 return true;
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);
104 Close();
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);
114 m_bPause = false;
115 m_bNoEffect = false;
116 m_bTransitionImmediately = false;
117 m_iSlideNumber = iSlideNumber;
119 m_bIsDirty = true;
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();
127 // reset our counter
128 m_iCounter = 0;
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;
138 else
139 m_displayEffect = (DISPLAY_EFFECT)((rand() % (EFFECT_RANDOM - 1)) + 1);
141 else
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;
154 m_fAngle = 0.0f;
155 if (m_pImage->GetOrientation() == 7)
156 { // rotate to 270 degrees
157 m_fAngle = 270.0f;
159 if (m_pImage->GetOrientation() == 2)
160 { // rotate to 180 degrees
161 m_fAngle = 180.0f;
163 if (m_pImage->GetOrientation() == 5)
164 { // rotate to 90 degrees
165 m_fAngle = 90.0f;
167 m_fZoomAmount = 1;
168 m_fZoomLeft = 0;
169 m_fZoomTop = 0;
170 m_fPosX = m_fPosY = 0.0f;
171 m_fPosZ = 1.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;
186 if (rand() % 2)
187 m_fPosX = -m_fPosX;
188 m_fVelocityX = -m_fPosX * 2.0f / m_iTotalFrames;
190 else
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;
196 if (rand() % 2)
197 m_fPosY = -m_fPosY;
198 m_fVelocityY = -m_fPosY * 2.0f / m_iTotalFrames;
201 else
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)
217 m_fPosZ = 1.0f;
218 m_fVelocityZ = 0.0001f * CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_slideshowZoomAmount;
222 m_transitionEnd.start = m_transitionStart.length + iFrames;
224 m_bDrawNextImage = false;
225 m_bIsLoaded = true;
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);
238 if (iAngle % 2)
239 return m_iOriginalHeight;
240 else
241 return m_iOriginalWidth;
244 int CSlideShowPic::GetOriginalHeight()
246 int iAngle = (int)(m_fAngle / 90.0f + 0.4f);
247 if (iAngle % 2)
248 return m_iOriginalWidth;
249 else
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());
259 m_bIsDirty = true;
262 static CRect GetRectangle(const float x[4], const float y[4])
264 CRect rect;
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);
269 return rect;
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)
277 || m_bIsDirty)
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())
289 return;
291 UpdateAlpha();
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)
297 bPaused = true;
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.
304 int i;
305 for (i = 0; i < 10; i++)
307 if (fabs(m_fZoomAmount - zoomamount[i]) < 0.01f * zoomamount[i])
309 m_fZoomAmount = zoomamount[i];
310 break;
313 m_bNoEffect = (m_fZoomAmount != 1.0f); // turn effect rendering back on.
315 m_transitionTemp.type = TRANSITION_NONE;
317 else
319 if (m_transitionTemp.type == TRANSITION_ROTATE)
320 m_fAngle += m_fTransitionAngle;
321 if (m_transitionTemp.type == TRANSITION_ZOOM)
322 m_fZoomAmount += m_fTransitionZoom;
326 // now just display
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;
368 if (m_fPosZ < 1.0f)
370 m_fPosZ = 1.0f;
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;
381 if (IsAnimating())
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);
387 m_iCounter++;
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
401 float x[4];
402 float y[4];
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)
431 bFillScreen = true;
432 if ((!bFillScreen && fScreenWidth*fPixelRatio > fScreenHeight*fSourceAR) || (bFillScreen && fScreenWidth*fPixelRatio < fScreenHeight*fSourceAR))
433 fScaleNorm = fScreenHeight / (m_fHeight * fPixelRatio);
434 bFillScreen = false;
435 if (m_displayEffect != EFFECT_NO_TIMEOUT && m_displayEffect != EFFECT_NONE && fScreenRatio < fSourceInvAR * fComp && fSourceInvAR < fScreenRatio * fComp)
436 bFillScreen = true;
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;
446 else
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)
452 fScale *= m_fPosZ;
453 // zoom image
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;
461 // center it
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)
468 float minx = x[0];
469 float maxx = x[0];
470 float miny = y[0];
471 float maxy = y[0];
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;
489 for (float& i : x)
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;
498 for (float& i : y)
499 i += m_fZoomTop * 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);
518 m_bIsDirty = false;
519 return;
522 float sx[4], sy[4];
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
546 float bx[4];
547 float by[4];
548 for (int i = 0; i < 4; i++)
550 if (sx[i] > 0)
551 bx[i] = sx[i] + 1;
552 else
553 bx[i] = sx[i] - 1;
554 if (sy[i] > 0)
555 by[i] = sy[i] + 1;
556 else
557 by[i] = sy[i] - 1;
558 sx[i] += fSmallX;
559 sy[i] += fSmallY;
560 bx[i] += fSmallX;
561 by[i] += fSmallY;
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
572 float scale;
573 if (fabs(x[1] - x[0]) > fabs(x[3] - x[0]))
574 scale = (sx[1] - sx[0]) / (x[1] - x[0]);
575 else
576 scale = (sx[3] - sx[0]) / (x[3] - x[0]);
577 float ox[4];
578 float oy[4];
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);
597 m_bIsDirty = false;
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;
616 return true;
619 void CSlideShowPic::Pause(bool bPause)
621 if (!m_bDrawNextImage)
622 m_bPause = bPause;
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;
651 if (immediate)
653 m_fAngle += fRotateAngle;
654 return;
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;
670 // reset the timer
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;
678 if (immediate)
680 m_fZoomAmount = fZoom;
681 return;
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;
687 // reset the timer
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
690 m_bNoEffect = true;
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)
703 case CROSSFADE:
704 // fade in at 1x speed
705 alpha =
706 static_cast<UTILS::COLOR::Color>(static_cast<float>(m_iCounter + 1) /
707 static_cast<float>(m_transitionStart.length) * 255.0f);
708 break;
709 case FADEIN_FADEOUT:
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});
715 break;
716 default:
717 alpha = 255; // opaque
721 if (m_iCounter >= m_transitionEnd.start)
722 { // do end transition
723 switch (m_transitionEnd.type)
725 case CROSSFADE:
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);
730 break;
731 case FADEIN_FADEOUT:
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});
738 break;
739 default:
740 alpha = 255; // opaque
744 if (alpha != m_alpha)
746 m_alpha = alpha;
747 m_bIsDirty = true;
751 void CSlideShowPic::Move(float fDeltaX, float fDeltaY)
753 m_fZoomLeft += fDeltaX;
754 m_fZoomTop += fDeltaY;
755 // reset the timer
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)
763 return;
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);