2012-04-19 14:35:52 +08:00
/****************************************************************************
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2010 - 2012 cocos2d - x . org
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2012-04-19 14:35:52 +08:00
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-07-25 21:35:00 +08:00
2014-05-17 05:36:00 +08:00
# include "platform/CCImage.h"
2013-06-18 17:10:54 +08:00
2012-04-19 14:35:52 +08:00
# include <string>
# include <ctype.h>
2014-05-17 05:36:00 +08:00
# include "base/CCData.h"
2013-05-18 08:11:52 +08:00
# ifdef EMSCRIPTEN
# include <SDL/SDL.h>
# include <SDL/SDL_image.h>
# endif // EMSCRIPTEN
2013-08-06 11:34:48 +08:00
extern " C "
{
2014-06-05 21:54:00 +08:00
# ifndef __ENABLE_COMPATIBILITY_WITH_UNIX_2003__
# define __ENABLE_COMPATIBILITY_WITH_UNIX_2003__
# include <stdio.h>
FILE * fopen $ UNIX2003 ( const char * filename , const char * mode )
{
return fopen ( filename , mode ) ;
}
size_t fwrite $ UNIX2003 ( const void * a , size_t b , size_t c , FILE * d )
{
return fwrite ( a , b , c , d ) ;
}
char * strerror $ UNIX2003 ( int errnum )
{
return strerror ( errnum ) ;
}
# endif
2013-07-25 21:35:00 +08:00
# include "png.h"
# include "tiffio.h"
2014-05-01 10:09:13 +08:00
# include "base/etc1.h"
2013-08-06 11:34:48 +08:00
# include "jpeglib.h"
}
2014-05-01 10:09:13 +08:00
# include "base/s3tc.h"
# include "base/atitc.h"
2014-05-17 05:36:00 +08:00
# include "base/TGAlib.h"
2013-10-14 14:01:00 +08:00
2014-03-22 20:51:39 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
2013-07-29 17:56:36 +08:00
# include "decode.h"
2014-03-22 20:51:39 +08:00
# endif
2013-07-25 21:35:00 +08:00
2014-04-30 08:37:36 +08:00
# include "base/ccMacros.h"
2013-10-14 14:01:00 +08:00
# include "CCCommon.h"
2013-07-25 21:35:00 +08:00
# include "CCStdC.h"
# include "CCFileUtils.h"
2014-05-01 10:09:13 +08:00
# include "base/CCConfiguration.h"
2014-05-17 05:36:00 +08:00
# include "base/ccUtils.h"
2014-04-30 08:37:36 +08:00
# include "base/ZipUtils.h"
2013-07-25 21:35:00 +08:00
# if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
2013-10-14 14:01:00 +08:00
# include "android/CCFileUtilsAndroid.h"
2013-07-25 21:35:00 +08:00
# endif
2013-08-16 14:03:30 +08:00
# define CC_GL_ATC_RGB_AMD 0x8C92
# define CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
# define CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
2012-05-25 16:52:47 +08:00
NS_CC_BEGIN
2013-07-25 21:35:00 +08:00
//////////////////////////////////////////////////////////////////////////
//struct and data for pvr structure
2013-08-08 14:11:22 +08:00
2013-08-01 15:53:52 +08:00
namespace
2013-07-25 21:35:00 +08:00
{
2013-08-01 15:53:52 +08:00
static const int PVR_TEXTURE_FLAG_TYPE_MASK = 0xff ;
2013-08-06 16:14:36 +08:00
2013-08-01 15:53:52 +08:00
// Values taken from PVRTexture.h from http://www.imgtec.com
2013-08-13 10:11:28 +08:00
enum class PVR2TextureFlag
{
2013-08-06 16:14:36 +08:00
Mipmap = ( 1 < < 8 ) , // has mip map levels
Twiddle = ( 1 < < 9 ) , // is twiddled
Bumpmap = ( 1 < < 10 ) , // has normals encoded for a bump map
Tiling = ( 1 < < 11 ) , // is bordered for tiled pvr
Cubemap = ( 1 < < 12 ) , // is a cubemap/skybox
FalseMipCol = ( 1 < < 13 ) , // are there false colored MIP levels
Volume = ( 1 < < 14 ) , // is this a volume texture
Alpha = ( 1 < < 15 ) , // v2.1 is there transparency info in the texture
VerticalFlip = ( 1 < < 16 ) , // v2.1 is the texture vertically flipped
} ;
2013-08-01 15:53:52 +08:00
2013-08-06 16:14:36 +08:00
enum class PVR3TextureFlag
{
PremultipliedAlpha = ( 1 < < 1 ) // has premultiplied alpha
2013-08-01 15:53:52 +08:00
} ;
2013-08-06 16:14:36 +08:00
static const char gPVRTexIdentifier [ 5 ] = " PVR! " ;
// v2
enum class PVR2TexturePixelFormat : unsigned char
{
RGBA4444 = 0x10 ,
RGBA5551 ,
RGBA8888 ,
RGB565 ,
RGB555 , // unsupported
RGB888 ,
I8 ,
AI88 ,
PVRTC2BPP_RGBA ,
PVRTC4BPP_RGBA ,
BGRA8888 ,
A8 ,
2013-08-13 10:11:28 +08:00
} ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v3
enum class PVR3TexturePixelFormat : uint64_t
{
PVRTC2BPP_RGB = 0ULL ,
PVRTC2BPP_RGBA = 1ULL ,
PVRTC4BPP_RGB = 2ULL ,
PVRTC4BPP_RGBA = 3ULL ,
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
BGRA8888 = 0x0808080861726762ULL ,
RGBA8888 = 0x0808080861626772ULL ,
RGBA4444 = 0x0404040461626772ULL ,
RGBA5551 = 0x0105050561626772ULL ,
RGB565 = 0x0005060500626772ULL ,
RGB888 = 0x0008080800626772ULL ,
A8 = 0x0000000800000061ULL ,
L8 = 0x000000080000006cULL ,
LA88 = 0x000008080000616cULL ,
} ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v2
typedef const std : : map < PVR2TexturePixelFormat , Texture2D : : PixelFormat > _pixel2_formathash ;
static const _pixel2_formathash : : value_type v2_pixel_formathash_value [ ] =
{
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : BGRA8888 , Texture2D : : PixelFormat : : BGRA8888 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : RGBA8888 , Texture2D : : PixelFormat : : RGBA8888 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : RGBA4444 , Texture2D : : PixelFormat : : RGBA4444 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : RGBA5551 , Texture2D : : PixelFormat : : RGB5A1 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : RGB565 , Texture2D : : PixelFormat : : RGB565 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : RGB888 , Texture2D : : PixelFormat : : RGB888 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : A8 , Texture2D : : PixelFormat : : A8 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : I8 , Texture2D : : PixelFormat : : I8 ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : AI88 , Texture2D : : PixelFormat : : AI88 ) ,
2013-08-06 16:14:36 +08:00
2013-07-25 21:35:00 +08:00
# ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
2013-08-13 10:11:28 +08:00
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : PVRTC2BPP_RGBA , Texture2D : : PixelFormat : : PVRTC2A ) ,
_pixel2_formathash : : value_type ( PVR2TexturePixelFormat : : PVRTC4BPP_RGBA , Texture2D : : PixelFormat : : PVRTC4A ) ,
2013-07-25 21:35:00 +08:00
# endif
2013-08-13 10:11:28 +08:00
} ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const int PVR2_MAX_TABLE_ELEMENTS = sizeof ( v2_pixel_formathash_value ) / sizeof ( v2_pixel_formathash_value [ 0 ] ) ;
static const _pixel2_formathash v2_pixel_formathash ( v2_pixel_formathash_value , v2_pixel_formathash_value + PVR2_MAX_TABLE_ELEMENTS ) ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
// v3
typedef const std : : map < PVR3TexturePixelFormat , Texture2D : : PixelFormat > _pixel3_formathash ;
static _pixel3_formathash : : value_type v3_pixel_formathash_value [ ] =
{
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : BGRA8888 , Texture2D : : PixelFormat : : BGRA8888 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : RGBA8888 , Texture2D : : PixelFormat : : RGBA8888 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : RGBA4444 , Texture2D : : PixelFormat : : RGBA4444 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : RGBA5551 , Texture2D : : PixelFormat : : RGB5A1 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : RGB565 , Texture2D : : PixelFormat : : RGB565 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : RGB888 , Texture2D : : PixelFormat : : RGB888 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : A8 , Texture2D : : PixelFormat : : A8 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : L8 , Texture2D : : PixelFormat : : I8 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : LA88 , Texture2D : : PixelFormat : : AI88 ) ,
2013-08-06 16:14:36 +08:00
2013-07-25 21:35:00 +08:00
# ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
2013-08-13 10:11:28 +08:00
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : PVRTC2BPP_RGB , Texture2D : : PixelFormat : : PVRTC2 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : PVRTC2BPP_RGBA , Texture2D : : PixelFormat : : PVRTC2A ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : PVRTC4BPP_RGB , Texture2D : : PixelFormat : : PVRTC4 ) ,
_pixel3_formathash : : value_type ( PVR3TexturePixelFormat : : PVRTC4BPP_RGBA , Texture2D : : PixelFormat : : PVRTC4A ) ,
2013-07-25 21:35:00 +08:00
# endif
2013-08-13 10:11:28 +08:00
} ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const int PVR3_MAX_TABLE_ELEMENTS = sizeof ( v3_pixel_formathash_value ) / sizeof ( v3_pixel_formathash_value [ 0 ] ) ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
static const _pixel3_formathash v3_pixel_formathash ( v3_pixel_formathash_value , v3_pixel_formathash_value + PVR3_MAX_TABLE_ELEMENTS ) ;
2013-08-06 16:14:36 +08:00
2013-08-13 10:11:28 +08:00
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 ;
} PVRv2TexHeader ;
2013-08-06 16:14:36 +08:00
2013-07-25 21:35:00 +08:00
# ifdef _MSC_VER
# pragma pack(push,1)
# endif
2013-08-13 10:11:28 +08:00
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 ;
2013-07-25 21:35:00 +08:00
# ifdef _MSC_VER
2013-08-13 10:11:28 +08:00
} PVRv3TexHeader ;
2013-07-25 21:35:00 +08:00
# pragma pack(pop)
# else
2013-08-06 16:14:36 +08:00
} __attribute__ ( ( packed ) ) PVRv3TexHeader ;
2013-07-25 21:35:00 +08:00
# endif
2013-08-01 15:53:52 +08:00
}
2013-07-25 21:35:00 +08:00
//pvr structure end
2013-08-06 11:19:45 +08:00
2013-07-25 21:35:00 +08:00
//////////////////////////////////////////////////////////////////////////
2013-08-06 11:19:45 +08:00
//struct and data for s3tc(dds) struct
2013-08-08 14:59:46 +08:00
namespace
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
struct DDColorKey
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t colorSpaceLowValue ;
uint32_t colorSpaceHighValue ;
} ;
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDSCaps
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t caps ;
uint32_t caps2 ;
uint32_t caps3 ;
uint32_t caps4 ;
} ;
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDPixelFormat
{
uint32_t size ;
uint32_t flags ;
uint32_t fourCC ;
uint32_t RGBBitCount ;
uint32_t RBitMask ;
uint32_t GBitMask ;
uint32_t BBitMask ;
uint32_t ABitMask ;
} ;
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct DDSURFACEDESC2
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
uint32_t size ;
uint32_t flags ;
uint32_t height ;
uint32_t width ;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
uint32_t pitch ;
uint32_t linearSize ;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN1 ;
union
{
2013-08-09 12:54:05 +08:00
uint32_t backBufferCount ;
uint32_t depth ;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN5 ;
union
{
2013-08-09 12:54:05 +08:00
uint32_t mipMapCount ;
uint32_t refreshRate ;
uint32_t srcVBHandle ;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN2 ;
2013-08-09 12:54:05 +08:00
uint32_t alphaBitDepth ;
uint32_t reserved ;
uint32_t surface ;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
DDColorKey ddckCKDestOverlay ;
uint32_t emptyFaceColor ;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN3 ;
2013-08-09 12:54:05 +08:00
DDColorKey ddckCKDestBlt ;
DDColorKey ddckCKSrcOverlay ;
DDColorKey ddckCKSrcBlt ;
2013-08-08 14:59:46 +08:00
union
{
2013-08-09 12:54:05 +08:00
DDPixelFormat ddpfPixelFormat ;
uint32_t FVF ;
2013-08-08 14:59:46 +08:00
} DUMMYUNIONNAMEN4 ;
2013-08-09 12:54:05 +08:00
DDSCaps ddsCaps ;
uint32_t textureStage ;
} ;
2013-08-06 11:19:45 +08:00
2013-08-08 14:59:46 +08:00
# pragma pack(push,1)
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
struct S3TCTexHeader
2013-08-06 11:19:45 +08:00
{
2013-08-08 14:59:46 +08:00
char fileCode [ 4 ] ;
DDSURFACEDESC2 ddsd ;
2013-08-09 12:54:05 +08:00
} ;
2013-08-06 11:19:45 +08:00
# pragma pack(pop)
2013-08-08 14:59:46 +08:00
}
2013-08-06 11:19:45 +08:00
//s3tc struct end
2013-08-16 11:02:44 +08:00
//////////////////////////////////////////////////////////////////////////
//struct and data for atitc(ktx) struct
namespace
{
struct ATITCTexHeader
{
//HEADER
char identifier [ 12 ] ;
uint32_t endianness ;
uint32_t glType ;
uint32_t glTypeSize ;
uint32_t glFormat ;
uint32_t glInternalFormat ;
uint32_t glBaseInternalFormat ;
uint32_t pixelWidth ;
uint32_t pixelHeight ;
uint32_t pixelDepth ;
uint32_t numberOfArrayElements ;
uint32_t numberOfFaces ;
uint32_t numberOfMipmapLevels ;
uint32_t bytesOfKeyValueData ;
} ;
}
//atittc struct end
//////////////////////////////////////////////////////////////////////////
2013-08-06 11:19:45 +08:00
2013-08-08 14:59:46 +08:00
namespace
{
2013-08-06 16:14:36 +08:00
typedef struct
2012-04-19 14:35:52 +08:00
{
2013-08-12 17:05:19 +08:00
const unsigned char * data ;
2013-12-06 16:32:06 +08:00
ssize_t size ;
2013-08-06 16:14:36 +08:00
int offset ;
} tImageSource ;
static void pngReadCallback ( png_structp png_ptr , png_bytep data , png_size_t length )
2012-04-19 14:35:52 +08:00
{
2013-08-06 16:14:36 +08:00
tImageSource * isource = ( tImageSource * ) png_get_io_ptr ( png_ptr ) ;
if ( ( int ) ( isource - > offset + length ) < = isource - > size )
{
memcpy ( data , isource - > data + isource - > offset , length ) ;
isource - > offset + = length ;
}
else
{
png_error ( png_ptr , " pngReaderCallback failed " ) ;
}
2012-04-19 14:35:52 +08:00
}
}
//////////////////////////////////////////////////////////////////////////
2013-06-20 14:13:12 +08:00
// Implement Image
2012-04-19 14:35:52 +08:00
//////////////////////////////////////////////////////////////////////////
2013-06-20 14:13:12 +08:00
Image : : Image ( )
2014-01-09 16:33:31 +08:00
: _data ( nullptr )
2013-07-25 21:35:00 +08:00
, _dataLen ( 0 )
, _width ( 0 )
2013-06-15 14:03:30 +08:00
, _height ( 0 )
2013-07-27 22:06:30 +08:00
, _fileType ( Format : : UNKOWN )
, _renderFormat ( Texture2D : : PixelFormat : : NONE )
2013-06-15 14:03:30 +08:00
, _preMulti ( false )
2013-07-25 21:35:00 +08:00
, _numberOfMipmaps ( 0 )
2013-11-13 11:22:34 +08:00
, _hasPremultipliedAlpha ( true )
2012-04-19 14:35:52 +08:00
{
}
2013-06-20 14:13:12 +08:00
Image : : ~ Image ( )
2012-04-19 14:35:52 +08:00
{
2014-01-09 15:26:05 +08:00
CC_SAFE_FREE ( _data ) ;
2012-04-19 14:35:52 +08:00
}
2013-12-24 10:51:47 +08:00
bool Image : : initWithImageFile ( const std : : string & path )
2012-04-19 14:35:52 +08:00
{
2013-12-24 10:51:47 +08:00
bool ret = false ;
_filePath = FileUtils : : getInstance ( ) - > fullPathForFilename ( path ) ;
2013-05-18 08:11:52 +08:00
# ifdef EMSCRIPTEN
// Emscripten includes a re-implementation of SDL that uses HTML5 canvas
// operations underneath. Consequently, loading images via IMG_Load (an SDL
// API) will be a lot faster than running libpng et al as compiled with
// Emscripten.
2013-07-23 21:49:00 +08:00
SDL_Surface * iSurf = IMG_Load ( fullPath . c_str ( ) ) ;
2013-05-18 08:11:52 +08:00
int size = 4 * ( iSurf - > w * iSurf - > h ) ;
2013-12-24 10:51:47 +08:00
ret = initWithRawData ( ( const unsigned char * ) iSurf - > pixels , size , iSurf - > w , iSurf - > h , 8 , true ) ;
2013-05-18 08:11:52 +08:00
2013-06-15 14:03:30 +08:00
unsigned int * tmp = ( unsigned int * ) _data ;
2013-05-18 08:11:52 +08:00
int nrPixels = iSurf - > w * iSurf - > h ;
for ( int i = 0 ; i < nrPixels ; i + + )
{
2013-06-15 14:03:30 +08:00
unsigned char * p = _data + i * 4 ;
2013-05-18 08:11:52 +08:00
tmp [ i ] = CC_RGB_PREMULTIPLY_ALPHA ( p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] ) ;
}
SDL_FreeSurface ( iSurf ) ;
# else
2013-12-18 14:58:17 +08:00
Data data = FileUtils : : getInstance ( ) - > getDataFromFile ( _filePath ) ;
2013-07-25 21:35:00 +08:00
2013-12-18 14:58:17 +08:00
if ( ! data . isNull ( ) )
2013-07-25 21:35:00 +08:00
{
2013-12-25 10:41:37 +08:00
ret = initWithImageData ( data . getBytes ( ) , data . getSize ( ) ) ;
2013-07-25 21:35:00 +08:00
}
2013-05-18 08:11:52 +08:00
# endif // EMSCRIPTEN
2013-12-24 10:51:47 +08:00
return ret ;
2012-04-19 14:35:52 +08:00
}
2013-12-24 15:49:58 +08:00
bool Image : : initWithImageFileThreadSafe ( const std : : string & fullpath )
2012-04-19 14:35:52 +08:00
{
2013-11-06 09:36:44 +08:00
bool ret = false ;
2013-11-29 14:31:42 +08:00
_filePath = fullpath ;
2013-12-18 14:58:17 +08:00
Data data = FileUtils : : getInstance ( ) - > getDataFromFile ( fullpath ) ;
if ( ! data . isNull ( ) )
2012-06-19 16:31:26 +08:00
{
2013-12-18 14:58:17 +08:00
ret = initWithImageData ( data . getBytes ( ) , data . getSize ( ) ) ;
2012-06-19 16:31:26 +08:00
}
2013-12-18 14:58:17 +08:00
2013-11-06 09:36:44 +08:00
return ret ;
2012-04-19 14:35:52 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithImageData ( const unsigned char * data , ssize_t dataLen )
2012-04-19 14:35:52 +08:00
{
2013-08-12 17:05:19 +08:00
bool ret = false ;
2013-08-12 11:54:54 +08:00
do
2012-04-19 14:35:52 +08:00
{
2013-07-25 21:35:00 +08:00
CC_BREAK_IF ( ! data | | dataLen < = 0 ) ;
2013-08-12 11:54:54 +08:00
unsigned char * unpackedData = nullptr ;
2013-12-05 17:19:01 +08:00
ssize_t unpackedLen = 0 ;
2013-08-12 11:54:54 +08:00
//detecgt and unzip the compress file
2013-11-12 10:09:47 +08:00
if ( ZipUtils : : isCCZBuffer ( data , dataLen ) )
2013-08-12 11:54:54 +08:00
{
2013-11-12 10:09:47 +08:00
unpackedLen = ZipUtils : : inflateCCZBuffer ( data , dataLen , & unpackedData ) ;
2013-08-16 16:10:39 +08:00
}
2013-11-12 10:09:47 +08:00
else if ( ZipUtils : : isGZipBuffer ( data , dataLen ) )
2013-08-12 11:54:54 +08:00
{
2013-11-12 10:09:47 +08:00
unpackedLen = ZipUtils : : inflateMemory ( const_cast < unsigned char * > ( data ) , dataLen , & unpackedData ) ;
2013-08-16 16:10:39 +08:00
}
else
2013-08-12 11:54:54 +08:00
{
2013-08-12 17:05:19 +08:00
unpackedData = const_cast < unsigned char * > ( data ) ;
2013-08-12 11:54:54 +08:00
unpackedLen = dataLen ;
}
2012-04-19 14:35:52 +08:00
2013-08-12 11:54:54 +08:00
_fileType = detectFormat ( unpackedData , unpackedLen ) ;
2013-07-17 17:12:04 +08:00
2013-07-25 21:35:00 +08:00
switch ( _fileType )
2012-04-19 14:35:52 +08:00
{
2013-07-27 22:06:30 +08:00
case Format : : PNG :
2013-08-12 17:05:19 +08:00
ret = initWithPngData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-07-27 22:06:30 +08:00
case Format : : JPG :
2013-08-12 17:05:19 +08:00
ret = initWithJpgData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-07-27 22:06:30 +08:00
case Format : : TIFF :
2013-08-12 17:05:19 +08:00
ret = initWithTiffData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-07-27 22:06:30 +08:00
case Format : : WEBP :
2013-08-12 17:05:19 +08:00
ret = initWithWebpData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-07-27 22:06:30 +08:00
case Format : : PVR :
2013-08-12 17:05:19 +08:00
ret = initWithPVRData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-07-27 22:06:30 +08:00
case Format : : ETC :
2013-08-12 17:05:19 +08:00
ret = initWithETCData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-08-06 11:19:45 +08:00
case Format : : S3TC :
2013-08-12 17:05:19 +08:00
ret = initWithS3TCData ( unpackedData , unpackedLen ) ;
2013-08-12 11:54:54 +08:00
break ;
2013-08-16 11:02:44 +08:00
case Format : : ATITC :
2013-08-16 14:27:13 +08:00
ret = initWithATITCData ( unpackedData , unpackedLen ) ;
break ;
2013-07-25 21:35:00 +08:00
default :
2013-11-29 14:31:42 +08:00
{
// load and detect image format
tImageTGA * tgaData = tgaLoadBuffer ( unpackedData , unpackedLen ) ;
if ( tgaData ! = nullptr & & tgaData - > status = = TGA_OK )
{
ret = initWithTGAData ( tgaData ) ;
}
else
{
CCAssert ( false , " unsupport image format! " ) ;
}
free ( tgaData ) ;
break ;
}
2013-08-12 11:54:54 +08:00
}
if ( unpackedData ! = data )
{
free ( unpackedData ) ;
2012-05-25 16:52:47 +08:00
}
2012-04-19 14:35:52 +08:00
} while ( 0 ) ;
2013-07-25 21:35:00 +08:00
2013-08-12 17:05:19 +08:00
return ret ;
2012-04-19 14:35:52 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : isPng ( const unsigned char * data , ssize_t dataLen )
2013-07-17 17:12:04 +08:00
{
2013-07-25 21:35:00 +08:00
if ( dataLen < = 8 )
2013-07-19 15:37:54 +08:00
{
return false ;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const unsigned char PNG_SIGNATURE [ ] = { 0x89 , 0x50 , 0x4e , 0x47 , 0x0d , 0x0a , 0x1a , 0x0a } ;
2013-07-17 17:12:04 +08:00
2013-07-25 21:35:00 +08:00
return memcmp ( PNG_SIGNATURE , data , sizeof ( PNG_SIGNATURE ) ) = = 0 ;
}
2013-12-05 17:19:01 +08:00
bool Image : : isEtc ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-08-02 15:01:27 +08:00
return etc1_pkm_is_valid ( ( etc1_byte * ) data ) ? true : false ;
2013-07-17 17:12:04 +08:00
}
2013-08-08 14:11:22 +08:00
2013-12-05 17:19:01 +08:00
bool Image : : isS3TC ( const unsigned char * data , ssize_t dataLen )
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
S3TCTexHeader * header = ( S3TCTexHeader * ) data ;
2013-08-06 11:19:45 +08:00
2013-08-16 11:02:44 +08:00
if ( strncmp ( header - > fileCode , " DDS " , 3 ) ! = 0 )
2013-08-06 11:19:45 +08:00
{
CCLOG ( " cocos2d: the file is not a dds file! " ) ;
return false ;
}
return true ;
}
2013-12-05 17:19:01 +08:00
bool Image : : isATITC ( const unsigned char * data , ssize_t dataLen )
2013-08-16 11:02:44 +08:00
{
ATITCTexHeader * header = ( ATITCTexHeader * ) data ;
if ( strncmp ( & header - > identifier [ 1 ] , " KTX " , 3 ) ! = 0 )
{
CCLOG ( " cocos3d: the file is not a ktx file! " ) ;
return false ;
}
return true ;
}
2013-12-05 17:19:01 +08:00
bool Image : : isJpg ( const unsigned char * data , ssize_t dataLen )
2013-07-17 17:12:04 +08:00
{
2013-07-25 21:35:00 +08:00
if ( dataLen < = 4 )
2013-07-19 15:37:54 +08:00
{
return false ;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const unsigned char JPG_SOI [ ] = { 0xFF , 0xD8 } ;
2013-07-17 17:12:04 +08:00
2013-07-25 21:35:00 +08:00
return memcmp ( data , JPG_SOI , 2 ) = = 0 ;
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : isTiff ( const unsigned char * data , ssize_t dataLen )
2013-07-17 17:12:04 +08:00
{
2013-07-25 21:35:00 +08:00
if ( dataLen < = 4 )
2013-07-19 15:37:54 +08:00
{
return false ;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const char * TIFF_II = " II " ;
static const char * TIFF_MM = " MM " ;
2013-07-17 17:12:04 +08:00
2013-08-06 16:14:36 +08:00
return ( memcmp ( data , TIFF_II , 2 ) = = 0 & & * ( static_cast < const unsigned char * > ( data ) + 2 ) = = 42 & & * ( static_cast < const unsigned char * > ( data ) + 3 ) = = 0 ) | |
( memcmp ( data , TIFF_MM , 2 ) = = 0 & & * ( static_cast < const unsigned char * > ( data ) + 2 ) = = 0 & & * ( static_cast < const unsigned char * > ( data ) + 3 ) = = 42 ) ;
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : isWebp ( const unsigned char * data , ssize_t dataLen )
2013-07-17 17:12:04 +08:00
{
2013-07-25 21:35:00 +08:00
if ( dataLen < = 12 )
2013-07-19 15:37:54 +08:00
{
return false ;
}
2013-07-17 17:12:04 +08:00
2013-07-19 15:37:54 +08:00
static const char * WEBP_RIFF = " RIFF " ;
static const char * WEBP_WEBP = " WEBP " ;
2013-07-17 17:12:04 +08:00
2013-07-25 21:35:00 +08:00
return memcmp ( data , WEBP_RIFF , 4 ) = = 0
2013-08-06 16:14:36 +08:00
& & memcmp ( static_cast < const unsigned char * > ( data ) + 8 , WEBP_WEBP , 4 ) = = 0 ;
2013-07-25 21:35:00 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : isPvr ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-11-13 11:22:34 +08:00
if ( static_cast < size_t > ( dataLen ) < sizeof ( PVRv2TexHeader ) | | static_cast < size_t > ( dataLen ) < sizeof ( PVRv3TexHeader ) )
2013-07-25 21:35:00 +08:00
{
return false ;
}
2013-08-12 17:05:19 +08:00
const PVRv2TexHeader * headerv2 = static_cast < const PVRv2TexHeader * > ( static_cast < const void * > ( data ) ) ;
const PVRv3TexHeader * headerv3 = static_cast < const PVRv3TexHeader * > ( static_cast < const void * > ( data ) ) ;
2013-07-25 21:35:00 +08:00
return memcmp ( & headerv2 - > pvrTag , gPVRTexIdentifier , strlen ( gPVRTexIdentifier ) ) = = 0 | | CC_SWAP_INT32_BIG_TO_HOST ( headerv3 - > version ) = = 0x50565203 ;
2013-07-17 17:12:04 +08:00
}
2013-12-05 17:19:01 +08:00
Image : : Format Image : : detectFormat ( const unsigned char * data , ssize_t dataLen )
2013-07-17 17:12:04 +08:00
{
2013-07-25 21:35:00 +08:00
if ( isPng ( data , dataLen ) )
2013-07-19 15:37:54 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : PNG ;
2013-08-16 16:10:39 +08:00
}
else if ( isJpg ( data , dataLen ) )
2013-07-19 15:37:54 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : JPG ;
2013-08-16 16:10:39 +08:00
}
else if ( isTiff ( data , dataLen ) )
2013-07-19 15:37:54 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : TIFF ;
2013-08-16 16:10:39 +08:00
}
else if ( isWebp ( data , dataLen ) )
2013-07-19 15:37:54 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : WEBP ;
2013-08-16 16:10:39 +08:00
}
else if ( isPvr ( data , dataLen ) )
2013-07-19 15:37:54 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : PVR ;
2013-08-16 16:10:39 +08:00
}
else if ( isEtc ( data , dataLen ) )
2013-07-25 21:35:00 +08:00
{
2013-07-27 22:06:30 +08:00
return Format : : ETC ;
2013-08-16 16:10:39 +08:00
}
else if ( isS3TC ( data , dataLen ) )
2013-08-06 11:19:45 +08:00
{
return Format : : S3TC ;
2013-08-16 16:10:39 +08:00
}
else if ( isATITC ( data , dataLen ) )
2013-08-16 11:02:44 +08:00
{
return Format : : ATITC ;
2013-07-25 21:35:00 +08:00
}
else
{
2013-07-27 22:06:30 +08:00
return Format : : UNKOWN ;
2013-07-19 15:37:54 +08:00
}
2013-07-17 17:12:04 +08:00
}
2013-07-25 21:35:00 +08:00
int Image : : getBitPerPixel ( )
{
2013-08-07 11:20:41 +08:00
return Texture2D : : getPixelFormatInfoMap ( ) . at ( _renderFormat ) . bpp ;
2013-07-25 21:35:00 +08:00
}
bool Image : : hasAlpha ( )
{
2013-08-07 11:20:41 +08:00
return Texture2D : : getPixelFormatInfoMap ( ) . at ( _renderFormat ) . alpha ;
2013-07-25 21:35:00 +08:00
}
bool Image : : isCompressed ( )
{
2013-08-07 11:20:41 +08:00
return Texture2D : : getPixelFormatInfoMap ( ) . at ( _renderFormat ) . compressed ;
2013-07-25 21:35:00 +08:00
}
2013-08-06 16:14:36 +08:00
namespace
{
2012-11-01 21:42:24 +08:00
/*
* ERROR HANDLING :
*
* The JPEG library ' s standard error handler ( jerror . c ) is divided into
* several " methods " which you can override individually . This lets you
* adjust the behavior without duplicating a lot of code , which you might
* have to update with each future release .
*
* We override the " error_exit " method so that control is returned to the
* library ' s caller when a fatal error occurs , rather than calling exit ( )
* as the standard error_exit method does .
*
* We use C ' s setjmp / longjmp facility to return control . This means that the
* routine which calls the JPEG library must first execute a setjmp ( ) call to
* establish the return point . We want the replacement error_exit to do a
* longjmp ( ) . But we need to make the setjmp buffer accessible to the
* error_exit routine . To do this , we make a private extension of the
* standard JPEG error handler object . ( If we were using C + + , we ' d say we
* were making a subclass of the regular error handler . )
*
* Here ' s the extended error handler struct :
*/
2013-08-06 16:14:36 +08:00
struct MyErrorMgr
{
struct jpeg_error_mgr pub ; /* "public" fields */
jmp_buf setjmp_buffer ; /* for return to caller */
} ;
typedef struct MyErrorMgr * MyErrorPtr ;
2013-08-06 11:34:48 +08:00
2013-08-06 16:14:36 +08:00
/*
* Here ' s the routine that will replace the standard error_exit method :
2013-08-06 11:34:48 +08:00
*/
2013-08-06 16:14:36 +08:00
METHODDEF ( void )
myErrorExit ( j_common_ptr cinfo )
{
/* cinfo->err really points to a MyErrorMgr struct, so coerce pointer */
MyErrorPtr myerr = ( MyErrorPtr ) cinfo - > err ;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
/* internal message function cann't show error message in some platforms, so we rewrite it here.
* edit it if has version confilict .
*/
//(*cinfo->err->output_message) (cinfo);
char buffer [ JMSG_LENGTH_MAX ] ;
( * cinfo - > err - > format_message ) ( cinfo , buffer ) ;
CCLOG ( " jpeg error: %s " , buffer ) ;
/* Return control to the setjmp point */
longjmp ( myerr - > setjmp_buffer , 1 ) ;
}
2012-11-01 21:42:24 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithJpgData ( const unsigned char * data , ssize_t dataLen )
2012-04-19 14:35:52 +08:00
{
/* these are standard libjpeg structures for reading(decompression) */
struct jpeg_decompress_struct cinfo ;
2012-11-01 21:42:24 +08:00
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct , to avoid dangling - pointer problems .
*/
2013-08-06 16:14:36 +08:00
struct MyErrorMgr jerr ;
2012-04-19 14:35:52 +08:00
/* libjpeg data structure for storing one row, that is, scanline of an image */
JSAMPROW row_pointer [ 1 ] = { 0 } ;
unsigned long location = 0 ;
unsigned int i = 0 ;
bool bRet = false ;
do
{
2012-11-01 21:42:24 +08:00
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo . err = jpeg_std_error ( & jerr . pub ) ;
2013-08-06 16:14:36 +08:00
jerr . pub . error_exit = myErrorExit ;
/* Establish the setjmp return context for MyErrorExit to use. */
2012-11-01 21:42:24 +08:00
if ( setjmp ( jerr . setjmp_buffer ) ) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object , close the input file , and return .
*/
jpeg_destroy_decompress ( & cinfo ) ;
break ;
}
2012-04-19 14:35:52 +08:00
/* setup decompression process and source, then read JPEG header */
jpeg_create_decompress ( & cinfo ) ;
2013-07-23 01:58:48 +08:00
# ifndef CC_TARGET_QT5
2013-08-12 17:05:19 +08:00
jpeg_mem_src ( & cinfo , const_cast < unsigned char * > ( data ) , dataLen ) ;
2013-07-23 01:58:48 +08:00
# endif /* CC_TARGET_QT5 */
2012-04-19 14:35:52 +08:00
/* reading the image header which contains image information */
2013-05-07 13:28:13 +08:00
# if (JPEG_LIB_VERSION >= 90)
// libjpeg 0.9 adds stricter types.
jpeg_read_header ( & cinfo , TRUE ) ;
# else
2012-04-19 14:35:52 +08:00
jpeg_read_header ( & cinfo , true ) ;
2013-05-07 13:28:13 +08:00
# endif
2012-04-19 14:35:52 +08:00
// we only support RGB or grayscale
2013-07-25 21:35:00 +08:00
if ( cinfo . jpeg_color_space = = JCS_GRAYSCALE )
2012-04-19 14:35:52 +08:00
{
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : I8 ;
2013-07-19 15:37:54 +08:00
} else
{
cinfo . out_color_space = JCS_RGB ;
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGB888 ;
2012-04-19 14:35:52 +08:00
}
/* Start decompression jpeg here */
jpeg_start_decompress ( & cinfo ) ;
/* init image info */
2013-08-12 17:05:19 +08:00
_width = cinfo . output_width ;
_height = cinfo . output_height ;
2013-06-15 14:03:30 +08:00
_preMulti = false ;
2013-11-29 15:13:16 +08:00
row_pointer [ 0 ] = static_cast < unsigned char * > ( malloc ( cinfo . output_width * cinfo . output_components * sizeof ( unsigned char ) ) ) ;
2012-04-19 14:35:52 +08:00
CC_BREAK_IF ( ! row_pointer [ 0 ] ) ;
2013-07-25 21:35:00 +08:00
_dataLen = cinfo . output_width * cinfo . output_height * cinfo . output_components ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2014-04-13 06:13:58 +08:00
CC_BREAK_IF ( ! _data ) ;
2012-04-19 14:35:52 +08:00
/* now actually read the jpeg into the raw buffer */
/* read one scan line at a time */
2012-11-01 21:42:24 +08:00
while ( cinfo . output_scanline < cinfo . output_height )
2012-04-19 14:35:52 +08:00
{
jpeg_read_scanlines ( & cinfo , row_pointer , 1 ) ;
2012-11-01 21:42:24 +08:00
for ( i = 0 ; i < cinfo . output_width * cinfo . output_components ; i + + )
2012-05-30 18:30:11 +08:00
{
2013-06-15 14:03:30 +08:00
_data [ location + + ] = row_pointer [ 0 ] [ i ] ;
2012-05-30 18:30:11 +08:00
}
2012-04-19 14:35:52 +08:00
}
2012-11-01 21:42:24 +08:00
/* When read image file with broken data, jpeg_finish_decompress() may cause error.
* Besides , jpeg_destroy_decompress ( ) shall deallocate and release all memory associated
* with the decompression object .
* So it doesn ' t need to call jpeg_finish_decompress ( ) .
*/
//jpeg_finish_decompress( &cinfo );
2012-04-19 14:35:52 +08:00
jpeg_destroy_decompress ( & cinfo ) ;
/* wrap up decompression, destroy objects, free pointers and close open files */
bRet = true ;
} while ( 0 ) ;
2013-11-29 15:13:16 +08:00
if ( row_pointer [ 0 ] ! = nullptr )
{
free ( row_pointer [ 0 ] ) ;
} ;
2012-04-19 14:35:52 +08:00
return bRet ;
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithPngData ( const unsigned char * data , ssize_t dataLen )
2012-04-19 14:35:52 +08:00
{
2013-07-19 15:37:54 +08:00
// length of bytes to check if it is a valid png file
2012-04-26 17:36:32 +08:00
# define PNGSIGSIZE 8
2012-04-19 14:35:52 +08:00
bool bRet = false ;
2012-04-26 17:36:32 +08:00
png_byte header [ PNGSIGSIZE ] = { 0 } ;
2012-04-19 14:35:52 +08:00
png_structp png_ptr = 0 ;
png_infop info_ptr = 0 ;
do
{
// png header len is 8 bytes
2013-07-25 21:35:00 +08:00
CC_BREAK_IF ( dataLen < PNGSIGSIZE ) ;
2012-04-19 14:35:52 +08:00
// check the data is png or not
2013-07-25 21:35:00 +08:00
memcpy ( header , data , PNGSIGSIZE ) ;
2012-04-26 17:36:32 +08:00
CC_BREAK_IF ( png_sig_cmp ( header , 0 , PNGSIGSIZE ) ) ;
2012-04-19 14:35:52 +08:00
// init png_struct
png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING , 0 , 0 , 0 ) ;
CC_BREAK_IF ( ! png_ptr ) ;
// init png_info
info_ptr = png_create_info_struct ( png_ptr ) ;
CC_BREAK_IF ( ! info_ptr ) ;
2012-04-26 17:36:32 +08:00
2013-03-02 01:09:58 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA && CC_TARGET_PLATFORM != CC_PLATFORM_NACL)
2012-04-19 14:35:52 +08:00
CC_BREAK_IF ( setjmp ( png_jmpbuf ( png_ptr ) ) ) ;
# endif
2012-04-26 17:36:32 +08:00
2012-04-19 14:35:52 +08:00
// set the read call back function
tImageSource imageSource ;
2013-07-25 21:35:00 +08:00
imageSource . data = ( unsigned char * ) data ;
imageSource . size = dataLen ;
2012-04-19 14:35:52 +08:00
imageSource . offset = 0 ;
png_set_read_fn ( png_ptr , & imageSource , pngReadCallback ) ;
2012-04-26 17:36:32 +08:00
// read png header info
2013-07-19 15:37:54 +08:00
2012-04-26 17:36:32 +08:00
// read png file info
png_read_info ( png_ptr , info_ptr ) ;
2013-07-19 15:37:54 +08:00
2013-06-15 14:03:30 +08:00
_width = png_get_image_width ( png_ptr , info_ptr ) ;
_height = png_get_image_height ( png_ptr , info_ptr ) ;
2013-07-25 21:35:00 +08:00
png_byte bit_depth = png_get_bit_depth ( png_ptr , info_ptr ) ;
2012-04-26 17:36:32 +08:00
png_uint_32 color_type = png_get_color_type ( png_ptr , info_ptr ) ;
2012-08-29 21:50:09 +08:00
//CCLOG("color type %u", color_type);
2013-07-19 15:37:54 +08:00
2012-07-24 16:43:48 +08:00
// force palette images to be expanded to 24-bit RGB
// it may include alpha channel
if ( color_type = = PNG_COLOR_TYPE_PALETTE )
{
png_set_palette_to_rgb ( png_ptr ) ;
}
2012-09-16 05:19:14 +08:00
// low-bit-depth grayscale images are to be expanded to 8 bits
2013-07-25 21:35:00 +08:00
if ( color_type = = PNG_COLOR_TYPE_GRAY & & bit_depth < 8 )
2012-07-24 16:43:48 +08:00
{
2013-07-25 21:35:00 +08:00
bit_depth = 8 ;
2012-07-26 11:42:31 +08:00
png_set_expand_gray_1_2_4_to_8 ( png_ptr ) ;
2012-04-26 17:36:32 +08:00
}
2012-07-24 16:43:48 +08:00
// expand any tRNS chunk data into a full alpha channel
if ( png_get_valid ( png_ptr , info_ptr , PNG_INFO_tRNS ) )
{
png_set_tRNS_to_alpha ( png_ptr ) ;
}
// reduce images with 16-bit samples to 8 bits
2013-07-25 21:35:00 +08:00
if ( bit_depth = = 16 )
2012-04-26 17:36:32 +08:00
{
2012-07-24 16:43:48 +08:00
png_set_strip_16 ( png_ptr ) ;
2012-04-26 17:36:32 +08:00
}
2013-07-17 17:12:04 +08:00
// Expanded earlier for grayscale, now take care of palette and rgb
2013-07-25 21:35:00 +08:00
if ( bit_depth < 8 ) {
2013-07-19 15:37:54 +08:00
png_set_packing ( png_ptr ) ;
}
// update info
png_read_update_info ( png_ptr , info_ptr ) ;
2013-07-25 21:35:00 +08:00
bit_depth = png_get_bit_depth ( png_ptr , info_ptr ) ;
2013-07-19 15:37:54 +08:00
color_type = png_get_color_type ( png_ptr , info_ptr ) ;
switch ( color_type )
{
case PNG_COLOR_TYPE_GRAY :
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : I8 ;
2013-07-25 21:35:00 +08:00
break ;
2013-07-19 15:37:54 +08:00
case PNG_COLOR_TYPE_GRAY_ALPHA :
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : AI88 ;
2013-07-19 15:37:54 +08:00
break ;
case PNG_COLOR_TYPE_RGB :
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGB888 ;
2013-07-25 21:35:00 +08:00
break ;
2013-07-19 15:37:54 +08:00
case PNG_COLOR_TYPE_RGB_ALPHA :
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
2013-07-19 15:37:54 +08:00
break ;
default :
break ;
}
2012-04-19 14:35:52 +08:00
2012-04-26 17:36:32 +08:00
// read png data
2013-12-06 16:32:06 +08:00
png_size_t rowbytes ;
2013-06-15 14:03:30 +08:00
png_bytep * row_pointers = ( png_bytep * ) malloc ( sizeof ( png_bytep ) * _height ) ;
2013-07-19 15:37:54 +08:00
2012-07-24 16:43:48 +08:00
rowbytes = png_get_rowbytes ( png_ptr , info_ptr ) ;
2013-07-19 15:37:54 +08:00
2013-07-25 21:35:00 +08:00
_dataLen = rowbytes * _height ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2014-04-13 06:13:58 +08:00
if ( ! _data )
{
if ( row_pointers ! = nullptr )
{
free ( row_pointers ) ;
}
break ;
}
2013-07-19 15:37:54 +08:00
2013-06-15 14:03:30 +08:00
for ( unsigned short i = 0 ; i < _height ; + + i )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
row_pointers [ i ] = _data + i * rowbytes ;
2012-07-24 16:43:48 +08:00
}
png_read_image ( png_ptr , row_pointers ) ;
2013-07-19 15:37:54 +08:00
2014-02-13 16:22:41 +08:00
png_read_end ( png_ptr , nullptr ) ;
2013-07-19 15:37:54 +08:00
2014-06-03 15:06:15 +08:00
// premultiplied alpha for RGBA8888
if ( color_type = = PNG_COLOR_TYPE_RGB_ALPHA )
{
premultipliedAlpha ( ) ;
}
else
{
_preMulti = false ;
}
2012-07-24 16:43:48 +08:00
2013-11-29 15:13:16 +08:00
if ( row_pointers ! = nullptr )
{
free ( row_pointers ) ;
2014-04-13 06:13:58 +08:00
}
2012-07-26 11:42:31 +08:00
2012-07-24 16:43:48 +08:00
bRet = true ;
2012-04-19 14:35:52 +08:00
} while ( 0 ) ;
if ( png_ptr )
{
png_destroy_read_struct ( & png_ptr , ( info_ptr ) ? & info_ptr : 0 , 0 ) ;
}
return bRet ;
}
2013-08-01 15:53:52 +08:00
namespace
2012-05-23 18:20:51 +08:00
{
2013-08-06 16:14:36 +08:00
static tmsize_t tiffReadProc ( thandle_t fd , void * buf , tmsize_t size )
2012-05-29 16:21:23 +08:00
{
2013-08-06 16:14:36 +08:00
tImageSource * isource = ( tImageSource * ) fd ;
uint8 * ma ;
uint64 mb ;
unsigned long n ;
unsigned long o ;
tmsize_t p ;
ma = ( uint8 * ) buf ;
mb = size ;
p = 0 ;
while ( mb > 0 )
2012-05-25 10:58:28 +08:00
{
2013-08-06 16:14:36 +08:00
n = 0x80000000UL ;
if ( ( uint64 ) n > mb )
n = ( unsigned long ) mb ;
if ( ( int ) ( isource - > offset + n ) < = isource - > size )
{
memcpy ( ma , isource - > data + isource - > offset , n ) ;
isource - > offset + = n ;
o = n ;
}
else
{
return 0 ;
}
ma + = o ;
mb - = o ;
p + = o ;
if ( o ! = n )
{
break ;
}
2012-05-25 10:58:28 +08:00
}
2013-08-06 16:14:36 +08:00
return p ;
2012-05-29 16:21:23 +08:00
}
2013-08-06 16:14:36 +08:00
static tmsize_t tiffWriteProc ( thandle_t fd , void * buf , tmsize_t size )
2012-05-23 18:20:51 +08:00
{
2013-08-06 16:14:36 +08:00
CC_UNUSED_PARAM ( fd ) ;
CC_UNUSED_PARAM ( buf ) ;
CC_UNUSED_PARAM ( size ) ;
return 0 ;
}
static uint64 tiffSeekProc ( thandle_t fd , uint64 off , int whence )
{
tImageSource * isource = ( tImageSource * ) fd ;
uint64 ret = - 1 ;
do
2012-05-23 18:20:51 +08:00
{
2013-08-06 16:14:36 +08:00
if ( whence = = SEEK_SET )
{
CC_BREAK_IF ( off > = ( uint64 ) isource - > size ) ;
ret = isource - > offset = ( uint32 ) off ;
}
else if ( whence = = SEEK_CUR )
{
CC_BREAK_IF ( isource - > offset + off > = ( uint64 ) isource - > size ) ;
ret = isource - > offset + = ( uint32 ) off ;
}
else if ( whence = = SEEK_END )
{
CC_BREAK_IF ( off > = ( uint64 ) isource - > size ) ;
ret = isource - > offset = ( uint32 ) ( isource - > size - 1 - off ) ;
}
else
{
CC_BREAK_IF ( off > = ( uint64 ) isource - > size ) ;
ret = isource - > offset = ( uint32 ) off ;
}
} while ( 0 ) ;
return ret ;
}
2013-08-01 15:53:52 +08:00
2013-08-06 16:14:36 +08:00
static uint64 tiffSizeProc ( thandle_t fd )
{
tImageSource * pImageSrc = ( tImageSource * ) fd ;
return pImageSrc - > size ;
}
static int tiffCloseProc ( thandle_t fd )
{
CC_UNUSED_PARAM ( fd ) ;
return 0 ;
}
static int tiffMapProc ( thandle_t fd , void * * pbase , toff_t * psize )
{
CC_UNUSED_PARAM ( fd ) ;
CC_UNUSED_PARAM ( pbase ) ;
CC_UNUSED_PARAM ( psize ) ;
return 0 ;
}
static void tiffUnmapProc ( thandle_t fd , void * base , toff_t size )
{
CC_UNUSED_PARAM ( fd ) ;
CC_UNUSED_PARAM ( base ) ;
CC_UNUSED_PARAM ( size ) ;
}
2012-05-23 18:20:51 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithTiffData ( const unsigned char * data , ssize_t dataLen )
2012-05-23 17:26:06 +08:00
{
bool bRet = false ;
do
{
2012-05-23 18:20:51 +08:00
// set the read call back function
tImageSource imageSource ;
2013-08-12 17:05:19 +08:00
imageSource . data = data ;
2013-07-25 21:35:00 +08:00
imageSource . size = dataLen ;
2012-05-23 18:20:51 +08:00
imageSource . offset = 0 ;
TIFF * tif = TIFFClientOpen ( " file.tif " , " r " , ( thandle_t ) & imageSource ,
2013-08-06 16:14:36 +08:00
tiffReadProc , tiffWriteProc ,
tiffSeekProc , tiffCloseProc , tiffSizeProc ,
tiffMapProc ,
tiffUnmapProc ) ;
2012-05-23 18:20:51 +08:00
2014-02-13 16:22:41 +08:00
CC_BREAK_IF ( nullptr = = tif ) ;
2012-05-23 17:26:06 +08:00
2012-05-29 17:11:33 +08:00
uint32 w = 0 , h = 0 ;
uint16 bitsPerSample = 0 , samplePerPixel = 0 , planarConfig = 0 ;
size_t npixels = 0 ;
2012-05-29 16:21:23 +08:00
TIFFGetField ( tif , TIFFTAG_IMAGEWIDTH , & w ) ;
TIFFGetField ( tif , TIFFTAG_IMAGELENGTH , & h ) ;
TIFFGetField ( tif , TIFFTAG_BITSPERSAMPLE , & bitsPerSample ) ;
TIFFGetField ( tif , TIFFTAG_SAMPLESPERPIXEL , & samplePerPixel ) ;
TIFFGetField ( tif , TIFFTAG_PLANARCONFIG , & planarConfig ) ;
npixels = w * h ;
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
2013-06-15 14:03:30 +08:00
_width = w ;
_height = h ;
2012-05-29 16:21:23 +08:00
2013-07-25 21:35:00 +08:00
_dataLen = npixels * sizeof ( uint32 ) ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2012-05-29 16:21:23 +08:00
2012-05-25 16:52:47 +08:00
uint32 * raster = ( uint32 * ) _TIFFmalloc ( npixels * sizeof ( uint32 ) ) ;
2014-02-13 16:22:41 +08:00
if ( raster ! = nullptr )
2012-05-25 16:52:47 +08:00
{
if ( TIFFReadRGBAImageOriented ( tif , w , h , raster , ORIENTATION_TOPLEFT , 0 ) )
{
2013-03-03 10:32:09 +08:00
/* the raster data is pre-multiplied by the alpha component
2013-07-25 21:35:00 +08:00
after invoking TIFFReadRGBAImageOriented */
2013-06-15 14:03:30 +08:00
_preMulti = true ;
2012-05-29 16:21:23 +08:00
2013-06-15 14:03:30 +08:00
memcpy ( _data , raster , npixels * sizeof ( uint32 ) ) ;
2012-05-25 16:52:47 +08:00
}
_TIFFfree ( raster ) ;
2012-05-29 16:21:23 +08:00
}
2012-05-23 17:26:06 +08:00
TIFFClose ( tif ) ;
bRet = true ;
} while ( 0 ) ;
return bRet ;
}
2013-08-06 16:14:36 +08:00
namespace
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
bool testFormatForPvr2TCSupport ( PVR2TexturePixelFormat format )
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
if ( ! Configuration : : getInstance ( ) - > supportsPVRTC ( ) )
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
if ( format = = PVR2TexturePixelFormat : : PVRTC2BPP_RGBA | |
format = = PVR2TexturePixelFormat : : PVRTC4BPP_RGBA )
{
return false ;
}
2013-07-25 21:35:00 +08:00
}
2013-08-06 16:14:36 +08:00
return true ;
2013-07-25 21:35:00 +08:00
}
2013-08-06 16:14:36 +08:00
bool testFormatForPvr3TCSupport ( PVR3TexturePixelFormat format )
{
if ( ! Configuration : : getInstance ( ) - > supportsPVRTC ( ) )
{
if ( format = = PVR3TexturePixelFormat : : PVRTC2BPP_RGB | |
format = = PVR3TexturePixelFormat : : PVRTC2BPP_RGBA | |
format = = PVR3TexturePixelFormat : : PVRTC4BPP_RGB | |
format = = PVR3TexturePixelFormat : : PVRTC4BPP_RGBA )
{
return false ;
}
}
return true ;
2013-07-25 21:35:00 +08:00
}
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithPVRv2Data ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-07-29 11:40:18 +08:00
int dataLength = 0 , dataOffset = 0 , dataSize = 0 ;
int blockSize = 0 , widthBlocks = 0 , heightBlocks = 0 ;
int width = 0 , height = 0 ;
2013-07-25 21:35:00 +08:00
//Cast first sizeof(PVRTexHeader) bytes of data stream as PVRTexHeader
2013-08-12 17:05:19 +08:00
const PVRv2TexHeader * header = static_cast < const PVRv2TexHeader * > ( static_cast < const void * > ( data ) ) ;
2013-07-25 21:35:00 +08:00
//Make sure that tag is in correct formatting
2013-08-06 16:14:36 +08:00
if ( memcmp ( & header - > pvrTag , gPVRTexIdentifier , strlen ( gPVRTexIdentifier ) ) ! = 0 )
2013-07-25 21:35:00 +08:00
{
return false ;
}
Configuration * configuration = Configuration : : getInstance ( ) ;
2013-07-30 11:10:05 +08:00
_hasPremultipliedAlpha = false ;
2013-08-06 16:14:36 +08:00
unsigned int flags = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > flags ) ;
PVR2TexturePixelFormat formatFlags = static_cast < PVR2TexturePixelFormat > ( flags & PVR_TEXTURE_FLAG_TYPE_MASK ) ;
2013-08-01 15:53:52 +08:00
bool flipped = ( flags & ( unsigned int ) PVR2TextureFlag : : VerticalFlip ) ? true : false ;
2013-07-25 21:35:00 +08:00
if ( flipped )
{
CCLOG ( " cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool " ) ;
}
if ( ! configuration - > supportsNPOT ( ) & &
2013-12-27 15:06:16 +08:00
( static_cast < int > ( header - > width ) ! = ccNextPOT ( header - > width )
| | static_cast < int > ( header - > height ) ! = ccNextPOT ( header - > height ) ) )
2013-07-25 21:35:00 +08:00
{
CCLOG ( " cocos2d: ERROR: Loading an NPOT texture (%dx%d) but is not supported on this device " , header - > width , header - > height ) ;
return false ;
}
2013-08-06 16:14:36 +08:00
if ( ! testFormatForPvr2TCSupport ( formatFlags ) )
2013-07-25 21:35:00 +08:00
{
2013-11-06 09:36:44 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant " , ( int ) formatFlags ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
if ( v2_pixel_formathash . find ( formatFlags ) = = v2_pixel_formathash . end ( ) )
{
2013-11-06 09:36:44 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant " , ( int ) formatFlags ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
2013-08-07 11:20:41 +08:00
auto it = Texture2D : : getPixelFormatInfoMap ( ) . find ( v2_pixel_formathash . at ( formatFlags ) ) ;
2013-07-25 21:35:00 +08:00
2013-08-07 11:20:41 +08:00
if ( it = = Texture2D : : getPixelFormatInfoMap ( ) . end ( ) )
2013-07-25 21:35:00 +08:00
{
2013-11-06 09:36:44 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant " , ( int ) formatFlags ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
_renderFormat = it - > first ;
//Reset num of mipmaps
_numberOfMipmaps = 0 ;
//Get size of mipmap
_width = width = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > width ) ;
_height = height = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > height ) ;
//Get ptr to where data starts..
dataLength = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > dataLength ) ;
//Move by size of header
2013-08-01 15:53:52 +08:00
_dataLen = dataLen - sizeof ( PVRv2TexHeader ) ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-01 15:53:52 +08:00
memcpy ( _data , ( unsigned char * ) data + sizeof ( PVRv2TexHeader ) , _dataLen ) ;
2013-07-25 21:35:00 +08:00
// Calculate the data size for each texture level and respect the minimum number of blocks
while ( dataOffset < dataLength )
{
switch ( formatFlags ) {
2013-08-01 15:53:52 +08:00
case PVR2TexturePixelFormat : : PVRTC2BPP_RGBA :
2013-07-25 21:35:00 +08:00
blockSize = 8 * 4 ; // Pixel by pixel block size for 2bpp
widthBlocks = width / 8 ;
heightBlocks = height / 4 ;
break ;
2013-08-01 15:53:52 +08:00
case PVR2TexturePixelFormat : : PVRTC4BPP_RGBA :
2013-07-25 21:35:00 +08:00
blockSize = 4 * 4 ; // Pixel by pixel block size for 4bpp
widthBlocks = width / 4 ;
heightBlocks = height / 4 ;
break ;
2013-08-01 15:53:52 +08:00
case PVR2TexturePixelFormat : : BGRA8888 :
2013-07-25 21:35:00 +08:00
if ( Configuration : : getInstance ( ) - > supportsBGRA8888 ( ) = = false )
{
CCLOG ( " cocos2d: Image. 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 * it - > second . bpp ) / 8 ) ;
2013-07-29 11:40:18 +08:00
int packetLength = ( dataLength - dataOffset ) ;
2013-07-25 21:35:00 +08:00
packetLength = packetLength > dataSize ? dataSize : packetLength ;
//Make record to the mipmaps array and increment counter
_mipmaps [ _numberOfMipmaps ] . address = _data + dataOffset ;
_mipmaps [ _numberOfMipmaps ] . len = packetLength ;
_numberOfMipmaps + + ;
dataOffset + = packetLength ;
//Update width and height to the next lower power of two
width = MAX ( width > > 1 , 1 ) ;
height = MAX ( height > > 1 , 1 ) ;
}
return true ;
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithPVRv3Data ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-11-13 11:22:34 +08:00
if ( static_cast < size_t > ( dataLen ) < sizeof ( PVRv3TexHeader ) )
2013-07-25 21:35:00 +08:00
{
return false ;
}
2013-08-12 17:05:19 +08:00
const PVRv3TexHeader * header = static_cast < const PVRv3TexHeader * > ( static_cast < const void * > ( data ) ) ;
2013-07-25 21:35:00 +08:00
// validate version
if ( CC_SWAP_INT32_BIG_TO_HOST ( header - > version ) ! = 0x50565203 )
{
CCLOG ( " cocos2d: WARNING: pvr file version mismatch " ) ;
return false ;
}
// parse pixel format
2013-08-06 16:14:36 +08:00
PVR3TexturePixelFormat pixelFormat = static_cast < PVR3TexturePixelFormat > ( header - > pixelFormat ) ;
2013-07-25 21:35:00 +08:00
2013-08-06 16:14:36 +08:00
if ( ! testFormatForPvr3TCSupport ( pixelFormat ) )
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant " ,
static_cast < unsigned long long > ( pixelFormat ) ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
if ( v3_pixel_formathash . find ( pixelFormat ) = = v3_pixel_formathash . end ( ) )
{
2013-08-06 16:14:36 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant " ,
static_cast < unsigned long long > ( pixelFormat ) ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
2013-08-07 11:20:41 +08:00
auto it = Texture2D : : getPixelFormatInfoMap ( ) . find ( v3_pixel_formathash . at ( pixelFormat ) ) ;
2013-07-25 21:35:00 +08:00
2013-08-07 11:20:41 +08:00
if ( it = = Texture2D : : getPixelFormatInfoMap ( ) . end ( ) )
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
CCLOG ( " cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant " ,
static_cast < unsigned long long > ( pixelFormat ) ) ;
2013-07-25 21:35:00 +08:00
return false ;
}
_renderFormat = it - > first ;
// flags
2013-07-29 11:40:18 +08:00
int flags = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > flags ) ;
2013-07-26 17:34:44 +08:00
// PVRv3 specifies premultiply alpha in a flag -- should always respect this in PVRv3 files
2013-08-01 15:53:52 +08:00
if ( flags & ( unsigned int ) PVR3TextureFlag : : PremultipliedAlpha )
2013-07-26 17:34:44 +08:00
{
_preMulti = true ;
}
2013-07-25 21:35:00 +08:00
// sizing
2013-07-29 11:40:18 +08:00
int width = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > width ) ;
int height = CC_SWAP_INT32_LITTLE_TO_HOST ( header - > height ) ;
2013-07-25 21:35:00 +08:00
_width = width ;
_height = height ;
2013-07-29 11:40:18 +08:00
int dataOffset = 0 , dataSize = 0 ;
int blockSize = 0 , widthBlocks = 0 , heightBlocks = 0 ;
2013-07-25 21:35:00 +08:00
2013-08-01 15:53:52 +08:00
_dataLen = dataLen - ( sizeof ( PVRv3TexHeader ) + header - > metadataLength ) ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-06 16:14:36 +08:00
memcpy ( _data , static_cast < const unsigned char * > ( data ) + sizeof ( PVRv3TexHeader ) + header - > metadataLength , _dataLen ) ;
2013-07-25 21:35:00 +08:00
_numberOfMipmaps = header - > numberOfMipmaps ;
2013-08-01 15:53:52 +08:00
CCAssert ( _numberOfMipmaps < MIPMAP_MAX , " Image: Maximum number of mimpaps reached. Increate the CC_MIPMAP_MAX value " ) ;
2013-07-25 21:35:00 +08:00
2013-07-29 11:40:18 +08:00
for ( int i = 0 ; i < _numberOfMipmaps ; i + + )
2013-07-25 21:35:00 +08:00
{
2013-08-01 15:53:52 +08:00
switch ( ( PVR3TexturePixelFormat ) pixelFormat )
2013-07-25 21:35:00 +08:00
{
2013-08-01 15:53:52 +08:00
case PVR3TexturePixelFormat : : PVRTC2BPP_RGB :
case PVR3TexturePixelFormat : : PVRTC2BPP_RGBA :
2013-07-25 21:35:00 +08:00
blockSize = 8 * 4 ; // Pixel by pixel block size for 2bpp
widthBlocks = width / 8 ;
heightBlocks = height / 4 ;
break ;
2013-08-01 15:53:52 +08:00
case PVR3TexturePixelFormat : : PVRTC4BPP_RGB :
case PVR3TexturePixelFormat : : PVRTC4BPP_RGBA :
2013-07-25 21:35:00 +08:00
blockSize = 4 * 4 ; // Pixel by pixel block size for 4bpp
widthBlocks = width / 4 ;
heightBlocks = height / 4 ;
break ;
2013-08-01 15:53:52 +08:00
case PVR3TexturePixelFormat : : BGRA8888 :
2013-07-25 21:35:00 +08:00
if ( ! Configuration : : getInstance ( ) - > supportsBGRA8888 ( ) )
{
CCLOG ( " cocos2d: Image. 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 * it - > second . bpp ) / 8 ) ;
2013-12-05 17:19:01 +08:00
auto packetLength = _dataLen - dataOffset ;
2013-07-25 21:35:00 +08:00
packetLength = packetLength > dataSize ? dataSize : packetLength ;
_mipmaps [ i ] . address = _data + dataOffset ;
2013-12-06 16:32:06 +08:00
_mipmaps [ i ] . len = static_cast < int > ( packetLength ) ;
2013-07-25 21:35:00 +08:00
dataOffset + = packetLength ;
CCAssert ( dataOffset < = _dataLen , " CCTexurePVR: Invalid lenght " ) ;
width = MAX ( width > > 1 , 1 ) ;
height = MAX ( height > > 1 , 1 ) ;
}
return true ;
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithETCData ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-08-06 16:14:36 +08:00
const etc1_byte * header = static_cast < const etc1_byte * > ( data ) ;
2013-07-26 17:34:44 +08:00
//check the data
if ( ! etc1_pkm_is_valid ( header ) )
{
return false ;
}
_width = etc1_pkm_get_width ( header ) ;
_height = etc1_pkm_get_height ( header ) ;
if ( 0 = = _width | | 0 = = _height )
{
return false ;
}
2013-07-25 21:35:00 +08:00
2013-07-26 17:34:44 +08:00
if ( Configuration : : getInstance ( ) - > supportsETC ( ) )
{
//old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy.
# ifdef GL_ETC1_RGB8_OES
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : ETC ;
2013-07-26 17:34:44 +08:00
_dataLen = dataLen - ETC_PKM_HEADER_SIZE ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-06 16:14:36 +08:00
memcpy ( _data , static_cast < const unsigned char * > ( data ) + ETC_PKM_HEADER_SIZE , _dataLen ) ;
2013-07-26 17:34:44 +08:00
return true ;
# endif
}
else
{
2013-09-24 08:03:28 +08:00
CCLOG ( " cocos2d: Hardware ETC1 decoder not present. Using software decoder " ) ;
2013-07-26 17:34:44 +08:00
//if it is not gles or device do not support ETC, decode texture by software
int bytePerPixel = 3 ;
unsigned int stride = _width * bytePerPixel ;
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGB888 ;
2013-07-26 17:34:44 +08:00
_dataLen = _width * _height * bytePerPixel ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-07-26 17:34:44 +08:00
2013-08-06 16:14:36 +08:00
if ( etc1_decode_image ( static_cast < const unsigned char * > ( data ) + ETC_PKM_HEADER_SIZE , static_cast < etc1_byte * > ( _data ) , _width , _height , bytePerPixel , stride ) ! = 0 )
2013-07-26 17:34:44 +08:00
{
_dataLen = 0 ;
2013-11-29 15:13:16 +08:00
if ( _data ! = nullptr )
{
free ( _data ) ;
}
2013-07-26 17:34:44 +08:00
return false ;
}
return true ;
}
return false ;
2013-07-25 21:35:00 +08:00
}
2013-11-29 14:31:42 +08:00
bool Image : : initWithTGAData ( tImageTGA * tgaData )
{
bool ret = false ;
do
{
CC_BREAK_IF ( tgaData = = nullptr ) ;
// tgaLoadBuffer only support type 2, 3, 10
if ( 2 = = tgaData - > type | | 10 = = tgaData - > type )
{
// true color
// unsupport RGB555
if ( tgaData - > pixelDepth = = 16 )
{
_renderFormat = Texture2D : : PixelFormat : : RGB5A1 ;
}
else if ( tgaData - > pixelDepth = = 24 )
{
_renderFormat = Texture2D : : PixelFormat : : RGB888 ;
}
else if ( tgaData - > pixelDepth = = 32 )
{
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
}
else
{
CCLOG ( " Image WARNING: unsupport true color tga data pixel format. FILE: %s " , _filePath . c_str ( ) ) ;
break ;
}
}
else if ( 3 = = tgaData - > type )
{
// gray
if ( 8 = = tgaData - > pixelDepth )
{
_renderFormat = Texture2D : : PixelFormat : : I8 ;
}
else
{
// actually this won't happen, if it happens, maybe the image file is not a tga
CCLOG ( " Image WARNING: unsupport gray tga data pixel format. FILE: %s " , _filePath . c_str ( ) ) ;
break ;
}
}
_width = tgaData - > width ;
_height = tgaData - > height ;
_data = tgaData - > imageData ;
_dataLen = _width * _height * tgaData - > pixelDepth / 8 ;
_fileType = Format : : TGA ;
2014-06-03 15:06:15 +08:00
2014-06-03 16:22:50 +08:00
_preMulti = false ;
2014-06-03 15:06:15 +08:00
2013-11-29 14:31:42 +08:00
ret = true ;
} while ( false ) ;
2014-01-09 15:26:05 +08:00
if ( ret )
2013-11-29 14:31:42 +08:00
{
const unsigned char tgaSuffix [ ] = " .tga " ;
for ( int i = 0 ; i < 4 ; + + i )
{
2013-12-04 15:34:05 +08:00
if ( tolower ( _filePath [ _filePath . length ( ) - i - 1 ] ) ! = tgaSuffix [ 3 - i ] )
2013-11-29 14:31:42 +08:00
{
CCLOG ( " Image WARNING: the image file suffix is not tga, but parsed as a tga image file. FILE: %s " , _filePath . c_str ( ) ) ;
break ;
} ;
}
}
else
{
2014-04-09 20:41:09 +08:00
if ( tgaData & & tgaData - > imageData ! = nullptr )
2013-11-29 14:31:42 +08:00
{
free ( tgaData - > imageData ) ;
2014-01-09 15:26:05 +08:00
_data = nullptr ;
2013-11-29 14:31:42 +08:00
}
}
return ret ;
}
2013-08-09 12:54:05 +08:00
namespace
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
static const uint32_t makeFourCC ( char ch0 , char ch1 , char ch2 , char ch3 )
{
const uint32_t fourCC = ( ( uint32_t ) ( char ) ( ch0 ) | ( ( uint32_t ) ( char ) ( ch1 ) < < 8 ) | ( ( uint32_t ) ( char ) ( ch2 ) < < 16 ) | ( ( uint32_t ) ( char ) ( ch3 ) < < 24 ) ) ;
return fourCC ;
}
2013-08-06 11:19:45 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithS3TCData ( const unsigned char * data , ssize_t dataLen )
2013-08-06 11:19:45 +08:00
{
2013-08-07 16:39:05 +08:00
const uint32_t FOURCC_DXT1 = makeFourCC ( ' D ' , ' X ' , ' T ' , ' 1 ' ) ;
const uint32_t FOURCC_DXT3 = makeFourCC ( ' D ' , ' X ' , ' T ' , ' 3 ' ) ;
const uint32_t FOURCC_DXT5 = makeFourCC ( ' D ' , ' X ' , ' T ' , ' 5 ' ) ;
2013-08-06 11:19:45 +08:00
/* load the .dds file */
2013-08-09 12:54:05 +08:00
S3TCTexHeader * header = ( S3TCTexHeader * ) data ;
2013-11-29 15:13:16 +08:00
unsigned char * pixelData = static_cast < unsigned char * > ( malloc ( ( dataLen - sizeof ( S3TCTexHeader ) ) * sizeof ( unsigned char ) ) ) ;
2013-08-12 17:05:19 +08:00
memcpy ( ( void * ) pixelData , data + sizeof ( S3TCTexHeader ) , dataLen - sizeof ( S3TCTexHeader ) ) ;
2013-08-06 11:19:45 +08:00
2013-08-09 12:54:05 +08:00
_width = header - > ddsd . width ;
_height = header - > ddsd . height ;
2014-02-20 13:48:09 +08:00
_numberOfMipmaps = MAX ( 1 , header - > ddsd . DUMMYUNIONNAMEN2 . mipMapCount ) ; //if dds header reports 0 mipmaps, set to 1 to force correct software decoding (if needed).
2013-08-16 11:02:44 +08:00
_dataLen = 0 ;
2013-08-09 12:54:05 +08:00
int blockSize = ( FOURCC_DXT1 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC ) ? 8 : 16 ;
2013-08-07 16:39:05 +08:00
2014-02-20 13:48:09 +08:00
/* calculate the dataLen */
2013-08-06 11:19:45 +08:00
int width = _width ;
int height = _height ;
2013-08-09 12:54:05 +08:00
if ( Configuration : : getInstance ( ) - > supportsS3TC ( ) ) //compressed data length
2013-08-06 11:19:45 +08:00
{
2013-08-09 12:54:05 +08:00
_dataLen = dataLen - sizeof ( S3TCTexHeader ) ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-09 12:54:05 +08:00
memcpy ( ( void * ) _data , ( void * ) pixelData , _dataLen ) ;
}
else //decompressed data length
2013-08-06 11:19:45 +08:00
{
2013-09-08 11:26:38 +08:00
for ( int i = 0 ; i < _numberOfMipmaps & & ( width | | height ) ; + + i )
2013-08-06 11:19:45 +08:00
{
if ( width = = 0 ) width = 1 ;
if ( height = = 0 ) height = 1 ;
_dataLen + = ( height * width * 4 ) ;
width > > = 1 ;
height > > = 1 ;
}
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-06 11:19:45 +08:00
}
2014-02-19 06:42:41 +08:00
/* if hardware supports s3tc, set pixelformat before loading mipmaps, to support non-mipmapped textures */
if ( Configuration : : getInstance ( ) - > supportsS3TC ( ) )
{ //decode texture throught hardware
if ( FOURCC_DXT1 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
{
_renderFormat = Texture2D : : PixelFormat : : S3TC_DXT1 ;
}
else if ( FOURCC_DXT3 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
{
_renderFormat = Texture2D : : PixelFormat : : S3TC_DXT3 ;
}
else if ( FOURCC_DXT5 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
{
_renderFormat = Texture2D : : PixelFormat : : S3TC_DXT5 ;
}
2014-02-20 13:48:09 +08:00
} else { //will software decode
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
2014-02-19 06:42:41 +08:00
}
2013-08-06 11:19:45 +08:00
/* load the mipmaps */
2013-08-07 16:39:05 +08:00
2013-08-09 14:37:47 +08:00
int encodeOffset = 0 ;
int decodeOffset = 0 ;
2013-08-09 12:54:05 +08:00
width = _width ; height = _height ;
2013-08-06 11:19:45 +08:00
2013-09-08 11:26:38 +08:00
for ( int i = 0 ; i < _numberOfMipmaps & & ( width | | height ) ; + + i )
2013-08-06 11:19:45 +08:00
{
if ( width = = 0 ) width = 1 ;
if ( height = = 0 ) height = 1 ;
int size = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize ;
if ( Configuration : : getInstance ( ) - > supportsS3TC ( ) )
2013-08-07 16:39:05 +08:00
{ //decode texture throught hardware
2013-08-09 14:37:47 +08:00
_mipmaps [ i ] . address = ( unsigned char * ) _data + encodeOffset ;
2013-08-06 11:19:45 +08:00
_mipmaps [ i ] . len = size ;
}
else
2013-08-07 16:39:05 +08:00
{ //if it is not gles or device do not support S3TC, decode texture by software
2013-09-24 08:03:28 +08:00
CCLOG ( " cocos2d: Hardware S3TC decoder not present. Using software decoder " ) ;
2013-08-06 11:19:45 +08:00
int bytePerPixel = 4 ;
unsigned int stride = width * bytePerPixel ;
std : : vector < unsigned char > decodeImageData ( stride * height ) ;
2013-08-09 12:54:05 +08:00
if ( FOURCC_DXT1 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , S3TCDecodeFlag : : DXT1 ) ;
2013-08-06 11:19:45 +08:00
}
2013-08-09 12:54:05 +08:00
else if ( FOURCC_DXT3 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , S3TCDecodeFlag : : DXT3 ) ;
2013-08-06 11:19:45 +08:00
}
2013-08-09 12:54:05 +08:00
else if ( FOURCC_DXT5 = = header - > ddsd . DUMMYUNIONNAMEN4 . ddpfPixelFormat . fourCC )
2013-08-06 11:19:45 +08:00
{
2013-08-09 14:37:47 +08:00
s3tc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , S3TCDecodeFlag : : DXT5 ) ;
2013-08-06 11:19:45 +08:00
}
2013-08-09 14:37:47 +08:00
_mipmaps [ i ] . address = ( unsigned char * ) _data + decodeOffset ;
2013-08-06 11:19:45 +08:00
_mipmaps [ i ] . len = ( stride * height ) ;
memcpy ( ( void * ) _mipmaps [ i ] . address , ( void * ) & decodeImageData [ 0 ] , _mipmaps [ i ] . len ) ;
2013-08-09 14:37:47 +08:00
decodeOffset + = stride * height ;
2013-08-06 11:19:45 +08:00
}
2013-08-09 15:00:26 +08:00
encodeOffset + = size ;
2013-08-06 11:19:45 +08:00
width > > = 1 ;
height > > = 1 ;
}
2013-08-07 16:39:05 +08:00
/* end load the mipmaps */
2013-11-29 15:13:16 +08:00
if ( pixelData ! = nullptr )
{
free ( pixelData ) ;
} ;
2013-08-06 11:19:45 +08:00
return true ;
}
2013-08-16 14:27:13 +08:00
2013-12-05 17:19:01 +08:00
bool Image : : initWithATITCData ( const unsigned char * data , ssize_t dataLen )
2013-08-16 11:02:44 +08:00
{
/* load the .ktx file */
ATITCTexHeader * header = ( ATITCTexHeader * ) data ;
_width = header - > pixelWidth ;
_height = header - > pixelHeight ;
_numberOfMipmaps = header - > numberOfMipmapLevels ;
int blockSize = 0 ;
switch ( header - > glInternalFormat )
{
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGB_AMD :
2013-08-16 11:02:44 +08:00
blockSize = 8 ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
blockSize = 16 ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
blockSize = 16 ;
break ;
default :
break ;
}
/* pixelData point to the compressed data address */
unsigned char * pixelData = ( unsigned char * ) data + sizeof ( ATITCTexHeader ) + header - > bytesOfKeyValueData + 4 ;
/* caculate the dataLen */
int width = _width ;
int height = _height ;
if ( Configuration : : getInstance ( ) - > supportsATITC ( ) ) //compressed data length
{
_dataLen = dataLen - sizeof ( ATITCTexHeader ) - header - > bytesOfKeyValueData - 4 ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-16 11:02:44 +08:00
memcpy ( ( void * ) _data , ( void * ) pixelData , _dataLen ) ;
}
else //decompressed data length
{
2013-09-08 11:26:38 +08:00
for ( int i = 0 ; i < _numberOfMipmaps & & ( width | | height ) ; + + i )
2013-08-16 11:02:44 +08:00
{
if ( width = = 0 ) width = 1 ;
if ( height = = 0 ) height = 1 ;
_dataLen + = ( height * width * 4 ) ;
width > > = 1 ;
height > > = 1 ;
}
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-08-16 11:02:44 +08:00
}
/* load the mipmaps */
int encodeOffset = 0 ;
int decodeOffset = 0 ;
width = _width ; height = _height ;
2013-09-08 11:26:38 +08:00
for ( int i = 0 ; i < _numberOfMipmaps & & ( width | | height ) ; + + i )
2013-08-16 11:02:44 +08:00
{
if ( width = = 0 ) width = 1 ;
if ( height = = 0 ) height = 1 ;
int size = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize ;
if ( Configuration : : getInstance ( ) - > supportsATITC ( ) )
{
/* decode texture throught hardware */
CCLOG ( " this is atitc H decode " ) ;
switch ( header - > glInternalFormat )
{
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGB_AMD :
2013-08-16 11:02:44 +08:00
_renderFormat = Texture2D : : PixelFormat : : ATC_RGB ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
_renderFormat = Texture2D : : PixelFormat : : ATC_EXPLICIT_ALPHA ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
_renderFormat = Texture2D : : PixelFormat : : ATC_INTERPOLATED_ALPHA ;
break ;
default :
break ;
}
_mipmaps [ i ] . address = ( unsigned char * ) _data + encodeOffset ;
_mipmaps [ i ] . len = size ;
}
else
{
/* if it is not gles or device do not support ATITC, decode texture by software */
2013-09-24 08:03:28 +08:00
CCLOG ( " cocos2d: Hardware ATITC decoder not present. Using software decoder " ) ;
2013-08-16 11:02:44 +08:00
int bytePerPixel = 4 ;
unsigned int stride = width * bytePerPixel ;
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
std : : vector < unsigned char > decodeImageData ( stride * height ) ;
switch ( header - > glInternalFormat )
{
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGB_AMD :
2013-08-16 11:02:44 +08:00
atitc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , ATITCDecodeFlag : : ATC_RGB ) ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
atitc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , ATITCDecodeFlag : : ATC_EXPLICIT_ALPHA ) ;
break ;
2013-08-16 14:03:30 +08:00
case CC_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD :
2013-08-16 11:02:44 +08:00
atitc_decode ( pixelData + encodeOffset , & decodeImageData [ 0 ] , width , height , ATITCDecodeFlag : : ATC_INTERPOLATED_ALPHA ) ;
break ;
default :
break ;
}
_mipmaps [ i ] . address = ( unsigned char * ) _data + decodeOffset ;
_mipmaps [ i ] . len = ( stride * height ) ;
memcpy ( ( void * ) _mipmaps [ i ] . address , ( void * ) & decodeImageData [ 0 ] , _mipmaps [ i ] . len ) ;
decodeOffset + = stride * height ;
}
encodeOffset + = ( size + 4 ) ;
width > > = 1 ;
height > > = 1 ;
}
/* end load the mipmaps */
return true ;
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithPVRData ( const unsigned char * data , ssize_t dataLen )
2013-07-25 21:35:00 +08:00
{
2013-07-29 14:04:51 +08:00
return initWithPVRv2Data ( data , dataLen ) | | initWithPVRv3Data ( data , dataLen ) ;
2013-07-25 21:35:00 +08:00
}
2013-12-05 17:19:01 +08:00
bool Image : : initWithWebpData ( const unsigned char * data , ssize_t dataLen )
2013-07-29 17:56:36 +08:00
{
2014-03-22 20:51:39 +08:00
bool bRet = false ;
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
CCLOG ( " WEBP image format not supported on WinRT or WP8 " ) ;
# else
2013-07-29 17:56:36 +08:00
do
{
WebPDecoderConfig config ;
if ( WebPInitDecoderConfig ( & config ) = = 0 ) break ;
2013-08-06 16:14:36 +08:00
if ( WebPGetFeatures ( static_cast < const uint8_t * > ( data ) , dataLen , & config . input ) ! = VP8_STATUS_OK ) break ;
2013-07-29 17:56:36 +08:00
if ( config . input . width = = 0 | | config . input . height = = 0 ) break ;
config . output . colorspace = MODE_RGBA ;
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
_width = config . input . width ;
_height = config . input . height ;
2013-11-11 07:28:27 +08:00
_dataLen = _width * _height * 4 ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-07-29 17:56:36 +08:00
2013-08-06 16:14:36 +08:00
config . output . u . RGBA . rgba = static_cast < uint8_t * > ( _data ) ;
2013-07-29 17:56:36 +08:00
config . output . u . RGBA . stride = _width * 4 ;
2013-11-11 07:28:27 +08:00
config . output . u . RGBA . size = _dataLen ;
2013-07-29 17:56:36 +08:00
config . output . is_external_memory = 1 ;
2013-08-06 16:14:36 +08:00
if ( WebPDecode ( static_cast < const uint8_t * > ( data ) , dataLen , & config ) ! = VP8_STATUS_OK )
2013-07-29 17:56:36 +08:00
{
2013-11-29 15:13:16 +08:00
free ( _data ) ;
2014-02-13 16:22:41 +08:00
_data = nullptr ;
2013-07-29 17:56:36 +08:00
break ;
}
bRet = true ;
} while ( 0 ) ;
2014-03-22 20:51:39 +08:00
# endif
2013-07-29 17:56:36 +08:00
return bRet ;
}
2014-03-22 20:51:39 +08:00
2013-12-05 17:19:01 +08:00
bool Image : : initWithRawData ( const unsigned char * data , ssize_t dataLen , int width , int height , int bitsPerComponent , bool preMulti )
2012-04-19 14:35:52 +08:00
{
bool bRet = false ;
do
{
2013-08-06 16:14:36 +08:00
CC_BREAK_IF ( 0 = = width | | 0 = = height ) ;
2012-04-19 14:35:52 +08:00
2013-08-06 16:14:36 +08:00
_height = height ;
_width = width ;
_preMulti = preMulti ;
2013-07-27 22:06:30 +08:00
_renderFormat = Texture2D : : PixelFormat : : RGBA8888 ;
2012-04-19 14:35:52 +08:00
2012-09-16 05:19:14 +08:00
// only RGBA8888 supported
2013-08-06 16:14:36 +08:00
int bytesPerComponent = 4 ;
_dataLen = height * width * bytesPerComponent ;
2013-11-29 15:13:16 +08:00
_data = static_cast < unsigned char * > ( malloc ( _dataLen * sizeof ( unsigned char ) ) ) ;
2013-06-15 14:03:30 +08:00
CC_BREAK_IF ( ! _data ) ;
2013-07-25 21:35:00 +08:00
memcpy ( _data , data , _dataLen ) ;
2012-04-19 14:35:52 +08:00
bRet = true ;
} while ( 0 ) ;
2013-05-18 08:11:52 +08:00
2012-04-19 14:35:52 +08:00
return bRet ;
}
2013-08-08 14:11:22 +08:00
2013-08-01 15:53:52 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
2013-11-15 09:19:16 +08:00
bool Image : : saveToFile ( const std : : string & filename , bool bIsToRGB )
2012-04-19 14:35:52 +08:00
{
2013-07-27 22:06:30 +08:00
//only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data
if ( isCompressed ( ) | | ( _renderFormat ! = Texture2D : : PixelFormat : : RGB888 & & _renderFormat ! = Texture2D : : PixelFormat : : RGBA8888 ) )
2013-07-26 17:34:44 +08:00
{
2013-07-27 22:06:30 +08:00
CCLOG ( " cocos2d: Image: saveToFile is only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data for now " ) ;
2013-07-26 17:34:44 +08:00
return false ;
}
2012-04-19 14:35:52 +08:00
bool bRet = false ;
do
{
2013-11-15 09:19:16 +08:00
CC_BREAK_IF ( filename . size ( ) < = 4 ) ;
2012-04-19 14:35:52 +08:00
2013-11-15 09:19:16 +08:00
std : : string strLowerCasePath ( filename ) ;
2012-04-19 14:35:52 +08:00
for ( unsigned int i = 0 ; i < strLowerCasePath . length ( ) ; + + i )
{
2013-11-15 09:19:16 +08:00
strLowerCasePath [ i ] = tolower ( filename [ i ] ) ;
2012-04-19 14:35:52 +08:00
}
if ( std : : string : : npos ! = strLowerCasePath . find ( " .png " ) )
{
2013-11-15 09:19:16 +08:00
CC_BREAK_IF ( ! saveImageToPNG ( filename , bIsToRGB ) ) ;
2012-04-19 14:35:52 +08:00
}
else if ( std : : string : : npos ! = strLowerCasePath . find ( " .jpg " ) )
{
2013-11-15 09:19:16 +08:00
CC_BREAK_IF ( ! saveImageToJPG ( filename ) ) ;
2012-04-19 14:35:52 +08:00
}
else
{
break ;
}
bRet = true ;
} while ( 0 ) ;
return bRet ;
}
2013-08-01 15:53:52 +08:00
# endif
2012-04-19 14:35:52 +08:00
2013-11-15 09:19:16 +08:00
bool Image : : saveImageToPNG ( const std : : string & filePath , bool isToRGB )
2012-04-19 14:35:52 +08:00
{
bool bRet = false ;
do
{
FILE * fp ;
png_structp png_ptr ;
png_infop info_ptr ;
png_colorp palette ;
png_bytep * row_pointers ;
2013-11-15 09:19:16 +08:00
fp = fopen ( filePath . c_str ( ) , " wb " ) ;
2014-02-13 16:22:41 +08:00
CC_BREAK_IF ( nullptr = = fp ) ;
2012-04-19 14:35:52 +08:00
2014-02-13 16:22:41 +08:00
png_ptr = png_create_write_struct ( PNG_LIBPNG_VER_STRING , nullptr , nullptr , nullptr ) ;
2012-04-19 14:35:52 +08:00
2014-02-13 16:22:41 +08:00
if ( nullptr = = png_ptr )
2012-04-19 14:35:52 +08:00
{
fclose ( fp ) ;
break ;
}
info_ptr = png_create_info_struct ( png_ptr ) ;
2014-02-13 16:22:41 +08:00
if ( nullptr = = info_ptr )
2012-04-19 14:35:52 +08:00
{
fclose ( fp ) ;
2014-02-13 16:22:41 +08:00
png_destroy_write_struct ( & png_ptr , nullptr ) ;
2012-04-19 14:35:52 +08:00
break ;
}
2013-03-02 01:09:58 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA && CC_TARGET_PLATFORM != CC_PLATFORM_NACL)
2012-04-19 14:35:52 +08:00
if ( setjmp ( png_jmpbuf ( png_ptr ) ) )
{
fclose ( fp ) ;
png_destroy_write_struct ( & png_ptr , & info_ptr ) ;
break ;
}
# endif
png_init_io ( png_ptr , fp ) ;
2013-08-06 16:14:36 +08:00
if ( ! isToRGB & & hasAlpha ( ) )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
png_set_IHDR ( png_ptr , info_ptr , _width , _height , 8 , PNG_COLOR_TYPE_RGB_ALPHA ,
2012-04-19 14:35:52 +08:00
PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_BASE , PNG_FILTER_TYPE_BASE ) ;
}
else
{
2013-06-15 14:03:30 +08:00
png_set_IHDR ( png_ptr , info_ptr , _width , _height , 8 , PNG_COLOR_TYPE_RGB ,
2012-04-19 14:35:52 +08:00
PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_BASE , PNG_FILTER_TYPE_BASE ) ;
}
palette = ( png_colorp ) png_malloc ( png_ptr , PNG_MAX_PALETTE_LENGTH * sizeof ( png_color ) ) ;
png_set_PLTE ( png_ptr , info_ptr , palette , PNG_MAX_PALETTE_LENGTH ) ;
png_write_info ( png_ptr , info_ptr ) ;
png_set_packing ( png_ptr ) ;
2013-06-15 14:03:30 +08:00
row_pointers = ( png_bytep * ) malloc ( _height * sizeof ( png_bytep ) ) ;
2014-02-13 16:22:41 +08:00
if ( row_pointers = = nullptr )
2012-04-19 14:35:52 +08:00
{
fclose ( fp ) ;
png_destroy_write_struct ( & png_ptr , & info_ptr ) ;
break ;
}
2014-02-13 16:22:41 +08:00
if ( ! hasAlpha ( ) )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
for ( int i = 0 ; i < ( int ) _height ; i + + )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
row_pointers [ i ] = ( png_bytep ) _data + i * _width * 3 ;
2012-04-19 14:35:52 +08:00
}
png_write_image ( png_ptr , row_pointers ) ;
free ( row_pointers ) ;
2014-02-13 16:22:41 +08:00
row_pointers = nullptr ;
2012-04-19 14:35:52 +08:00
}
else
{
2013-08-06 16:14:36 +08:00
if ( isToRGB )
2012-04-19 14:35:52 +08:00
{
2014-04-09 16:37:56 +08:00
unsigned char * pTempData = static_cast < unsigned char * > ( malloc ( _width * _height * 3 * sizeof ( unsigned char ) ) ) ;
2014-02-13 16:22:41 +08:00
if ( nullptr = = pTempData )
2012-04-19 14:35:52 +08:00
{
fclose ( fp ) ;
png_destroy_write_struct ( & png_ptr , & info_ptr ) ;
2014-04-13 06:13:58 +08:00
free ( row_pointers ) ;
row_pointers = nullptr ;
2012-04-19 14:35:52 +08:00
break ;
}
2013-06-15 14:03:30 +08:00
for ( int i = 0 ; i < _height ; + + i )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
for ( int j = 0 ; j < _width ; + + j )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
pTempData [ ( i * _width + j ) * 3 ] = _data [ ( i * _width + j ) * 4 ] ;
pTempData [ ( i * _width + j ) * 3 + 1 ] = _data [ ( i * _width + j ) * 4 + 1 ] ;
pTempData [ ( i * _width + j ) * 3 + 2 ] = _data [ ( i * _width + j ) * 4 + 2 ] ;
2012-04-19 14:35:52 +08:00
}
}
2013-06-15 14:03:30 +08:00
for ( int i = 0 ; i < ( int ) _height ; i + + )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
row_pointers [ i ] = ( png_bytep ) pTempData + i * _width * 3 ;
2012-04-19 14:35:52 +08:00
}
png_write_image ( png_ptr , row_pointers ) ;
free ( row_pointers ) ;
2014-02-13 16:22:41 +08:00
row_pointers = nullptr ;
2012-04-19 14:35:52 +08:00
2013-11-29 15:13:16 +08:00
if ( pTempData ! = nullptr )
{
free ( pTempData ) ;
}
2012-04-19 14:35:52 +08:00
}
else
{
2013-06-15 14:03:30 +08:00
for ( int i = 0 ; i < ( int ) _height ; i + + )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
row_pointers [ i ] = ( png_bytep ) _data + i * _width * 4 ;
2012-04-19 14:35:52 +08:00
}
png_write_image ( png_ptr , row_pointers ) ;
free ( row_pointers ) ;
2014-02-13 16:22:41 +08:00
row_pointers = nullptr ;
2012-04-19 14:35:52 +08:00
}
}
png_write_end ( png_ptr , info_ptr ) ;
png_free ( png_ptr , palette ) ;
2014-02-13 16:22:41 +08:00
palette = nullptr ;
2012-04-19 14:35:52 +08:00
png_destroy_write_struct ( & png_ptr , & info_ptr ) ;
fclose ( fp ) ;
bRet = true ;
} while ( 0 ) ;
return bRet ;
}
2013-11-15 09:19:16 +08:00
bool Image : : saveImageToJPG ( const std : : string & filePath )
2012-04-19 14:35:52 +08:00
{
bool bRet = false ;
do
{
struct jpeg_compress_struct cinfo ;
struct jpeg_error_mgr jerr ;
FILE * outfile ; /* target file */
JSAMPROW row_pointer [ 1 ] ; /* pointer to JSAMPLE row[s] */
int row_stride ; /* physical row width in image buffer */
cinfo . err = jpeg_std_error ( & jerr ) ;
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress ( & cinfo ) ;
2014-02-13 16:22:41 +08:00
CC_BREAK_IF ( ( outfile = fopen ( filePath . c_str ( ) , " wb " ) ) = = nullptr ) ;
2012-04-19 14:35:52 +08:00
jpeg_stdio_dest ( & cinfo , outfile ) ;
2013-06-15 14:03:30 +08:00
cinfo . image_width = _width ; /* image width and height, in pixels */
cinfo . image_height = _height ;
2012-04-19 14:35:52 +08:00
cinfo . input_components = 3 ; /* # of color components per pixel */
cinfo . in_color_space = JCS_RGB ; /* colorspace of input image */
jpeg_set_defaults ( & cinfo ) ;
2014-05-22 18:54:29 +08:00
jpeg_set_quality ( & cinfo , 90 , TRUE ) ;
2012-04-19 14:35:52 +08:00
jpeg_start_compress ( & cinfo , TRUE ) ;
2013-06-15 14:03:30 +08:00
row_stride = _width * 3 ; /* JSAMPLEs per row in image_buffer */
2012-04-19 14:35:52 +08:00
2013-07-26 17:34:44 +08:00
if ( hasAlpha ( ) )
2012-04-19 14:35:52 +08:00
{
2013-11-29 15:13:16 +08:00
unsigned char * pTempData = static_cast < unsigned char * > ( malloc ( _width * _height * 3 * sizeof ( unsigned char ) ) ) ;
2014-02-13 16:22:41 +08:00
if ( nullptr = = pTempData )
2012-04-19 14:35:52 +08:00
{
jpeg_finish_compress ( & cinfo ) ;
jpeg_destroy_compress ( & cinfo ) ;
fclose ( outfile ) ;
break ;
}
2013-06-15 14:03:30 +08:00
for ( int i = 0 ; i < _height ; + + i )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
for ( int j = 0 ; j < _width ; + + j )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
pTempData [ ( i * _width + j ) * 3 ] = _data [ ( i * _width + j ) * 4 ] ;
pTempData [ ( i * _width + j ) * 3 + 1 ] = _data [ ( i * _width + j ) * 4 + 1 ] ;
pTempData [ ( i * _width + j ) * 3 + 2 ] = _data [ ( i * _width + j ) * 4 + 2 ] ;
2012-04-19 14:35:52 +08:00
}
}
while ( cinfo . next_scanline < cinfo . image_height ) {
row_pointer [ 0 ] = & pTempData [ cinfo . next_scanline * row_stride ] ;
( void ) jpeg_write_scanlines ( & cinfo , row_pointer , 1 ) ;
}
2013-11-29 15:13:16 +08:00
if ( pTempData ! = nullptr )
{
free ( pTempData ) ;
}
2012-04-19 14:35:52 +08:00
}
else
{
while ( cinfo . next_scanline < cinfo . image_height ) {
2013-06-15 14:03:30 +08:00
row_pointer [ 0 ] = & _data [ cinfo . next_scanline * row_stride ] ;
2012-04-19 14:35:52 +08:00
( void ) jpeg_write_scanlines ( & cinfo , row_pointer , 1 ) ;
}
}
jpeg_finish_compress ( & cinfo ) ;
fclose ( outfile ) ;
jpeg_destroy_compress ( & cinfo ) ;
bRet = true ;
} while ( 0 ) ;
return bRet ;
}
2014-06-03 15:06:15 +08:00
void Image : : premultipliedAlpha ( )
{
2014-06-03 16:22:50 +08:00
CCASSERT ( _renderFormat = = Texture2D : : PixelFormat : : RGBA8888 , " The pixel format should be RGBA8888! " ) ;
2014-06-03 15:06:15 +08:00
2014-06-03 15:19:01 +08:00
unsigned int * fourBytes = ( unsigned int * ) _data ;
2014-06-03 15:06:15 +08:00
for ( int i = 0 ; i < _width * _height ; i + + )
{
unsigned char * p = _data + i * 4 ;
fourBytes [ i ] = CC_RGB_PREMULTIPLY_ALPHA ( p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] ) ;
}
_preMulti = true ;
}
2012-04-19 14:35:52 +08:00
NS_CC_END