diff options
author | yuvalt <yuvalt@svn> | 2009-09-28 11:22:33 +0000 |
---|---|---|
committer | yuvalt <yuvalt@svn> | 2009-09-28 11:22:33 +0000 |
commit | 06626487ad04850a6bb66ed55aced8c62f855f4e (patch) | |
tree | 0c4e4856ce98b26b37f09afba0f1f3481dbc94cd /guilib/TextureBundle.cpp | |
parent | 7ce41e8e293e15aa067dd691517ddb3fab2b3adf (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.cpp | 499 |
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); } |