Freehand drawing app with cocos2d-x V3.3 using RenderTexture

Hi,
i would like to create free handdrawing app with cocos2d-x V3.3 using RenderTexture like this:

bool Canvas::init()
 {
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
    return false;
}

Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

_texture = RenderTexture::create(visibleSize.width, visibleSize.height, Texture2D::PixelFormat::RGBA8888);
_texture->retain();
_texture->setPosition(visibleSize/2);
this->addChild(_texture);

_brush= Sprite::create("brush1.png");
_brush->setColor( cocos2d::Color3B::BLACK );
_brush->retain();

_texture->beginWithClear(1, 1, 1, 1);
_texture->end();

auto listener = EventListenerTouchOneByOne::create();
//listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(Canvas::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(Canvas::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(Canvas::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

return  true;
}

bool Canvas::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {

    return  true;

 }

void Canvas::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event) {
  

    
    auto start=Director::getInstance()->convertToGL( touch->getLocationInView());
    auto end = Director::getInstance()->convertToGL(touch->getPreviousLocationInView());
    
    _texture->begin();
    
    float distance = start.distance(end);
    
    for (int i = 0; i < distance; i++)
    {
        float difx = end.x - start.x;
        float dify = end.y - start.y;
        float delta = (float)i / distance;
        _brush->setPosition(
                            Vec2(start.x + (difx * delta), start.y + (dify * delta)));
      //  CCLOG("drawPoint: x:%f y:%f",_brush->getPosition().x,_brush->getPosition().y);
		
        _brush->visit();
    }
    _texture->end();

}

void Canvas::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event) {
    
}

But i have this result:

Please help me to get connected and smooth drawing.
Thanks.

1 Like

No help :frowning: !

It seems like the _brush->visit(); isnā€™t called in each iteration of the loop for .

it worked here, with cocos2d-x 2.0.1 !

Off the top of my head I would suggest instead of just calling visit(), actually track the last position and draw a line from it to the current position, rinse and repeat. No, I have no code sample to go with this.

Thanks @tieudaotu but i would like to draw sprites, not just points

I had the same issue and I found the solution in the tests.
From what I understand it seems drawing the same sprite over and over get optimised and there are only few remaining.
In the tests they create a new sprite at each iteration which force the renderer to draw it I think.

Here is the code :

void RenderTextureSave::onTouchesMoved(const std::vector<Touch*>& touches, Event* event)
{
    auto touch = touches[0];
    auto start = touch->getLocation();
    auto end = touch->getPreviousLocation();

    // begin drawing to the render texture
    _target->begin();

    // for extra points, we'll draw this smoothly from the last position and vary the sprite's
    // scale/rotation/offset
    float distance = start.getDistance(end);
    if (distance > 1)
    {
        int d = (int)distance;
        _brushs.clear();
        for(int i = 0; i < d; ++i)
        {
            Sprite * sprite = Sprite::create("Images/fire.png");
            sprite->setColor(Color3B::RED);
            sprite->setOpacity(20);
            _brushs.pushBack(sprite);
        }
        for (int i = 0; i < d; i++)
        {
            float difx = end.x - start.x;
            float dify = end.y - start.y;
            float delta = (float)i / distance;
            _brushs.at(i)->setPosition(Vec2(start.x + (difx * delta), start.y + (dify * delta)));
            _brushs.at(i)->setRotation(rand() % 360);
            float r = (float)(rand() % 50 / 50.f) + 0.25f;
            _brushs.at(i)->setScale(r);
            /*_brush->setColor(Color3B(CCRANDOM_0_1() * 127 + 128, 255, 255));*/
            // Use CCRANDOM_0_1() will cause error when loading libtests.so on android, I don't know why.
            _brushs.at(i)->setColor(Color3B(rand() % 127 + 128, 255, 255));
            // Call visit to draw the brush, don't call draw..
            _brushs.at(i)->visit();
        }
    }

    // finish drawing and return context back to the screen
    _target->end();
}
1 Like

Thanks @niiiico

Its working perfect but I can not erase line after this code. If I remove ā€œ_brushs.clear();ā€ line then I will be able to erase line but line drawing not smooth. How can I achieve both functionality erase and smooth drawing?

Thanks

Sorry from bringing this back from the dead,
But is there a good solution to this problem? i followed the post, added it to my code and indeed,
The drawings look great.
but when i want to move the line i just draw (should be possible, all the ā€˜dotsā€™ are sprites), it causes some weird things like moving only part of the line, and as mentioned, no deleting.
anyone?

Hi,

I know this is long dead, but then also this might help someone.

This is how u delete
_target->clear(0, 0, 0, 0);

Hi,

Itā€™s very helpful for me
Thanx.