fixed: curl could assert if something threw an exception inside
[xbmc:xbmc-antiquated.git] / guilib / TextureManager.cpp
1 #include "include.h"
2 #include "TextureManager.h"
3 #include "AnimatedGif.h"
4 #include "PackedTexture.h"
5 #include "GraphicContext.h"
6 #include "../xbmc/utils/SingleLock.h"
7 #include "../xbmc/StringUtils.h"
8 #include "../xbmc/utils/CharsetConverter.h"
9
10 #ifdef HAS_XBOX_D3D
11 #include <XGraphics.h>
12 #endif
13
14
15 extern "C" void dllprintf( const char *format, ... );
16
17 CGUITextureManager g_TextureManager;
18
19 CTexture::CTexture()
20 {
21   m_iReferenceCount = 0;
22   m_pTexture = NULL;
23   m_iDelay = 100;
24   m_iWidth = m_iHeight = 0;
25   m_iLoops = 0;
26   m_pPalette = NULL;
27   m_bPacked = false;
28   m_memUsage = 0;
29   m_format = D3DFMT_UNKNOWN;
30 }
31
32 CTexture::CTexture(LPDIRECT3DTEXTURE8 pTexture, int iWidth, int iHeight, bool bPacked, int iDelay, LPDIRECT3DPALETTE8 pPalette)
33 {
34   m_iLoops = 0;
35   m_iReferenceCount = 0;
36   m_pTexture = pTexture;
37   m_iDelay = 2 * iDelay;
38   m_iWidth = iWidth;
39   m_iHeight = iHeight;
40 #ifdef HAS_XBOX_D3D
41   m_pPalette = pPalette;
42   if (m_pPalette)
43     m_pPalette->AddRef();
44 #endif
45   m_bPacked = bPacked;
46   ReadTextureInfo();
47 }
48
49 CTexture::~CTexture()
50 {
51   FreeTexture();
52 }
53
54 void CTexture::FreeTexture()
55 {
56   CSingleLock lock(g_graphicsContext);
57
58   if (m_pTexture)
59   {
60     if (m_bPacked)
61     {
62 #ifdef HAS_XBOX_D3D
63       m_pTexture->BlockUntilNotBusy();
64       void* Data = (void*)(*(DWORD*)(((char*)m_pTexture) + sizeof(D3DTexture)));
65       if (Data)
66         XPhysicalFree(Data);
67       delete [] m_pTexture;
68 #else
69       m_pTexture->Release();
70 #endif
71     }
72     else
73       m_pTexture->Release();
74     m_pTexture = NULL;
75   }
76 #ifdef HAS_XBOX_D3D
77   if (m_pPalette)
78   {
79     if (m_bPacked)
80     {
81       if ((m_pPalette->Common & D3DCOMMON_REFCOUNT_MASK) > 1)
82         m_pPalette->Release();
83       else
84         delete m_pPalette;
85     }
86     else
87       m_pPalette->Release();
88   }
89 #endif
90   m_pPalette = NULL;
91 }
92
93 void CTexture::Dump() const
94 {
95   if (!m_iReferenceCount) return ;
96   CStdString strLog;
97   strLog.Format("refcount:%i\n:", m_iReferenceCount);
98   OutputDebugString(strLog.c_str());
99 }
100
101 void CTexture::SetLoops(int iLoops)
102 {
103   m_iLoops = iLoops;
104 }
105
106 int CTexture::GetLoops() const
107 {
108   return m_iLoops;
109 }
110
111 void CTexture::SetDelay(int iDelay)
112 {
113   if (iDelay)
114   {
115     m_iDelay = 2 * iDelay;
116   }
117   else
118   {
119     m_iDelay = 100;
120   }
121 }
122 void CTexture::Flush()
123 {
124   if (!m_iReferenceCount)
125     FreeTexture();
126 }
127
128 bool CTexture::Release()
129 {
130   if (!m_pTexture) return true;
131   if (!m_iReferenceCount) return true;
132   if (m_iReferenceCount > 0)
133   {
134     m_iReferenceCount--;
135   }
136
137   if (!m_iReferenceCount)
138   {
139     FreeTexture();
140     return true;
141   }
142   return false;
143 }
144
145 int CTexture::GetDelay() const
146 {
147   return m_iDelay;
148 }
149
150 int CTexture::GetRef() const
151 {
152   return m_iReferenceCount;
153 }
154
155 void CTexture::ReadTextureInfo()
156 {
157   m_memUsage = 0;
158   D3DSURFACE_DESC desc;
159   if (m_pTexture && D3D_OK == m_pTexture->GetLevelDesc(0, &desc))
160   {
161     m_memUsage += desc.Size;
162     m_format = desc.Format;
163   }
164   // palette as well? if (m_pPalette)
165 /*
166   if (m_pPalette)
167   {
168     D3DPALETTESIZE size = m_pPalette->GetSize();
169     switch size
170   }*/
171 }
172
173 DWORD CTexture::GetMemoryUsage() const
174 {
175   return m_memUsage;
176 }
177
178 LPDIRECT3DTEXTURE8 CTexture::GetTexture(int& iWidth, int& iHeight, LPDIRECT3DPALETTE8& pPal, bool &linearTexture)
179 {
180   if (!m_pTexture) return NULL;
181   m_iReferenceCount++;
182   iWidth = m_iWidth;
183   iHeight = m_iHeight;
184   pPal = m_pPalette;
185   linearTexture = (m_format == D3DFMT_LIN_A8R8G8B8);
186   return m_pTexture;
187 }
188
189 //-----------------------------------------------------------------------------
190 CTextureMap::CTextureMap()
191 {
192   m_strTextureName = "";
193 }
194
195 CTextureMap::CTextureMap(const CStdString& strTextureName)
196 {
197   m_strTextureName = strTextureName;
198 }
199
200 CTextureMap::~CTextureMap()
201 {
202   for (int i = 0; i < (int)m_vecTexures.size(); ++i)
203   {
204     CTexture* pTexture = m_vecTexures[i];
205     delete pTexture ;
206   }
207   m_vecTexures.erase(m_vecTexures.begin(), m_vecTexures.end());
208 }
209
210 void CTextureMap::Dump() const
211 {
212   if (IsEmpty()) return ;
213   CStdString strLog;
214   strLog.Format("  texure:%s has %i frames\n", m_strTextureName.c_str(), m_vecTexures.size());
215   OutputDebugString(strLog.c_str());
216
217   for (int i = 0; i < (int)m_vecTexures.size(); ++i)
218   {
219     const CTexture* pTexture = m_vecTexures[i];
220
221     strLog.Format("    item:%i ", i);
222     OutputDebugString(strLog.c_str());
223     pTexture->Dump();
224   }
225 }
226
227
228 const CStdString& CTextureMap:: GetName() const
229 {
230   return m_strTextureName;
231 }
232
233 int CTextureMap::size() const
234 {
235   return m_vecTexures.size();
236 }
237
238 bool CTextureMap::IsEmpty() const
239 {
240   int iRef = 0;
241   for (int i = 0; i < (int)m_vecTexures.size(); ++i)
242   {
243     iRef += m_vecTexures[i]->GetRef();
244   }
245   return (iRef == 0);
246 }
247
248 void CTextureMap::Add(CTexture* pTexture)
249 {
250   m_vecTexures.push_back(pTexture);
251 }
252
253 bool CTextureMap::Release(int iPicture)
254 {
255   if (iPicture < 0 || iPicture >= (int)m_vecTexures.size()) return true;
256
257   CTexture* pTexture = m_vecTexures[iPicture];
258   return pTexture->Release();
259 }
260
261 int CTextureMap::GetLoops(int iPicture) const
262 {
263   if (iPicture < 0 || iPicture >= (int)m_vecTexures.size()) return 0;
264   CTexture* pTexture = m_vecTexures[iPicture];
265   return pTexture->GetLoops();
266 }
267
268 int CTextureMap::GetDelay(int iPicture) const
269 {
270   if (iPicture < 0 || iPicture >= (int)m_vecTexures.size()) return 100;
271
272   CTexture* pTexture = m_vecTexures[iPicture];
273   return pTexture->GetDelay();
274 }
275
276
277 LPDIRECT3DTEXTURE8 CTextureMap::GetTexture(int iPicture, int& iWidth, int& iHeight, LPDIRECT3DPALETTE8& pPal, bool &linearTexture)
278 {
279   if (iPicture < 0 || iPicture >= (int)m_vecTexures.size()) return NULL;
280
281   CTexture* pTexture = m_vecTexures[iPicture];
282   return pTexture->GetTexture(iWidth, iHeight, pPal, linearTexture);
283 }
284
285 void CTextureMap::Flush()
286 {
287   for (int i = 0; i < (int)m_vecTexures.size(); ++i)
288   {
289     m_vecTexures[i]->Flush();
290   }
291 }
292
293 DWORD CTextureMap::GetMemoryUsage() const
294 {
295   DWORD memUsage = 0;
296   for (int i = 0; i < (int)m_vecTexures.size(); ++i)
297   {
298     memUsage += m_vecTexures[i]->GetMemoryUsage();
299   }
300   return memUsage;
301 }
302
303
304 //------------------------------------------------------------------------------
305 CGUITextureManager::CGUITextureManager(void)
306 {
307 #ifdef HAS_XBOX_D3D
308   D3DXSetDXT3DXT5(TRUE);
309 #endif
310   for (int bundle = 0; bundle < 2; bundle++)
311     m_iNextPreload[bundle] = m_PreLoadNames[bundle].end();
312   // we set the theme bundle to be the first bundle (thus prioritising it
313   m_TexBundle[0].SetThemeBundle(true);
314 }
315
316 CGUITextureManager::~CGUITextureManager(void)
317 {
318   Cleanup();
319 }
320
321
322 LPDIRECT3DTEXTURE8 CGUITextureManager::GetTexture(const CStdString& strTextureName, int iItem, int& iWidth, int& iHeight, LPDIRECT3DPALETTE8& pPal, bool &linearTexture)
323 {
324   //  CLog::Log(LOGINFO, " refcount++ for  GetTexture(%s)\n", strTextureName.c_str());
325   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
326   {
327     CTextureMap *pMap = m_vecTextures[i];
328     if (pMap->GetName() == strTextureName)
329     {
330       //CLog::Log(LOGDEBUG, "Total memusage %u", GetMemoryUsage());
331       return pMap->GetTexture(iItem, iWidth, iHeight, pPal, linearTexture);
332     }
333   }
334   return NULL;
335 }
336
337 int CGUITextureManager::GetLoops(const CStdString& strTextureName, int iPicture) const
338 {
339   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
340   {
341     CTextureMap *pMap = m_vecTextures[i];
342     if (pMap->GetName() == strTextureName)
343     {
344       return pMap->GetLoops(iPicture);
345     }
346   }
347   return 0;
348 }
349 int CGUITextureManager::GetDelay(const CStdString& strTextureName, int iPicture) const
350 {
351   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
352   {
353     CTextureMap *pMap = m_vecTextures[i];
354     if (pMap->GetName() == strTextureName)
355     {
356       return pMap->GetDelay(iPicture);
357     }
358   }
359   return 100;
360 }
361
362 // Round a number to the nearest power of 2 rounding up
363 // runs pretty quickly - the only expensive op is the bsr
364 // alternive would be to dec the source, round down and double the result
365 // which is slightly faster but rounds 1 to 2
366 DWORD __forceinline __stdcall PadPow2(DWORD x)
367 {
368   __asm {
369     mov edx, x    // put the value in edx
370     xor ecx, ecx  // clear ecx - if x is 0 bsr doesn't alter it
371     bsr ecx, edx  // find MSB position
372     mov eax, 1    // shift 1 by result effectively
373     shl eax, cl   // doing a round down to power of 2
374     cmp eax, edx  // check if x was already a power of two
375     adc ecx, 0    // if it wasn't then CF is set so add to ecx
376     mov eax, 1    // shift 1 by result again, this does a round
377     shl eax, cl   // up as a result of adding CF to ecx
378   }
379   // return result in eax
380 }
381
382 void CGUITextureManager::StartPreLoad()
383 {
384   for (int bundle = 0; bundle < 2; bundle++)
385     m_PreLoadNames[bundle].clear();
386 }
387
388 void CGUITextureManager::PreLoad(const CStdString& strTextureName)
389 {
390   if (strTextureName.c_str()[1] == ':' || strTextureName == "-")
391     return ;
392
393   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
394   {
395     CTextureMap *pMap = m_vecTextures[i];
396     if (pMap->GetName() == strTextureName)
397       return ;
398   }
399
400   for (int bundle = 0; bundle < 2; bundle++)
401   {
402     for (list<CStdString>::iterator i = m_PreLoadNames[bundle].begin(); i != m_PreLoadNames[bundle].end(); ++i)
403     {
404       if (*i == strTextureName)
405         return ;
406     }
407
408     if (m_TexBundle[bundle].HasFile(strTextureName))
409     {
410       m_PreLoadNames[bundle].push_back(strTextureName);
411       return;
412     }
413   }
414 }
415
416 void CGUITextureManager::EndPreLoad()
417 {
418   for (int i = 0; i < 2; i++)
419   {
420     m_iNextPreload[i] = m_PreLoadNames[i].begin();
421     // preload next file
422     if (m_iNextPreload[i] != m_PreLoadNames[i].end())
423       m_TexBundle[i].PreloadFile(*m_iNextPreload[i]);
424   }
425 }
426
427 void CGUITextureManager::FlushPreLoad()
428 {
429   for (int i = 0; i < 2; i++)
430   {
431     m_PreLoadNames[i].clear();
432     m_iNextPreload[i] = m_PreLoadNames[i].end();
433   }
434 }
435
436 int CGUITextureManager::Load(const CStdString& strTextureName, DWORD dwColorKey, bool checkBundleOnly /*= false */)
437 {
438   if (strTextureName == "-")
439     return 0;
440   if (strTextureName.Find("://") >= 0)
441     return 0;
442
443   // first check of texture exists...
444   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
445   {
446     CTextureMap *pMap = m_vecTextures[i];
447     if (pMap->GetName() == strTextureName)
448     {
449       for (int i = 0; i < 2; i++)
450       {
451         if (m_iNextPreload[i] != m_PreLoadNames[i].end() && (*m_iNextPreload[i] == strTextureName))
452         {
453           ++m_iNextPreload[i];
454           // preload next file
455           if (m_iNextPreload[i] != m_PreLoadNames[i].end())
456             m_TexBundle[i].PreloadFile(*m_iNextPreload[i]);
457         }
458       }
459       return pMap->size();
460     }
461   }
462
463   //Lock here, we will do stuff that could break rendering
464   CSingleLock lock(g_graphicsContext);
465
466 #ifdef ALLOW_TEXTURE_COMPRESSION
467   LPDIRECT3DTEXTURE8 pTexture;
468   LPDIRECT3DPALETTE8 pPal = 0;
469
470   int bundle = -1;
471   const CStdString* pstrBundleTex = NULL;
472   for (int i = 0; i < 2; i++)
473   {
474     if (m_iNextPreload[i] != m_PreLoadNames[i].end() && (*m_iNextPreload[i] == strTextureName)) // || *m_iNextPreload == strPalTex))
475     {
476       pstrBundleTex = &strTextureName;
477
478       bundle = i;
479       ++m_iNextPreload[i];
480       // preload next file
481       if (m_iNextPreload[i] != m_PreLoadNames[i].end())
482         m_TexBundle[i].PreloadFile(*m_iNextPreload[i]);
483       break;
484     }
485     else if (m_TexBundle[i].HasFile(strTextureName))
486     {
487       pstrBundleTex = &strTextureName;
488       bundle = i;
489       break;
490     }
491   }
492
493   CStdString strPath;
494
495   if (checkBundleOnly && bundle == -1)
496     return 0;
497
498   if (bundle == -1)
499     strPath = GetTexturePath(strTextureName);
500   else
501     strPath = strTextureName;
502
503 #ifdef _DEBUG
504   LARGE_INTEGER start;
505   QueryPerformanceCounter(&start);
506 #endif
507
508   bool bPacked;
509   CStdString strPackedPath;
510   if (bundle == -1)
511   {
512     strPackedPath = strPath;
513     strPackedPath += ".xpr";
514     bPacked = (GetFileAttributes(strPackedPath.c_str()) != -1);
515   }
516   else
517     bPacked = false;
518
519   D3DXIMAGE_INFO info;
520
521   if (strPath.Right(4).ToLower() == ".gif")
522   {
523     CTextureMap* pMap;
524
525     if (bPacked || bundle >= 0)
526     {
527       LPDIRECT3DTEXTURE8* pTextures;
528       int nLoops = 0;
529       int* Delay;
530       int nImages;
531       if (bundle >= 0)
532       {
533         nImages = m_TexBundle[bundle].LoadAnim(g_graphicsContext.Get3DDevice(), *pstrBundleTex, &info, &pTextures, &pPal, nLoops, &Delay);
534         if (!nImages)
535         {
536           CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", pstrBundleTex->c_str());
537           return 0;
538         }
539       }
540       else // packed
541       {
542 #ifdef HAS_XBOX_D3D
543         nImages = LoadPackedAnim(g_graphicsContext.Get3DDevice(), strPackedPath.c_str(), &info, &pTextures, &pPal, nLoops, &Delay);
544         if (!nImages)
545 #endif
546         {
547           if (!strnicmp(strPackedPath.c_str(), "q:\\skin", 7))
548             CLog::Log(LOGERROR, "Texture manager unable to load packed file: %s", strPackedPath.c_str());
549           return 0;
550         }
551       }
552
553       pMap = new CTextureMap(strTextureName);
554       for (int iImage = 0; iImage < nImages; ++iImage)
555       {
556         CTexture* pclsTexture = new CTexture(pTextures[iImage], info.Width, info.Height, true, 100, pPal);
557         pclsTexture->SetDelay(Delay[iImage]);
558         pclsTexture->SetLoops(nLoops);
559         pMap->Add(pclsTexture);
560       }
561
562       delete [] pTextures;
563       delete [] Delay;
564 #ifdef HAS_XBOX_D3D
565       pPal->Release();
566 #endif
567     }
568     else
569     {
570       CAnimatedGifSet AnimatedGifSet;
571       int iImages = AnimatedGifSet.LoadGIF(strPath.c_str());
572       if (iImages == 0)
573       {
574         if (!strnicmp(strPath.c_str(), "q:\\skin", 7))
575           CLog::Log(LOGERROR, "Texture manager unable to load file: %s", strPath.c_str());
576         return 0;
577       }
578       int iWidth = AnimatedGifSet.FrameWidth;
579       int iHeight = AnimatedGifSet.FrameHeight;
580
581       int iPaletteSize = (1 << AnimatedGifSet.m_vecimg[0]->BPP);
582 #ifdef HAS_XBOX_D3D
583       g_graphicsContext.Get3DDevice()->CreatePalette(D3DPALETTE_256, &pPal);
584       PALETTEENTRY* pal;
585       pPal->Lock((D3DCOLOR**)&pal, 0);
586
587       memcpy(pal, AnimatedGifSet.m_vecimg[0]->Palette, sizeof(PALETTEENTRY)*iPaletteSize);
588       for (int i = 0; i < iPaletteSize; i++)
589         pal[i].peFlags = 0xff; // alpha
590       if (AnimatedGifSet.m_vecimg[0]->Transparency && AnimatedGifSet.m_vecimg[0]->Transparent >= 0)
591         pal[AnimatedGifSet.m_vecimg[0]->Transparent].peFlags = 0;
592
593       pPal->Unlock();
594 #endif
595       pMap = new CTextureMap(strTextureName);
596       for (int iImage = 0; iImage < iImages; iImage++)
597       {
598         int w = PadPow2(iWidth);
599         int h = PadPow2(iHeight);
600 #ifdef HAS_XBOX_D3D
601         if (D3DXCreateTexture(g_graphicsContext.Get3DDevice(), w, h, 1, 0, D3DFMT_P8, D3DPOOL_MANAGED, &pTexture) == D3D_OK)
602 #else
603         if (D3DXCreateTexture(g_graphicsContext.Get3DDevice(), w, h, 1, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_MANAGED, &pTexture) == D3D_OK)
604 #endif
605         {
606           CAnimatedGif* pImage = AnimatedGifSet.m_vecimg[iImage];
607           D3DLOCKED_RECT lr;
608           RECT rc = { 0, 0, pImage->Width, pImage->Height };
609           if ( D3D_OK == pTexture->LockRect( 0, &lr, &rc, 0 ))
610           {
611 #ifdef HAS_XBOX_D3D
612             POINT pt = { 0, 0 };
613             XGSwizzleRect(pImage->Raster, pImage->BytesPerRow, &rc, lr.pBits, w, h, &pt, 1);
614 #else
615             COLOR *palette = AnimatedGifSet.m_vecimg[0]->Palette;
616             // set the alpha values to fully opaque
617             for (int i = 0; i < iPaletteSize; i++)
618               palette[i].x = 0xff;
619             // and set the transparent colour
620             if (AnimatedGifSet.m_vecimg[0]->Transparency && AnimatedGifSet.m_vecimg[0]->Transparent >= 0)
621               palette[AnimatedGifSet.m_vecimg[0]->Transparent].x = 0;
622             
623             for (int y = 0; y < pImage->Height; y++)
624             {
625               BYTE *dest = (BYTE *)lr.pBits + y * lr.Pitch;
626               BYTE *source = (BYTE *)pImage->Raster + y * pImage->BytesPerRow;
627               for (int x = 0; x < pImage->Width; x++)
628               {
629                 COLOR col = palette[*source++];
630                 *dest++ = col.b;
631                 *dest++ = col.g;
632                 *dest++ = col.r;
633                 *dest++ = col.x;
634               }
635             }
636 #endif
637             pTexture->UnlockRect( 0 );
638
639             CTexture* pclsTexture = new CTexture(pTexture, iWidth, iHeight, false, 100, pPal);
640             pclsTexture->SetDelay(pImage->Delay);
641             pclsTexture->SetLoops(AnimatedGifSet.nLoops);
642
643             pMap->Add(pclsTexture);
644           }
645         }
646       } // of for (int iImage=0; iImage < iImages; iImage++)
647
648 #ifdef HAS_XBOX_D3D
649       pPal->Release();
650 #endif
651     }
652
653 #ifdef _DEBUG
654     LARGE_INTEGER end, freq;
655     QueryPerformanceCounter(&end);
656     QueryPerformanceFrequency(&freq);
657     char temp[200];
658     sprintf(temp, "Load %s: %.1fms%s\n", strPath.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, bPacked ? " (packed)" : (bundle >= 0) ? " (bundled)" : "");
659     OutputDebugString(temp);
660 #endif
661
662     m_vecTextures.push_back(pMap);
663     return pMap->size();
664   } // of if (strPath.Right(4).ToLower()==".gif")
665
666   if (bundle >= 0)
667   {
668     if (FAILED(m_TexBundle[bundle].LoadTexture(g_graphicsContext.Get3DDevice(), *pstrBundleTex, &info, &pTexture, &pPal)))
669     {
670       CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", pstrBundleTex->c_str());
671       return 0;
672     }
673   }
674   else if (bPacked)
675   {
676 #ifdef HAS_XBOX_D3D
677     if (FAILED(LoadPackedTexture(g_graphicsContext.Get3DDevice(), strPackedPath.c_str(), &info, &pTexture, &pPal)))
678 #endif
679     {
680       if (!strnicmp(strPackedPath.c_str(), "q:\\skin", 7))
681         CLog::Log(LOGERROR, "Texture manager unable to load packed file: %s", strPackedPath.c_str());
682       return 0;
683     }
684   }
685   else
686   {
687     if (strPath.Right(4).ToLower() == ".dds")
688     {
689       if ( D3DXCreateTextureFromFileEx(g_graphicsContext.Get3DDevice(), strPath.c_str(),
690                                        D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
691                                        D3DX_FILTER_NONE , D3DX_FILTER_NONE, dwColorKey, &info, NULL, &pTexture) != D3D_OK)
692       {
693         if (!strnicmp(strPath.c_str(), "q:\\skin", 7))
694           CLog::Log(LOGERROR, "Texture manager unable to load file: %s", strPath.c_str());
695         return 0;
696       }
697     }
698     else
699     {
700       // normal picture
701       // convert from utf8
702       CStdString texturePath;
703       g_charsetConverter.utf8ToStringCharset(strPath, texturePath);
704
705       if ( D3DXCreateTextureFromFileEx(g_graphicsContext.Get3DDevice(), texturePath.c_str(),
706                                        D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_MANAGED,
707                                        D3DX_FILTER_NONE , D3DX_FILTER_NONE, dwColorKey, &info, NULL, &pTexture) != D3D_OK)
708       {
709         if (!strnicmp(strPath.c_str(), "q:\\skin", 7))
710           CLog::Log(LOGERROR, "Texture manager unable to load file: %s", strPath.c_str());
711         return 0;
712
713       }
714     }
715   }
716
717 #ifdef _DEBUG
718   LARGE_INTEGER end, freq;
719   QueryPerformanceCounter(&end);
720   QueryPerformanceFrequency(&freq);
721   char temp[200];
722   sprintf(temp, "Load %s: %.1fms%s\n", strPath.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, bPacked ? " (packed)" : (bundle >= 0) ? " (bundled)" : "");
723   OutputDebugString(temp);
724 #endif
725
726   CTextureMap* pMap = new CTextureMap(strTextureName);
727   CTexture* pclsTexture = new CTexture(pTexture, info.Width, info.Height, bPacked || bundle >= 0, 100, pPal);
728   pMap->Add(pclsTexture);
729   m_vecTextures.push_back(pMap);
730 #ifdef HAS_XBOX_D3D
731   if (pPal)
732     pPal->Release();
733 #endif
734 #else
735
736   LPDIRECT3DTEXTURE8 pTexture;
737   CStdString strPath = GetTexturePath(strTextureName);
738
739   //OutputDebugString(strPath.c_str());
740   //OutputDebugString("\n");
741
742   if (strPath.Right(4).ToLower() == ".gif")
743   {
744
745     CAnimatedGifSet AnimatedGifSet;
746     int iImages = AnimatedGifSet.LoadGIF(strPath.c_str());
747     if (iImages == 0)
748     {
749       CStdString strText = strPath;
750       strText.MakeLower();
751       // dont release skin textures, they are reloaded each time
752       if (strstr(strPath.c_str(), "q:\\skin") )
753       {
754         CLog::Log(LOGERROR, "Texture manager unable to find file:%s", strPath.c_str());
755       }
756       return 0;
757     }
758     int iWidth = AnimatedGifSet.FrameWidth;
759     int iHeight = AnimatedGifSet.FrameHeight;
760
761     CTextureMap* pMap = new CTextureMap(strTextureName);
762     for (int iImage = 0; iImage < iImages; iImage++)
763     {
764       if (D3DXCreateTexture(g_graphicsContext.Get3DDevice(), iWidth,
765           iHeight,
766           1,  // levels
767           0,  //usage
768           D3DFMT_LIN_A8R8G8B8 ,
769           0,
770           &pTexture) == D3D_OK)
771       {
772         CAnimatedGif* pImage = AnimatedGifSet.m_vecimg[iImage];
773         //dllprintf("%s loops:%i", strTextureName.c_str(),AnimatedGifSet.nLoops);
774         D3DLOCKED_RECT lr;
775         if ( D3D_OK == pTexture->LockRect( 0, &lr, NULL, 0 ))
776         {
777           DWORD strideScreen = lr.Pitch;
778           for (DWORD y = 0; y < (DWORD)pImage->Height; y++)
779           {
780             BYTE *pDest = (BYTE*)lr.pBits + strideScreen * y;
781             for (DWORD x = 0;x < (DWORD)pImage->Width; x++)
782             {
783               byte byAlpha = 0xff;
784               byte iPaletteColor = (byte)pImage->Pixel( x, y);
785               if (pImage->Transparency)
786               {
787                 int iTransparentColor = pImage->Transparent;
788                 if (iTransparentColor < 0) iTransparentColor = 0;
789                 if (iPaletteColor == iTransparentColor)
790                 {
791                   byAlpha = 0x0;
792                 }
793               }
794               COLOR& Color = pImage->Palette[iPaletteColor];
795
796               *pDest++ = Color.b;
797               *pDest++ = Color.g;
798               *pDest++ = Color.r;
799               *pDest++ = byAlpha;
800             } // of for (DWORD x=0; x < (DWORD)pImage->Width; x++)
801           } // of for (DWORD y=0; y < (DWORD)pImage->Height; y++)
802           pTexture->UnlockRect( 0 );
803         } // of if ( D3D_OK == pTexture->LockRect( 0, &lr, NULL, 0 ))
804         CTexture* pclsTexture = new CTexture(pTexture, iWidth, iHeight, false);
805         pclsTexture->SetDelay(pImage->Delay);
806         pclsTexture->SetLoops(AnimatedGifSet.nLoops);
807
808         pMap->Add(pclsTexture);
809       } // of if (g_graphicsContext.Get3DDevice()->CreateTexture
810     } // of for (int iImage=0; iImage < iImages; iImage++)
811     m_vecTextures.push_back(pMap);
812     return pMap->size();
813   } // of if (strPath.Right(4).ToLower()==".gif")
814
815   // normal picture
816   D3DXIMAGE_INFO info;
817   if ( D3DXCreateTextureFromFileEx(g_graphicsContext.Get3DDevice(), strPath.c_str(),
818                                    D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
819                                    D3DX_FILTER_NONE , D3DX_FILTER_NONE, dwColorKey, &info, NULL, &pTexture) != D3D_OK)
820   {
821     CStdString strText = strPath;
822     strText.MakeLower();
823     // dont release skin textures, they are reloaded each time
824     if (strstr(strPath.c_str(), "q:\\skin") )
825     {
826       CLog::Log(LOGERROR, "Texture manager unable to find file:%s", strPath.c_str());
827     }
828     return NULL;
829   }
830   //CStdString strLog;
831   //strLog.Format("%s %ix%i\n", strTextureName.c_str(),info.Width,info.Height);
832   //OutputDebugString(strLog.c_str());
833   CTextureMap* pMap = new CTextureMap(strTextureName);
834   CTexture* pclsTexture = new CTexture(pTexture, info.Width, info.Height, false);
835   pMap->Add(pclsTexture);
836   m_vecTextures.push_back(pMap);
837   return 1;
838
839 #endif
840   return 1;
841 }
842
843 void CGUITextureManager::ReleaseTexture(const CStdString& strTextureName, int iPicture)
844 {
845   CSingleLock lock(g_graphicsContext);
846
847   MEMORYSTATUS stat;
848   GlobalMemoryStatus(&stat);
849   DWORD dwMegFree = stat.dwAvailPhys / (1024 * 1024);
850   if (dwMegFree > 29)
851   {
852     // dont release skin textures, they are reloaded each time
853     //if (strTextureName.GetAt(1) != ':') return;
854     //CLog::Log(LOGINFO, "release:%s", strTextureName.c_str());
855   }
856
857
858   ivecTextures i;
859   i = m_vecTextures.begin();
860   while (i != m_vecTextures.end())
861   {
862     CTextureMap* pMap = *i;
863     if (pMap->GetName() == strTextureName)
864     {
865       pMap->Release(iPicture);
866
867       if (pMap->IsEmpty() )
868       {
869         //CLog::Log(LOGINFO, "  cleanup:%s", strTextureName.c_str());
870         delete pMap;
871         i = m_vecTextures.erase(i);
872       }
873       else
874       {
875         ++i;
876       }
877       //++i;
878     }
879     else
880     {
881       ++i;
882     }
883   }
884 }
885
886 void CGUITextureManager::Cleanup()
887 {
888   CSingleLock lock(g_graphicsContext);
889
890   ivecTextures i;
891   i = m_vecTextures.begin();
892   while (i != m_vecTextures.end())
893   {
894     CTextureMap* pMap = *i;
895     delete pMap;
896     i = m_vecTextures.erase(i);
897   }
898   for (int i = 0; i < 2; i++)
899     m_TexBundle[i].Cleanup();
900 }
901
902 void CGUITextureManager::Dump() const
903 {
904   CStdString strLog;
905   strLog.Format("total texturemaps size:%i\n", m_vecTextures.size());
906   OutputDebugString(strLog.c_str());
907
908   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
909   {
910     const CTextureMap* pMap = m_vecTextures[i];
911     if (!pMap->IsEmpty())
912     {
913       strLog.Format("map:%i\n", i);
914       OutputDebugString(strLog.c_str());
915       pMap->Dump();
916     }
917   }
918 }
919
920 void CGUITextureManager::Flush()
921 {
922   CSingleLock lock(g_graphicsContext);
923
924   ivecTextures i;
925   i = m_vecTextures.begin();
926   while (i != m_vecTextures.end())
927   {
928     CTextureMap* pMap = *i;
929     pMap->Flush();
930     if (pMap->IsEmpty() )
931     {
932       delete pMap;
933       i = m_vecTextures.erase(i);
934     }
935     else
936     {
937       ++i;
938     }
939   }
940 }
941
942 DWORD CGUITextureManager::GetMemoryUsage() const
943 {
944   DWORD memUsage = 0;
945   for (int i = 0; i < (int)m_vecTextures.size(); ++i)
946   {
947     memUsage += m_vecTextures[i]->GetMemoryUsage();
948   }
949   return memUsage;
950 }
951
952 CStdString CGUITextureManager::GetTexturePath(const CStdString &textureName)
953 {
954   CStdString path;
955   if (textureName.c_str()[1] == ':')
956     path = textureName;
957   else
958     path.Format("%s\\media\\%s", g_graphicsContext.GetMediaDir().c_str(), textureName.c_str());
959   return path;
960 }
961
962 void CGUITextureManager::GetBundledTexturesFromPath(const CStdString& texturePath, std::vector<CStdString> &items)
963 {
964   m_TexBundle[0].GetTexturesFromPath(texturePath, items);
965   if (items.empty())
966     m_TexBundle[1].GetTexturesFromPath(texturePath, items);
967 }