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/>.
21 #include "libsquish/squish.h"
23 #include "TextureBundleXBT.h"
25 #include "GraphicContext.h"
26 #include "utils/log.h"
27 #include "addons/Skin.h"
28 #include "settings/Settings.h"
29 #include "filesystem/SpecialProtocol.h"
30 #include "utils/EndianSwap.h"
31 #include "utils/URIUtils.h"
32 #include "utils/StringUtils.h"
34 #include <lzo/lzo1x.h>
35 #include "utils/StringUtils.h"
38 #pragma comment(lib,"liblzo2.lib")
41 CTextureBundleXBT::CTextureBundleXBT(void)
43 m_themeBundle = false;
47 CTextureBundleXBT::~CTextureBundleXBT(void)
52 bool CTextureBundleXBT::OpenBundle()
56 // Find the correct texture file (skin or theme)
61 // if we are the theme bundle, we only load if the user has chosen
62 // a valid theme (or the skin has a default one)
63 CStdString theme = CSettings::Get().GetString("lookandfeel.skintheme");
64 if (!theme.empty() && theme.CompareNoCase("SKINDEFAULT"))
66 CStdString themeXBT(URIUtils::ReplaceExtension(theme, ".xbt"));
67 strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
68 strPath = URIUtils::AddFileToFolder(strPath, themeXBT);
77 strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xbt");
80 strPath = CSpecialProtocol::TranslatePathConvertCase(strPath);
82 // Load the texture file
83 if (!m_XBTFReader.Open(strPath))
88 CLog::Log(LOGDEBUG, "%s - Opened bundle %s", __FUNCTION__, strPath.c_str());
90 m_TimeStamp = m_XBTFReader.GetLastModificationTimestamp();
92 if (lzo_init() != LZO_E_OK)
100 bool CTextureBundleXBT::HasFile(const CStdString& Filename)
102 if (!m_XBTFReader.IsOpen() && !OpenBundle())
105 if (m_XBTFReader.GetLastModificationTimestamp() > m_TimeStamp)
107 CLog::Log(LOGINFO, "Texture bundle has changed, reloading");
112 CStdString name = Normalize(Filename);
113 return m_XBTFReader.Exists(name);
116 void CTextureBundleXBT::GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures)
118 if (path.GetLength() > 1 && path[1] == ':')
121 if (!m_XBTFReader.IsOpen() && !OpenBundle())
124 CStdString testPath = Normalize(path);
125 URIUtils::AddSlashAtEnd(testPath);
127 std::vector<CXBTFFile>& files = m_XBTFReader.GetFiles();
128 for (size_t i = 0; i < files.size(); i++)
130 CStdString path = files[i].GetPath();
131 if (StringUtils::StartsWithNoCase(path, testPath))
132 textures.push_back(path);
136 bool CTextureBundleXBT::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
137 int &width, int &height)
139 CStdString name = Normalize(Filename);
141 CXBTFFile* file = m_XBTFReader.Find(name);
145 if (file->GetFrames().size() == 0)
148 CXBTFFrame& frame = file->GetFrames().at(0);
149 if (!ConvertFrameToTexture(Filename, frame, ppTexture))
154 width = frame.GetWidth();
155 height = frame.GetHeight();
160 int CTextureBundleXBT::LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures,
161 int &width, int &height, int& nLoops, int** ppDelays)
163 CStdString name = Normalize(Filename);
165 CXBTFFile* file = m_XBTFReader.Find(name);
169 if (file->GetFrames().size() == 0)
172 size_t nTextures = file->GetFrames().size();
173 *ppTextures = new CBaseTexture*[nTextures];
174 *ppDelays = new int[nTextures];
176 for (size_t i = 0; i < nTextures; i++)
178 CXBTFFrame& frame = file->GetFrames().at(i);
180 if (!ConvertFrameToTexture(Filename, frame, &((*ppTextures)[i])))
185 (*ppDelays)[i] = frame.GetDuration();
188 width = file->GetFrames().at(0).GetWidth();
189 height = file->GetFrames().at(0).GetHeight();
190 nLoops = file->GetLoop();
195 bool CTextureBundleXBT::ConvertFrameToTexture(const CStdString& name, CXBTFFrame& frame, CBaseTexture** ppTexture)
197 // found texture - allocate the necessary buffers
198 squish::u8 *buffer = new squish::u8[(size_t)frame.GetPackedSize()];
201 CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %"PRIu64" bytes)", name.c_str(), frame.GetPackedSize());
205 // load the compressed texture
206 if (!m_XBTFReader.Load(frame, buffer))
208 CLog::Log(LOGERROR, "Error loading texture: %s", name.c_str());
213 // check if it's packed with lzo
214 if (frame.IsPacked())
216 squish::u8 *unpacked = new squish::u8[(size_t)frame.GetUnpackedSize()];
217 if (unpacked == NULL)
219 CLog::Log(LOGERROR, "Out of memory unpacking texture: %s (need %"PRIu64" bytes)", name.c_str(), frame.GetUnpackedSize());
223 lzo_uint s = (lzo_uint)frame.GetUnpackedSize();
224 if (lzo1x_decompress_safe(buffer, (lzo_uint)frame.GetPackedSize(), unpacked, &s, NULL) != LZO_E_OK ||
225 s != frame.GetUnpackedSize())
227 CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", name.c_str());
236 // create an xbmc texture
237 *ppTexture = new CTexture();
238 (*ppTexture)->LoadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, frame.GetFormat(), frame.HasAlpha(), buffer);
245 void CTextureBundleXBT::Cleanup()
247 if (m_XBTFReader.IsOpen())
249 m_XBTFReader.Close();
250 CLog::Log(LOGDEBUG, "%s - Closed %sbundle", __FUNCTION__, m_themeBundle ? "theme " : "");
254 void CTextureBundleXBT::SetThemeBundle(bool themeBundle)
256 m_themeBundle = themeBundle;
259 // normalize to how it's stored within the bundle
260 // lower case + using forward slash rather than back slash
261 CStdString CTextureBundleXBT::Normalize(const CStdString &name)
263 CStdString newName(name);
265 StringUtils::Trim(newName);
266 StringUtils::ToLower(newName);
267 newName.Replace('\\','/');