fba135012fbd673d65da9fed2efa0966009acce9
[vuplus_xbmc] / xbmc / guilib / TextureBundleXBT.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "libsquish/squish.h"
22 #include "system.h"
23 #include "TextureBundleXBT.h"
24 #include "Texture.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 "XBTF.h"
33 #include <lzo/lzo1x.h>
34 #include "utils/StringUtils.h"
35
36 #ifdef TARGET_WINDOWS
37 #pragma comment(lib,"liblzo2.lib")
38 #endif
39
40 CTextureBundleXBT::CTextureBundleXBT(void)
41 {
42   m_themeBundle = false;
43   m_TimeStamp = 0;
44 }
45
46 CTextureBundleXBT::~CTextureBundleXBT(void)
47 {
48   Cleanup();
49 }
50
51 bool CTextureBundleXBT::OpenBundle()
52 {
53   Cleanup();
54
55   // Find the correct texture file (skin or theme)
56   CStdString strPath;
57
58   if (m_themeBundle)
59   {
60     // if we are the theme bundle, we only load if the user has chosen
61     // a valid theme (or the skin has a default one)
62     CStdString theme = CSettings::Get().GetString("lookandfeel.skintheme");
63     if (!theme.IsEmpty() && theme.CompareNoCase("SKINDEFAULT"))
64     {
65       CStdString themeXBT(URIUtils::ReplaceExtension(theme, ".xbt"));
66       strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
67       strPath = URIUtils::AddFileToFolder(strPath, themeXBT);
68     }
69     else
70     {
71       return false;
72     }
73   }
74   else
75   {
76     strPath = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xbt");
77   }
78
79   strPath = CSpecialProtocol::TranslatePathConvertCase(strPath);
80
81   // Load the texture file
82   if (!m_XBTFReader.Open(strPath))
83   {
84     return false;
85   }
86
87   CLog::Log(LOGDEBUG, "%s - Opened bundle %s", __FUNCTION__, strPath.c_str());
88
89   m_TimeStamp = m_XBTFReader.GetLastModificationTimestamp();
90
91   if (lzo_init() != LZO_E_OK)
92   {
93     return false;
94   }
95
96   return true;
97 }
98
99 bool CTextureBundleXBT::HasFile(const CStdString& Filename)
100 {
101   if (!m_XBTFReader.IsOpen() && !OpenBundle())
102     return false;
103
104   if (m_XBTFReader.GetLastModificationTimestamp() > m_TimeStamp)
105   {
106     CLog::Log(LOGINFO, "Texture bundle has changed, reloading");
107     if (!OpenBundle())
108       return false;
109   }
110
111   CStdString name = Normalize(Filename);
112   return m_XBTFReader.Exists(name);
113 }
114
115 void CTextureBundleXBT::GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures)
116 {
117   if (path.GetLength() > 1 && path[1] == ':')
118     return;
119
120   if (!m_XBTFReader.IsOpen() && !OpenBundle())
121     return;
122
123   CStdString testPath = Normalize(path);
124   URIUtils::AddSlashAtEnd(testPath);
125
126   std::vector<CXBTFFile>& files = m_XBTFReader.GetFiles();
127   for (size_t i = 0; i < files.size(); i++)
128   {
129     CStdString path = files[i].GetPath();
130     if (StringUtils::StartsWithNoCase(path, testPath))
131       textures.push_back(path);
132   }
133 }
134
135 bool CTextureBundleXBT::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
136                                      int &width, int &height)
137 {
138   CStdString name = Normalize(Filename);
139
140   CXBTFFile* file = m_XBTFReader.Find(name);
141   if (!file)
142     return false;
143
144   if (file->GetFrames().size() == 0)
145     return false;
146
147   CXBTFFrame& frame = file->GetFrames().at(0);
148   if (!ConvertFrameToTexture(Filename, frame, ppTexture))
149   {
150     return false;
151   }
152
153   width = frame.GetWidth();
154   height = frame.GetHeight();
155
156   return true;
157 }
158
159 int CTextureBundleXBT::LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures,
160                               int &width, int &height, int& nLoops, int** ppDelays)
161 {
162   CStdString name = Normalize(Filename);
163
164   CXBTFFile* file = m_XBTFReader.Find(name);
165   if (!file)
166     return false;
167
168   if (file->GetFrames().size() == 0)
169     return false;
170
171   size_t nTextures = file->GetFrames().size();
172   *ppTextures = new CBaseTexture*[nTextures];
173   *ppDelays = new int[nTextures];
174
175   for (size_t i = 0; i < nTextures; i++)
176   {
177     CXBTFFrame& frame = file->GetFrames().at(i);
178
179     if (!ConvertFrameToTexture(Filename, frame, &((*ppTextures)[i])))
180     {
181       return false;
182     }
183
184     (*ppDelays)[i] = frame.GetDuration();
185   }
186
187   width = file->GetFrames().at(0).GetWidth();
188   height = file->GetFrames().at(0).GetHeight();
189   nLoops = file->GetLoop();
190
191   return nTextures;
192 }
193
194 bool CTextureBundleXBT::ConvertFrameToTexture(const CStdString& name, CXBTFFrame& frame, CBaseTexture** ppTexture)
195 {
196   // found texture - allocate the necessary buffers
197   squish::u8 *buffer = new squish::u8[(size_t)frame.GetPackedSize()];
198   if (buffer == NULL)
199   {
200     CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %"PRIu64" bytes)", name.c_str(), frame.GetPackedSize());
201     return false;
202   }
203
204   // load the compressed texture
205   if (!m_XBTFReader.Load(frame, buffer))
206   {
207     CLog::Log(LOGERROR, "Error loading texture: %s", name.c_str());
208     delete[] buffer;
209     return false;
210   }
211
212   // check if it's packed with lzo
213   if (frame.IsPacked())
214   { // unpack
215     squish::u8 *unpacked = new squish::u8[(size_t)frame.GetUnpackedSize()];
216     if (unpacked == NULL)
217     {
218       CLog::Log(LOGERROR, "Out of memory unpacking texture: %s (need %"PRIu64" bytes)", name.c_str(), frame.GetUnpackedSize());
219       delete[] buffer;
220       return false;
221     }
222     lzo_uint s = (lzo_uint)frame.GetUnpackedSize();
223     if (lzo1x_decompress_safe(buffer, (lzo_uint)frame.GetPackedSize(), unpacked, &s, NULL) != LZO_E_OK ||
224         s != frame.GetUnpackedSize())
225     {
226       CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", name.c_str());
227       delete[] buffer;
228       delete[] unpacked;
229       return false;
230     }
231     delete[] buffer;
232     buffer = unpacked;
233   }
234
235   // create an xbmc texture
236   *ppTexture = new CTexture();
237   (*ppTexture)->LoadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, frame.GetFormat(), frame.HasAlpha(), buffer);
238
239   delete[] buffer;
240
241   return true;
242 }
243
244 void CTextureBundleXBT::Cleanup()
245 {
246   if (m_XBTFReader.IsOpen())
247   {
248     m_XBTFReader.Close();
249     CLog::Log(LOGDEBUG, "%s - Closed %sbundle", __FUNCTION__, m_themeBundle ? "theme " : "");
250   }
251 }
252
253 void CTextureBundleXBT::SetThemeBundle(bool themeBundle)
254 {
255   m_themeBundle = themeBundle;
256 }
257
258 // normalize to how it's stored within the bundle
259 // lower case + using forward slash rather than back slash
260 CStdString CTextureBundleXBT::Normalize(const CStdString &name)
261 {
262   CStdString newName(name);
263   newName.Normalize();
264   newName.Replace('\\','/');
265
266   return newName;
267 }