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 | |
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
37 files changed, 3240 insertions, 522 deletions
diff --git a/Makefile.in b/Makefile.in index 89b6fa9862..843d147b6b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -40,6 +40,7 @@ BIN_DIRS= \ xbmc/lib/libXDAAP \ xbmc/lib/sqLite \ xbmc/lib/UnrarXLib \ + xbmc/lib/libsquish \ xbmc/visualizations \ xbmc/screensavers \ xbmc/utils \ @@ -52,7 +53,8 @@ EC_DIRS= \ tools/EventClients XBMCTEX_DIRS= \ - tools/XBMCTex + tools/XBMCTex \ + tools/XBMCTexXBT DVDPCODECS_DIRS= \ xbmc/cores/dvdplayer/Codecs \ @@ -181,7 +183,7 @@ configure: configure.in @false # skin textures -skins: tools/XBMCTex/XBMCTex force +skins: tools/XBMCTex/XBMCTex tools/XBMCTexXBT/XBMCTexXBT force $(MAKE) -C $(PM3_MEDIA) $(MAKE) -C $(PM3HD_MEDIA) @@ -265,6 +267,8 @@ xbmc/lib/sqLite/sqllite.a: force $(MAKE) -C xbmc/lib/sqLite xbmc/lib/UnrarXLib/UnrarXLib.a: force $(MAKE) -C xbmc/lib/UnrarXLib +xbmc/lib/libsquish/libsquish.a: force + $(MAKE) -C xbmc/lib/libsquish xbmc/linux/linux.a: force $(MAKE) -C xbmc/linux xbmc/screensavers/screensaver.a: force @@ -401,6 +405,7 @@ OBJSXBMC= \ xbmc/lib/libGoAhead/libGoAhead-@ARCH@.a \ xbmc/lib/sqLite/sqllite.a \ xbmc/lib/UnrarXLib/UnrarXLib.a \ + xbmc/lib/libsquish/libsquish.a \ xbmc/linux/linux.a \ xbmc/screensavers/screensaver.a \ xbmc/settings/settings.a \ @@ -449,9 +454,12 @@ ifeq ($(findstring osx,$(ARCH)), osx) # hack this for now $(MAKE) -C tools/XBMCTex -f Makefile.osx else - $(MAKE) -C tools/XBMCTex/ + $(MAKE) -C tools/XBMCTex/ endif +tools/XBMCTexXBT/XBMCTexXBT: + $(MAKE) -C tools/XBMCTexXBT/ + install-bin: xbmc.bin # developement convenience target sudo install -D xbmc.bin $(prefix)/share/xbmc diff --git a/guilib/DirectXGraphics.cpp b/guilib/DirectXGraphics.cpp index 5563b51304..3a3d107c46 100644 --- a/guilib/DirectXGraphics.cpp +++ b/guilib/DirectXGraphics.cpp @@ -22,6 +22,7 @@ #include "DirectXGraphics.h" #include "Texture.h" #include "FileSystem/File.h" +#include "XBTF.h" LPVOID XPhysicalAlloc(SIZE_T s, DWORD ulPhysicalAddress, DWORD ulAlignment, DWORD flProtect) { @@ -394,7 +395,7 @@ void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture **ppTextur DWORD width, height, pitch, offset; ParseTextureHeader(pTex, fmt, width, height, pitch, offset); - *ppTexture = new CTexture(width, height, 32); + *ppTexture = new CTexture(width, height, 32, XB_FMT_B8G8R8A8); if (*ppTexture) { @@ -446,9 +447,9 @@ void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture **ppTextur } if (IsPalettedFormat(fmt)) - (*ppTexture)->LoadPaletted(width, height, pitch, texDataStart, color); + (*ppTexture)->LoadPaletted(width, height, pitch, XB_FMT_B8G8R8A8, texDataStart, color); else - (*ppTexture)->LoadFromMemory(width, height, pitch, 32, texDataStart); + (*ppTexture)->LoadFromMemory(width, height, pitch, 32, XB_FMT_B8G8R8A8, texDataStart); if (IsSwizzledFormat(fmt) || fmt == XB_D3DFMT_DXT1 || fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4) { diff --git a/guilib/Makefile b/guilib/Makefile index 78819e5a71..fd24650ca6 100644 --- a/guilib/Makefile +++ b/guilib/Makefile @@ -1,4 +1,4 @@ -INCLUDES=-I. -I../ -Icommon -I../xbmc -I../xbmc/cores -I../xbmc/linux -I../xbmc/utils -I/usr/include/freetype2 -I/usr/include/SDL +INCLUDES=-I. -I../ -Icommon -I../xbmc -I../xbmc/cores -I../xbmc/linux -I../xbmc/utils -I/usr/include/freetype2 -I/usr/include/SDL -I../xbmc/lib/squish SRCS=AnimatedGif.cpp \ AudioContext.cpp \ @@ -56,6 +56,8 @@ SRCS=AnimatedGif.cpp \ Key.cpp \ LocalizeStrings.cpp \ SkinInfo.cpp \ + TextureBundleXPR.cpp \ + TextureBundleXBT.cpp \ TextureBundle.cpp \ TextureManager.cpp \ VisibleEffect.cpp \ @@ -74,6 +76,8 @@ SRCS=AnimatedGif.cpp \ Texture.cpp \ TextureGL.cpp \ GUIControlProfiler.cpp \ + XBTF.cpp \ + XBTFReader.cpp \ LIB=guilib.a diff --git a/guilib/Texture.cpp b/guilib/Texture.cpp index 0f78d6b083..d4e96d642a 100644 --- a/guilib/Texture.cpp +++ b/guilib/Texture.cpp @@ -30,7 +30,7 @@ /************************************************************************/ /* */ /************************************************************************/ -CBaseTexture::CBaseTexture(unsigned int width, unsigned int height, unsigned int BPP) +CBaseTexture::CBaseTexture(unsigned int width, unsigned int height, unsigned int BPP, unsigned int format) { m_imageWidth = width; m_imageHeight = height; @@ -40,6 +40,7 @@ CBaseTexture::CBaseTexture(unsigned int width, unsigned int height, unsigned int m_loadedToGPU = false; m_nTextureHeight = 0; m_nTextureWidth = 0; + m_format = format; } CBaseTexture::~CBaseTexture() @@ -47,13 +48,14 @@ CBaseTexture::~CBaseTexture() delete[] m_pPixels; } -void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned int BPP) +void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned int BPP, unsigned int format) { if (BPP != 0) m_nBPP = BPP; m_imageWidth = width; m_imageHeight = height; + m_format = format; if (g_Windowing.NeedPower2Texture()) { @@ -67,40 +69,62 @@ void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned in } delete[] m_pPixels; - m_pPixels = new unsigned char[m_nTextureWidth * m_nTextureHeight * m_nBPP / 8]; + + switch (m_format) + { + case XB_FMT_DXT1: + m_bufferSize = ((m_imageWidth + 3) / 4) * ((m_imageHeight + 3) / 4) * 8; + break; + case XB_FMT_DXT3: + case XB_FMT_DXT5: + m_bufferSize = ((m_imageWidth + 3) / 4) * ((m_imageHeight + 3) / 4) * 16; + break; + default: + m_bufferSize = m_nTextureWidth * m_nTextureHeight * m_nBPP / 8; + break; + } + + m_pPixels = new unsigned char[m_bufferSize]; } -void CBaseTexture::Update(int w, int h, int pitch, const unsigned char *pixels, bool loadToGPU) +void CBaseTexture::Update(int w, int h, int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU) { if (pixels == NULL) return; - Allocate(w, h, 0); + Allocate(w, h, 0, format); - // Resize texture to POT if needed - const unsigned char *src = pixels; - unsigned char* resized = m_pPixels; - - for (int y = 0; y < h; y++) + if (m_imageHeight != m_nTextureHeight && m_imageWidth != m_nTextureWidth) { - memcpy(resized, src, pitch); // make sure pitch is not bigger than our width - src += pitch; - - // repeat last column to simulate clamp_to_edge - for(unsigned int i = pitch; i < m_nTextureWidth*4; i+=4) - memcpy(resized+i, src-4, 4); - - resized += (m_nTextureWidth * 4); + // Resize texture to POT if needed + const unsigned char *src = pixels; + unsigned char* resized = m_pPixels; + + for (int y = 0; y < h; y++) + { + memcpy(resized, src, pitch); // make sure pitch is not bigger than our width + src += pitch; + + // repeat last column to simulate clamp_to_edge + for(unsigned int i = pitch; i < m_nTextureWidth*4; i+=4) + memcpy(resized+i, src-4, 4); + + resized += (m_nTextureWidth * 4); + } + + // clamp to edge - repeat last row + unsigned char *dest = m_pPixels + h*GetPitch(); + for (unsigned int y = h; y < m_nTextureHeight; y++) + { + memcpy(dest, dest-GetPitch(), GetPitch()); + dest += GetPitch(); + } } - - // clamp to edge - repeat last row - unsigned char *dest = m_pPixels + h*GetPitch(); - for (unsigned int y = h; y < m_nTextureHeight; y++) + else { - memcpy(dest, dest-GetPitch(), GetPitch()); - dest += GetPitch(); + memcpy(m_pPixels, pixels, m_bufferSize); } - + if (loadToGPU) LoadToGPU(); } @@ -116,22 +140,23 @@ bool CBaseTexture::LoadFromFile(const CStdString& texturePath) return true; } -bool CBaseTexture::LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned char* pPixels) +bool CBaseTexture::LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned int format, unsigned char* pPixels) { m_imageWidth = width; m_imageHeight = height; m_nBPP = BPP; - Update(width, height, pitch, pPixels, false); + m_format = format; + Update(width, height, pitch, format, pPixels, false); return true; } -bool CBaseTexture::LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, const unsigned char *pixels, const COLOR *palette) +bool CBaseTexture::LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, const COLOR *palette) { if (pixels == NULL || palette == NULL) return false; - Allocate(width, height, 32); + Allocate(width, height, 32, format); for (unsigned int y = 0; y < height; y++) { diff --git a/guilib/Texture.h b/guilib/Texture.h index 73751efd10..d0f2152a0c 100644 --- a/guilib/Texture.h +++ b/guilib/Texture.h @@ -29,6 +29,7 @@ #include "gui3d.h" #include "StdString.h" +#include "XBTF.h" #pragma pack(1) struct COLOR {unsigned char b,g,r,x;}; // Windows GDI expects 4bytes per color @@ -48,13 +49,13 @@ class CBaseTexture { public: - CBaseTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0); + CBaseTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0, unsigned int format = XB_FMT_B8G8R8A8); virtual ~CBaseTexture(); // TODO: Clean up this interface once things have settled down (none of these need to be virtual) virtual bool LoadFromFile(const CStdString& texturePath); - virtual bool LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned char* pPixels); - bool LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, const unsigned char *pixels, const COLOR *palette); + virtual bool LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned int format, unsigned char* pPixels); + bool LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, const COLOR *palette); virtual void CreateTextureObject() = 0; virtual void DestroyTextureObject() = 0; @@ -69,8 +70,8 @@ public: unsigned int GetHeight() const { return m_imageHeight; } unsigned int GetBPP() const { return m_nBPP; } - void Update(int w, int h, int pitch, const unsigned char *pixels, bool loadToGPU); - void Allocate(unsigned int width, unsigned int height, unsigned int BPP); + void Update(int w, int h, int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU); + void Allocate(unsigned int width, unsigned int height, unsigned int BPP, unsigned int format); static unsigned int PadPow2(unsigned int x); @@ -82,7 +83,9 @@ protected: unsigned int m_nBPP; XBMC::TexturePtr m_pTexture; unsigned char* m_pPixels; + unsigned int m_bufferSize; bool m_loadedToGPU; + unsigned int m_format; }; #if defined(HAS_GL) || defined(HAS_GLES) 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); } diff --git a/guilib/TextureBundle.h b/guilib/TextureBundle.h index 5ae9aebca0..d9584dd5f8 100644 --- a/guilib/TextureBundle.h +++ b/guilib/TextureBundle.h @@ -22,32 +22,11 @@ */ #include "StdString.h" -#include <stdint.h> -#include <map> - -class CAutoTexBuffer; -class CBaseTexture; +#include "TextureBundleXPR.h" +#include "TextureBundleXBT.h" class CTextureBundle { - struct FileHeader_t - { - uint32_t Offset; - uint32_t UnpackedSize; - uint32_t PackedSize; - }; - - FILE* m_hFile; - time_t m_TimeStamp; - - std::map<CStdString, FileHeader_t> m_FileHeaders; - typedef std::map<CStdString, FileHeader_t>::iterator iFiles; - - bool m_themeBundle; - - bool OpenBundle(); - bool LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf); - public: CTextureBundle(void); ~CTextureBundle(void); @@ -59,11 +38,16 @@ public: void GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures); static CStdString Normalize(const CStdString &name); - bool LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture, - int &width, int &height); + bool LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture, int &width, int &height); - int LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures, - int &width, int &height, int& nLoops, int** ppDelays); + int LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures, int &width, int &height, int& nLoops, int** ppDelays); + +private: + CTextureBundleXPR m_tbXPR; + CTextureBundleXBT m_tbXBT; + + bool m_useXPR; + bool m_useXBT; }; diff --git a/guilib/TextureBundleXBT.cpp b/guilib/TextureBundleXBT.cpp new file mode 100644 index 0000000000..8e10e5b631 --- /dev/null +++ b/guilib/TextureBundleXBT.cpp @@ -0,0 +1,281 @@ +/* + * 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 "squish.h" +#include "system.h" +#include "TextureBundleXBT.h" +#include "Texture.h" +#include "GraphicContext.h" +#include "utils/log.h" +#include "SkinInfo.h" +#include "GUISettings.h" +#include "Util.h" +#include "FileSystem/SpecialProtocol.h" +#include "utils/EndianSwap.h" +#include "XBTF.h" +#include "WindowingFactory.h" +#ifndef _LINUX +#include "lib/liblzo/LZO1X.H" +#else +#include <lzo/lzo1x.h> +#endif + +#if !defined(__GNUC__) +#pragma comment(lib,"../../xbmc/lib/liblzo/lzo.lib") +#endif + +CTextureBundleXBT::CTextureBundleXBT(void) +{ + m_themeBundle = false; +} + +CTextureBundleXBT::~CTextureBundleXBT(void) +{ + Cleanup(); +} + +bool CTextureBundleXBT::OpenBundle() +{ + m_supportsCompressedTextures = g_Windowing.SupportsCompressedTextures(); + + Cleanup(); + + // Find the correct texture file (skin or theme) + CStdString strPath; + + if (m_themeBundle) + { + // 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.Find(".xbt") != -1 && themeXPR.CompareNoCase("SKINDEFAULT")) + { + strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media"); + strPath = CUtil::AddFileToFolder(strPath, themeXPR); + } + else + { + return false; + } + } + else + { + strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xbt"); + } + + strPath = PTH_IC(strPath); + + // Load the texture file + if (!m_XBTFReader.Open(strPath)) + { + return false; + } + + m_TimeStamp = m_XBTFReader.GetLastModificationTimestamp(); + + if (lzo_init() != LZO_E_OK) + { + return false; + } + + return true; +} + +bool CTextureBundleXBT::HasFile(const CStdString& Filename) +{ + if (!m_XBTFReader.IsOpen() && !OpenBundle()) + return false; + + if (m_XBTFReader.GetLastModificationTimestamp() > m_TimeStamp) + { + CLog::Log(LOGINFO, "Texture bundle has changed, reloading"); + if (!OpenBundle()) + return false; + } + + CStdString name = Normalize(Filename); + bool result = m_XBTFReader.Exists(name, XB_FMT_DXT5); + return result; +} + +void CTextureBundleXBT::GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures) +{ + if (path.GetLength() > 1 && path[1] == ':') + return; + + if (!m_XBTFReader.IsOpen() && !OpenBundle()) + return; + + CStdString testPath = Normalize(path); + CUtil::AddSlashAtEnd(testPath); + int testLength = testPath.GetLength(); + + std::vector<CXBTFFile>& files = m_XBTFReader.GetFiles(); + for (size_t i = 0; i < files.size(); i++) + { + CStdString path = files[i].GetPath(); + if (path.Left(testLength).Equals(testPath)) + textures.push_back(path); + } +} + +bool CTextureBundleXBT::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture, + int &width, int &height) +{ + CStdString name = Normalize(Filename); + + CXBTFFile* file = m_XBTFReader.Find(name, XB_FMT_DXT5); + if (!file) + return false; + + if (file->GetFrames().size() == 0) + return false; + + CXBTFFrame& frame = file->GetFrames().at(0); + if (!ConvertFrameToTexture(Filename, frame, file->GetFormat(), ppTexture)) + { + return false; + } + + width = frame.GetWidth(); + height = frame.GetHeight(); + + return true; +} + +int CTextureBundleXBT::LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures, + int &width, int &height, int& nLoops, int** ppDelays) +{ + CStdString name = Normalize(Filename); + + CXBTFFile* file = m_XBTFReader.Find(name, XB_FMT_DXT5); + if (!file) + return false; + + if (file->GetFrames().size() == 0) + return false; + + size_t nTextures = file->GetFrames().size(); + *ppTextures = new CBaseTexture*[nTextures]; + *ppDelays = new int[nTextures]; + + for (size_t i = 0; i < nTextures; i++) + { + CXBTFFrame& frame = file->GetFrames().at(i); + + if (!ConvertFrameToTexture(Filename, frame, file->GetFormat(), &((*ppTextures)[i]))) + { + return false; + } + + (*ppDelays)[i] = frame.GetDuration(); + } + + width = file->GetFrames().at(0).GetWidth(); + height = file->GetFrames().at(0).GetHeight(); + nLoops = file->GetLoop(); + + return nTextures; +} + +bool CTextureBundleXBT::ConvertFrameToTexture(const CStdString& name, CXBTFFrame& frame, int format, CBaseTexture** ppTexture) +{ + // found texture - allocate the necessary buffers + unsigned char* PackedBuf = (unsigned char*) malloc(frame.GetPackedSize()); + if (PackedBuf == NULL) + { + CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %llu bytes)", name.c_str(), frame.GetPackedSize()); + return false; + } + + // load the compressed texture + if (!m_XBTFReader.Load(frame, PackedBuf)) + { + CLog::Log(LOGERROR, "Error loading texture: %s", name.c_str()); + free(PackedBuf); + return false; + } + + squish::u8* UnpackedBuf = NULL; + if (!m_supportsCompressedTextures || g_Windowing.NeedPower2Texture() || format == XB_FMT_LZO) + { + UnpackedBuf = new squish::u8[frame.GetWidth() * frame.GetHeight() * 4]; + if (UnpackedBuf == NULL) + { + CLog::Log(LOGERROR, "Out of memory unpacking texture: %s (need %llu bytes)", name.c_str(), frame.GetUnpackedSize()); + free(PackedBuf); + return false; + } + + if (format == XB_FMT_LZO) + { + lzo_uint s = frame.GetUnpackedSize(); + if (lzo1x_decompress(PackedBuf, frame.GetPackedSize(), UnpackedBuf, &s, NULL) != LZO_E_OK || + s != frame.GetUnpackedSize()) + { + CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", name.c_str()); + free(PackedBuf); + delete [] UnpackedBuf; + return false; + } + } + else + { + squish::DecompressImage(UnpackedBuf, frame.GetWidth(), frame.GetHeight(), (const squish::u8*) PackedBuf, squish::kDxt5); + } + + format = XB_FMT_R8G8B8A8; + } + + // create an xbmc texture + *ppTexture = new CTexture(frame.GetWidth(), frame.GetHeight(), 32, format); + (*ppTexture)->LoadFromMemory(frame.GetWidth(), frame.GetHeight(), frame.GetWidth() * 4, 32, format, m_supportsCompressedTextures ? PackedBuf : UnpackedBuf); + + free(PackedBuf); + if (UnpackedBuf) + delete [] UnpackedBuf; + + return true; +} + +void CTextureBundleXBT::Cleanup() +{ + if (m_XBTFReader.IsOpen()) + { + m_XBTFReader.Close(); + } +} + +void CTextureBundleXBT::SetThemeBundle(bool themeBundle) +{ + m_themeBundle = themeBundle; +} + +// normalize to how it's stored within the bundle +// lower case + using forward slash rather than back slash +CStdString CTextureBundleXBT::Normalize(const CStdString &name) +{ + CStdString newName(name); + newName.Normalize(); + newName.Replace('\\','/'); + + return newName; +} diff --git a/guilib/TextureBundleXBT.h b/guilib/TextureBundleXBT.h new file mode 100644 index 0000000000..a5f1d7a3b8 --- /dev/null +++ b/guilib/TextureBundleXBT.h @@ -0,0 +1,59 @@ +#pragma once + +/* + * Copyright (C) 2005-2008 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 "StdString.h" +#include <map> +#include "XBTFReader.h" + +class CBaseTexture; + +class CTextureBundleXBT +{ +public: + CTextureBundleXBT(void); + ~CTextureBundleXBT(void); + + void Cleanup(); + void SetThemeBundle(bool themeBundle); + bool HasFile(const CStdString& Filename); + void GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures); + static CStdString Normalize(const CStdString &name); + + bool LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture, + int &width, int &height); + + int LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures, + int &width, int &height, int& nLoops, int** ppDelays); + +private: + bool OpenBundle(); + bool ConvertFrameToTexture(const CStdString& name, CXBTFFrame& frame, int format, CBaseTexture** ppTexture); + + time_t m_TimeStamp; + + bool m_themeBundle; + bool m_supportsCompressedTextures; + CXBTFReader m_XBTFReader; +}; + + diff --git a/guilib/TextureBundleXPR.cpp b/guilib/TextureBundleXPR.cpp new file mode 100644 index 0000000000..69d7462b7c --- /dev/null +++ b/guilib/TextureBundleXPR.cpp @@ -0,0 +1,487 @@ + + +#include "system.h" +#include "TextureBundleXPR.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; } +}; + +CTextureBundleXPR::CTextureBundleXPR(void) +{ + m_hFile = NULL; + m_themeBundle = false; +} + +CTextureBundleXPR::~CTextureBundleXPR(void) +{ + if (m_hFile != NULL) + fclose(m_hFile); +} + +bool CTextureBundleXPR::OpenBundle() +{ + DWORD AlignedSize; + DWORD HeaderSize; + int Version; + XPR_HEADER* pXPRHeader; + + if (m_hFile != NULL) + Cleanup(); + + CStdString strPath; + + if (m_themeBundle) + { + // 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; + } + 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 + { + char Name[116]; + DWORD Offset; + DWORD UnpackedSize; + DWORD PackedSize; + } + *FileHeader; + FileHeader = (DiskFileHeader_t*)(HeaderBuf + sizeof(XPR_HEADER)); + + n = (HeaderSize - sizeof(XPR_HEADER)) / sizeof(DiskFileHeader_t); + for (unsigned i = 0; i < n; ++i) + { + 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); + } + + 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 CTextureBundleXPR::Cleanup() +{ + if (m_hFile != NULL) + fclose(m_hFile); + m_hFile = NULL; + + m_FileHeaders.clear(); +} + +bool CTextureBundleXPR::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) + { + CLog::Log(LOGINFO, "Texture bundle has changed, reloading"); + Cleanup(); + if (!OpenBundle()) + return false; + } + + CStdString name = Normalize(Filename); + return m_FileHeaders.find(name) != m_FileHeaders.end(); +} + +void CTextureBundleXPR::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 (it->first.Left(testLength).Equals(testPath)) + textures.push_back(it->first); + } +} + +bool CTextureBundleXPR::LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf) +{ + 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 %d 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)) + { + 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; + } + + try + { + free(buffer); + } + catch (...) + { + CLog::Log(LOGERROR, "Error freeing preload buffer."); + } + + return success; +} + +bool CTextureBundleXPR::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 CTextureBundleXPR::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 + { + DWORD nLoops; + WORD RealSize[2]; + } + *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) + { + 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); + } + + ResDataOffset = ((DWORD)(Next - UnpackedBuf) + 127) & ~127; + ResData = UnpackedBuf + ResDataOffset; + + *ppTextures = new CBaseTexture*[nTextures]; + for (int i = 0; i < nTextures; ++i) + { + if ((ppTex[i]->Common & D3DCOMMON_TYPE_MASK) != D3DCOMMON_TYPE_TEXTURE) + goto PackedAnimError; + + GetTextureFromData(ppTex[i], ResData, &(*ppTextures)[i]); + delete[] ppTex[i]; + } + + 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) + { + for (int i = 0; i < nTextures; ++i) + delete [] ppTex[i]; + delete [] ppTex; + } + delete [] *ppDelays; + return 0; +} + +void CTextureBundleXPR::SetThemeBundle(bool themeBundle) +{ + m_themeBundle = themeBundle; +} + +// normalize to how it's stored within the bundle +// lower case + using \\ rather than / +CStdString CTextureBundleXPR::Normalize(const CStdString &name) +{ + CStdString newName(name); + newName.Normalize(); + newName.Replace('/','\\'); + return newName; +} diff --git a/guilib/TextureBundleXPR.h b/guilib/TextureBundleXPR.h new file mode 100644 index 0000000000..b68ac7c3b6 --- /dev/null +++ b/guilib/TextureBundleXPR.h @@ -0,0 +1,69 @@ +#pragma once + +/* + * Copyright (C) 2005-2008 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 "StdString.h" +#include <stdint.h> +#include <map> + +class CAutoTexBuffer; +class CBaseTexture; + +class CTextureBundleXPR +{ + struct FileHeader_t + { + uint32_t Offset; + uint32_t UnpackedSize; + uint32_t PackedSize; + }; + + FILE* m_hFile; + time_t m_TimeStamp; + + std::map<CStdString, FileHeader_t> m_FileHeaders; + typedef std::map<CStdString, FileHeader_t>::iterator iFiles; + + bool m_themeBundle; + + bool OpenBundle(); + bool LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf); + +public: + CTextureBundleXPR(void); + ~CTextureBundleXPR(void); + + void Cleanup(); + + void SetThemeBundle(bool themeBundle); + bool HasFile(const CStdString& Filename); + void GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures); + static CStdString Normalize(const CStdString &name); + + bool LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture, + int &width, int &height); + + int LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures, + int &width, int &height, int& nLoops, int** ppDelays); +}; + + diff --git a/guilib/TextureDX.cpp b/guilib/TextureDX.cpp index 7ed3c05816..b596b3c6a3 100644 --- a/guilib/TextureDX.cpp +++ b/guilib/TextureDX.cpp @@ -29,10 +29,10 @@ /************************************************************************/ /* CDXTexture */ /************************************************************************/ -CDXTexture::CDXTexture(unsigned int width, unsigned int height, unsigned int BPP) -: CBaseTexture(width, height, BPP) +CDXTexture::CDXTexture(unsigned int width, unsigned int height, unsigned int BPP, unsigned int format) +: CBaseTexture(width, height, BPP, format) { - Allocate(m_imageWidth, m_imageHeight, m_nBPP); + Allocate(m_imageWidth, m_imageHeight, m_nBPP, m_format); } CDXTexture::~CDXTexture() diff --git a/guilib/TextureDX.h b/guilib/TextureDX.h index db49a9cbd7..fc927ed582 100644 --- a/guilib/TextureDX.h +++ b/guilib/TextureDX.h @@ -39,7 +39,7 @@ class CDXTexture : public CBaseTexture { public: - CDXTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0); + CDXTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0, unsigned int format = XB_FMT_UNKNOWN); virtual ~CDXTexture(); void CreateTextureObject(); diff --git a/guilib/TextureGL.cpp b/guilib/TextureGL.cpp index af4422a0d1..812ab626c8 100644 --- a/guilib/TextureGL.cpp +++ b/guilib/TextureGL.cpp @@ -31,14 +31,14 @@ using namespace std; /************************************************************************/ /* CGLTexture */ /************************************************************************/ -CGLTexture::CGLTexture(unsigned int width, unsigned int height, unsigned int BPP) -: CBaseTexture(width, height, BPP) +CGLTexture::CGLTexture(unsigned int width, unsigned int height, unsigned int BPP, unsigned int format) +: CBaseTexture(width, height, BPP, format) { m_nTextureWidth = 0; m_nTextureHeight = 0; if(m_imageWidth != 0 && m_imageHeight != 0) - Allocate(m_imageWidth, m_imageHeight, m_nBPP); + Allocate(m_imageWidth, m_imageHeight, m_nBPP, m_format); } CGLTexture::~CGLTexture() @@ -96,13 +96,42 @@ void CGLTexture::LoadToGPU() m_nTextureWidth = maxSize; } + GLenum format; + + switch (m_format) + { + case XB_FMT_DXT1: + format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case XB_FMT_DXT3: + format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case XB_FMT_DXT5: + format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case XB_FMT_R8G8B8A8: + format = GL_RGBA; + break; + default: #ifdef HAS_GL - GLenum format = GL_BGRA; + format = GL_BGRA; #elif HAS_GLES - GLenum format = GL_BGRA_EXT; + format = GL_BGRA_EXT; #endif - glTexImage2D(GL_TEXTURE_2D, 0, 4, m_nTextureWidth, m_nTextureHeight, 0, - format, GL_UNSIGNED_BYTE, m_pPixels); + break; + } + + if ((m_format & XB_FMT_DXT_MASK) == 0) + { + glTexImage2D(GL_TEXTURE_2D, 0, 4, m_nTextureWidth, m_nTextureHeight, 0, + format, GL_UNSIGNED_BYTE, m_pPixels); + } + else + { + glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, + m_nTextureWidth, m_nTextureHeight, 0, m_bufferSize, m_pPixels); + } + #ifndef HAS_GLES glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); #endif diff --git a/guilib/TextureGL.h b/guilib/TextureGL.h index 962c6f462d..8631beae2a 100644 --- a/guilib/TextureGL.h +++ b/guilib/TextureGL.h @@ -39,7 +39,7 @@ class CGLTexture : public CBaseTexture { public: - CGLTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0); + CGLTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0, unsigned int format = XB_FMT_B8G8R8A8); virtual ~CGLTexture(); void CreateTextureObject(); diff --git a/guilib/TextureManager.cpp b/guilib/TextureManager.cpp index 385404de64..c734d33a6a 100644 --- a/guilib/TextureManager.cpp +++ b/guilib/TextureManager.cpp @@ -232,9 +232,6 @@ const CTextureArray& CGUITextureManager::GetTexture(const CStdString& strTexture return emptyTexture; } - - - /************************************************************************/ /* */ /************************************************************************/ @@ -365,7 +362,7 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO if (glTexture) { CAnimatedGif* pImage = AnimatedGifSet.m_vecimg[iImage]; - glTexture->LoadPaletted(pImage->Width, pImage->Height, pImage->BytesPerRow, (unsigned char *)pImage->Raster, palette); + glTexture->LoadPaletted(pImage->Width, pImage->Height, pImage->BytesPerRow, XB_FMT_B8G8R8A8, (unsigned char *)pImage->Raster, palette); pMap->Add(glTexture, pImage->Delay); } } // of for (int iImage=0; iImage < iImages; iImage++) diff --git a/guilib/XBTF.cpp b/guilib/XBTF.cpp new file mode 100644 index 0000000000..e0a572d80b --- /dev/null +++ b/guilib/XBTF.cpp @@ -0,0 +1,218 @@ +/* + * 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 <strings.h> +#include "XBTF.h" + +CXBTFFrame::CXBTFFrame() +{ + m_width = 0; + m_height = 0; + m_packedSize = 0; + m_unpackedSize = 0; + m_offset = 0; +} + +unsigned int CXBTFFrame::GetWidth() const +{ + return m_width; +} + +void CXBTFFrame::SetWidth(unsigned int width) +{ + m_width = width; +} + +unsigned int CXBTFFrame::GetHeight() const +{ + return m_height; +} + +void CXBTFFrame::SetHeight(unsigned int height) +{ + m_height = height; +} + +unsigned long long CXBTFFrame::GetPackedSize() const +{ + return m_packedSize; +} + +void CXBTFFrame::SetPackedSize(unsigned long long size) +{ + m_packedSize = size; +} + +unsigned long long CXBTFFrame::GetUnpackedSize() const +{ + return m_unpackedSize; +} + +void CXBTFFrame::SetUnpackedSize(unsigned long long size) +{ + m_unpackedSize = size; +} + +void CXBTFFrame::SetX(unsigned int x) +{ + m_x = x; +} + +unsigned int CXBTFFrame::GetX() const +{ + return m_x; +} + +void CXBTFFrame::SetY(unsigned int y) +{ + m_y = y; +} + +unsigned int CXBTFFrame::GetY() const +{ + return m_y; +} + +unsigned long long CXBTFFrame::GetOffset() const +{ + return m_offset; +} + +void CXBTFFrame::SetOffset(unsigned long long offset) +{ + m_offset = offset; +} + +unsigned int CXBTFFrame::GetDuration() const +{ + return m_duration; +} + +void CXBTFFrame::SetDuration(unsigned int duration) +{ + m_duration = duration; +} + + +unsigned long long CXBTFFrame::GetHeaderSize() const +{ + unsigned long long result = + sizeof(m_width) + + sizeof(m_height) + + sizeof(m_x) + + sizeof(m_y) + + sizeof(m_packedSize) + + sizeof(m_unpackedSize) + + sizeof(m_offset) + + sizeof(m_duration); + + return result; +} + +CXBTFFile::CXBTFFile() +{ + bzero(m_path, sizeof(m_path)); + m_loop = 0; + m_format = XB_FMT_UNKNOWN; +} + +CXBTFFile::CXBTFFile(const CXBTFFile& ref) +{ + strcpy(m_path, ref.m_path); + m_loop = ref.m_loop; + m_format = ref.m_format; + m_frames = ref.m_frames; +} + +char* CXBTFFile::GetPath() +{ + return m_path; +} + +void CXBTFFile::SetPath(const std::string& path) +{ + bzero(m_path, sizeof(m_path)); + strncpy(m_path, path.c_str(), sizeof(m_path) - 1); +} + +int CXBTFFile::GetLoop() const +{ + return m_loop; +} + +void CXBTFFile::SetLoop(int loop) +{ + m_loop = loop; +} + +unsigned int CXBTFFile::GetFormat() const +{ + return m_format; +} + +void CXBTFFile::SetFormat(unsigned int format) +{ + m_format = format; +} + +std::vector<CXBTFFrame>& CXBTFFile::GetFrames() +{ + return m_frames; +} + +unsigned long long CXBTFFile::GetHeaderSize() const +{ + unsigned long long result = + sizeof(m_path) + + sizeof(m_loop) + + sizeof(m_format) + + sizeof(unsigned int); /* Number of frames */ + + for (size_t i = 0; i < m_frames.size(); i++) + { + result += m_frames[i].GetHeaderSize(); + } + + return result; +} + +CXBTF::CXBTF() +{ +} + +unsigned long long CXBTF::GetHeaderSize() const +{ + unsigned long long result = + 4 /* Magic */ + + 1 /* Vesion */ + + sizeof(unsigned int) /* Number of Files */; + + for (size_t i = 0; i < m_files.size(); i++) + { + result += m_files[i].GetHeaderSize(); + } + + return result; +} + +std::vector<CXBTFFile>& CXBTF::GetFiles() +{ + return m_files; +} diff --git a/guilib/XBTF.h b/guilib/XBTF.h new file mode 100644 index 0000000000..0a0d10ab2d --- /dev/null +++ b/guilib/XBTF.h @@ -0,0 +1,105 @@ +/* + * 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 + * + */ +#ifndef XBTF_H_ +#define XBTF_H_ + +#include <string> +#include <vector> + +#define XBTF_MAGIC "XBTF" +#define XBTF_VERSION "1" + +#define XB_FMT_DXT_MASK 14 +#define XB_FMT_UNKNOWN 1 +#define XB_FMT_DXT1 2 +#define XB_FMT_DXT3 4 +#define XB_FMT_DXT5 8 +#define XB_FMT_B8G8R8A8 16 +#define XB_FMT_R8G8B8A8 32 +#define XB_FMT_LZO 64 + +class CXBTFFrame +{ +public: + CXBTFFrame(); + unsigned int GetWidth() const; + void SetWidth(unsigned int width); + unsigned int GetX() const; + void SetX(unsigned int x); + unsigned int GetY() const; + void SetY(unsigned int y); + unsigned int GetHeight() const; + void SetHeight(unsigned int height); + unsigned long long GetUnpackedSize() const; + void SetUnpackedSize(unsigned long long size); + unsigned long long GetPackedSize() const; + void SetPackedSize(unsigned long long size); + unsigned long long GetOffset() const; + void SetOffset(unsigned long long offset); + unsigned long long GetHeaderSize() const; + unsigned int GetDuration() const; + void SetDuration(unsigned int duration); + +private: + unsigned int m_width; + unsigned int m_height; + unsigned int m_x; + unsigned int m_y; + unsigned long long m_packedSize; + unsigned long long m_unpackedSize; + unsigned long long m_offset; + unsigned int m_duration; +}; + +class CXBTFFile +{ +public: + CXBTFFile(); + CXBTFFile(const CXBTFFile& ref); + char* GetPath(); + void SetPath(const std::string& path); + int GetLoop() const; + void SetLoop(int loop); + unsigned int GetFormat() const; + void SetFormat(unsigned int format); + + std::vector<CXBTFFrame>& GetFrames(); + unsigned long long GetHeaderSize() const; + +private: + char m_path[256]; + int m_loop; + unsigned int m_format; + std::vector<CXBTFFrame> m_frames; +}; + +class CXBTF +{ +public: + CXBTF(); + unsigned long long GetHeaderSize() const; + std::vector<CXBTFFile>& GetFiles(); + +private: + std::vector<CXBTFFile> m_files; +}; + +#endif diff --git a/guilib/XBTFReader.cpp b/guilib/XBTFReader.cpp new file mode 100644 index 0000000000..9855dbae1b --- /dev/null +++ b/guilib/XBTFReader.cpp @@ -0,0 +1,201 @@ +/* + * 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 <sys/stat.h> +#include "XBTFReader.h" +#include "EndianSwap.h" +#include "CharsetConverter.h" + +#define READ_STR(str, size, file) fread(str, size, 1, file) +#define READ_U32(i, file) fread(&i, 4, 1, file); i = Endian_SwapLE32(i); +#define READ_U64(i, file) fread(&i, 8, 1, file); i = Endian_SwapLE64(i); + +CXBTFReader::CXBTFReader() +{ + m_file = NULL; +} + +bool CXBTFReader::IsOpen() const +{ + return m_file != NULL; +} + +bool CXBTFReader::Open(const CStdString& fileName) +{ + m_fileName = fileName; + +#ifndef _LINUX + CStdStringW strPathW; + g_charsetConverter.utf8ToW(_P(m_fileName), strPathW, false); + m_file = _wfopen(strPathW.c_str(), L"rb"); +#else + m_file = fopen(m_fileName.c_str(), "rb"); +#endif + if (m_file == NULL) + { + return false; + } + + char magic[4]; + READ_STR(magic, 4, m_file); + + if (strncmp(magic, XBTF_MAGIC, sizeof(magic)) != 0) + { + return false; + } + + char version[1]; + READ_STR(version, 1, m_file); + + if (strncmp(version, XBTF_VERSION, sizeof(version)) != 0) + { + return false; + } + + unsigned int nofFiles; + READ_U32(nofFiles, m_file); + for (unsigned int i = 0; i < nofFiles; i++) + { + CXBTFFile file; + unsigned int u32; + unsigned long long u64; + + READ_STR(file.GetPath(), 256, m_file); + READ_U32(u32, m_file); + file.SetFormat(u32); + READ_U32(u32, m_file); + file.SetLoop(u32); + + unsigned int nofFrames; + READ_U32(nofFrames, m_file); + + for (unsigned int j = 0; j < nofFrames; j++) + { + CXBTFFrame frame; + + READ_U32(u32, m_file); + frame.SetWidth(u32); + READ_U32(u32, m_file); + frame.SetHeight(u32); + READ_U32(u32, m_file); + frame.SetX(u32); + READ_U32(u32, m_file); + frame.SetY(u32); + READ_U64(u64, m_file); + frame.SetPackedSize(u64); + READ_U64(u64, m_file); + frame.SetUnpackedSize(u64); + READ_U32(u32, m_file); + frame.SetDuration(u32); + READ_U64(u64, m_file); + frame.SetOffset(u64); + + file.GetFrames().push_back(frame); + } + + m_xbtf.GetFiles().push_back(file); + + std::pair<CStdString, unsigned int> key = std::make_pair(file.GetPath(), file.GetFormat()); + m_filesMap[key] = file; + } + + // Sanity check + fpos_t pos; + fgetpos(m_file, &pos); + if ((unsigned int) pos != m_xbtf.GetHeaderSize()) + { + printf("Expected header size (%llu) != actual size (%llu)\n", m_xbtf.GetHeaderSize(), pos); + return false; + } + + return true; +} + +void CXBTFReader::Close() +{ + if (m_file) + { + fclose(m_file); + m_file = NULL; + } + + m_xbtf.GetFiles().clear(); + m_filesMap.clear(); +} + +time_t CXBTFReader::GetLastModificationTimestamp() +{ + if (!m_file) + { + return 0; + } + + struct stat fileStat; + if (fstat(fileno(m_file), &fileStat) == -1) + { + return 0; + } + + return fileStat.st_mtime; +} + +bool CXBTFReader::Exists(const CStdString& name, int formatMask) +{ + return Find(name, formatMask) != NULL; +} + +CXBTFFile* CXBTFReader::Find(const CStdString& name, int formatMask) +{ + std::pair<CStdString, unsigned int> key = std::make_pair(name, formatMask); + + std::map<std::pair<CStdString, unsigned int>, CXBTFFile>::iterator iter = m_filesMap.find(key); + if (iter == m_filesMap.end()) + { + return NULL; + } + + return &(iter->second); +} + +bool CXBTFReader::Load(const CXBTFFrame& frame, unsigned char* buffer) +{ + if (!m_file) + { + return false; + } + + if (fseek(m_file, frame.GetOffset(), SEEK_SET) == -1) + { + return false; + } + + if (fread(buffer, 1, frame.GetPackedSize(), m_file) != frame.GetPackedSize()) + { + return false; + } + + return true; +} + +std::vector<CXBTFFile>& CXBTFReader::GetFiles() +{ + return m_xbtf.GetFiles(); +} diff --git a/guilib/XBTFReader.h b/guilib/XBTFReader.h new file mode 100644 index 0000000000..a24d44084d --- /dev/null +++ b/guilib/XBTFReader.h @@ -0,0 +1,50 @@ +/* + * 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 + * + */ + +#ifndef XBTFREADER_H_ +#define XBTFREADER_H_ + +#include <vector> +#include <map> +#include "StdString.h" +#include "XBTF.h" + +class CXBTFReader +{ +public: + CXBTFReader(); + bool IsOpen() const; + bool Open(const CStdString& fileName); + void Close(); + time_t GetLastModificationTimestamp(); + bool Exists(const CStdString& name, int formatMask); + CXBTFFile* Find(const CStdString& name, int formatMask); + bool Load(const CXBTFFrame& frame, unsigned char* buffer); + std::vector<CXBTFFile>& GetFiles(); + +private: + CXBTF m_xbtf; + CStdString m_fileName; + FILE* m_file; + std::map<std::pair<CStdString, unsigned int>, CXBTFFile> m_filesMap; +}; + +#endif diff --git a/skin/PM3.HD/media/Makefile b/skin/PM3.HD/media/Makefile index 4ea9204b5f..3074a96711 100644 --- a/skin/PM3.HD/media/Makefile +++ b/skin/PM3.HD/media/Makefile @@ -1,5 +1,5 @@ -TARGET=Textures.xpr -XBMCTEX=../../../tools/XBMCTex/XBMCTex +TARGET=Textures.xbt +XBMCTEX=../../../tools/XBMCTexXBT/XBMCTexXBT IMAGES= \ Apple\ Movie\ Trailers/G.png \ Apple\ Movie\ Trailers/NC-17.png \ @@ -325,7 +325,7 @@ $(TARGET): $(XBMCTEX) $(IMAGES) $(XBMCTEX) -input . -output $(TARGET) $(XBMCTEX): force - $(MAKE) -C ../../../tools/XBMCTex + $(MAKE) -C ../../../tools/XBMCTexXBT clean: rm -f $(TARGET) diff --git a/skin/Project Mayhem III/media/Makefile b/skin/Project Mayhem III/media/Makefile index 473c7c08db..e24063e066 100644 --- a/skin/Project Mayhem III/media/Makefile +++ b/skin/Project Mayhem III/media/Makefile @@ -1,5 +1,5 @@ -TARGET=Textures.xpr -XBMCTEX=../../../tools/XBMCTex/XBMCTex +TARGET=Textures.xbt +XBMCTEX=../../../tools/XBMCTexXBT/XBMCTexXBT IMAGES= \ busy/busy1.png \ busy/busy2.png \ @@ -378,7 +378,7 @@ $(TARGET): $(XBMCTEX) $(IMAGES) $(XBMCTEX) -input . -output $(TARGET) $(XBMCTEX): force - $(MAKE) -C ../../../tools/XBMCTex + $(MAKE) -C ../../../tools/XBMCTexXBT clean: rm -f $(TARGET) diff --git a/tools/XBMCTexXBT/Makefile b/tools/XBMCTexXBT/Makefile new file mode 100644 index 0000000000..845e6cbf66 --- /dev/null +++ b/tools/XBMCTexXBT/Makefile @@ -0,0 +1,17 @@ +INCLUDES =-I../../xbmc/utils -I../../guilib -I../../xbmc/linux -I../../xbmc/lib/libsquish +DEFINES = +LIBS = ../../xbmc/lib/libsquish/libsquish.a ../../guilib/XBTF.o -L/opt/local/lib -lSDL_image -lSDL +OBJS = \ + SDL_anigif.o \ + XBTFWriter.o \ + XBMCTex.o \ + +TARGET = XBMCTexXBT +CLEAN_FILES=$(TARGET) + +all: $(TARGET) + +include ../../Makefile.include + +$(TARGET): $(OBJS) + $(CXX) $(OBJS) $(LDFLAGS) $(LIBS) -o $(TARGET) diff --git a/tools/XBMCTexXBT/SDL_anigif.c b/tools/XBMCTexXBT/SDL_anigif.c new file mode 100644 index 0000000000..b77b7bcdb0 --- /dev/null +++ b/tools/XBMCTexXBT/SDL_anigif.c @@ -0,0 +1,776 @@ +/*
+ SDL_anigif: An example animated GIF image loading library for use with SDL
+ SDL_image Copyright (C) 1997-2006 Sam Lantinga
+ Animated GIF "derived work" Copyright (C) 2006 Doug McFadyen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "SDL_anigif.h"
+
+
+
+/* Code from here to end of file has been adapted from XPaint: */
+/* +-------------------------------------------------------------------+ */
+/* | Copyright 1990, 1991, 1993 David Koblas. | */
+/* | Copyright 1996 Torsten Martinsen. | */
+/* | Permission to use, copy, modify, and distribute this software | */
+/* | and its documentation for any purpose and without fee is hereby | */
+/* | granted, provided that the above copyright notice appear in all | */
+/* | copies and that both that copyright notice and this permission | */
+/* | notice appear in supporting documentation. This software is | */
+/* | provided "as is" without express or implied warranty. | */
+/* +-------------------------------------------------------------------+ */
+/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
+/* Animated GIF support by Doug McFadyen -- 10/19/06 */
+
+#define MAXCOLORMAPSIZE 256
+
+#define TRUE 1
+#define FALSE 0
+
+#define CM_RED 0
+#define CM_GREEN 1
+#define CM_BLUE 2
+
+#define MAX_LWZ_BITS 12
+
+#define INTERLACE 0x40
+#define LOCALCOLORMAP 0x80
+#define BitSet(byte,bit) (((byte) & (bit)) == (bit))
+#define LM_to_uint(a,b) (((b)<<8)|(a))
+
+#define SDL_SetError(t) ((void)0) /* We're not SDL so ignore error reporting */
+
+
+typedef struct
+{
+ unsigned int Width;
+ unsigned int Height;
+ unsigned char ColorMap[3][MAXCOLORMAPSIZE];
+ unsigned int BitPixel;
+ unsigned int ColorResolution;
+ unsigned int Background;
+ unsigned int AspectRatio;
+} gifscreen;
+
+typedef struct
+{
+ int transparent;
+ int delayTime;
+ int inputFlag;
+ int disposal;
+} gif89;
+
+typedef struct
+{
+ /* global data */
+ SDL_RWops* src;
+ gifscreen gs;
+ gif89 g89;
+ int zerodatablock;
+ /* AG_LoadGIF_RW data */
+ unsigned char localColorMap[3][MAXCOLORMAPSIZE];
+ /* GetCode data */
+ unsigned char buf[280];
+ int curbit, lastbit, done, lastbyte;
+ /* LWZReadByte data */
+ int fresh, code, incode;
+ int codesize, setcodesize;
+ int maxcode, maxcodesize;
+ int firstcode, oldcode;
+ int clearcode, endcode;
+ int table[2][(1 << MAX_LWZ_BITS)];
+ int stack[(1 << (MAX_LWZ_BITS))*2], *sp;
+} gifdata;
+
+
+
+static int ReadColorMap( gifdata* gd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] );
+static int DoExtension( gifdata* gd, int label );
+static int GetDataBlock( gifdata* gd, unsigned char* buf );
+static int GetCode( gifdata* gd, int code_size, int flag );
+static int LWZReadByte( gifdata* gd, int flag, int input_code_size );
+static SDL_Surface* ReadImage( gifdata* gd, int len, int height, int, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore );
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+int AG_isGIF( SDL_RWops* src )
+{
+ int isGIF = FALSE;
+
+ if ( src )
+ {
+ int start = SDL_RWtell( src );
+ char magic[6];
+
+ if ( SDL_RWread(src,magic,sizeof(magic),1) )
+ {
+ if ( (strncmp(magic,"GIF",3) == 0) && ((memcmp(magic+3,"87a",3) == 0) || (memcmp(magic+3,"89a",3) == 0)) )
+ {
+ isGIF = TRUE;
+ }
+ }
+
+ SDL_RWseek( src, start, SEEK_SET );
+ }
+
+ return isGIF;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+int AG_LoadGIF( const char* file, AG_Frame* frames, int size )
+{
+ int n = 0;
+
+ SDL_RWops* src = SDL_RWFromFile( file, "rb" );
+
+ if ( src )
+ {
+ n = AG_LoadGIF_RW( src, frames, size );
+ SDL_RWclose( src );
+ }
+
+ return n;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+void AG_FreeSurfaces( AG_Frame* frames, int nFrames )
+{
+ int i;
+
+ if ( frames )
+ {
+ for ( i = 0; i < nFrames; i++ )
+ {
+ if ( frames[i].surface )
+ {
+ SDL_FreeSurface( frames[i].surface );
+ frames[i].surface = NULL;
+ }
+ }
+ }
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+int AG_ConvertSurfacesToDisplayFormat( AG_Frame* frames, int nFrames )
+{
+ int i;
+ int n = 0;
+
+ if ( frames )
+ {
+ for ( i = 0; i < nFrames; i++ )
+ {
+ if ( frames[i].surface )
+ {
+ SDL_Surface* surface = (frames[i].surface->flags & SDL_SRCCOLORKEY) ? SDL_DisplayFormatAlpha(frames[i].surface) : SDL_DisplayFormat(frames[i].surface);
+
+ if ( surface )
+ {
+ SDL_FreeSurface( frames[i].surface );
+ frames[i].surface = surface;
+ n++;
+ }
+ }
+ }
+ }
+
+ return n;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+int AG_NormalizeSurfacesToDisplayFormat( AG_Frame* frames, int nFrames )
+{
+ int n = 0;
+
+ if ( nFrames > 0 && frames && frames[0].surface )
+ {
+ SDL_Surface* mainSurface = (frames[0].surface->flags & SDL_SRCCOLORKEY) ? SDL_DisplayFormatAlpha(frames[0].surface) : SDL_DisplayFormat(frames[0].surface);
+ const int newDispose = (frames[0].surface->flags & SDL_SRCCOLORKEY) ? AG_DISPOSE_RESTORE_BACKGROUND : AG_DISPOSE_NONE;
+
+ if ( mainSurface )
+ {
+ int i;
+ int lastDispose = AG_DISPOSE_NA;
+ int iRestore = 0;
+ const Uint8 alpha = (frames[0].disposal == AG_DISPOSE_NONE) ? SDL_ALPHA_OPAQUE : SDL_ALPHA_TRANSPARENT;
+
+ SDL_FillRect( mainSurface, NULL, SDL_MapRGBA(mainSurface->format,0,0,0,alpha) );
+
+ for ( i = 0; i < nFrames; i++ )
+ {
+ if ( frames[i].surface )
+ {
+ SDL_Surface* surface = SDL_ConvertSurface( mainSurface, mainSurface->format, mainSurface->flags );
+
+ if ( surface )
+ {
+ SDL_Rect r;
+
+ if ( lastDispose == AG_DISPOSE_NONE )
+ SDL_BlitSurface( frames[i-1].surface, NULL, surface, NULL );
+
+ if ( lastDispose == AG_DISPOSE_RESTORE_PREVIOUS )
+ SDL_BlitSurface( frames[iRestore].surface, NULL, surface, NULL );
+ if ( frames[i].disposal != AG_DISPOSE_RESTORE_PREVIOUS )
+ iRestore = i;
+
+ r.x = (Sint16)frames[i].x;
+ r.y = (Sint16)frames[i].y;
+ SDL_BlitSurface( frames[i].surface, NULL, surface, &r );
+
+ SDL_FreeSurface( frames[i].surface );
+ frames[i].surface = surface;
+ frames[i].x = frames[i].y = 0;
+ lastDispose = frames[i].disposal;
+ frames[i].disposal = newDispose;
+ n++;
+ }
+ }
+ }
+
+ SDL_FreeSurface( mainSurface );
+ }
+ }
+
+ return n;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+int AG_LoadGIF_RW( SDL_RWops* src, AG_Frame* frames, int maxFrames )
+{
+ int start;
+ unsigned char buf[16];
+ unsigned char c;
+ int useGlobalColormap;
+ int bitPixel;
+ int iFrame = 0;
+ char version[4];
+ SDL_Surface* image = NULL;
+ gifdata* gd;
+
+ if ( src == NULL )
+ return 0;
+
+ gd = malloc( sizeof(*gd) );
+ memset( gd, 0, sizeof(*gd) );
+ gd->src = src;
+
+ start = SDL_RWtell( src );
+
+ if ( !SDL_RWread(src,buf,6,1) )
+ {
+ SDL_SetError( "error reading magic number" );
+ goto done;
+ }
+
+ if ( strncmp((char*)buf,"GIF",3) != 0 )
+ {
+ SDL_SetError( "not a GIF file" );
+ goto done;
+ }
+
+ strncpy( version, (char*)buf+3, 3 );
+ version[3] = '\0';
+
+ if ( (strcmp(version,"87a") != 0) && (strcmp(version,"89a") != 0) )
+ {
+ SDL_SetError( "bad version number, not '87a' or '89a'" );
+ goto done;
+ }
+
+ gd->g89.transparent = -1;
+ gd->g89.delayTime = -1;
+ gd->g89.inputFlag = -1;
+ gd->g89.disposal = AG_DISPOSE_NA;
+
+ if ( !SDL_RWread(src,buf,7,1) )
+ {
+ SDL_SetError( "failed to read screen descriptor" );
+ goto done;
+ }
+
+ gd->gs.Width = LM_to_uint(buf[0],buf[1]);
+ gd->gs.Height = LM_to_uint(buf[2],buf[3]);
+ gd->gs.BitPixel = 2 << (buf[4] & 0x07);
+ gd->gs.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
+ gd->gs.Background = buf[5];
+ gd->gs.AspectRatio = buf[6];
+
+ if ( BitSet(buf[4],LOCALCOLORMAP) ) /* Global Colormap */
+ {
+ if ( ReadColorMap(gd,gd->gs.BitPixel,gd->gs.ColorMap) )
+ {
+ SDL_SetError( "error reading global colormap" );
+ goto done;
+ }
+ }
+
+ do
+ {
+ if ( !SDL_RWread(src,&c,1,1) )
+ {
+ SDL_SetError( "EOF / read error on image data" );
+ goto done;
+ }
+
+ if ( c == ';' ) /* GIF terminator */
+ goto done;
+
+ if ( c == '!' ) /* Extension */
+ {
+ if ( !SDL_RWread(src,&c,1,1) )
+ {
+ SDL_SetError( "EOF / read error on extention function code" );
+ goto done;
+ }
+ DoExtension( gd, c );
+ continue;
+ }
+
+ if ( c != ',' ) /* Not a valid start character */
+ continue;
+
+ if ( !SDL_RWread(src,buf,9,1) )
+ {
+ SDL_SetError( "couldn't read left/top/width/height" );
+ goto done;
+ }
+
+ useGlobalColormap = !BitSet(buf[8],LOCALCOLORMAP);
+ bitPixel = 1 << ((buf[8] & 0x07) + 1);
+
+ if ( !useGlobalColormap )
+ {
+ if ( ReadColorMap(gd,bitPixel,gd->localColorMap) )
+ {
+ SDL_SetError( "error reading local colormap" );
+ goto done;
+ }
+ image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), bitPixel, gd->localColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) );
+ }
+ else
+ {
+ image = ReadImage( gd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), gd->gs.BitPixel, gd->gs.ColorMap, BitSet(buf[8],INTERLACE), (frames==NULL) );
+ }
+
+ if ( frames )
+ {
+ if ( image == NULL )
+ goto done;
+
+ if ( gd->g89.transparent >= 0 )
+ SDL_SetColorKey( image, SDL_SRCCOLORKEY, gd->g89.transparent );
+
+ frames[iFrame].surface = image;
+ frames[iFrame].x = LM_to_uint(buf[0], buf[1]);
+ frames[iFrame].y = LM_to_uint(buf[2], buf[3]);
+ frames[iFrame].disposal = gd->g89.disposal;
+ frames[iFrame].delay = gd->g89.delayTime*10;
+/* gd->g89.transparent = -1; ** Hmmm, not sure if this should be reset for each frame? */
+ }
+
+ iFrame++;
+ } while ( iFrame < maxFrames || frames == NULL );
+
+done:
+ if ( image == NULL )
+ SDL_RWseek( src, start, SEEK_SET );
+
+ free( gd );
+
+ return iFrame;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static int ReadColorMap( gifdata* gd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] )
+{
+ int i;
+ unsigned char rgb[3];
+ int flag;
+
+ flag = TRUE;
+
+ for ( i = 0; i < number; ++i )
+ {
+ if ( !SDL_RWread(gd->src,rgb,sizeof(rgb),1) )
+ {
+ SDL_SetError( "bad colormap" );
+ return 1;
+ }
+
+ buffer[CM_RED][i] = rgb[0];
+ buffer[CM_GREEN][i] = rgb[1];
+ buffer[CM_BLUE][i] = rgb[2];
+ flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
+ }
+
+ return FALSE;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static int DoExtension( gifdata* gd, int label )
+{
+ unsigned char buf[256];
+
+ switch ( label )
+ {
+ case 0x01: /* Plain Text Extension */
+ break;
+
+ case 0xff: /* Application Extension */
+ break;
+
+ case 0xfe: /* Comment Extension */
+ while ( GetDataBlock(gd,buf) != 0 )
+ ;
+ return FALSE;
+
+ case 0xf9: /* Graphic Control Extension */
+ (void)GetDataBlock( gd, buf );
+ gd->g89.disposal = (buf[0] >> 2) & 0x7;
+ gd->g89.inputFlag = (buf[0] >> 1) & 0x1;
+ gd->g89.delayTime = LM_to_uint(buf[1],buf[2]);
+ if ( (buf[0] & 0x1) != 0 )
+ gd->g89.transparent = buf[3];
+
+ while ( GetDataBlock(gd,buf) != 0 )
+ ;
+ return FALSE;
+ }
+
+ while ( GetDataBlock(gd,buf) != 0 )
+ ;
+
+ return FALSE;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static int GetDataBlock( gifdata* gd, unsigned char* buf )
+{
+ unsigned char count;
+
+ if ( !SDL_RWread(gd->src,&count,1,1) )
+ {
+ /* pm_message("error in getting DataBlock size" ); */
+ return -1;
+ }
+
+ gd->zerodatablock = count == 0;
+
+ if ( (count != 0) && !SDL_RWread(gd->src,buf,count,1) )
+ {
+ /* pm_message("error in reading DataBlock" ); */
+ return -1;
+ }
+
+ return count;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static int GetCode( gifdata* gd, int code_size, int flag )
+{
+ int i, j, ret;
+ int count;
+
+ if ( flag )
+ {
+ gd->curbit = 0;
+ gd->lastbit = 0;
+ gd->done = FALSE;
+ return 0;
+ }
+
+ if ( (gd->curbit + code_size) >= gd->lastbit )
+ {
+ if ( gd->done )
+ {
+ if ( gd->curbit >= gd->lastbit )
+ SDL_SetError( "ran off the end of my bits" );
+ return -1;
+ }
+
+ gd->buf[0] = gd->buf[gd->lastbyte - 2];
+ gd->buf[1] = gd->buf[gd->lastbyte - 1];
+
+ if ( (count = GetDataBlock(gd, &gd->buf[2])) == 0 )
+ gd->done = TRUE;
+
+ gd->lastbyte = 2 + count;
+ gd->curbit = (gd->curbit - gd->lastbit) + 16;
+ gd->lastbit = (2 + count)*8;
+ }
+
+ ret = 0;
+ for ( i = gd->curbit, j = 0; j < code_size; ++i, ++j )
+ ret |= ((gd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
+
+ gd->curbit += code_size;
+
+ return ret;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static int LWZReadByte( gifdata* gd, int flag, int input_code_size )
+{
+ int i, code, incode;
+
+ if ( flag )
+ {
+ gd->setcodesize = input_code_size;
+ gd->codesize = gd->setcodesize + 1;
+ gd->clearcode = 1 << gd->setcodesize;
+ gd->endcode = gd->clearcode + 1;
+ gd->maxcodesize = gd->clearcode*2;
+ gd->maxcode = gd->clearcode + 2;
+
+ GetCode( gd, 0, TRUE );
+
+ gd->fresh = TRUE;
+
+ for ( i = 0; i < gd->clearcode; ++i )
+ {
+ gd->table[0][i] = 0;
+ gd->table[1][i] = i;
+ }
+
+ for ( ; i < (1 << MAX_LWZ_BITS); ++i )
+ gd->table[0][i] = gd->table[1][0] = 0;
+
+ gd->sp = gd->stack;
+ return 0;
+ }
+ else if ( gd->fresh )
+ {
+ gd->fresh = FALSE;
+ do
+ {
+ gd->firstcode = gd->oldcode = GetCode( gd, gd->codesize, FALSE );
+ } while ( gd->firstcode == gd->clearcode );
+ return gd->firstcode;
+ }
+
+ if ( gd->sp > gd->stack )
+ return *--gd->sp;
+
+ while ( (code = GetCode(gd,gd->codesize,FALSE)) >= 0 )
+ {
+ if ( code == gd->clearcode )
+ {
+ for ( i = 0; i < gd->clearcode; ++i )
+ {
+ gd->table[0][i] = 0;
+ gd->table[1][i] = i;
+ }
+
+ for ( ; i < (1 << MAX_LWZ_BITS); ++i )
+ gd->table[0][i] = gd->table[1][i] = 0;
+
+ gd->codesize = gd->setcodesize + 1;
+ gd->maxcodesize = gd->clearcode*2;
+ gd->maxcode = gd->clearcode + 2;
+ gd->sp = gd->stack;
+ gd->firstcode = gd->oldcode = GetCode( gd, gd->codesize, FALSE );
+ return gd->firstcode;
+ }
+ else if ( code == gd->endcode )
+ {
+ int count;
+ unsigned char buf[260];
+
+ if ( gd->zerodatablock )
+ return -2;
+
+ while ( (count = GetDataBlock(gd,buf)) > 0 )
+ ;
+
+ if ( count != 0 )
+ {
+ /* pm_message("missing EOD in data stream (common occurence)"); */
+ }
+ return -2;
+ }
+
+ incode = code;
+
+ if ( code >= gd->maxcode )
+ {
+ *gd->sp++ = gd->firstcode;
+ code = gd->oldcode;
+ }
+
+ while ( code >= gd->clearcode )
+ {
+ *gd->sp++ = gd->table[1][code];
+ if ( code == gd->table[0][code] )
+ SDL_SetError( "circular table entry BIG ERROR" );
+ code = gd->table[0][code];
+ }
+
+ *gd->sp++ = gd->firstcode = gd->table[1][code];
+
+ if ( (code = gd->maxcode) < (1 << MAX_LWZ_BITS) )
+ {
+ gd->table[0][code] = gd->oldcode;
+ gd->table[1][code] = gd->firstcode;
+ ++gd->maxcode;
+ if ( (gd->maxcode >= gd->maxcodesize) && (gd->maxcodesize < (1 << MAX_LWZ_BITS)) )
+ {
+ gd->maxcodesize *= 2;
+ ++gd->codesize;
+ }
+ }
+
+ gd->oldcode = incode;
+
+ if ( gd->sp > gd->stack )
+ return *--gd->sp;
+ }
+
+ return code;
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/*
+/*--------------------------------------------------------------------------*/
+static SDL_Surface* ReadImage( gifdata* gd, int len, int height, int cmapSize, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore )
+{
+ SDL_Surface* image;
+ unsigned char c;
+ int i, v;
+ int xpos = 0, ypos = 0, pass = 0;
+
+ /* Initialize the compression routines */
+ if ( !SDL_RWread(gd->src,&c,1,1) )
+ {
+ SDL_SetError( "EOF / read error on image data" );
+ return NULL;
+ }
+
+ if ( LWZReadByte(gd,TRUE,c) < 0 )
+ {
+ SDL_SetError( "error reading image" );
+ return NULL;
+ }
+
+ /* If this is an "uninteresting picture" ignore it. */
+ if ( ignore )
+ {
+ while ( LWZReadByte(gd,FALSE,c) >= 0 )
+ ;
+ return NULL;
+ }
+
+ image = SDL_AllocSurface( SDL_SWSURFACE, len, height, 8, 0, 0, 0, 0 );
+
+ for ( i = 0; i < cmapSize; i++ )
+ {
+ image->format->palette->colors[i].r = cmap[CM_RED][i];
+ image->format->palette->colors[i].g = cmap[CM_GREEN][i];
+ image->format->palette->colors[i].b = cmap[CM_BLUE][i];
+ }
+
+ while ( (v = LWZReadByte(gd,FALSE,c)) >= 0 )
+ {
+ ((Uint8*)image->pixels)[xpos + ypos*image->pitch] = (Uint8)v;
+ ++xpos;
+
+ if ( xpos == len )
+ {
+ xpos = 0;
+ if ( interlace )
+ {
+ switch ( pass )
+ {
+ case 0:
+ case 1: ypos += 8; break;
+ case 2: ypos += 4; break;
+ case 3: ypos += 2; break;
+ }
+
+ if ( ypos >= height )
+ {
+ ++pass;
+ switch ( pass )
+ {
+ case 1: ypos = 4; break;
+ case 2: ypos = 2; break;
+ case 3: ypos = 1; break;
+ default: goto fini;
+ }
+ }
+ }
+ else
+ {
+ ++ypos;
+ }
+ }
+
+ if ( ypos >= height )
+ break;
+ }
+
+fini:
+ return image;
+}
+
diff --git a/tools/XBMCTexXBT/SDL_anigif.h b/tools/XBMCTexXBT/SDL_anigif.h new file mode 100644 index 0000000000..7fad7c8fdb --- /dev/null +++ b/tools/XBMCTexXBT/SDL_anigif.h @@ -0,0 +1,62 @@ +/*
+ SDL_anigif: An example animated GIF image loading library for use with SDL
+ SDL_image Copyright (C) 1997-2006 Sam Lantinga
+ Animated GIF "derived work" Copyright (C) 2006 Doug McFadyen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _SDL_ANIGIF_H
+#define _SDL_ANIGIF_H
+
+#include <SDL/SDL.h>
+#include <SDL/begin_code.h>
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+
+typedef struct
+{
+ SDL_Surface* surface; /* SDL surface for this frame */
+ int x, y; /* Frame offset position */
+ int disposal; /* Disposal code */
+ int delay; /* Frame delay in ms */
+ int user; /* User data (not used by aniGIF) */
+} AG_Frame;
+
+#define AG_DISPOSE_NA 0 /* No disposal specified */
+#define AG_DISPOSE_NONE 1 /* Do not dispose */
+#define AG_DISPOSE_RESTORE_BACKGROUND 2 /* Restore to background */
+#define AG_DISPOSE_RESTORE_PREVIOUS 3 /* Restore to previous */
+
+
+
+extern DECLSPEC int AG_isGIF( SDL_RWops* src );
+extern DECLSPEC int AG_LoadGIF( const char* file, AG_Frame* frames, int maxFrames );
+extern DECLSPEC void AG_FreeSurfaces( AG_Frame* frames, int nFrames );
+extern DECLSPEC int AG_ConvertSurfacesToDisplayFormat( AG_Frame* frames, int nFrames );
+extern DECLSPEC int AG_NormalizeSurfacesToDisplayFormat( AG_Frame* frames, int nFrames );
+extern DECLSPEC int AG_LoadGIF_RW( SDL_RWops* src, AG_Frame* frames, int size );
+
+
+
+#ifdef __cplusplus
+ }
+#endif
+#include <SDL/close_code.h>
+
+#endif /* _SDL_ANIGIF_H */
diff --git a/tools/XBMCTexXBT/XBMCTex.cpp b/tools/XBMCTexXBT/XBMCTex.cpp new file mode 100644 index 0000000000..abe5deb89e --- /dev/null +++ b/tools/XBMCTexXBT/XBMCTex.cpp @@ -0,0 +1,321 @@ +/* + * 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 <sys/types.h> +#include <dirent.h> +#include <squish.h> +#include <string> +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> +#include "XBTF.h" +#include "XBTFWriter.h" +#include "SDL_anigif.h" +#include "cmdlineargs.h" + +#define DIR_SEPARATOR "/" +#define DIR_SEPARATOR_CHAR '/' + +#undef main + +// returns true for png, bmp, tga, jpg and dds files, otherwise returns false +bool IsGraphicsFile(char *strFileName) +{ + size_t n = strlen(strFileName); + if (n < 4) + return false; + + if (strncasecmp(&strFileName[n-4], ".png", 4) && + strncasecmp(&strFileName[n-4], ".bmp", 4) && + strncasecmp(&strFileName[n-4], ".tga", 4) && + strncasecmp(&strFileName[n-4], ".gif", 4) && + strncasecmp(&strFileName[n-4], ".jpg", 4)) + return false; + + return true; +} + +// returns true for png, bmp, tga, jpg and dds files, otherwise returns false +bool IsGIF(const char *strFileName) +{ + size_t n = strlen(strFileName); + if (n < 4) + return false; + + if (strncasecmp(&strFileName[n-4], ".gif", 4)) + return false; + + return true; +} + +void CreateSkeletonHeaderImpl(CXBTF& xbtf, std::string fullPath, std::string relativePath) +{ + struct dirent* dp; + DIR *dirp = opendir(fullPath.c_str()); + + while ((dp = readdir(dirp)) != NULL) + { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + { + continue; + } + + if (dp->d_type == DT_DIR) + { + std::string tmpPath = relativePath; + if (tmpPath.size() > 0) + { + tmpPath += "/"; + } + + CreateSkeletonHeaderImpl(xbtf, fullPath + DIR_SEPARATOR + dp->d_name, + tmpPath + dp->d_name); + } + else if (IsGraphicsFile(dp->d_name)) + { + std::string fileName = ""; + if (relativePath.size() > 0) + { + fileName += relativePath; + fileName += "/"; + } + + fileName += dp->d_name; + + CXBTFFile file; + file.SetPath(fileName); + file.SetFormat(XB_FMT_DXT5); + xbtf.GetFiles().push_back(file); + } + } + + closedir(dirp); +} + +void CreateSkeletonHeader(CXBTF& xbtf, std::string fullPath) +{ + std::string temp; + CreateSkeletonHeaderImpl(xbtf, fullPath, temp); +} + +CXBTFFrame createXBTFFrame(SDL_Surface* image, CXBTFWriter& writer, unsigned int format) +{ + // Convert to RGBA + SDL_PixelFormat rgbaFormat; + bzero(&rgbaFormat, sizeof(SDL_PixelFormat)); + rgbaFormat.BitsPerPixel = 32; + rgbaFormat.BytesPerPixel = 4; + + // For DXT5 we need RGBA +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + rgbaFormat.Rmask = 0x000000ff; + rgbaFormat.Rshift = 0; + rgbaFormat.Gmask = 0x0000ff00; + rgbaFormat.Gshift = 8; + rgbaFormat.Bmask = 0x00ff0000; + rgbaFormat.Bshift = 16; + rgbaFormat.Amask = 0xff000000; + rgbaFormat.Ashift = 24; +#else + rgbaFormat.Amask = 0x000000ff; + rgbaFormat.Ashift = 0; + rgbaFormat.Rmask = 0x0000ff00; + rgbaFormat.Rshift = 8; + rgbaFormat.Gmask = 0x00ff0000; + rgbaFormat.Gshift = 16; + rgbaFormat.Bmask = 0xff000000; + rgbaFormat.Bshift = 24; +#endif + + + SDL_Surface *rgbaImage = SDL_ConvertSurface(image, &rgbaFormat, 0); + + int compressedSize = 0; + CXBTFFrame frame; + + // Compress to DXT5 + compressedSize = squish::GetStorageRequirements(image->w, rgbaImage->h, squish::kDxt5); + squish::u8* compressed = new squish::u8[compressedSize]; + squish::CompressImage((const squish::u8*) rgbaImage->pixels, image->w, rgbaImage->h, compressed, squish::kDxt5); + frame.SetPackedSize(compressedSize); + frame.SetUnpackedSize(compressedSize); + + // Write the texture to a temporary file + writer.AppendContent((unsigned char*) compressed, compressedSize); + + delete [] compressed; + + SDL_FreeSurface(rgbaImage); + + // Update the header + frame.SetWidth(image->w); + frame.SetHeight(image->h); + frame.SetX(0); + frame.SetY(0); + frame.SetDuration(0); + + return frame; +} + +void Usage() +{ + puts("Usage:"); + puts(" -help Show this screen."); + puts(" -input <dir> Input directory. Default: current dir"); + puts(" -output <dir> Output directory/filename. Default: Textures.xpr"); +} + +int createBundle(const std::string& InputDir, const std::string& OutputFile) +{ + CXBTF xbtf; + CreateSkeletonHeader(xbtf, InputDir); + + CXBTFWriter writer(xbtf, OutputFile); + if (!writer.Create()) + { + printf("Error creating file\n"); + return 1; + } + + std::vector<CXBTFFile>& files = xbtf.GetFiles(); + for (size_t i = 0; i < files.size(); i++) + { + CXBTFFile& file = files[i]; + + int format = file.GetFormat(); + + printf("Converting %s to DXT5 ", file.GetPath()); + + std::string fullPath = InputDir; + fullPath += file.GetPath(); + + if (!IsGIF(fullPath.c_str())) + { + // Load the image + SDL_Surface* image = IMG_Load(fullPath.c_str()); + if (!image) + { + printf("...unable to load image\n"); + continue; + } + + CXBTFFrame frame = createXBTFFrame(image, writer, format); + + file.SetLoop(0); + file.GetFrames().push_back(frame); + + printf("(%dx%d)\n", image->w, image->h); + + SDL_FreeSurface(image); + } + else + { + int gnAG = AG_LoadGIF(fullPath.c_str(), NULL, 0); + AG_Frame* gpAG = new AG_Frame[gnAG]; + AG_LoadGIF(fullPath.c_str(), gpAG, gnAG); + + printf("(%dx%d) -- %d frames\n", gpAG[0].surface->w, gpAG[0].surface->h, gnAG); + + for (int j = 0; j < gnAG; j++) + { + CXBTFFrame frame = createXBTFFrame(gpAG[j].surface, writer, format); + frame.SetX(gpAG[j].x); + frame.SetX(gpAG[j].y); + frame.SetDuration(gpAG[j].delay); + file.GetFrames().push_back(frame); + } + + AG_FreeSurfaces(gpAG, gnAG); + delete [] gpAG; + + file.SetLoop(0); + } + } + + if (!writer.UpdateHeader()) + { + printf("Error writing header to file\n"); + return 1; + } + + if (!writer.Close()) + { + printf("Error closing file\n"); + return 1; + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + bool valid = false; + CmdLineArgs args(argc, (const char**)argv); + + if (args.size() == 1) + { + Usage(); + return 1; + } + + std::string InputDir; + std::string OutputFilename = "Textures.xbt"; + + for (unsigned int i = 1; i < args.size(); ++i) + { + if (!stricmp(args[i], "-help") || !stricmp(args[i], "-h") || !stricmp(args[i], "-?")) + { + Usage(); + return 1; + } + else if (!stricmp(args[i], "-input") || !stricmp(args[i], "-i")) + { + InputDir = args[++i]; + valid = true; + } + else if (!stricmp(args[i], "-output") || !stricmp(args[i], "-o")) + { + OutputFilename = args[++i]; + valid = true; +#ifdef _LINUX + char *c = NULL; + while ((c = (char *)strchr(OutputFilename.c_str(), '\\')) != NULL) *c = '/'; +#endif + } + else + { + printf("Unrecognized command line flag: %s\n", args[i]); + } + } + + if (!valid) + { + Usage(); + return 1; + } + + size_t pos = InputDir.find_last_of(DIR_SEPARATOR); + if (pos != InputDir.length()-1) + { + InputDir += DIR_SEPARATOR; + } + + createBundle(InputDir, OutputFilename); +} diff --git a/tools/XBMCTexXBT/XBTFWriter.cpp b/tools/XBMCTexXBT/XBTFWriter.cpp new file mode 100644 index 0000000000..c196a0837a --- /dev/null +++ b/tools/XBMCTexXBT/XBTFWriter.cpp @@ -0,0 +1,133 @@ +#include "XBTFWriter.h" +#include "EndianSwap.h" + +#define TEMP_FILE "temp.xbt" +#define TEMP_SIZE (10*1024*1024) + +#define WRITE_STR(str, size, file) fwrite(str, size, 1, file) +#define WRITE_U32(i, file) { unsigned long _n = i; _n = Endian_SwapLE32(i); fwrite(&_n, 4, 1, file); } +#define WRITE_U64(i, file) { unsigned long long _n = i; _n = Endian_SwapLE64(i); fwrite(&_n, 8, 1, file); } + +CXBTFWriter::CXBTFWriter(CXBTF& xbtf, const std::string outputFile) : m_xbtf(xbtf) +{ + m_outputFile = outputFile; + m_file = NULL; +} + +bool CXBTFWriter::Create() +{ + m_file = fopen(m_outputFile.c_str(), "wb"); + if (m_file == NULL) + { + return false; + } + + m_tempFile = fopen(TEMP_FILE, "wb"); + if (m_tempFile == NULL) + { + return false; + } + + return true; +} + +bool CXBTFWriter::Close() +{ + if (m_file == NULL || m_tempFile == NULL) + { + return false; + } + + fclose(m_tempFile); + m_tempFile = fopen(TEMP_FILE, "rb"); + if (m_tempFile == NULL) + { + return false; + } + + unsigned char* tmp = new unsigned char[10*1024*1024]; + size_t bytesRead; + while ((bytesRead = fread(tmp, 1, TEMP_SIZE, m_tempFile)) > 0) + { + fwrite(tmp, bytesRead, 1, m_file); + } + + fclose(m_file); + fclose(m_tempFile); + unlink(TEMP_FILE); + + return true; +} + +bool CXBTFWriter::AppendContent(unsigned char* data, size_t length) +{ + if (m_tempFile == NULL) + { + return false; + } + + fwrite(data, length, 1, m_tempFile); + + return true; +} + +bool CXBTFWriter::UpdateHeader() +{ + if (m_file == NULL) + { + return false; + } + + unsigned long long offset = m_xbtf.GetHeaderSize(); + + WRITE_STR(XBTF_MAGIC, 4, m_file); + WRITE_STR(XBTF_VERSION, 1, m_file); + + std::vector<CXBTFFile>& files = m_xbtf.GetFiles(); + WRITE_U32(files.size(), m_file); + for (size_t i = 0; i < files.size(); i++) + { + CXBTFFile& file = files[i]; + + // Convert path to lower case + char* ch = file.GetPath(); + while (*ch) + { + *ch = tolower(*ch); + ch++; + } + + WRITE_STR(file.GetPath(), 256, m_file); + WRITE_U32(file.GetFormat(), m_file); + WRITE_U32(file.GetLoop(), m_file); + + std::vector<CXBTFFrame>& frames = file.GetFrames(); + WRITE_U32(frames.size(), m_file); + for (size_t j = 0; j < frames.size(); j++) + { + CXBTFFrame& frame = frames[j]; + frame.SetOffset(offset); + offset += frame.GetPackedSize(); + + WRITE_U32(frame.GetWidth(), m_file); + WRITE_U32(frame.GetHeight(), m_file); + WRITE_U32(frame.GetX(), m_file); + WRITE_U32(frame.GetY(), m_file); + WRITE_U64(frame.GetPackedSize(), m_file); + WRITE_U64(frame.GetUnpackedSize(), m_file); + WRITE_U32(frame.GetDuration(), m_file); + WRITE_U64(frame.GetOffset(), m_file); + } + } + + // Sanity check + fpos_t pos; + fgetpos(m_file, &pos); + if ((unsigned int) pos != m_xbtf.GetHeaderSize()) + { + printf("Expected header size (%llu) != actual size (%llu)\n", m_xbtf.GetHeaderSize(), pos); + return false; + } + + return true; +} diff --git a/tools/XBMCTexXBT/XBTFWriter.h b/tools/XBMCTexXBT/XBTFWriter.h new file mode 100644 index 0000000000..810f3ddce3 --- /dev/null +++ b/tools/XBMCTexXBT/XBTFWriter.h @@ -0,0 +1,24 @@ +#ifndef XBTFWRITER_H_ +#define XBTFWRITER_H_ + +#include <string> +#include <stdio.h> +#include "XBTF.h" + +class CXBTFWriter +{ +public: + CXBTFWriter(CXBTF& xbtf, const std::string outputFile); + bool Create(); + bool Close(); + bool AppendContent(unsigned char* data, size_t length); + bool UpdateHeader(); + +private: + CXBTF& m_xbtf; + std::string m_outputFile; + FILE* m_file; + FILE* m_tempFile; +}; + +#endif diff --git a/tools/XBMCTexXBT/cmdlineargs.h b/tools/XBMCTexXBT/cmdlineargs.h new file mode 100644 index 0000000000..a9f5891722 --- /dev/null +++ b/tools/XBMCTexXBT/cmdlineargs.h @@ -0,0 +1,123 @@ +#ifndef CMDLINEARGS_H +#define CMDLINEARGS_H + +#ifdef _LINUX +#include "PlatformDefs.h" +#include "xwinapi.h" +typedef LPSTR PSZ; +#define _snprintf snprintf +#else +#include <windows.h> +#endif +#include <vector> +#include <string> + +class CmdLineArgs : public std::vector<char*> +{ +public: + CmdLineArgs () + { + // Save local copy of the command line string, because + // ParseCmdLine() modifies this string while parsing it. + PSZ cmdline = GetCommandLine(); + m_cmdline = new char [strlen (cmdline) + 1]; + if (m_cmdline) + { + strcpy (m_cmdline, cmdline); + ParseCmdLine(); + } else { +#ifdef _LINUX + delete[] cmdline; +#endif + } + } + + CmdLineArgs (const int argc, const char **argv) + { + std::string cmdline; + for (int i = 0 ; i<argc ; i++) + { + cmdline += std::string(argv[i]); + if ( i != (argc-1) ) + { + cmdline += " "; + } + } + m_cmdline = new char [cmdline.length() + 1]; + if (m_cmdline) + { + strcpy(m_cmdline, cmdline.c_str()); + ParseCmdLine(); + } + } + + ~CmdLineArgs() + { + delete[] m_cmdline; + } + +private: + PSZ m_cmdline; // the command line string + + //////////////////////////////////////////////////////////////////////////////// + // Parse m_cmdline into individual tokens, which are delimited by spaces. If a + // token begins with a quote, then that token is terminated by the next quote + // followed immediately by a space or terminator. This allows tokens to contain + // spaces. + // This input string: This "is" a ""test"" "of the parsing" alg"o"rithm. + // Produces these tokens: This, is, a, "test", of the parsing, alg"o"rithm + //////////////////////////////////////////////////////////////////////////////// + void ParseCmdLine () + { + enum { TERM = '\0', + QUOTE = '\"' }; + + bool bInQuotes = false; + PSZ pargs = m_cmdline; + + while (*pargs) + { + while (isspace (*pargs)) // skip leading whitespace + pargs++; + + bInQuotes = (*pargs == QUOTE); // see if this token is quoted + + if (bInQuotes) // skip leading quote + pargs++; + + push_back (pargs); // store position of current token + + // Find next token. + // NOTE: Args are normally terminated by whitespace, unless the + // arg is quoted. That's why we handle the two cases separately, + // even though they are very similar. + if (bInQuotes) + { + // find next quote followed by a space or terminator + while (*pargs && + !(*pargs == QUOTE && (isspace (pargs[1]) || pargs[1] == TERM))) + pargs++; + if (*pargs) + { + *pargs = TERM; // terminate token + if (pargs[1]) // if quoted token not followed by a terminator + pargs += 2; // advance to next token + } + } + else + { + // skip to next non-whitespace character + while (*pargs && !isspace (*pargs)) + pargs++; + if (*pargs && isspace (*pargs)) // end of token + { + *pargs = TERM; // terminate token + pargs++; // advance to next token or terminator + } + } + } // while (*pargs) + } // ParseCmdLine() +}; // class CmdLineArgs + + +#endif // CMDLINEARGS_H diff --git a/tools/XBMCTexXBT/xwinapi.cpp b/tools/XBMCTexXBT/xwinapi.cpp new file mode 100644 index 0000000000..ea5955c837 --- /dev/null +++ b/tools/XBMCTexXBT/xwinapi.cpp @@ -0,0 +1,81 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include "xwinapi.h" +#ifdef __APPLE__ +#include "OSXGNUReplacements.h" +#endif + +// I hope this doesn't need to handle unicode... +LPTSTR GetCommandLine() { + pid_t pid = 0; + char procFile[32], + *cmdline = NULL; + FILE *fp = NULL; + size_t cmdlinelen = 0; + int i; + + pid = getpid(); + sprintf(procFile, "/proc/%u/cmdline", pid); + if((fp = fopen(procFile, "r")) == NULL) + return NULL; + + // getline() allocates memory so be sure to free it + // after calling GetCommandLine() + if (getline(&cmdline, &cmdlinelen, fp) == -1) + { + fclose(fp); + return NULL; + } + + fclose(fp); + fp = NULL; + + for (i = 0; i < (int)cmdlinelen; i++) { + if (cmdline[i] == 0x00) { + if (cmdline[i + 1] == 0x00) + break; + cmdline[i] = ' '; + } + } + + cmdline = (char *)realloc(cmdline, strlen(cmdline) + 1); + return cmdline; +} + +DWORD GetCurrentDirectory(DWORD nBufferLength, LPTSTR lpBuffer) { + bool bSizeTest = (nBufferLength == 0 && lpBuffer == NULL); + if (getcwd(lpBuffer, nBufferLength) == NULL) { + if (errno == ERANGE) { + LPTSTR tmp = NULL; + if (getcwd(tmp, 0) == NULL ) + nBufferLength = 0; + else + nBufferLength = strlen(tmp) + 1; + + free(tmp); + return nBufferLength; + } + return 0; + } + if (bSizeTest) { + nBufferLength = strlen(lpBuffer) + 1; + free(lpBuffer); + lpBuffer = NULL; + return nBufferLength; + } + return strlen(lpBuffer); +} + +BOOL SetCurrentDirectory(LPCTSTR lpPathName) { + return (chdir(lpPathName) == 0); +} + +DWORD GetLastError( ) { + return errno; +} + diff --git a/tools/XBMCTexXBT/xwinapi.h b/tools/XBMCTexXBT/xwinapi.h new file mode 100644 index 0000000000..be97e4c00a --- /dev/null +++ b/tools/XBMCTexXBT/xwinapi.h @@ -0,0 +1,11 @@ +#ifndef XWINAPI_H__ +#define XWINAPI_H__ + +#include "PlatformDefs.h" + +LPTSTR GetCommandLine(); +DWORD GetCurrentDirectory(DWORD nBufferLength, LPTSTR lpBuffer); +BOOL SetCurrentDirectory(LPCTSTR lpPathName); +DWORD GetLastError(); +#endif // XWINAPI_H__ + diff --git a/xbmc/Picture.cpp b/xbmc/Picture.cpp index 7aec6ed080..55b3c0cfa0 100644 --- a/xbmc/Picture.cpp +++ b/xbmc/Picture.cpp @@ -55,7 +55,7 @@ bool CPicture::Load(const CStdString& strFileName, CBaseTexture* pTexture, int i return false; } - pTexture->Allocate(m_info.width, m_info.height, 32); + pTexture->Allocate(m_info.width, m_info.height, 32, XB_FMT_B8G8R8A8); if (pTexture) { diff --git a/xbmc/RenderSystem.h b/xbmc/RenderSystem.h index 024881b06a..d2672b2033 100644 --- a/xbmc/RenderSystem.h +++ b/xbmc/RenderSystem.h @@ -74,6 +74,7 @@ public: virtual void GetViewPort(CRect& viewPort) = 0; virtual bool NeedPower2Texture() = 0; + virtual bool SupportsCompressedTextures() = 0; virtual void CaptureStateBlock() = 0; virtual void ApplyStateBlock() = 0; diff --git a/xbmc/RenderSystemDX.h b/xbmc/RenderSystemDX.h index 7aa305a867..35bdb3d540 100644 --- a/xbmc/RenderSystemDX.h +++ b/xbmc/RenderSystemDX.h @@ -52,6 +52,7 @@ public: virtual void GetViewPort(CRect& viewPort); virtual bool NeedPower2Texture() { return m_NeedPower2Texture; } + virtual bool SupportsCompressedTextures() { return false; /* TODO: temporary until we add support for compressed textures in DX */ } virtual void CaptureStateBlock(); virtual void ApplyStateBlock(); diff --git a/xbmc/RenderSystemGL.cpp b/xbmc/RenderSystemGL.cpp index 4c0ac85375..18f28be320 100644 --- a/xbmc/RenderSystemGL.cpp +++ b/xbmc/RenderSystemGL.cpp @@ -68,7 +68,7 @@ bool CRenderSystemGL::InitRenderSystem() // Check if we need DPOT m_NeedPower2Texture = true; - if (m_RenderVerdenVersionMajor >= 2 && GLEW_ARB_texture_non_power_of_two) + if (GLEW_ARB_texture_non_power_of_two) m_NeedPower2Texture = false; // Get our driver vendor and renderer @@ -433,4 +433,9 @@ void CRenderSystemGL::SetViewPort(CRect& viewPort) glViewport((GLint) viewPort.x1, (GLint) (m_height - viewPort.y1 - viewPort.Height()), (GLsizei) viewPort.Width(), (GLsizei) viewPort.Height()); } +bool CRenderSystemGL::SupportsCompressedTextures() +{ + return glewIsSupported("GL_EXT_texture_compression_s3tc"); +} + #endif diff --git a/xbmc/RenderSystemGL.h b/xbmc/RenderSystemGL.h index f51bf1342e..255472ac22 100644 --- a/xbmc/RenderSystemGL.h +++ b/xbmc/RenderSystemGL.h @@ -50,6 +50,7 @@ public: virtual void GetViewPort(CRect& viewPort); virtual bool NeedPower2Texture() { return m_NeedPower2Texture; } + virtual bool SupportsCompressedTextures(); virtual void CaptureStateBlock(); virtual void ApplyStateBlock(); diff --git a/xbmc/karaoke/karaokelyricscdg.cpp b/xbmc/karaoke/karaokelyricscdg.cpp index 8baadd7ec6..3cc19452d7 100644 --- a/xbmc/karaoke/karaokelyricscdg.cpp +++ b/xbmc/karaoke/karaokelyricscdg.cpp @@ -151,7 +151,7 @@ void CKaraokeLyricsCDG::Render() if (buf) { RenderIntoBuffer( buf, WIDTH, HEIGHT, WIDTH * HEIGHT ); - m_pCdgTexture->Update( WIDTH, HEIGHT, WIDTH * 4, buf, false ); + m_pCdgTexture->Update( WIDTH, HEIGHT, WIDTH * 4, XB_FMT_B8G8R8A8, buf, false ); } delete [] buf; |