cleanup: removed some unneeded routines
[xbmc:xbmc-antiquated.git] / XBMC / guilib / GUIMultiImage.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "include.h"
23 #include "GUIMultiImage.h"
24 #include "TextureManager.h"
25 #include "FileSystem/Directory.h"
26 #include "Util.h"
27 #include "FileItem.h"
28
29 using namespace std;
30 using namespace DIRECTORY;
31
32 CGUIMultiImage::CGUIMultiImage(DWORD dwParentID, DWORD dwControlId, float posX, float posY, float width, float height, const CTextureInfo& texture, DWORD timePerImage, DWORD fadeTime, bool randomized, bool loop, DWORD timeToPauseAtEnd)
33     : CGUIControl(dwParentID, dwControlId, posX, posY, width, height)
34 {
35   m_textureInfo = texture;
36   m_currentImage = 0;
37   m_timePerImage = timePerImage;
38   m_timeToPauseAtEnd = timeToPauseAtEnd;
39   m_fadeTime = fadeTime;
40   m_randomized = randomized;
41   m_loop = loop;
42   m_aspect = CAspectRatio::AR_STRETCH;
43   ControlType = GUICONTROL_MULTI_IMAGE;
44   m_bDynamicResourceAlloc=false;
45   m_directoryLoaded = false;
46 }
47
48 CGUIMultiImage::CGUIMultiImage(const CGUIMultiImage &from)
49 : CGUIControl(from)
50 {
51   m_textureInfo = from.m_textureInfo;
52   m_texturePath = from.m_texturePath;
53   m_timePerImage = from.m_timePerImage;
54   m_timeToPauseAtEnd = from.m_timeToPauseAtEnd;
55   m_fadeTime = from.m_fadeTime;
56   m_randomized = from.m_randomized;
57   m_loop = from.m_loop;
58   m_aspect = from.m_aspect;
59   m_directoryLoaded = false;
60   if (m_texturePath.IsConstant())
61     m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
62   m_currentImage = 0;
63   ControlType = GUICONTROL_MULTI_IMAGE;
64 }
65
66 CGUIMultiImage::~CGUIMultiImage(void)
67 {
68 }
69
70 void CGUIMultiImage::UpdateVisibility(const CGUIListItem *item)
71 {
72   CGUIControl::UpdateVisibility(item);
73
74   // check if we're hidden, and deallocate if so
75   if (!IsVisible() && m_visible != DELAYED)
76   {
77     if (m_bDynamicResourceAlloc && m_bAllocated)
78       FreeResources();
79     return;
80   }
81
82   // we are either delayed or visible, so we can allocate our resources
83
84   // check for conditional information before we
85   // alloc as this can free our resources
86   if (!m_texturePath.IsConstant())
87   {
88     CStdString texturePath(m_texturePath.GetLabel(m_dwParentID));
89     if (texturePath != m_currentPath && !texturePath.IsEmpty())
90     {
91       m_currentPath = texturePath;
92       FreeResources();
93       LoadDirectory();
94     }
95   }
96
97   // and allocate our resources
98   if (!m_bAllocated)
99     AllocResources();
100 }
101
102 void CGUIMultiImage::Render()
103 {
104   if (!m_images.empty())
105   {
106     // Set a viewport so that we don't render outside the defined area
107     g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height);
108
109     unsigned int nextImage = m_currentImage + 1;
110     if (nextImage >= m_images.size())
111       nextImage = m_loop ? 0 : m_currentImage;  // stay on the last image if <loop>no</loop>
112
113     if (nextImage != m_currentImage)
114     {
115       // check if we should be loading a new image yet
116       DWORD timeToShow = m_timePerImage;
117       if (0 == nextImage) // last image should be paused for a bit longer if that's what the skinner wishes.
118         timeToShow += m_timeToPauseAtEnd;
119       if (m_imageTimer.IsRunning() && m_imageTimer.GetElapsedMilliseconds() > timeToShow)
120       {
121         m_imageTimer.Stop();
122         // grab a new image
123         LoadImage(nextImage);
124         // start the fade timer
125         m_fadeTimer.StartZero();
126       }
127
128       // check if we are still fading
129       if (m_fadeTimer.IsRunning())
130       {
131         // check if the fade timer has run out
132         float timeFading = m_fadeTimer.GetElapsedMilliseconds();
133         if (timeFading >= m_fadeTime)
134         {
135           m_fadeTimer.Stop();
136           // swap images
137           m_images[m_currentImage]->FreeResources();
138           m_images[nextImage]->SetAlpha(255);
139           m_currentImage = nextImage;
140           // start the load timer
141           m_imageTimer.StartZero();
142         }
143         else
144         { // perform the fade in of next image
145           float fadeAmount = timeFading / m_fadeTime;
146           float alpha = (float)(m_diffuseColor >> 24) / 255.0f;
147           if (alpha < 1 && alpha > 0)
148           { // we have a semi-transparent image, so we need to use a more complicated
149             // fade technique.  Assuming a black background (not generally true, but still...)
150             // we have
151             // b(t) = [a - b(1-t)*a] / a*(1-b(1-t)*a),
152             // where a = alpha, and b(t):[0,1] -> [0,1] is the blend function.
153             // solving, we get
154             // b(t) = [1 - (1-a)^t] / a
155             float blendIn = (1 - pow(1-alpha, fadeAmount)) / alpha;
156             m_images[nextImage]->SetAlpha((unsigned char)(255 * blendIn));
157             float blendOut = (1 - blendIn) / (1 - blendIn*alpha); // no need to use pow() again here
158             m_images[m_currentImage]->SetAlpha((unsigned char)(255 * blendOut));
159           }
160           else
161           { // simple case, just fade in the second image
162             m_images[m_currentImage]->SetAlpha(255);
163             m_images[nextImage]->SetAlpha((unsigned char)(255*fadeAmount));
164           }
165           m_images[m_currentImage]->Render();
166         }
167         m_images[nextImage]->Render();
168       }
169       else
170       { // only one image - render it.
171         m_images[m_currentImage]->Render();
172       }
173     }
174     else
175     { // only one image - render it.
176       m_images[m_currentImage]->Render();
177     }
178     g_graphicsContext.RestoreClipRegion();
179   }
180   CGUIControl::Render();
181 }
182
183 bool CGUIMultiImage::OnAction(const CAction &action)
184 {
185   return false;
186 }
187
188 bool CGUIMultiImage::OnMessage(CGUIMessage &message)
189 {
190   if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
191   {
192     if (!m_texturePath.IsConstant())
193       FreeResources();
194     return true;
195   }
196   return CGUIControl::OnMessage(message);
197 }
198
199 void CGUIMultiImage::PreAllocResources()
200 {
201   FreeResources();
202 }
203
204 void CGUIMultiImage::AllocResources()
205 {
206   FreeResources();
207   CGUIControl::AllocResources();
208
209   if (!m_directoryLoaded)
210     LoadDirectory();
211
212   // Randomize or sort our images if necessary
213   if (m_randomized)
214     random_shuffle(m_files.begin(), m_files.end());
215
216   for (unsigned int i=0; i < m_files.size(); i++)
217   {
218     CTextureInfo info(m_textureInfo);
219     info.filename = m_files[i];
220     CGUITexture *pImage = new CGUITexture(m_posX, m_posY, m_width, m_height, info);
221     if (pImage)
222       m_images.push_back(pImage);
223   }
224   // Load in the current image, and reset our timer
225   m_imageTimer.StartZero();
226   m_fadeTimer.Stop();
227   m_currentImage = 0;
228   if (m_images.empty())
229     return;
230
231   LoadImage(m_currentImage);
232 }
233
234 void CGUIMultiImage::LoadImage(int image)
235 {
236   if (image < 0 || image >= (int)m_images.size())
237     return;
238
239   m_images[image]->AllocResources();
240   m_images[image]->SetColorDiffuse(m_diffuseColor);
241
242   // Scale image so that it will fill our render area
243   if (m_aspect.ratio != CAspectRatio::AR_STRETCH)
244   {
245     // to get the pixel ratio, we must use the SCALED output sizes
246     float pixelRatio = g_graphicsContext.GetScalingPixelRatio();
247
248     float sourceAspectRatio = m_images[image]->GetTextureWidth() / m_images[image]->GetTextureHeight();
249     float aspectRatio = sourceAspectRatio / pixelRatio;
250
251     float newWidth = m_width;
252     float newHeight = newWidth / aspectRatio;
253     if ((m_aspect.ratio == CAspectRatio::AR_SCALE && newHeight < m_height) ||
254       (m_aspect.ratio == CAspectRatio::AR_KEEP && newHeight > m_height))
255     {
256       newHeight = m_height;
257       newWidth = newHeight * aspectRatio;
258     }
259     m_images[image]->SetPosition(m_posX - (newWidth - m_width)*0.5f, m_posY - (newHeight - m_height)*0.5f);
260     m_images[image]->SetWidth(newWidth);
261     m_images[image]->SetHeight(newHeight);
262   }
263 }
264
265 void CGUIMultiImage::FreeResources()
266 {
267   for (unsigned int i = 0; i < m_images.size(); ++i)
268   {
269     m_images[i]->FreeResources();
270     delete m_images[i];
271   }
272
273   m_images.clear();
274   m_currentImage = 0;
275   CGUIControl::FreeResources();
276 }
277
278 void CGUIMultiImage::DynamicResourceAlloc(bool bOnOff)
279 {
280   CGUIControl::DynamicResourceAlloc(bOnOff);
281   m_bDynamicResourceAlloc=bOnOff;
282 }
283
284 bool CGUIMultiImage::CanFocus() const
285 {
286   return false;
287 }
288
289 void CGUIMultiImage::SetAspectRatio(const CAspectRatio &ratio)
290 {
291   if (m_aspect != ratio)
292   {
293     m_aspect = ratio;
294     m_bInvalidated = true;
295   }
296 }
297
298 void CGUIMultiImage::LoadDirectory()
299 {
300   // Load any images from our texture bundle first
301   m_files.clear();
302
303   // don't load any images if our path is empty
304   if (m_currentPath.IsEmpty()) return;
305
306   // check to see if we have a single image or a folder of images
307   CFileItem item(m_currentPath, false);
308   if (item.IsPicture())
309   {
310     m_files.push_back(g_TextureManager.GetTexturePath(m_currentPath));
311   }
312   else
313   { // folder of images
314     g_TextureManager.GetBundledTexturesFromPath(m_currentPath, m_files);
315
316     // Load in our images from the directory specified
317     // m_currentPath is relative (as are all skin paths)
318     CStdString realPath = g_TextureManager.GetTexturePath(m_currentPath, true);
319     if (realPath.IsEmpty())
320       return;
321
322     CUtil::AddSlashAtEnd(realPath);
323     CFileItemList items;
324     CDirectory::GetDirectory(realPath, items);
325     for (int i=0; i < items.Size(); i++)
326     {
327       CFileItemPtr pItem = items[i];
328       if (pItem->IsPicture())
329         m_files.push_back(pItem->m_strPath);
330     }
331   }
332
333   // sort our images - they'll be randomized in AllocResources() if necessary
334   sort(m_files.begin(), m_files.end());
335
336   // flag as loaded - no point in constantly reloading them
337   m_directoryLoaded = true;
338 }
339
340 void CGUIMultiImage::SetInfo(const CGUIInfoLabel &info)
341 {
342   m_texturePath = info;
343   if (m_texturePath.IsConstant())
344     m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
345 }