2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 #include "windowing/WindowingFactory.h"
24 #include "utils/log.h"
25 #include "utils/URIUtils.h"
26 #include "pictures/DllImageLib.h"
28 #include "filesystem/SpecialProtocol.h"
30 #if defined(__APPLE__) && defined(__arm__)
31 #include <ImageIO/ImageIO.h>
32 #include "filesystem/File.h"
33 #include "osx/DarwinUtils.h"
36 /************************************************************************/
38 /************************************************************************/
39 CBaseTexture::CBaseTexture(unsigned int width, unsigned int height, unsigned int format)
46 m_loadedToGPU = false;
47 Allocate(width, height, format);
50 CBaseTexture::~CBaseTexture()
55 void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned int format)
58 m_imageHeight = height;
62 m_textureWidth = m_imageWidth;
63 m_textureHeight = m_imageHeight;
65 if (m_format & XB_FMT_DXT_MASK)
66 while (GetPitch() < g_Windowing.GetMinDXTPitch())
67 m_textureWidth += GetBlockSize();
69 if (!g_Windowing.SupportsNPOT((m_format & XB_FMT_DXT_MASK) != 0))
71 m_textureWidth = PadPow2(m_textureWidth);
72 m_textureHeight = PadPow2(m_textureHeight);
74 if (m_format & XB_FMT_DXT_MASK)
75 { // DXT textures must be a multiple of 4 in width and height
76 m_textureWidth = ((m_textureWidth + 3) / 4) * 4;
77 m_textureHeight = ((m_textureHeight + 3) / 4) * 4;
80 // check for max texture size
81 #define CLAMP(x, y) { if (x > y) x = y; }
82 CLAMP(m_textureWidth, g_Windowing.GetMaxTextureSize());
83 CLAMP(m_textureHeight, g_Windowing.GetMaxTextureSize());
84 CLAMP(m_imageWidth, m_textureWidth);
85 CLAMP(m_imageHeight, m_textureHeight);
87 m_pixels = new unsigned char[GetPitch() * GetRows()];
90 void CBaseTexture::Update(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU)
95 if (format & XB_FMT_DXT_MASK && !g_Windowing.SupportsDXT())
96 { // compressed format that we don't support
97 Allocate(width, height, XB_FMT_A8R8G8B8);
98 CDDSImage::Decompress(m_pixels, std::min(width, m_textureWidth), std::min(height, m_textureHeight), GetPitch(m_textureWidth), pixels, format);
102 Allocate(width, height, format);
104 unsigned int srcPitch = pitch ? pitch : GetPitch(width);
105 unsigned int srcRows = GetRows(height);
106 unsigned int dstPitch = GetPitch(m_textureWidth);
107 unsigned int dstRows = GetRows(m_textureHeight);
109 if (srcPitch == dstPitch)
110 memcpy(m_pixels, pixels, srcPitch * std::min(srcRows, dstRows));
113 const unsigned char *src = pixels;
114 unsigned char* dst = m_pixels;
115 for (unsigned int y = 0; y < srcRows && y < dstRows; y++)
117 memcpy(dst, src, std::min(srcPitch, dstPitch));
129 void CBaseTexture::ClampToEdge()
131 unsigned int imagePitch = GetPitch(m_imageWidth);
132 unsigned int imageRows = GetRows(m_imageHeight);
133 unsigned int texturePitch = GetPitch(m_textureWidth);
134 unsigned int textureRows = GetRows(m_textureHeight);
135 if (imagePitch < texturePitch)
137 unsigned int blockSize = GetBlockSize();
138 unsigned char *src = m_pixels + imagePitch - blockSize;
139 unsigned char *dst = m_pixels;
140 for (unsigned int y = 0; y < imageRows; y++)
142 for (unsigned int x = imagePitch; x < texturePitch; x += blockSize)
143 memcpy(dst + x, src, blockSize);
148 if (imageRows < textureRows)
150 unsigned char *dst = m_pixels + imageRows * texturePitch;
151 for (unsigned int y = imageRows; y < textureRows; y++)
153 memcpy(dst, dst - texturePitch, texturePitch);
159 bool CBaseTexture::LoadFromFile(const CStdString& texturePath, unsigned int maxWidth, unsigned int maxHeight,
160 bool autoRotate, unsigned int *originalWidth, unsigned int *originalHeight)
162 if (URIUtils::GetExtension(texturePath).Equals(".dds"))
163 { // special case for DDS images
165 if (image.ReadFile(texturePath))
167 Update(image.GetWidth(), image.GetHeight(), 0, image.GetFormat(), image.GetData(), false);
173 //ImageLib is sooo sloow for jpegs. Try our own decoder first. If it fails, fall back to ImageLib.
174 if (URIUtils::GetExtension(texturePath).Equals(".jpg") || URIUtils::GetExtension(texturePath).Equals(".tbn"))
177 if (jpegfile.Open(texturePath))
179 if (jpegfile.Width() > 0 && jpegfile.Height() > 0)
181 Allocate(jpegfile.Width(), jpegfile.Height(), XB_FMT_A8R8G8B8);
182 if (jpegfile.Decode(m_pixels, GetPitch(), XB_FMT_A8R8G8B8))
184 if (autoRotate && jpegfile.Orientation())
185 m_orientation = jpegfile.Orientation() - 1;
198 memset(&image, 0, sizeof(image));
200 unsigned int width = maxWidth ? std::min(maxWidth, g_Windowing.GetMaxTextureSize()) : g_Windowing.GetMaxTextureSize();
201 unsigned int height = maxHeight ? std::min(maxHeight, g_Windowing.GetMaxTextureSize()) : g_Windowing.GetMaxTextureSize();
203 if(!dll.LoadImage(texturePath.c_str(), width, height, &image))
205 CLog::Log(LOGERROR, "Texture manager unable to load file: %s", texturePath.c_str());
209 m_hasAlpha = NULL != image.alpha;
211 Allocate(image.width, image.height, XB_FMT_A8R8G8B8);
212 if (autoRotate && image.exifInfo.Orientation)
213 m_orientation = image.exifInfo.Orientation - 1;
215 *originalWidth = image.originalwidth;
217 *originalHeight = image.originalheight;
219 unsigned int dstPitch = GetPitch();
220 unsigned int srcPitch = ((image.width + 1)* 3 / 4) * 4; // bitmap row length is aligned to 4 bytes
222 unsigned char *dst = m_pixels;
223 unsigned char *src = image.texture + (m_imageHeight - 1) * srcPitch;
225 for (unsigned int y = 0; y < m_imageHeight; y++)
227 unsigned char *dst2 = dst;
228 unsigned char *src2 = src;
229 for (unsigned int x = 0; x < m_imageWidth; x++, dst2 += 4, src2 += 3)
243 src = image.alpha + (m_imageHeight - 1) * m_imageWidth;
245 for (unsigned int y = 0; y < m_imageHeight; y++)
247 unsigned char *dst2 = dst;
248 unsigned char *src2 = src;
250 for (unsigned int x = 0; x < m_imageWidth; x++, dst2+=4, src2++)
256 dll.ReleaseImage(&image);
263 bool CBaseTexture::LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, bool hasAlpha, unsigned char* pixels)
265 m_imageWidth = width;
266 m_imageHeight = height;
268 m_hasAlpha = hasAlpha;
269 Update(width, height, pitch, format, pixels, false);
273 bool CBaseTexture::LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, const COLOR *palette)
275 if (pixels == NULL || palette == NULL)
278 Allocate(width, height, format);
280 for (unsigned int y = 0; y < m_imageHeight; y++)
282 unsigned char *dest = m_pixels + y * GetPitch();
283 const unsigned char *src = pixels + y * pitch;
284 for (unsigned int x = 0; x < m_imageWidth; x++)
286 COLOR col = palette[*src++];
297 unsigned int CBaseTexture::PadPow2(unsigned int x)
308 bool CBaseTexture::SwapBlueRed(unsigned char *pixels, unsigned int height, unsigned int pitch, unsigned int elements, unsigned int offset)
310 if (!pixels) return false;
311 unsigned char *dst = pixels;
312 for (unsigned int y = 0; y < height; y++)
314 dst = pixels + (y * pitch);
315 for (unsigned int x = 0; x < pitch; x+=elements)
316 std::swap(dst[x+offset], dst[x+2+offset]);
321 unsigned int CBaseTexture::GetPitch(unsigned int width) const
326 return ((width + 3) / 4) * 8;
329 case XB_FMT_DXT5_YCoCg:
330 return ((width + 3) / 4) * 16;
334 return (((width + 1)* 3 / 4) * 4);
336 case XB_FMT_A8R8G8B8:
342 unsigned int CBaseTexture::GetRows(unsigned int height) const
347 return (height + 3) / 4;
350 case XB_FMT_DXT5_YCoCg:
351 return (height + 3) / 4;
357 unsigned int CBaseTexture::GetBlockSize() const
365 case XB_FMT_DXT5_YCoCg:
374 bool CBaseTexture::HasAlpha() const