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.
11 #include "GUIMessage.h"
12 #include "utils/log.h"
16 using namespace KODI::GUILIB
;
18 CGUIImage::CGUIImage(int parentID
,
24 const CTextureInfo
& texture
)
25 : CGUIControl(parentID
, controlID
, posX
, posY
, width
, height
),
26 m_texture(CGUITexture::CreateTexture(posX
, posY
, width
, height
, texture
))
29 m_currentFadeTime
= 0;
31 ControlType
= GUICONTROL_IMAGE
;
32 m_bDynamicResourceAlloc
=false;
35 CGUIImage::CGUIImage(const CGUIImage
& left
)
37 m_image(left
.m_image
),
39 m_texture(left
.m_texture
->Clone()),
44 m_crossFadeTime
= left
.m_crossFadeTime
;
46 m_currentFadeTime
= 0;
48 ControlType
= GUICONTROL_IMAGE
;
49 m_bDynamicResourceAlloc
=false;
52 CGUIImage::~CGUIImage(void) = default;
54 void CGUIImage::UpdateVisibility(const CGUIListItem
*item
)
56 CGUIControl::UpdateVisibility(item
);
58 // now that we've checked for conditional info, we can
59 // check for allocation
63 void CGUIImage::UpdateDiffuseColor(const CGUIListItem
* item
)
65 if (m_texture
->SetDiffuseColor(m_diffuseColor
, item
))
71 void CGUIImage::UpdateInfo(const CGUIListItem
*item
)
73 // The texture may also depend on info conditions. Update the diffuse color in that case.
74 if (m_texture
->GetDiffuseColor().HasInfo())
75 UpdateDiffuseColor(item
);
77 if (m_info
.IsConstant())
78 return; // nothing to do
80 // don't allow image to change while animating out
81 if (HasProcessed() && IsAnimating(ANIM_TYPE_HIDDEN
) && !IsVisibleFromSkin())
85 SetFileName(m_info
.GetItemLabel(item
, true, &m_currentFallback
));
87 SetFileName(m_info
.GetLabel(m_parentID
, true, &m_currentFallback
));
90 void CGUIImage::AllocateOnDemand()
92 // if we're hidden, we can free our resources and return
93 if (!IsVisible() && m_visible
!= DELAYED
)
95 if (m_bDynamicResourceAlloc
&& m_texture
->IsAllocated())
96 FreeResourcesButNotAnims();
100 // either visible or delayed - we need the resources allocated in either case
101 if (!m_texture
->IsAllocated())
105 void CGUIImage::Process(unsigned int currentTime
, CDirtyRegionList
&dirtyregions
)
107 // check whether our image failed to allocate, and if so drop back to the fallback image
108 if (m_texture
->FailedToAlloc() && m_texture
->GetFileName() != m_info
.GetFallback())
110 if (!m_currentFallback
.empty() && m_texture
->GetFileName() != m_currentFallback
)
111 m_texture
->SetFileName(m_currentFallback
);
113 m_texture
->SetFileName(m_info
.GetFallback());
118 // make sure our texture has started allocating
119 if (m_texture
->AllocResources())
122 // compute the frame time
123 unsigned int frameTime
= 0;
124 if (m_lastRenderTime
)
125 frameTime
= currentTime
- m_lastRenderTime
;
127 frameTime
= (unsigned int)(1000 / CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS());
128 m_lastRenderTime
= currentTime
;
130 if (m_fadingTextures
.size()) // have some fading images
131 { // anything other than the last old texture needs to be faded out as per usual
132 for (std::vector
<CFadingTexture
*>::iterator i
= m_fadingTextures
.begin(); i
!= m_fadingTextures
.end() - 1;)
134 if (!ProcessFading(*i
, frameTime
, currentTime
))
135 i
= m_fadingTextures
.erase(i
);
140 if (m_texture
->ReadyToRender() || m_texture
->GetFileName().empty())
141 { // fade out the last one as well
142 if (!ProcessFading(m_fadingTextures
[m_fadingTextures
.size() - 1], frameTime
, currentTime
))
143 m_fadingTextures
.erase(m_fadingTextures
.end() - 1);
146 { // keep the last one fading in
147 CFadingTexture
*texture
= m_fadingTextures
[m_fadingTextures
.size() - 1];
148 texture
->m_fadeTime
+= frameTime
;
149 if (texture
->m_fadeTime
> m_crossFadeTime
)
150 texture
->m_fadeTime
= m_crossFadeTime
;
152 if (texture
->m_texture
->SetAlpha(GetFadeLevel(texture
->m_fadeTime
)))
154 if (texture
->m_texture
->SetDiffuseColor(m_diffuseColor
))
156 if (texture
->m_texture
->Process(currentTime
))
161 if (m_texture
->ReadyToRender() || m_texture
->GetFileName().empty())
162 { // fade the new one in
163 m_currentFadeTime
+= frameTime
;
164 if (m_currentFadeTime
> m_crossFadeTime
|| frameTime
== 0) // for if we allocate straight away on creation
165 m_currentFadeTime
= m_crossFadeTime
;
167 if (m_texture
->SetAlpha(GetFadeLevel(m_currentFadeTime
)))
171 if (!m_texture
->GetDiffuseColor().HasInfo())
172 UpdateDiffuseColor(nullptr);
174 if (m_texture
->Process(currentTime
))
177 CGUIControl::Process(currentTime
, dirtyregions
);
180 void CGUIImage::Render()
182 if (!IsVisible()) return;
184 for (auto& itr
: m_fadingTextures
)
185 itr
->m_texture
->Render();
189 CGUIControl::Render();
192 bool CGUIImage::ProcessFading(CGUIImage::CFadingTexture
*texture
, unsigned int frameTime
, unsigned int currentTime
)
195 if (texture
->m_fadeTime
<= frameTime
)
196 { // time to kill off the texture
201 // render this texture
202 texture
->m_fadeTime
-= frameTime
;
204 if (texture
->m_texture
->SetAlpha(GetFadeLevel(texture
->m_fadeTime
)))
206 if (texture
->m_texture
->SetDiffuseColor(m_diffuseColor
))
208 if (texture
->m_texture
->Process(currentTime
))
214 bool CGUIImage::OnAction(const CAction
&action
)
219 bool CGUIImage::OnMessage(CGUIMessage
& message
)
221 if (message
.GetMessage() == GUI_MSG_REFRESH_THUMBS
)
223 if (!m_info
.IsConstant())
224 FreeTextures(true); // true as we want to free the texture immediately
227 else if (message
.GetMessage() == GUI_MSG_SET_FILENAME
)
229 SetFileName(message
.GetLabel());
232 else if (message
.GetMessage() == GUI_MSG_GET_FILENAME
)
234 message
.SetLabel(GetFileName());
237 return CGUIControl::OnMessage(message
);
240 void CGUIImage::AllocResources()
242 if (m_texture
->GetFileName().empty())
245 CGUIControl::AllocResources();
246 m_texture
->AllocResources();
249 void CGUIImage::FreeTextures(bool immediately
/* = false */)
251 m_texture
->FreeResources(immediately
);
252 for (unsigned int i
= 0; i
< m_fadingTextures
.size(); i
++)
253 delete m_fadingTextures
[i
];
254 m_fadingTextures
.clear();
255 m_currentTexture
.clear();
256 if (!m_info
.IsConstant()) // constant textures never change
257 m_texture
->SetFileName("");
260 void CGUIImage::FreeResources(bool immediately
)
262 FreeTextures(immediately
);
263 CGUIControl::FreeResources(immediately
);
266 void CGUIImage::SetInvalid()
268 m_texture
->SetInvalid();
269 CGUIControl::SetInvalid();
272 // WORKAROUND - we are currently resetting all animations when this is called, which shouldn't be the case
273 // see CGUIControl::FreeResources() - this needs remedying.
274 void CGUIImage::FreeResourcesButNotAnims()
278 m_hasProcessed
= false;
281 void CGUIImage::DynamicResourceAlloc(bool bOnOff
)
283 m_bDynamicResourceAlloc
= bOnOff
;
284 m_texture
->DynamicResourceAlloc(bOnOff
);
285 CGUIControl::DynamicResourceAlloc(bOnOff
);
288 bool CGUIImage::CanFocus() const
293 float CGUIImage::GetTextureWidth() const
295 return m_texture
->GetTextureWidth();
298 float CGUIImage::GetTextureHeight() const
300 return m_texture
->GetTextureHeight();
303 CRect
CGUIImage::CalcRenderRegion() const
305 CRect region
= m_texture
->GetRenderRect();
307 for (const auto& itr
: m_fadingTextures
)
308 region
.Union(itr
->m_texture
->GetRenderRect());
310 return CGUIControl::CalcRenderRegion().Intersect(region
);
313 const std::string
&CGUIImage::GetFileName() const
315 return m_texture
->GetFileName();
318 void CGUIImage::SetAspectRatio(const CAspectRatio
&aspect
)
320 m_texture
->SetAspectRatio(aspect
);
323 void CGUIImage::SetCrossFade(unsigned int time
)
325 m_crossFadeTime
= time
;
326 if (!m_crossFadeTime
&& m_texture
->IsLazyLoaded() && !m_info
.GetFallback().empty())
330 void CGUIImage::SetFileName(const std::string
& strFileName
, bool setConstant
, const bool useCache
)
333 m_info
.SetLabel(strFileName
, "", GetParentID());
335 // Set whether or not to use cache
336 m_texture
->SetUseCache(useCache
);
340 // set filename on the next texture
341 if (m_currentTexture
== strFileName
)
342 return; // nothing to do - we already have this image
344 if (m_texture
->ReadyToRender() || m_texture
->GetFileName().empty())
345 { // save the current image
346 m_fadingTextures
.push_back(new CFadingTexture(m_texture
.get(), m_currentFadeTime
));
349 m_currentFadeTime
= 0;
351 if (m_currentTexture
!= strFileName
)
352 { // texture is changing - attempt to load it, and save the name in m_currentTexture.
353 // we'll check whether it loaded or not in Render()
354 m_currentTexture
= strFileName
;
355 if (m_texture
->SetFileName(m_currentTexture
))
361 void CGUIImage::DumpTextureUse()
363 if (m_texture
->IsAllocated())
366 CLog::Log(LOGDEBUG
, "Image control {} using texture {}", GetID(), m_texture
->GetFileName());
368 CLog::Log(LOGDEBUG
, "Using texture {}", m_texture
->GetFileName());
373 void CGUIImage::SetWidth(float width
)
375 m_texture
->SetWidth(width
);
376 CGUIControl::SetWidth(m_texture
->GetWidth());
379 void CGUIImage::SetHeight(float height
)
381 m_texture
->SetHeight(height
);
382 CGUIControl::SetHeight(m_texture
->GetHeight());
385 void CGUIImage::SetPosition(float posX
, float posY
)
387 m_texture
->SetPosition(posX
, posY
);
388 CGUIControl::SetPosition(posX
, posY
);
391 void CGUIImage::SetInfo(const GUIINFO::CGUIInfoLabel
&info
)
394 // a constant image never needs updating
395 if (m_info
.IsConstant())
396 m_texture
->SetFileName(m_info
.GetLabel(0));
399 unsigned char CGUIImage::GetFadeLevel(unsigned int time
) const
401 float amount
= (float)time
/ m_crossFadeTime
;
402 // we want a semi-transparent image, so we need to use a more complicated
403 // fade technique. Assuming a black background (not generally true, but still...)
405 // b(t) = [a - b(1-t)*a] / a*(1-b(1-t)*a),
406 // where a = alpha, and b(t):[0,1] -> [0,1] is the blend function.
408 // b(t) = [1 - (1-a)^t] / a
409 const float alpha
= 0.7f
;
410 return (unsigned char)(255.0f
* (1 - pow(1-alpha
, amount
))/alpha
);
413 std::string
CGUIImage::GetDescription(void) const
415 return GetFileName();