Hi,
I am trying to do this coloring book.
I have followed @Lazy_Gamer approach & implemented the flood fill algorithm but i am unable to understand why my code is not working.
// on “init” you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
registerTouch();
auto bg = Sprite::create("SCN_bg.png");
bg->setPosition(Vec2(visibleSize.width/2, visibleSize.height/2));
this->addChild(bg);
std::string filename = "SCN_Clear_apple.png";
img = new Image();
img->initWithImageFile(filename);
CCLOG("%s loaded. Size: %dx%d. Bits per pixel: %d", filename.c_str(), img->getWidth(), img->getHeight(), img->getBitPerPixel());
if(img->hasAlpha())
rgbProfile = 4;
else
rgbProfile = 3;
//data = new unsigned char[img->getDataLen() * rgbProfile];
data = img->getData(); //pixel data
width = img->getWidth();
height = img->getHeight();
//memset(data + img->getDataLen() / 4, 255, img->getDataLen() / 4); //white rectangle
//setColor4B(83, 109, Color4B::RED, data); //single red pixel
texture = new Texture2D();
texture->initWithImage(img);
sprite = Sprite::createWithTexture(texture);
sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
addChild(sprite);
setColor4B(85, 109, Color4B::GREEN, data); //single green pixel
//we have to update texture
//texture->updateWithData(data, 0, 0, img->getWidth(), img->getHeight()); //here's how to update whole data
texture->updateWithData(data, 85, 109, 1, 1); //you can also update only part of it to increase performance
return true;
}
void HelloWorld::setColor4B(int x, int y, Color4B color, unsigned char* data)
{
int index = (x + y * img->getWidth()) << 2; //the same as * 4
data[index] = color.r;
data[index + 1] = color.g;
data[index + 2] = color.b;
data[index + 3] = color.a;
// for(int i = 0; i < width; ++i)
// {
// for(int j = 0; j < height; ++j)
// {
//
//
// int index = (i + j * width) << 2; //the same as * 4
// data[index] = color.r;
// data[index + 1] = color.g;
// data[index + 2] = color.b;
// data[index + 3] = color.a;
// }
// }
}
void HelloWorld::FloodFillBorder(int cx, int cy, cocos2d::Color4B fillColor, cocos2d::Color4B borderColor)
{
std::queue pixelPoints;
int noOfPixels = width * height;
std::vector<bool> vCheckedPixels(noOfPixels, false);
pixelPoints.push(Point(cx, cy));
while(pixelPoints.size() > 0)
{
Vec2 current = pixelPoints.back();
pixelPoints.pop();
for(int i = current.x; i < width; ++i)
{
int index = (i + (int)current.y * width) << 2;
unsigned char * pixel = &data[index];
// You can see/change pixels' RGBA value(0-255) here !
Color4B tempValues; // pixel value at this position
// tempValues.r = *pixel;
// tempValues.g = *(pixel + 1);
// tempValues.b = *(pixel + 2);
// tempValues.a = *(pixel + 3);
tempValues.r = data[index];
tempValues.g = data[index + 1];
tempValues.b = data[index + 2];
tempValues.a = data[index + 3];
if( pixel == nullptr || tempValues == borderColor )
break;
data[index] = fillColor.r;
data[index + 1] = fillColor.g;
data[index + 2] = fillColor.b;
data[index + 2] = fillColor.a;
vCheckedPixels[i + ((int)current.y * width)] = true;
texture->updateWithData(data, current.x, current.y, 1, 1);
if(current.y + 1 < height)
{
int topIndex = (i + ((int)current.y * width + width)) << 2;
//unsigned char topPixel = data[topIndex];
Color4B topPixelColor;
topPixelColor.r = data[topIndex];
topPixelColor.g = data[topIndex + 1];
topPixelColor.b = data[topIndex + 2];
topPixelColor.a = data[topIndex + 3];
if(vCheckedPixels[i + ((int)current.y * width) + width] == false && topPixelColor != borderColor)
{
pixelPoints.push(Point(i, current.y + 1));
//pixelPoints.push(Point(i, topIndex));
}
}
if(current.y - 1 >= 0)
{
int bottomIndex = (i + ((int)current.y * width - width)) << 2;
//unsigned char topPixel = data[topIndex];
Color4B bottomPixelColor;
bottomPixelColor.r = data[bottomIndex];
bottomPixelColor.g = data[bottomIndex + 1];
bottomPixelColor.b = data[bottomIndex + 2];
bottomPixelColor.a = data[bottomIndex + 3];
if(vCheckedPixels[i + ((int)current.y * width) - width] == false && bottomPixelColor != borderColor)
{
pixelPoints.push(Point(i, current.y + 1));
//pixelPoints.push(Point(i, bottomIndex));
}
}
}
for(int i = current.x - 1; i >= 0; --i)
{
int index = (i + ((int)current.y * width)) << 2;
unsigned char * pixel = &data[index];
// You can see/change pixels' RGBA value(0-255) here !
Color4B tempValues; // pixel value at this position
tempValues.r = data[index];
tempValues.g = data[index + 1];
tempValues.b = data[index + 2];
tempValues.a = data[index + 3];
if( pixel == nullptr || tempValues == borderColor )
break;
data[index] = fillColor.r;
data[index + 1] = fillColor.g;
data[index + 2] = fillColor.b;
data[index + 3] = fillColor.a;
texture->updateWithData(data, current.x, current.y, 1, 1);
vCheckedPixels[i + ((int)current.y * width)] = true;
if(current.y + 1 < height)
{
int topIndex = (i + ((int)current.y * width) + width) << 2;
//unsigned char topPixel = data[topIndex];
Color4B topPixelColor;
topPixelColor.r = data[topIndex];
topPixelColor.g = data[topIndex + 1];
topPixelColor.b = data[topIndex + 2];
topPixelColor.b = data[topIndex + 3];
if(vCheckedPixels[i + ((int)current.y * width) + width] == false && topPixelColor != borderColor)
{
pixelPoints.push(Point(i, current.y + 1));
//pixelPoints.push(Point(i, topIndex));
}
}
if(current.y - 1 >= 0)
{
int bottomIndex = (i + ((int)current.y * width - width)) << 2;
//unsigned char topPixel = data[topIndex];
Color4B bottomPixelColor;
bottomPixelColor.r = data[bottomIndex];
bottomPixelColor.g = data[bottomIndex + 1];
bottomPixelColor.b = data[bottomIndex + 2];
bottomPixelColor.a = data[bottomIndex + 3];
if(vCheckedPixels[i + ((int)current.y * width) - width] == false && bottomPixelColor != borderColor)
{
pixelPoints.push(Point(i, current.y + 1));
//pixelPoints.push(Point(i, bottomIndex));
}
}
}
//texture->updateWithData(data, current.x, current.y, 1, 1);
}
//texture->updateWithData(data, 0, 0, width, height);
}
void HelloWorld::registerTouch()
{
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, this);
auto keyListener = EventListenerKeyboard::create();
keyListener->onKeyReleased = CC_CALLBACK_2(HelloWorld::onKeyReleased, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(keyListener, this);
}
bool HelloWorld::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
auto touchLocation = touch->getLocation();
touchLocation = this->convertToNodeSpace(touchLocation);
if(sprite->getBoundingBox().containsPoint(touchLocation))
{
int actualTexCoordinateX;
int actualTexCoordinateY;
int paddingX, paddingY;
paddingX = sprite->getPosition().x - width/2;
paddingY = sprite->getPosition().y - height/2;
actualTexCoordinateX = touchLocation.x - paddingX;
actualTexCoordinateY = touchLocation.y - paddingY;
FloodFillBorder(actualTexCoordinateX, actualTexCoordinateY, Color4B::GREEN, Color4B::BLACK);
}
return true;
}Archive.zip (533.0 KB)
I have also uploaded my classes & Resources.
Please tell me where i am doing wrong.