aboutsummaryrefslogtreecommitdiff
path: root/guilib/TextureBundle.cpp
diff options
context:
space:
mode:
authoryuvalt <yuvalt@svn>2009-09-28 11:22:33 +0000
committeryuvalt <yuvalt@svn>2009-09-28 11:22:33 +0000
commit06626487ad04850a6bb66ed55aced8c62f855f4e (patch)
tree0c4e4856ce98b26b37f09afba0f1f3481dbc94cd /guilib/TextureBundle.cpp
parent7ce41e8e293e15aa067dd691517ddb3fab2b3adf (diff)
support DXT5 textures with a new texture bundle(r)
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@23209 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'guilib/TextureBundle.cpp')
-rw-r--r--guilib/TextureBundle.cpp499
1 files changed, 70 insertions, 429 deletions
diff --git a/guilib/TextureBundle.cpp b/guilib/TextureBundle.cpp
index 7f025a4ac6..a3a38aeef1 100644
--- a/guilib/TextureBundle.cpp
+++ b/guilib/TextureBundle.cpp
@@ -1,487 +1,128 @@
-
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
#include "system.h"
#include "TextureBundle.h"
-#include "Texture.h"
-#include "GraphicContext.h"
-#include "DirectXGraphics.h"
-#include "utils/log.h"
-#ifndef _LINUX
-#include <sys/stat.h>
-#include "utils/CharsetConverter.h"
-#include "lib/liblzo/LZO1X.H"
-#else
-#include <lzo/lzo1x.h>
-#endif
-#include "SkinInfo.h"
-#include "GUISettings.h"
-#include "Util.h"
-#include "FileSystem/SpecialProtocol.h"
-#include "utils/EndianSwap.h"
-
-#if !defined(__GNUC__)
-#pragma comment(lib,"../../xbmc/lib/liblzo/lzo.lib")
-#endif
-
-// alignment of file blocks - should be a multiple of the sector size of the disk and a power of 2
-// HDD sector = 512 bytes, DVD/CD sector = 2048 bytes
-#undef ALIGN
-#define ALIGN (512)
-
-
-enum XPR_FLAGS
-{
- XPRFLAG_PALETTE = 0x00000001,
- XPRFLAG_ANIM = 0x00000002
-};
-
-class CAutoBuffer
-{
- BYTE* p;
-public:
- CAutoBuffer() { p = 0; }
- explicit CAutoBuffer(size_t s) { p = (BYTE*)malloc(s); }
- ~CAutoBuffer() { free(p); }
-operator BYTE*() { return p; }
- void Set(BYTE* buf) { free(p); p = buf; }
- bool Resize(size_t s);
-void Release() { p = 0; }
-};
-
-bool CAutoBuffer::Resize(size_t s)
-{
- if (s == 0)
- {
- if (!p)
- return false;
- free(p);
- p = 0;
- return true;
- }
- void* q = realloc(p, s);
- if (q)
- {
- p = (BYTE*)q;
- return true;
- }
- return false;
-}
-
-// as above but for texture allocation (do not change from XPhysicalAlloc!)
-class CAutoTexBuffer
-{
- BYTE* p;
-public:
- CAutoTexBuffer() { p = 0; }
- explicit CAutoTexBuffer(size_t s) { p = (BYTE*)XPhysicalAlloc(s, MAXULONG_PTR, 128, PAGE_READWRITE); }
- ~CAutoTexBuffer() { if (p) XPhysicalFree(p); }
-operator BYTE*() { return p; }
- BYTE* Set(BYTE* buf) { if (p) XPhysicalFree(p); return p = buf; }
-void Release() { p = 0; }
-};
CTextureBundle::CTextureBundle(void)
{
- m_hFile = NULL;
- m_themeBundle = false;
+ m_useXPR = false;
+ m_useXBT = false;
}
CTextureBundle::~CTextureBundle(void)
{
- if (m_hFile != NULL)
- fclose(m_hFile);
}
-bool CTextureBundle::OpenBundle()
+bool CTextureBundle::HasFile(const CStdString& Filename)
{
- DWORD AlignedSize;
- DWORD HeaderSize;
- int Version;
- XPR_HEADER* pXPRHeader;
-
- if (m_hFile != NULL)
- Cleanup();
-
- CStdString strPath;
-
- if (m_themeBundle)
+ if (m_useXBT)
{
- // if we are the theme bundle, we only load if the user has chosen
- // a valid theme (or the skin has a default one)
- CStdString themeXPR = g_guiSettings.GetString("lookandfeel.skintheme");
- if (!themeXPR.IsEmpty() && themeXPR.CompareNoCase("SKINDEFAULT"))
- {
- strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
- strPath = CUtil::AddFileToFolder(strPath, themeXPR);
- }
- else
- return false;
+ return m_tbXBT.HasFile(Filename);
}
- else
- strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xpr");
-
- strPath = PTH_IC(strPath);
-
-#ifndef _LINUX
- CStdStringW strPathW;
- g_charsetConverter.utf8ToW(_P(strPath), strPathW, false);
- m_hFile = _wfopen(strPathW.c_str(), L"rb");
-#else
- m_hFile = fopen(strPath.c_str(), "rb");
-#endif
- if (m_hFile == NULL)
- return false;
-
- struct stat fileStat;
- if (fstat(fileno(m_hFile), &fileStat) == -1)
- return false;
- m_TimeStamp = fileStat.st_mtime;
-
- CAutoBuffer HeaderBuf(ALIGN);
- DWORD n;
-
- n = fread(HeaderBuf, 1, ALIGN, m_hFile);
- if (n < ALIGN)
- goto LoadError;
-
- pXPRHeader = (XPR_HEADER*)(BYTE*)HeaderBuf;
- pXPRHeader->dwMagic = Endian_SwapLE32(pXPRHeader->dwMagic);
- Version = (pXPRHeader->dwMagic >> 24) - '0';
- pXPRHeader->dwMagic -= Version << 24;
- Version &= 0x0f;
-
- if (pXPRHeader->dwMagic != XPR_MAGIC_VALUE || Version < 2)
- goto LoadError;
-
- HeaderSize = Endian_SwapLE32(pXPRHeader->dwHeaderSize);
- AlignedSize = (HeaderSize - 1) & ~(ALIGN - 1); // align to sector, but remove the first sector
- HeaderBuf.Resize(AlignedSize + ALIGN);
-
- if (fseek(m_hFile, ALIGN, SEEK_SET) == -1)
- goto LoadError;
- n = fread(HeaderBuf + ALIGN, 1, AlignedSize, m_hFile);
- if (n < ALIGN)
- goto LoadError;
-
- struct DiskFileHeader_t
+ else if (m_useXPR)
{
- char Name[116];
- DWORD Offset;
- DWORD UnpackedSize;
- DWORD PackedSize;
+ return m_tbXPR.HasFile(Filename);
}
- *FileHeader;
- FileHeader = (DiskFileHeader_t*)(HeaderBuf + sizeof(XPR_HEADER));
-
- n = (HeaderSize - sizeof(XPR_HEADER)) / sizeof(DiskFileHeader_t);
- for (unsigned i = 0; i < n; ++i)
+ else if (m_tbXBT.HasFile(Filename))
+ {
+ m_useXBT = true;
+ return true;
+ }
+ else if (m_tbXPR.HasFile(Filename))
{
- std::pair<CStdString, FileHeader_t> entry;
- entry.first = Normalize(FileHeader[i].Name);
- entry.second.Offset = Endian_SwapLE32(FileHeader[i].Offset);
- entry.second.UnpackedSize = Endian_SwapLE32(FileHeader[i].UnpackedSize);
- entry.second.PackedSize = Endian_SwapLE32(FileHeader[i].PackedSize);
- m_FileHeaders.insert(entry);
+ m_useXPR = true;
+ return true;
}
-
- if (lzo_init() != LZO_E_OK)
- goto LoadError;
-
- return true;
-
-LoadError:
- CLog::Log(LOGERROR, "Unable to load file: %s: %s", strPath.c_str(), strerror(errno));
- fclose(m_hFile);
- m_hFile = NULL;
-
- return false;
-}
-
-void CTextureBundle::Cleanup()
-{
- if (m_hFile != NULL)
- fclose(m_hFile);
- m_hFile = NULL;
-
- m_FileHeaders.clear();
-}
-
-bool CTextureBundle::HasFile(const CStdString& Filename)
-{
- if (m_hFile == NULL && !OpenBundle())
- return false;
-
- struct stat fileStat;
- if (fstat(fileno(m_hFile), &fileStat) == -1)
- return false;
- if (fileStat.st_mtime > m_TimeStamp)
+ else
{
- CLog::Log(LOGINFO, "Texture bundle has changed, reloading");
- Cleanup();
- if (!OpenBundle())
- return false;
+ return false;
}
-
- CStdString name = Normalize(Filename);
- return m_FileHeaders.find(name) != m_FileHeaders.end();
}
void CTextureBundle::GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures)
{
- if (path.GetLength() > 1 && path[1] == ':')
- return;
-
- if (m_hFile == NULL && !OpenBundle())
- return;
-
- CStdString testPath = Normalize(path);
- if (!CUtil::HasSlashAtEnd(testPath))
- testPath += "\\";
- int testLength = testPath.GetLength();
- std::map<CStdString, FileHeader_t>::iterator it;
- for (it = m_FileHeaders.begin(); it != m_FileHeaders.end(); it++)
+ if (m_useXBT)
{
- if (it->first.Left(testLength).Equals(testPath))
- textures.push_back(it->first);
+ m_tbXBT.GetTexturesFromPath(path, textures);
}
+ else if (m_useXPR)
+ {
+ m_tbXPR.GetTexturesFromPath(path, textures);
+ }
}
-bool CTextureBundle::LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf)
+bool CTextureBundle::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
+ int &width, int &height)
{
- CStdString name = Normalize(Filename);
-
- std::map<CStdString, FileHeader_t>::iterator file = m_FileHeaders.find(name);
- if (file == m_FileHeaders.end())
- return false;
-
- // found texture - allocate the necessary buffers
- DWORD ReadSize = (file->second.PackedSize + (ALIGN - 1)) & ~(ALIGN - 1);
- BYTE *buffer = (BYTE*)malloc(ReadSize);
-
- if (!buffer || !UnpackedBuf.Set((BYTE*)XPhysicalAlloc(file->second.UnpackedSize, MAXULONG_PTR, 128, PAGE_READWRITE)))
- { // failed due to lack of memory
-#ifndef _LINUX
- MEMORYSTATUS stat;
- GlobalMemoryStatus(&stat);
- CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %lu bytes, have %lu bytes)", name.c_str(),
- file->second.UnpackedSize + file->second.PackedSize, stat.dwAvailPhys);
-#elif defined(__APPLE__)
- CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %lu bytes)", name.c_str(),
- file->second.UnpackedSize + file->second.PackedSize);
-#else
- struct sysinfo info;
- sysinfo(&info);
- CLog::Log(LOGERROR, "Out of memory loading texture: %s "
- "(need %u bytes, have %lu bytes)",
- name.c_str(), file->second.UnpackedSize + file->second.PackedSize,
- info.totalram);
-#endif
- free(buffer);
- return false;
- }
-
- // read the file into our buffer
- DWORD n;
- fseek(m_hFile, file->second.Offset, SEEK_SET);
- n = fread(buffer, 1, ReadSize, m_hFile);
- if (n < ReadSize && !feof(m_hFile))
+ if (m_useXBT)
{
- CLog::Log(LOGERROR, "Error loading texture: %s: %s", Filename.c_str(), strerror(ferror(m_hFile)));
- free(buffer);
- return false;
- }
-
- // allocate a buffer for our unpacked texture
- lzo_uint s = file->second.UnpackedSize;
- bool success = true;
- if (lzo1x_decompress(buffer, file->second.PackedSize, UnpackedBuf, &s, NULL) != LZO_E_OK ||
- s != file->second.UnpackedSize)
- {
- CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", Filename.c_str());
- success = false;
+ return m_tbXBT.LoadTexture(Filename, ppTexture, width, height);
}
-
- try
+ else if (m_useXPR)
{
- free(buffer);
+ return m_tbXPR.LoadTexture(Filename, ppTexture, width, height);
}
- catch (...)
+ else
{
- CLog::Log(LOGERROR, "Error freeing preload buffer.");
- }
-
- return success;
-}
-
-bool CTextureBundle::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
- int &width, int &height)
-{
- DWORD ResDataOffset;
- *ppTexture = NULL;
-
- CAutoTexBuffer UnpackedBuf;
- if (!LoadFile(Filename, UnpackedBuf))
return false;
-
- D3DTexture *pTex = (D3DTexture *)(new char[sizeof (D3DTexture)]);
- D3DPalette* pPal = 0;
- void* ResData = 0;
-
- WORD RealSize[2];
-
- enum XPR_FLAGS
- {
- XPRFLAG_PALETTE = 0x00000001,
- XPRFLAG_ANIM = 0x00000002
- };
-
- BYTE* Next = UnpackedBuf;
-
- DWORD flags = Endian_SwapLE32(*(DWORD*)Next);
- Next += sizeof(DWORD);
- if ((flags & XPRFLAG_ANIM) || (flags >> 16) > 1)
- goto PackedLoadError;
-
- if (flags & XPRFLAG_PALETTE)
- Next += sizeof(D3DPalette);
-
- memcpy(pTex, Next, sizeof(D3DTexture));
- pTex->Common = Endian_SwapLE32(pTex->Common);
- pTex->Data = Endian_SwapLE32(pTex->Data);
- pTex->Lock = Endian_SwapLE32(pTex->Lock);
- pTex->Format = Endian_SwapLE32(pTex->Format);
- pTex->Size = Endian_SwapLE32(pTex->Size);
- Next += sizeof(D3DTexture);
-
- memcpy(RealSize, Next, 4);
- Next += 4;
-
- ResDataOffset = ((Next - UnpackedBuf) + 127) & ~127;
- ResData = UnpackedBuf + ResDataOffset;
-
- if ((pTex->Common & D3DCOMMON_TYPE_MASK) != D3DCOMMON_TYPE_TEXTURE)
- goto PackedLoadError;
-
- GetTextureFromData(pTex, ResData, ppTexture);
- delete[] pTex;
-
- width = Endian_SwapLE16(RealSize[0]);
- height = Endian_SwapLE16(RealSize[1]);
-/* DXMERGE - this was previously used to specify the format of the image - probably only affects directx?
-#ifndef HAS_SDL
- D3DSURFACE_DESC desc;
- (*ppTexture)->GetLevelDesc(0, &desc);
- pInfo->Format = desc.Format;
-#endif
-*/
- return true;
-
-PackedLoadError:
- CLog::Log(LOGERROR, "Error loading texture: %s: Invalid data", Filename.c_str());
- delete[] pTex;
- delete pPal;
- return false;
+ }
}
int CTextureBundle::LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures,
int &width, int &height, int& nLoops, int** ppDelays)
{
- DWORD ResDataOffset;
- int nTextures = 0;
-
- *ppTextures = NULL; *ppDelays = NULL;
-
- CAutoTexBuffer UnpackedBuf;
- if (!LoadFile(Filename, UnpackedBuf))
- return 0;
-
- struct AnimInfo_t
+ if (m_useXBT)
{
- DWORD nLoops;
- WORD RealSize[2];
+ return m_tbXBT.LoadAnim(Filename, ppTextures, width, height, nLoops, ppDelays);
}
- *pAnimInfo;
-
- D3DTexture** ppTex = 0;
- void* ResData = 0;
-
- BYTE* Next = UnpackedBuf;
-
- DWORD flags = Endian_SwapLE32(*(DWORD*)Next);
- Next += sizeof(DWORD);
- if (!(flags & XPRFLAG_ANIM))
- goto PackedAnimError;
-
- pAnimInfo = (AnimInfo_t*)Next;
- Next += sizeof(AnimInfo_t);
- nLoops = Endian_SwapLE32(pAnimInfo->nLoops);
-
- if (flags & XPRFLAG_PALETTE)
- Next += sizeof(D3DPalette);
-
- nTextures = flags >> 16;
- ppTex = new D3DTexture * [nTextures];
- *ppDelays = new int[nTextures];
- for (int i = 0; i < nTextures; ++i)
+ else if (m_useXPR)
{
- ppTex[i] = (D3DTexture *)(new char[sizeof (D3DTexture)+ sizeof (DWORD)]);
-
- memcpy(ppTex[i], Next, sizeof(D3DTexture));
- ppTex[i]->Common = Endian_SwapLE32(ppTex[i]->Common);
- ppTex[i]->Data = Endian_SwapLE32(ppTex[i]->Data);
- ppTex[i]->Lock = Endian_SwapLE32(ppTex[i]->Lock);
- ppTex[i]->Format = Endian_SwapLE32(ppTex[i]->Format);
- ppTex[i]->Size = Endian_SwapLE32(ppTex[i]->Size);
- Next += sizeof(D3DTexture);
-
- (*ppDelays)[i] = Endian_SwapLE32(*(int*)Next);
- Next += sizeof(int);
+ return m_tbXPR.LoadAnim(Filename, ppTextures, width, height, nLoops, ppDelays);
}
-
- ResDataOffset = ((DWORD)(Next - UnpackedBuf) + 127) & ~127;
- ResData = UnpackedBuf + ResDataOffset;
-
- *ppTextures = new CBaseTexture*[nTextures];
- for (int i = 0; i < nTextures; ++i)
+ else
{
- if ((ppTex[i]->Common & D3DCOMMON_TYPE_MASK) != D3DCOMMON_TYPE_TEXTURE)
- goto PackedAnimError;
+ return 0;
+ }
+}
- GetTextureFromData(ppTex[i], ResData, &(*ppTextures)[i]);
- delete[] ppTex[i];
+void CTextureBundle::Cleanup()
+{
+ if (m_useXBT)
+ {
+ m_tbXBT.Cleanup();
}
-
- delete[] ppTex;
- ppTex = 0;
-
- width = Endian_SwapLE16(pAnimInfo->RealSize[0]);
- height = Endian_SwapLE16(pAnimInfo->RealSize[1]);
-
- return nTextures;
-
-PackedAnimError:
- CLog::Log(LOGERROR, "Error loading texture: %s: Invalid data", Filename.c_str());
- if (ppTex)
+ else if (m_useXPR)
{
- for (int i = 0; i < nTextures; ++i)
- delete [] ppTex[i];
- delete [] ppTex;
+ m_tbXPR.Cleanup();
}
- delete [] *ppDelays;
- return 0;
}
-
+
void CTextureBundle::SetThemeBundle(bool themeBundle)
{
- m_themeBundle = themeBundle;
+ m_tbXPR.SetThemeBundle(themeBundle);
+ m_tbXBT.SetThemeBundle(themeBundle);
}
-// normalize to how it's stored within the bundle
-// lower case + using \\ rather than /
CStdString CTextureBundle::Normalize(const CStdString &name)
{
- CStdString newName(name);
- newName.Normalize();
- newName.Replace('/','\\');
- return newName;
+ return CTextureBundleXBT::Normalize(name);
}