From a1570e931f0b75b9a22f9ec5ec9d9c5de6bcae9c Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 27 Apr 2012 15:53:29 +0800 Subject: [PATCH 1/2] issue #931:make convert to rgb565 and A8 correct --- cocos2dx/platform/ios/CCImage.mm | 255 ++++-------------- cocos2dx/textures/CCTexture2D.cpp | 66 ++++- .../gen/org/cocos2dx/tests/R.java | 52 ++-- .../project.pbxproj.REMOVED.git-id | 2 +- tests/tests/Texture2dTest/Texture2dTest.cpp | 4 +- 5 files changed, 133 insertions(+), 246 deletions(-) diff --git a/cocos2dx/platform/ios/CCImage.mm b/cocos2dx/platform/ios/CCImage.mm index e07906dfa3..70413d5e2b 100644 --- a/cocos2dx/platform/ios/CCImage.mm +++ b/cocos2dx/platform/ios/CCImage.mm @@ -42,217 +42,62 @@ typedef struct unsigned char* data; } tImageInfo; -static unsigned int nextPOT(unsigned int x) +static bool _initWithImage(CGImageRef cgImage, tImageInfo *pImageinfo) { - x = x - 1; - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >> 16); - return x + 1; -} - -typedef enum { - kCCTexture2DPixelFormat_Automatic = 0, - //! 32-bit texture: RGBA8888 - kCCTexture2DPixelFormat_RGBA8888, - //! 24-bit texture: RGBA888 - kCCTexture2DPixelFormat_RGB888, - //! 16-bit texture without Alpha channel - kCCTexture2DPixelFormat_RGB565, - //! 8-bit textures used as masks - kCCTexture2DPixelFormat_A8, - //! 16-bit textures: RGBA4444 - kCCTexture2DPixelFormat_RGBA4444, - //! 16-bit textures: RGB5A1 - kCCTexture2DPixelFormat_RGB5A1, - - //! Default texture format: RGBA8888 - kCCTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_RGBA8888, - - // backward compatibility stuff - kTexture2DPixelFormat_Automatic = kCCTexture2DPixelFormat_Automatic, - kTexture2DPixelFormat_RGBA8888 = kCCTexture2DPixelFormat_RGBA8888, - kTexture2DPixelFormat_RGB888 = kCCTexture2DPixelFormat_RGB888, - kTexture2DPixelFormat_RGB565 = kCCTexture2DPixelFormat_RGB565, - kTexture2DPixelFormat_A8 = kCCTexture2DPixelFormat_A8, - kTexture2DPixelFormat_RGBA4444 = kCCTexture2DPixelFormat_RGBA4444, - kTexture2DPixelFormat_RGB5A1 = kCCTexture2DPixelFormat_RGB5A1, - kTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_Default - -} CCTexture2DPixelFormat; - -static bool _initPremultipliedATextureWithImage(CGImageRef image, NSUInteger POTWide, NSUInteger POTHigh, tImageInfo *pImageInfo) -{ - NSUInteger i; - CGContextRef context = nil; - unsigned char* data = nil;; - CGColorSpaceRef colorSpace; - unsigned char* tempData; - unsigned int* inPixel32; - unsigned short* outPixel16; - bool hasAlpha; - CGImageAlphaInfo info; - CGSize imageSize; - CCTexture2DPixelFormat pixelFormat; - - info = CGImageGetAlphaInfo(image); - hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO); - - size_t bpp = CGImageGetBitsPerComponent(image); - colorSpace = CGImageGetColorSpace(image); - - if(colorSpace) - { - if(hasAlpha || bpp >= 8) - { - pixelFormat = kCCTexture2DPixelFormat_Default; - } - else - { - pixelFormat = kCCTexture2DPixelFormat_RGB565; - } - } - else - { - // NOTE: No colorspace means a mask image - pixelFormat = kCCTexture2DPixelFormat_A8; - } - - imageSize.width = CGImageGetWidth(image); - imageSize.height = CGImageGetHeight(image); - - // Create the bitmap graphics context - - switch(pixelFormat) - { - case kCCTexture2DPixelFormat_RGBA8888: - case kCCTexture2DPixelFormat_RGBA4444: - case kCCTexture2DPixelFormat_RGB5A1: - colorSpace = CGColorSpaceCreateDeviceRGB(); - data = new unsigned char[POTHigh * POTWide * 4]; - info = hasAlpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); - CGColorSpaceRelease(colorSpace); - break; - - case kCCTexture2DPixelFormat_RGB565: - colorSpace = CGColorSpaceCreateDeviceRGB(); - data = new unsigned char[POTHigh * POTWide * 4]; - info = kCGImageAlphaNoneSkipLast; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); - CGColorSpaceRelease(colorSpace); - break; - case kCCTexture2DPixelFormat_A8: - data = new unsigned char[POTHigh * POTWide]; - info = kCGImageAlphaOnly; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, NULL, info); - break; - default: - return false; - } - - CGRect rect; - rect.size.width = POTWide; - rect.size.height = POTHigh; - rect.origin.x = 0; - rect.origin.y = 0; - - CGContextClearRect(context, rect); - CGContextTranslateCTM(context, 0, POTHigh - imageSize.height); - rect.size.width = CGImageGetWidth(image); - rect.size.height = CGImageGetHeight(image); - rect.origin.x = 0; - rect.origin.y = 0; - CGContextDrawImage(context, rect, image); - - // Repack the pixel data into the right format - - if(pixelFormat == kCCTexture2DPixelFormat_RGB565) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); - } - - delete[] data; - data = tempData; - - } - else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A - } - - delete[] data; - data = tempData; - - } - else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A - } - - delete[] data; - data = tempData; - } - - // should be after calling super init - pImageInfo->isPremultipliedAlpha = true; - pImageInfo->hasAlpha = true; - pImageInfo->bitsPerComponent = bpp; - pImageInfo->width = imageSize.width; - pImageInfo->height = imageSize.height; - - if (pImageInfo->data) - { - delete [] pImageInfo->data; - } - pImageInfo->data = data; - - CGContextRelease(context); - return true; -} - -static bool _initWithImage(CGImageRef CGImage, tImageInfo *pImageinfo) -{ - NSUInteger POTWide, POTHigh; - - if(CGImage == NULL) + if(cgImage == NULL) { return false; } - POTWide = CGImageGetWidth(CGImage); - POTHigh = CGImageGetHeight(CGImage); + // get image info - // always load premultiplied images - _initPremultipliedATextureWithImage(CGImage, POTWide, POTHigh, pImageinfo); + pImageinfo->width = CGImageGetWidth(cgImage); + pImageinfo->height = CGImageGetHeight(cgImage); + + CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage); + pImageinfo->hasAlpha = (info == kCGImageAlphaPremultipliedLast) + || (info == kCGImageAlphaPremultipliedFirst) + || (info == kCGImageAlphaLast) + || (info == kCGImageAlphaFirst); + + pImageinfo->isPremultipliedAlpha = (info == kCGImageAlphaPremultipliedLast) + || (info == kCGImageAlphaPremultipliedFirst); + + CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); + if (colorSpace) + { + if (pImageinfo->hasAlpha) + { + info = kCGImageAlphaPremultipliedLast; + } + else + { + info = kCGImageAlphaNoneSkipLast; + } + } + else + { + return false; + } + + // change to RGBA8888 + pImageinfo->hasAlpha = true; + pImageinfo->bitsPerComponent = 8; + pImageinfo->data = new unsigned char[pImageinfo->width * pImageinfo->height * 4]; + colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(pImageinfo->data, + pImageinfo->width, + pImageinfo->height, + 8, + 4 * pImageinfo->width, + colorSpace, + info | kCGBitmapByteOrder32Big); + + CGContextClearRect(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height)); + CGContextTranslateCTM(context, 0, 0); + CGContextDrawImage(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height), cgImage); + + CGContextRelease(context); return true; } diff --git a/cocos2dx/textures/CCTexture2D.cpp b/cocos2dx/textures/CCTexture2D.cpp index 9568a62966..9bbc5feeaf 100644 --- a/cocos2dx/textures/CCTexture2D.cpp +++ b/cocos2dx/textures/CCTexture2D.cpp @@ -305,19 +305,38 @@ bool CCTexture2D::initPremultipliedATextureWithImage(CCImage *image, unsigned in if (pixelFormat == kCCTexture2DPixelFormat_RGB565) { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB" - - tempData = new unsigned char[width * height * 2]; - outPixel16 = (unsigned short*)tempData; - inPixel8 = (unsigned char*)image->getData(); - - for(unsigned int i = 0; i < length; ++i) + if (hasAlpha) { - *outPixel16++ = - (((*inPixel8++ & 0xFF) >> 3) << 11) | // R - (((*inPixel8++ & 0xFF) >> 2) << 5) | // G - (((*inPixel8++ & 0xFF) >> 3) << 0); // B + // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" + + tempData = new unsigned char[width * height * 2]; + outPixel16 = (unsigned short*)tempData; + inPixel32 = (unsigned int*)image->getData(); + + for(unsigned int i = 0; i < length; ++i, ++inPixel32) + { + *outPixel16++ = + ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R + ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G + ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B + } } + else + { + // Convert "RRRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB" + + tempData = new unsigned char[width * height * 2]; + outPixel16 = (unsigned short*)tempData; + inPixel8 = (unsigned char*)image->getData(); + + for(unsigned int i = 0; i < length; ++i) + { + *outPixel16++ = + (((*inPixel8++ & 0xFF) >> 3) << 11) | // R + (((*inPixel8++ & 0xFF) >> 2) << 5) | // G + (((*inPixel8++ & 0xFF) >> 3) << 0); // B + } + } } else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) { @@ -354,7 +373,30 @@ bool CCTexture2D::initPremultipliedATextureWithImage(CCImage *image, unsigned in } else if (pixelFormat == kCCTexture2DPixelFormat_A8) { - // fixed me, how to convert? + // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "AAAAAAAA" + inPixel32 = (unsigned int*)image->getData(); + tempData = new unsigned char[width * height]; + unsigned char *outPixel8 = tempData; + + for(unsigned int i = 0; i < length; ++i, ++inPixel32) + { + *outPixel8++ = (*inPixel32 >> 24) & 0xFF; // A + } + } + + if (hasAlpha && pixelFormat == kCCTexture2DPixelFormat_RGB888) + { + // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB" + inPixel32 = (unsigned int*)image->getData(); + tempData = new unsigned char[width * height * 3]; + unsigned char *outPixel8 = tempData; + + for(unsigned int i = 0; i < length; ++i, ++inPixel32) + { + *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R + *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G + *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B + } } initWithData(tempData, pixelFormat, width, height, imageSize); diff --git a/tests/proj.android/gen/org/cocos2dx/tests/R.java b/tests/proj.android/gen/org/cocos2dx/tests/R.java index 3a5224563e..298ffe08a6 100644 --- a/tests/proj.android/gen/org/cocos2dx/tests/R.java +++ b/tests/proj.android/gen/org/cocos2dx/tests/R.java @@ -1,26 +1,26 @@ -/* AUTO-GENERATED FILE. DO NOT MODIFY. - * - * This class was automatically generated by the - * aapt tool from the resource data it found. It - * should not be modified by hand. - */ - -package org.cocos2dx.tests; - -public final class R { - public static final class attr { - } - public static final class drawable { - public static final int icon=0x7f020000; - } - public static final class id { - public static final int test_demo_gl_surfaceview=0x7f050001; - public static final int textField=0x7f050000; - } - public static final class layout { - public static final int test_demo=0x7f030000; - } - public static final class string { - public static final int app_name=0x7f040000; - } -} +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.cocos2dx.tests; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class id { + public static final int test_demo_gl_surfaceview=0x7f050001; + public static final int textField=0x7f050000; + } + public static final class layout { + public static final int test_demo=0x7f030000; + } + public static final class string { + public static final int app_name=0x7f040000; + } +} diff --git a/tests/proj.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id b/tests/proj.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id index 757cabf91a..42e4bf174d 100644 --- a/tests/proj.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/tests/proj.ios/test.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -941978c520f1726cf972dfa50fcfee7f72769685 \ No newline at end of file +0ffd9a2963117b5a53222965ff2d95f8178971f2 \ No newline at end of file diff --git a/tests/tests/Texture2dTest/Texture2dTest.cpp b/tests/tests/Texture2dTest/Texture2dTest.cpp index 7c3506ab4b..d9c396b0b9 100644 --- a/tests/tests/Texture2dTest/Texture2dTest.cpp +++ b/tests/tests/Texture2dTest/Texture2dTest.cpp @@ -985,7 +985,7 @@ void TexturePixelFormat::onEnter() // RGB565 image (16-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGB565); CCSprite *sprite5 = CCSprite::spriteWithFile("Images/test-rgba1.png"); - sprite5->setPosition(ccp(4*s.width/7, s.height/2+32)); + sprite5->setPosition(ccp(5*s.width/7, s.height/2+32)); addChild(sprite5, 0); // remove texture from texture manager @@ -994,7 +994,7 @@ void TexturePixelFormat::onEnter() // A8 image (8-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_A8); CCSprite *sprite6 = CCSprite::spriteWithFile("Images/test-rgba1.png"); - sprite6->setPosition(ccp(5*s.width/7, s.height/2+32)); + sprite6->setPosition(ccp(6*s.width/7, s.height/2+32)); addChild(sprite6, 0); // remove texture from texture manager From a4e8c9ad1793784bac9e5dceebad4be92c1bb080 Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 27 Apr 2012 18:37:11 +0800 Subject: [PATCH 2/2] fixed #931: refactor CCImage and CCTexture2D --- .../project.pbxproj.REMOVED.git-id | 2 +- cocos2dx/platform/CCImageCommon_cpp.h | 25 ++++++++++++++++++- cocos2dx/platform/ios/CCImage.mm | 7 +++--- tests/tests/Texture2dTest/Texture2dTest.cpp | 2 +- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/HelloWorld/proj.ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id b/HelloWorld/proj.ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id index 295331ad8b..de02f8069a 100644 --- a/HelloWorld/proj.ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/HelloWorld/proj.ios/HelloWorld.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -7dc2eddab8c675364c06b0818030b2ed1792ca81 \ No newline at end of file +918b8b44c7b180874afc0599a0e1b2b4e13f1e2a \ No newline at end of file diff --git a/cocos2dx/platform/CCImageCommon_cpp.h b/cocos2dx/platform/CCImageCommon_cpp.h index 7a759b7511..2d29c442e7 100644 --- a/cocos2dx/platform/CCImageCommon_cpp.h +++ b/cocos2dx/platform/CCImageCommon_cpp.h @@ -300,10 +300,33 @@ bool CCImage::_initWithPngData(void * pData, int nDatalen) row_pointers[i] = (png_bytep)m_pData + q; } png_read_image(png_ptr, row_pointers); + + if (m_bHasAlpha) + { + // premultiply alpha, or the effect will wrong when want to use other pixel format in CCTexture2D, + // such as RGB888, RGB5A1 +#define CC_RGB_PREMULTIPLY_APLHA(vr, vg, vb, va) \ +(unsigned)(((unsigned)((unsigned char)(vr) * ((unsigned char)(va) + 1)) >> 8) | \ +((unsigned)((unsigned char)(vg) * ((unsigned char)(va) + 1) >> 8) << 8) | \ +((unsigned)((unsigned char)(vb) * ((unsigned char)(va) + 1) >> 8) << 16) | \ +((unsigned)(unsigned char)(va) << 24)) + + unsigned int *tmp = (unsigned int *)m_pData; + for(unsigned int i = 0; i < m_nHeight; i++) + { + for(int j = 0; j < m_nWidth * channels; j += 4) + { + *tmp++ = CC_RGB_PREMULTIPLY_APLHA( row_pointers[i][j], row_pointers[i][j + 1], + row_pointers[i][j + 2], row_pointers[i][j + 3] ); + } + } + + m_bPreMulti = true; + } + free(row_pointers); bRet = true; } - } while (0); out: diff --git a/cocos2dx/platform/ios/CCImage.mm b/cocos2dx/platform/ios/CCImage.mm index 70413d5e2b..fe02567471 100644 --- a/cocos2dx/platform/ios/CCImage.mm +++ b/cocos2dx/platform/ios/CCImage.mm @@ -60,19 +60,18 @@ static bool _initWithImage(CGImageRef cgImage, tImageInfo *pImageinfo) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst); - pImageinfo->isPremultipliedAlpha = (info == kCGImageAlphaPremultipliedLast) - || (info == kCGImageAlphaPremultipliedFirst); - CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); if (colorSpace) { if (pImageinfo->hasAlpha) { info = kCGImageAlphaPremultipliedLast; + pImageinfo->isPremultipliedAlpha = true; } else { info = kCGImageAlphaNoneSkipLast; + pImageinfo->isPremultipliedAlpha = false; } } else @@ -94,7 +93,7 @@ static bool _initWithImage(CGImageRef cgImage, tImageInfo *pImageinfo) info | kCGBitmapByteOrder32Big); CGContextClearRect(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height)); - CGContextTranslateCTM(context, 0, 0); + //CGContextTranslateCTM(context, 0, 0); CGContextDrawImage(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height), cgImage); CGContextRelease(context); diff --git a/tests/tests/Texture2dTest/Texture2dTest.cpp b/tests/tests/Texture2dTest/Texture2dTest.cpp index d9c396b0b9..c9f656b267 100644 --- a/tests/tests/Texture2dTest/Texture2dTest.cpp +++ b/tests/tests/Texture2dTest/Texture2dTest.cpp @@ -994,7 +994,7 @@ void TexturePixelFormat::onEnter() // A8 image (8-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_A8); CCSprite *sprite6 = CCSprite::spriteWithFile("Images/test-rgba1.png"); - sprite6->setPosition(ccp(6*s.width/7, s.height/2+32)); + sprite6->setPosition(ccp(6*s.width/7, s.height/2-32)); addChild(sprite6, 0); // remove texture from texture manager