mirror of https://github.com/axmolengine/axmol.git
656 lines
21 KiB
C++
656 lines
21 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2011 Jirka Fajfr for cocos2d-x
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
|
Copyright (c) 2008 Apple Inc. All Rights Reserved.
|
|
|
|
http://www.cocos2d-x.org
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "CCTexture2D.h"
|
|
#include "CCTexturePVR.h"
|
|
#include "ccMacros.h"
|
|
#include "CCConfiguration.h"
|
|
#include "support/ccUtils.h"
|
|
#include "CCStdC.h"
|
|
#include "platform/CCFileUtils.h"
|
|
#include "support/zip_support/ZipUtils.h"
|
|
#include "shaders/ccGLStateCache.h"
|
|
#include <ctype.h>
|
|
#include <cctype>
|
|
|
|
NS_CC_BEGIN
|
|
|
|
#define PVR_TEXTURE_FLAG_TYPE_MASK 0xff
|
|
|
|
//
|
|
// XXX DO NO ALTER THE ORDER IN THIS LIST XXX
|
|
//
|
|
static const ccPVRTexturePixelFormatInfo PVRTableFormats[] = {
|
|
|
|
// 0: BGRA_8888
|
|
{GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32, false, true, kCCTexture2DPixelFormat_RGBA8888},
|
|
// 1: RGBA_8888
|
|
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, false, true, kCCTexture2DPixelFormat_RGBA8888},
|
|
// 2: RGBA_4444
|
|
{GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, false, true, kCCTexture2DPixelFormat_RGBA4444},
|
|
// 3: RGBA_5551
|
|
{GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, false, true, kCCTexture2DPixelFormat_RGB5A1},
|
|
// 4: RGB_565
|
|
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, false, false, kCCTexture2DPixelFormat_RGB565},
|
|
// 5: RGB_888
|
|
{GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 24, false, false, kCCTexture2DPixelFormat_RGB888},
|
|
// 6: A_8
|
|
{GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, false, false, kCCTexture2DPixelFormat_A8},
|
|
// 7: L_8
|
|
{GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, false, false, kCCTexture2DPixelFormat_I8},
|
|
// 8: LA_88
|
|
{GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, false, true, kCCTexture2DPixelFormat_AI88},
|
|
|
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
|
|
// 9: PVRTC 2BPP RGB
|
|
{GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, false, kCCTexture2DPixelFormat_PVRTC2},
|
|
// 10: PVRTC 2BPP RGBA
|
|
{GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, true, kCCTexture2DPixelFormat_PVRTC2},
|
|
// 11: PVRTC 4BPP RGB
|
|
{GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false, kCCTexture2DPixelFormat_PVRTC4},
|
|
// 12: PVRTC 4BPP RGBA
|
|
{GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, true, kCCTexture2DPixelFormat_PVRTC4},
|
|
#endif // (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
|
|
};
|
|
|
|
struct _pixelformat_hash {
|
|
uint64_t pixelFormat;
|
|
const ccPVRTexturePixelFormatInfo * pixelFormatInfo;
|
|
};
|
|
|
|
// Values taken from PVRTexture.h from http://www.imgtec.com
|
|
enum {
|
|
kPVRTextureFlagMipmap = (1<<8), // has mip map levels
|
|
kPVRTextureFlagTwiddle = (1<<9), // is twiddled
|
|
kPVRTextureFlagBumpmap = (1<<10), // has normals encoded for a bump map
|
|
kPVRTextureFlagTiling = (1<<11), // is bordered for tiled pvr
|
|
kPVRTextureFlagCubemap = (1<<12), // is a cubemap/skybox
|
|
kPVRTextureFlagFalseMipCol = (1<<13), // are there false colored MIP levels
|
|
kPVRTextureFlagVolume = (1<<14), // is this a volume texture
|
|
kPVRTextureFlagAlpha = (1<<15), // v2.1 is there transparency info in the texture
|
|
kPVRTextureFlagVerticalFlip = (1<<16), // v2.1 is the texture vertically flipped
|
|
};
|
|
|
|
static char gPVRTexIdentifier[5] = "PVR!";
|
|
|
|
// v2
|
|
typedef enum
|
|
{
|
|
kPVR2TexturePixelFormat_RGBA_4444= 0x10,
|
|
kPVR2TexturePixelFormat_RGBA_5551,
|
|
kPVR2TexturePixelFormat_RGBA_8888,
|
|
kPVR2TexturePixelFormat_RGB_565,
|
|
kPVR2TexturePixelFormat_RGB_555, // unsupported
|
|
kPVR2TexturePixelFormat_RGB_888,
|
|
kPVR2TexturePixelFormat_I_8,
|
|
kPVR2TexturePixelFormat_AI_88,
|
|
kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA,
|
|
kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA,
|
|
kPVR2TexturePixelFormat_BGRA_8888,
|
|
kPVR2TexturePixelFormat_A_8,
|
|
} ccPVR2TexturePixelFormat;
|
|
|
|
// v3
|
|
/* supported predefined formats */
|
|
#define kPVR3TexturePixelFormat_PVRTC_2BPP_RGB 0
|
|
#define kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA 1
|
|
#define kPVR3TexturePixelFormat_PVRTC_4BPP_RGB 2
|
|
#define kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA 3
|
|
|
|
/* supported channel type formats */
|
|
#define kPVR3TexturePixelFormat_BGRA_8888 0x0808080861726762ULL
|
|
#define kPVR3TexturePixelFormat_RGBA_8888 0x0808080861626772ULL
|
|
#define kPVR3TexturePixelFormat_RGBA_4444 0x0404040461626772ULL
|
|
#define kPVR3TexturePixelFormat_RGBA_5551 0x0105050561626772ULL
|
|
#define kPVR3TexturePixelFormat_RGB_565 0x0005060500626772ULL
|
|
#define kPVR3TexturePixelFormat_RGB_888 0x0008080800626772ULL
|
|
#define kPVR3TexturePixelFormat_A_8 0x0000000800000061ULL
|
|
#define kPVR3TexturePixelFormat_L_8 0x000000080000006cULL
|
|
#define kPVR3TexturePixelFormat_LA_88 0x000008080000616cULL
|
|
|
|
|
|
// v2
|
|
static struct _pixelformat_hash v2_pixelformat_hash[] = {
|
|
|
|
{ kPVR2TexturePixelFormat_BGRA_8888, &PVRTableFormats[0] },
|
|
{ kPVR2TexturePixelFormat_RGBA_8888, &PVRTableFormats[1] },
|
|
{ kPVR2TexturePixelFormat_RGBA_4444, &PVRTableFormats[2] },
|
|
{ kPVR2TexturePixelFormat_RGBA_5551, &PVRTableFormats[3] },
|
|
{ kPVR2TexturePixelFormat_RGB_565, &PVRTableFormats[4] },
|
|
{ kPVR2TexturePixelFormat_RGB_888, &PVRTableFormats[5] },
|
|
{ kPVR2TexturePixelFormat_A_8, &PVRTableFormats[6] },
|
|
{ kPVR2TexturePixelFormat_I_8, &PVRTableFormats[7] },
|
|
{ kPVR2TexturePixelFormat_AI_88, &PVRTableFormats[8] },
|
|
|
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
|
|
{ kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA, &PVRTableFormats[10] },
|
|
{ kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA, &PVRTableFormats[12] },
|
|
#endif // iphone only
|
|
};
|
|
|
|
#define PVR2_MAX_TABLE_ELEMENTS (sizeof(v2_pixelformat_hash) / sizeof(v2_pixelformat_hash[0]))
|
|
|
|
// v3
|
|
struct _pixelformat_hash v3_pixelformat_hash[] = {
|
|
|
|
{kPVR3TexturePixelFormat_BGRA_8888, &PVRTableFormats[0] },
|
|
{kPVR3TexturePixelFormat_RGBA_8888, &PVRTableFormats[1] },
|
|
{kPVR3TexturePixelFormat_RGBA_4444, &PVRTableFormats[2] },
|
|
{kPVR3TexturePixelFormat_RGBA_5551, &PVRTableFormats[3] },
|
|
{kPVR3TexturePixelFormat_RGB_565, &PVRTableFormats[4] },
|
|
{kPVR3TexturePixelFormat_RGB_888, &PVRTableFormats[5] },
|
|
{kPVR3TexturePixelFormat_A_8, &PVRTableFormats[6] },
|
|
{kPVR3TexturePixelFormat_L_8, &PVRTableFormats[7] },
|
|
{kPVR3TexturePixelFormat_LA_88, &PVRTableFormats[8] },
|
|
|
|
#ifdef __CC_PLATFORM_IOS
|
|
{kPVR3TexturePixelFormat_PVRTC_2BPP_RGB, &PVRTableFormats[9] },
|
|
{kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA, &PVRTableFormats[10] },
|
|
{kPVR3TexturePixelFormat_PVRTC_4BPP_RGB, &PVRTableFormats[11] },
|
|
{kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA, &PVRTableFormats[12] },
|
|
#endif // #__CC_PLATFORM_IOS
|
|
};
|
|
|
|
|
|
//Tells How large is tableFormats
|
|
#define PVR3_MAX_TABLE_ELEMENTS (sizeof(v3_pixelformat_hash) / sizeof(v3_pixelformat_hash[0]))
|
|
|
|
|
|
typedef struct _PVRTexHeader
|
|
{
|
|
unsigned int headerLength;
|
|
unsigned int height;
|
|
unsigned int width;
|
|
unsigned int numMipmaps;
|
|
unsigned int flags;
|
|
unsigned int dataLength;
|
|
unsigned int bpp;
|
|
unsigned int bitmaskRed;
|
|
unsigned int bitmaskGreen;
|
|
unsigned int bitmaskBlue;
|
|
unsigned int bitmaskAlpha;
|
|
unsigned int pvrTag;
|
|
unsigned int numSurfs;
|
|
} ccPVRv2TexHeader;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma pack(push,1)
|
|
#endif
|
|
typedef struct {
|
|
uint32_t version;
|
|
uint32_t flags;
|
|
uint64_t pixelFormat;
|
|
uint32_t colorSpace;
|
|
uint32_t channelType;
|
|
uint32_t height;
|
|
uint32_t width;
|
|
uint32_t depth;
|
|
uint32_t numberOfSurfaces;
|
|
uint32_t numberOfFaces;
|
|
uint32_t numberOfMipmaps;
|
|
uint32_t metadataLength;
|
|
#ifdef _MSC_VER
|
|
} ccPVRv3TexHeader;
|
|
#pragma pack(pop)
|
|
#else
|
|
} __attribute__((packed)) ccPVRv3TexHeader;
|
|
#endif
|
|
|
|
|
|
CCTexturePVR::CCTexturePVR()
|
|
: m_pPixelFormatInfo(NULL)
|
|
, m_uNumberOfMipmaps(0)
|
|
, m_uWidth(0)
|
|
, m_uHeight(0)
|
|
, m_bRetainName(false)
|
|
, m_bHasAlpha(false)
|
|
, m_uName(0)
|
|
, m_eFormat(kCCTexture2DPixelFormat_Default)
|
|
{
|
|
}
|
|
|
|
CCTexturePVR::~CCTexturePVR()
|
|
{
|
|
CCLOGINFO( "cocos2d: deallocing CCTexturePVR" );
|
|
|
|
if (m_uName != 0 && ! m_bRetainName)
|
|
{
|
|
ccGLDeleteTexture(m_uName);
|
|
}
|
|
}
|
|
|
|
bool CCTexturePVR::unpackPVRv2Data(unsigned char* data, unsigned int len)
|
|
{
|
|
bool success = false;
|
|
ccPVRv2TexHeader *header = NULL;
|
|
unsigned int flags, pvrTag;
|
|
unsigned int dataLength = 0, dataOffset = 0, dataSize = 0;
|
|
unsigned int blockSize = 0, widthBlocks = 0, heightBlocks = 0;
|
|
unsigned int width = 0, height = 0, bpp = 4;
|
|
unsigned char *bytes = NULL;
|
|
unsigned int formatFlags;
|
|
|
|
//Cast first sizeof(PVRTexHeader) bytes of data stream as PVRTexHeader
|
|
header = (ccPVRv2TexHeader *)data;
|
|
|
|
//Make sure that tag is in correct formatting
|
|
pvrTag = CC_SWAP_INT32_LITTLE_TO_HOST(header->pvrTag);
|
|
|
|
if (gPVRTexIdentifier[0] != ((pvrTag >> 0) & 0xff) ||
|
|
gPVRTexIdentifier[1] != ((pvrTag >> 8) & 0xff) ||
|
|
gPVRTexIdentifier[2] != ((pvrTag >> 16) & 0xff) ||
|
|
gPVRTexIdentifier[3] != ((pvrTag >> 24) & 0xff))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CCConfiguration *configuration = CCConfiguration::sharedConfiguration();
|
|
|
|
flags = CC_SWAP_INT32_LITTLE_TO_HOST(header->flags);
|
|
formatFlags = flags & PVR_TEXTURE_FLAG_TYPE_MASK;
|
|
bool flipped = (flags & kPVRTextureFlagVerticalFlip) ? true : false;
|
|
if (flipped)
|
|
{
|
|
CCLOG("cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool");
|
|
}
|
|
|
|
if (! configuration->supportsNPOT() &&
|
|
(header->width != ccNextPOT(header->width) || header->height != ccNextPOT(header->height)))
|
|
{
|
|
CCLOG("cocos2d: ERROR: Loading an NPOT texture (%dx%d) but is not supported on this device", header->width, header->height);
|
|
return false;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < (unsigned int)PVR2_MAX_TABLE_ELEMENTS; i++)
|
|
{
|
|
//Does image format in table fits to the one parsed from header?
|
|
if (v2_pixelformat_hash[i].pixelFormat == formatFlags)
|
|
{
|
|
m_pPixelFormatInfo = v2_pixelformat_hash[i].pixelFormatInfo;
|
|
|
|
//Reset num of mipmaps
|
|
m_uNumberOfMipmaps = 0;
|
|
|
|
//Get size of mipmap
|
|
m_uWidth = width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width);
|
|
m_uHeight = height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height);
|
|
|
|
//Do we use alpha ?
|
|
if (CC_SWAP_INT32_LITTLE_TO_HOST(header->bitmaskAlpha))
|
|
{
|
|
m_bHasAlpha = true;
|
|
}
|
|
else
|
|
{
|
|
m_bHasAlpha = false;
|
|
}
|
|
|
|
//Get ptr to where data starts..
|
|
dataLength = CC_SWAP_INT32_LITTLE_TO_HOST(header->dataLength);
|
|
|
|
//Move by size of header
|
|
bytes = ((unsigned char *)data) + sizeof(ccPVRv2TexHeader);
|
|
m_eFormat = m_pPixelFormatInfo->ccPixelFormat;
|
|
bpp = m_pPixelFormatInfo->bpp;
|
|
|
|
// Calculate the data size for each texture level and respect the minimum number of blocks
|
|
while (dataOffset < dataLength)
|
|
{
|
|
switch (formatFlags) {
|
|
case kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA:
|
|
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
|
|
widthBlocks = width / 8;
|
|
heightBlocks = height / 4;
|
|
break;
|
|
case kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA:
|
|
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
|
|
widthBlocks = width / 4;
|
|
heightBlocks = height / 4;
|
|
break;
|
|
case kPVR2TexturePixelFormat_BGRA_8888:
|
|
if (CCConfiguration::sharedConfiguration()->supportsBGRA8888() == false)
|
|
{
|
|
CCLOG("cocos2d: TexturePVR. BGRA8888 not supported on this device");
|
|
return false;
|
|
}
|
|
default:
|
|
blockSize = 1;
|
|
widthBlocks = width;
|
|
heightBlocks = height;
|
|
break;
|
|
}
|
|
|
|
// Clamp to minimum number of blocks
|
|
if (widthBlocks < 2)
|
|
{
|
|
widthBlocks = 2;
|
|
}
|
|
if (heightBlocks < 2)
|
|
{
|
|
heightBlocks = 2;
|
|
}
|
|
|
|
dataSize = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
|
|
unsigned int packetLength = (dataLength - dataOffset);
|
|
packetLength = packetLength > dataSize ? dataSize : packetLength;
|
|
|
|
//Make record to the mipmaps array and increment counter
|
|
m_asMipmaps[m_uNumberOfMipmaps].address = bytes + dataOffset;
|
|
m_asMipmaps[m_uNumberOfMipmaps].len = packetLength;
|
|
m_uNumberOfMipmaps++;
|
|
|
|
//Check that we didn't overflow
|
|
CCAssert(m_uNumberOfMipmaps < CC_PVRMIPMAP_MAX,
|
|
"TexturePVR: Maximum number of mipmaps reached. Increase the CC_PVRMIPMAP_MAX value");
|
|
|
|
dataOffset += packetLength;
|
|
|
|
//Update width and height to the next lower power of two
|
|
width = MAX(width >> 1, 1);
|
|
height = MAX(height >> 1, 1);
|
|
}
|
|
|
|
//Mark pass as success
|
|
success = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! success)
|
|
{
|
|
CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%2x. Re-encode it with a OpenGL pixel format variant", formatFlags);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool CCTexturePVR::unpackPVRv3Data(unsigned char* dataPointer, unsigned int dataLength)
|
|
{
|
|
if (dataLength < sizeof(ccPVRv3TexHeader))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ccPVRv3TexHeader *header = (ccPVRv3TexHeader *)dataPointer;
|
|
|
|
// validate version
|
|
if (CC_SWAP_INT32_BIG_TO_HOST(header->version) != 0x50565203)
|
|
{
|
|
CCLOG("cocos2d: WARNING: pvr file version mismatch");
|
|
return false;
|
|
}
|
|
|
|
// parse pixel format
|
|
uint64_t pixelFormat = header->pixelFormat;
|
|
|
|
|
|
bool infoValid = false;
|
|
|
|
for(int i = 0; i < PVR3_MAX_TABLE_ELEMENTS; i++)
|
|
{
|
|
if( v3_pixelformat_hash[i].pixelFormat == pixelFormat )
|
|
{
|
|
m_pPixelFormatInfo = v3_pixelformat_hash[i].pixelFormatInfo;
|
|
m_bHasAlpha = m_pPixelFormatInfo->alpha;
|
|
infoValid = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// unsupported / bad pixel format
|
|
if (! infoValid)
|
|
{
|
|
CCLOG("cocos2d: WARNING: unsupported pvr pixelformat: %llx", pixelFormat );
|
|
return false;
|
|
}
|
|
|
|
// sizing
|
|
uint32_t width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width);
|
|
uint32_t height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height);
|
|
m_uWidth = width;
|
|
m_uHeight = height;
|
|
uint32_t dataOffset = 0, dataSize = 0;
|
|
uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0;
|
|
uint8_t *bytes = NULL;
|
|
|
|
dataOffset = (sizeof(ccPVRv3TexHeader) + header->metadataLength);
|
|
bytes = dataPointer;
|
|
|
|
m_uNumberOfMipmaps = header->numberOfMipmaps;
|
|
CCAssert(m_uNumberOfMipmaps < CC_PVRMIPMAP_MAX, @"TexturePVR: Maximum number of mimpaps reached. Increate the CC_PVRMIPMAP_MAX value");
|
|
|
|
for (int i = 0; i < m_uNumberOfMipmaps; i++)
|
|
{
|
|
switch (pixelFormat)
|
|
{
|
|
case kPVR3TexturePixelFormat_PVRTC_2BPP_RGB :
|
|
case kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA :
|
|
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
|
|
widthBlocks = width / 8;
|
|
heightBlocks = height / 4;
|
|
break;
|
|
case kPVR3TexturePixelFormat_PVRTC_4BPP_RGB :
|
|
case kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA :
|
|
blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
|
|
widthBlocks = width / 4;
|
|
heightBlocks = height / 4;
|
|
break;
|
|
case kPVR3TexturePixelFormat_BGRA_8888:
|
|
if( ! CCConfiguration::sharedConfiguration()->supportsBGRA8888())
|
|
{
|
|
CCLOG("cocos2d: TexturePVR. BGRA8888 not supported on this device");
|
|
return false;
|
|
}
|
|
default:
|
|
blockSize = 1;
|
|
widthBlocks = width;
|
|
heightBlocks = height;
|
|
break;
|
|
}
|
|
|
|
// Clamp to minimum number of blocks
|
|
if (widthBlocks < 2)
|
|
{
|
|
widthBlocks = 2;
|
|
}
|
|
if (heightBlocks < 2)
|
|
{
|
|
heightBlocks = 2;
|
|
}
|
|
|
|
dataSize = widthBlocks * heightBlocks * ((blockSize * m_pPixelFormatInfo->bpp) / 8);
|
|
unsigned int packetLength = ((unsigned int)dataLength-dataOffset);
|
|
packetLength = packetLength > dataSize ? dataSize : packetLength;
|
|
|
|
m_asMipmaps[i].address = bytes+dataOffset;
|
|
m_asMipmaps[i].len = packetLength;
|
|
|
|
dataOffset += packetLength;
|
|
CCAssert(dataOffset <= dataLength, "CCTexurePVR: Invalid lenght");
|
|
|
|
|
|
width = MAX(width >> 1, 1);
|
|
height = MAX(height >> 1, 1);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCTexturePVR::createGLTexture()
|
|
{
|
|
unsigned int width = m_uWidth;
|
|
unsigned int height = m_uHeight;
|
|
GLenum err;
|
|
|
|
if (m_uNumberOfMipmaps > 0)
|
|
{
|
|
if (m_uName != 0)
|
|
{
|
|
ccGLDeleteTexture(m_uName);
|
|
}
|
|
|
|
// From PVR sources: "PVR files are never row aligned."
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
|
|
|
|
glGenTextures(1, &m_uName);
|
|
glBindTexture(GL_TEXTURE_2D, m_uName);
|
|
|
|
// Default: Anti alias.
|
|
if (m_uNumberOfMipmaps == 1)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
|
|
CHECK_GL_ERROR_DEBUG(); // clean possible GL error
|
|
|
|
GLenum internalFormat = m_pPixelFormatInfo->internalFormat;
|
|
GLenum format = m_pPixelFormatInfo->format;
|
|
GLenum type = m_pPixelFormatInfo->type;
|
|
bool compressed = m_pPixelFormatInfo->compressed;
|
|
|
|
// Generate textures with mipmaps
|
|
for (unsigned int i = 0; i < m_uNumberOfMipmaps; ++i)
|
|
{
|
|
if (compressed && ! CCConfiguration::sharedConfiguration()->supportsPVRTC())
|
|
{
|
|
CCLOG("cocos2d: WARNING: PVRTC images are not supported");
|
|
return false;
|
|
}
|
|
|
|
unsigned char *data = m_asMipmaps[i].address;
|
|
GLsizei datalen = m_asMipmaps[i].len;
|
|
|
|
if (compressed)
|
|
{
|
|
glCompressedTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, datalen, data);
|
|
}
|
|
else
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, format, type, data);
|
|
}
|
|
|
|
if (i > 0 && (width != height || ccNextPOT(width) != width ))
|
|
{
|
|
CCLOG("cocos2d: TexturePVR. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%u != height=%u", i, width, height);
|
|
}
|
|
|
|
err = glGetError();
|
|
if (err != GL_NO_ERROR)
|
|
{
|
|
CCLOG("cocos2d: TexturePVR: Error uploading compressed texture level: %u . glError: 0x%04X", i, err);
|
|
return false;
|
|
}
|
|
|
|
width = MAX(width >> 1, 1);
|
|
height = MAX(height >> 1, 1);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CCTexturePVR::initWithContentsOfFile(const char* path)
|
|
{
|
|
unsigned char* pvrdata = NULL;
|
|
int pvrlen = 0;
|
|
|
|
std::string lowerCase(path);
|
|
for (unsigned int i = 0; i < lowerCase.length(); ++i)
|
|
{
|
|
lowerCase[i] = tolower(lowerCase[i]);
|
|
}
|
|
|
|
if (lowerCase.find(".ccz") != std::string::npos)
|
|
{
|
|
pvrlen = ZipUtils::ccInflateCCZFile(path, &pvrdata);
|
|
}
|
|
else if (lowerCase.find(".gz") != std::string::npos)
|
|
{
|
|
pvrlen = ZipUtils::ccInflateGZipFile(path, &pvrdata);
|
|
}
|
|
else
|
|
{
|
|
pvrdata = CCFileUtils::sharedFileUtils()->getFileData(path, "rb", (unsigned long *)(&pvrlen));
|
|
}
|
|
|
|
if (pvrlen < 0)
|
|
{
|
|
this->release();
|
|
return false;
|
|
}
|
|
|
|
m_uNumberOfMipmaps = 0;
|
|
|
|
m_uName = 0;
|
|
m_uWidth = m_uHeight = 0;
|
|
m_pPixelFormatInfo = NULL;
|
|
m_bHasAlpha = false;
|
|
|
|
m_bRetainName = false; // cocos2d integration
|
|
|
|
if (! ((unpackPVRv2Data(pvrdata, pvrlen) || unpackPVRv3Data(pvrdata, pvrlen)) && createGLTexture()) )
|
|
{
|
|
CC_SAFE_DELETE_ARRAY(pvrdata);
|
|
this->release();
|
|
return false;
|
|
}
|
|
|
|
CC_SAFE_DELETE_ARRAY(pvrdata);
|
|
|
|
return true;
|
|
}
|
|
|
|
CCTexturePVR * CCTexturePVR::create(const char* path)
|
|
{
|
|
CCTexturePVR * pTexture = new CCTexturePVR();
|
|
if (pTexture)
|
|
{
|
|
if (pTexture->initWithContentsOfFile(path))
|
|
{
|
|
pTexture->autorelease();
|
|
}
|
|
else
|
|
{
|
|
delete pTexture;
|
|
pTexture = NULL;
|
|
}
|
|
}
|
|
|
|
return pTexture;
|
|
}
|
|
|
|
NS_CC_END
|
|
|