2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "TextureManager.h"
23 #include "utils/log.h"
24 #include "utils/TimeUtils.h"
28 CGUIImage::CGUIImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture)
29 : CGUIControl(parentID, controlID, posX, posY, width, height)
30 , m_texture(posX, posY, width, height, texture)
33 m_currentFadeTime = 0;
35 ControlType = GUICONTROL_IMAGE;
36 m_bDynamicResourceAlloc=false;
39 CGUIImage::CGUIImage(const CGUIImage &left)
41 m_image(left.m_image),
43 m_texture(left.m_texture),
48 m_crossFadeTime = left.m_crossFadeTime;
50 m_currentFadeTime = 0;
52 ControlType = GUICONTROL_IMAGE;
53 m_bDynamicResourceAlloc=false;
56 CGUIImage::~CGUIImage(void)
61 void CGUIImage::UpdateVisibility(const CGUIListItem *item)
63 CGUIControl::UpdateVisibility(item);
65 // now that we've checked for conditional info, we can
66 // check for allocation
70 void CGUIImage::UpdateInfo(const CGUIListItem *item)
72 if (m_info.IsConstant())
73 return; // nothing to do
75 // don't allow image to change while animating out
76 if (HasProcessed() && IsAnimating(ANIM_TYPE_HIDDEN) && !IsVisibleFromSkin())
80 SetFileName(m_info.GetItemLabel(item, true, &m_currentFallback));
82 SetFileName(m_info.GetLabel(m_parentID, true, &m_currentFallback));
85 void CGUIImage::AllocateOnDemand()
87 // if we're hidden, we can free our resources and return
88 if (!IsVisible() && m_visible != DELAYED)
90 if (m_bDynamicResourceAlloc && m_texture.IsAllocated())
91 FreeResourcesButNotAnims();
95 // either visible or delayed - we need the resources allocated in either case
96 if (!m_texture.IsAllocated())
100 void CGUIImage::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
102 // check whether our image failed to allocate, and if so drop back to the fallback image
103 if (m_texture.FailedToAlloc() && !m_texture.GetFileName().Equals(m_info.GetFallback()))
105 if (!m_currentFallback.empty() && !m_texture.GetFileName().Equals(m_currentFallback))
106 m_texture.SetFileName(m_currentFallback);
108 m_texture.SetFileName(m_info.GetFallback());
113 // make sure our texture has started allocating
114 if (m_texture.AllocResources())
117 // compute the frame time
118 unsigned int frameTime = 0;
119 if (m_lastRenderTime)
120 frameTime = currentTime - m_lastRenderTime;
121 m_lastRenderTime = currentTime;
123 if (m_fadingTextures.size()) // have some fading images
124 { // anything other than the last old texture needs to be faded out as per usual
125 for (vector<CFadingTexture *>::iterator i = m_fadingTextures.begin(); i != m_fadingTextures.end() - 1;)
127 if (!ProcessFading(*i, frameTime, currentTime))
128 i = m_fadingTextures.erase(i);
133 if (m_texture.ReadyToRender() || m_texture.GetFileName().empty())
134 { // fade out the last one as well
135 if (!ProcessFading(m_fadingTextures[m_fadingTextures.size() - 1], frameTime, currentTime))
136 m_fadingTextures.erase(m_fadingTextures.end() - 1);
139 { // keep the last one fading in
140 CFadingTexture *texture = m_fadingTextures[m_fadingTextures.size() - 1];
141 texture->m_fadeTime += frameTime;
142 if (texture->m_fadeTime > m_crossFadeTime)
143 texture->m_fadeTime = m_crossFadeTime;
145 if (texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime)))
147 if (texture->m_texture->SetDiffuseColor(m_diffuseColor))
149 if (texture->m_texture->Process(currentTime))
154 if (m_texture.ReadyToRender() || m_texture.GetFileName().empty())
155 { // fade the new one in
156 m_currentFadeTime += frameTime;
157 if (m_currentFadeTime > m_crossFadeTime || frameTime == 0) // for if we allocate straight away on creation
158 m_currentFadeTime = m_crossFadeTime;
160 if (m_texture.SetAlpha(GetFadeLevel(m_currentFadeTime)))
164 if (m_texture.SetDiffuseColor(m_diffuseColor))
167 if (m_texture.Process(currentTime))
170 CGUIControl::Process(currentTime, dirtyregions);
173 void CGUIImage::Render()
175 if (!IsVisible()) return;
177 for (vector<CFadingTexture *>::iterator itr = m_fadingTextures.begin(); itr != m_fadingTextures.end(); ++itr)
178 (*itr)->m_texture->Render();
182 CGUIControl::Render();
185 bool CGUIImage::ProcessFading(CGUIImage::CFadingTexture *texture, unsigned int frameTime, unsigned int currentTime)
188 if (texture->m_fadeTime <= frameTime)
189 { // time to kill off the texture
194 // render this texture
195 texture->m_fadeTime -= frameTime;
197 if (texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime)))
199 if (texture->m_texture->SetDiffuseColor(m_diffuseColor))
201 if (texture->m_texture->Process(currentTime))
207 bool CGUIImage::OnAction(const CAction &action)
212 bool CGUIImage::OnMessage(CGUIMessage& message)
214 if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
216 if (!m_info.IsConstant())
217 FreeTextures(true); // true as we want to free the texture immediately
220 return CGUIControl::OnMessage(message);
223 void CGUIImage::AllocResources()
225 if (m_texture.GetFileName().empty())
228 CGUIControl::AllocResources();
229 m_texture.AllocResources();
232 void CGUIImage::FreeTextures(bool immediately /* = false */)
234 m_texture.FreeResources(immediately);
235 for (unsigned int i = 0; i < m_fadingTextures.size(); i++)
236 delete m_fadingTextures[i];
237 m_fadingTextures.clear();
238 m_currentTexture.clear();
239 if (!m_info.IsConstant()) // constant textures never change
240 m_texture.SetFileName("");
243 void CGUIImage::FreeResources(bool immediately)
245 FreeTextures(immediately);
246 CGUIControl::FreeResources(immediately);
249 void CGUIImage::SetInvalid()
251 m_texture.SetInvalid();
252 CGUIControl::SetInvalid();
255 // WORKAROUND - we are currently resetting all animations when this is called, which shouldn't be the case
256 // see CGUIControl::FreeResources() - this needs remedying.
257 void CGUIImage::FreeResourcesButNotAnims()
261 m_hasProcessed = false;
264 void CGUIImage::DynamicResourceAlloc(bool bOnOff)
266 m_bDynamicResourceAlloc = bOnOff;
267 m_texture.DynamicResourceAlloc(bOnOff);
268 CGUIControl::DynamicResourceAlloc(bOnOff);
271 bool CGUIImage::CanFocus() const
276 float CGUIImage::GetTextureWidth() const
278 return m_texture.GetTextureWidth();
281 float CGUIImage::GetTextureHeight() const
283 return m_texture.GetTextureHeight();
286 CRect CGUIImage::CalcRenderRegion() const
288 CRect region = m_texture.GetRenderRect();
290 for (vector<CFadingTexture *>::const_iterator itr = m_fadingTextures.begin(); itr != m_fadingTextures.end(); ++itr)
291 region.Union( (*itr)->m_texture->GetRenderRect() );
293 return CGUIControl::CalcRenderRegion().Intersect(region);
296 const CStdString &CGUIImage::GetFileName() const
298 return m_texture.GetFileName();
301 void CGUIImage::SetAspectRatio(const CAspectRatio &aspect)
303 m_texture.SetAspectRatio(aspect);
306 void CGUIImage::SetCrossFade(unsigned int time)
308 m_crossFadeTime = time;
309 if (!m_crossFadeTime && m_texture.IsLazyLoaded() && !m_info.GetFallback().empty())
313 void CGUIImage::SetFileName(const CStdString& strFileName, bool setConstant, const bool useCache)
316 m_info.SetLabel(strFileName, "", GetParentID());
318 // Set whether or not to use cache
319 m_texture.SetUseCache(useCache);
323 // set filename on the next texture
324 if (m_currentTexture.Equals(strFileName))
325 return; // nothing to do - we already have this image
327 if (m_texture.ReadyToRender() || m_texture.GetFileName().empty())
328 { // save the current image
329 m_fadingTextures.push_back(new CFadingTexture(m_texture, m_currentFadeTime));
332 m_currentFadeTime = 0;
334 if (!m_currentTexture.Equals(strFileName))
335 { // texture is changing - attempt to load it, and save the name in m_currentTexture.
336 // we'll check whether it loaded or not in Render()
337 m_currentTexture = strFileName;
338 if (m_texture.SetFileName(m_currentTexture))
344 void CGUIImage::DumpTextureUse()
346 if (m_texture.IsAllocated())
349 CLog::Log(LOGDEBUG, "Image control %u using texture %s",
350 GetID(), m_texture.GetFileName().c_str());
352 CLog::Log(LOGDEBUG, "Using texture %s", m_texture.GetFileName().c_str());
357 void CGUIImage::SetWidth(float width)
359 m_texture.SetWidth(width);
360 CGUIControl::SetWidth(m_texture.GetWidth());
363 void CGUIImage::SetHeight(float height)
365 m_texture.SetHeight(height);
366 CGUIControl::SetHeight(m_texture.GetHeight());
369 void CGUIImage::SetPosition(float posX, float posY)
371 m_texture.SetPosition(posX, posY);
372 CGUIControl::SetPosition(posX, posY);
375 void CGUIImage::SetInfo(const CGUIInfoLabel &info)
378 // a constant image never needs updating
379 if (m_info.IsConstant())
380 m_texture.SetFileName(m_info.GetLabel(0));
383 unsigned char CGUIImage::GetFadeLevel(unsigned int time) const
385 float amount = (float)time / m_crossFadeTime;
386 // we want a semi-transparent image, so we need to use a more complicated
387 // fade technique. Assuming a black background (not generally true, but still...)
389 // b(t) = [a - b(1-t)*a] / a*(1-b(1-t)*a),
390 // where a = alpha, and b(t):[0,1] -> [0,1] is the blend function.
392 // b(t) = [1 - (1-a)^t] / a
393 const float alpha = 0.7f;
394 return (unsigned char)(255.0f * (1 - pow(1-alpha, amount))/alpha);
397 CStdString CGUIImage::GetDescription(void) const
399 return GetFileName();