There have been some posts about problems with black borders around sprites with cocos2d-x-3.0 and I have seen them for myself. The same sprite textures do not have black borders in cocos2d-x-2.x.x. I discovered the problem is that in cocos2d-x-3.0, when a PNG file is loaded in, alpha is not pre-multiplied. However, in cocos2d-x-2.x.x, there is code to pre-mulitply the alpha.
I believe BlendFunc::ALPHA_NON_PREMULTIPLIED is blending properly, but that when it blends properly, it adds the black borders. What we really want is to pre-multiply the alpha, and then use BlendFunc::ALPHA_PREMULTIPLIED, which does not add the black borders. (I am not 100% certain about this, but I think it is true)
Is this a bug or a feature? Was it intentional in cocos2d-x-3.0 to not pre-multiply the alpha when loading a PNG, or was this a mistake that was overlooked?
Here is how I fixed the problem in cocos2d-x-3.0rc1:
In the file CCImage.cpp (CCImageCommon_cpp.h for earlier versions of cocos2d-x-3.0), in the method initWithPngData(), right after the call to png_read_end(), replace this code:
_preMulti = false;
with this (which is what was done in cocos2d-x-2.x.x with variable names changed appropriately):
png_uint_32 channel = rowbytes/_width;
if (channel == 4)
{
_hasPremultipliedAlpha = true;
unsigned int *tmp = (unsigned int *)_data;
for(unsigned short i = 0; i < _height; i++)
{
for(unsigned int j = 0; j < rowbytes; j += 4)
{
*tmp++ = CC_RGB_PREMULTIPLY_ALPHA( row_pointers[i][j], row_pointers[i][j + 1],
row_pointers[i][j + 2], row_pointers[i][j + 3] );
}
}
_preMulti = true;
}
For my test case to illustrate the problem, I added this code to HelloWorldScene.cpp:
auto s1 = Sprite::create("circle.png");
s1->setPosition(75, 100);
this->addChild(s1);
auto s2 = Sprite::create("circle.png");
s2->setPosition(100, 100);
this->addChild(s2);
I have seen the black borders on windows and android, but I’m guessing it affects all platforms.
black_border_example.png (131.7 KB)
circle.png (0.5 KB)