Renderer Expression: !_isRendering

Hi,

I am trying to use a rendertexture in helloworld application win32 but always an rendering exception is happening.
I don’t know how to solve it. I am using cocos2dx-v3.6

Assert failed: Cannot add command while rendering
Assertion failed!

Program: …ShaderTestv3\proj.win32\Debug.win32\libcocos2d.dll
File: …\renderer\CCRenderer.cpp
Line: 379

Expression: !_isRendering

But I am adding the command when the init code of the scene is running.

The exception happens in line “mRTex->beginWithClear(0, 0, 0, 1);”

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if (!Layer::init())
    {
        return false;
    }

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

    mRTex = RenderTexture::create(visibleSize.width, visibleSize.height);
    this->addChild(mRTex, 0, 0);
    mRTex->setScale(1.0);
    mRTex->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
    //mRTex->getSprite()->getTexture()->setAliasTexParameters();

    // add "HelloWorld" splash screen"
    auto sprite = Sprite::create("HelloWorld.png");

    // position the sprite on the center of the screen
    sprite->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));

    // add the sprite as a child to this layer
    mRTex->addChild(sprite, 0);

    this->scheduleUpdate();

    // 3: Draw into the texture
    //Caution!!!  if you want to use your own opengl draw call ,you must wrap them with a custom command
    _customCommand.init(mRTex->getGlobalZOrder());
    _customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);
    auto renderer = Director::getInstance()->getRenderer();
    renderer->addCommand(&_customCommand);

    return true;
}

void HelloWorld::visit(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags)
{

}

void HelloWorld::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags)
{
}

void HelloWorld::onDraw()
{
    mRTex->beginWithClear(0, 0, 0, 1);

    Vector<Node*>& lChildren = this->getChildren();
    for (int i = 0; i < lChildren.size(); i++)
    {
        cocos2d::Sprite* lNode = (cocos2d::Sprite*)lChildren.at(i);
        lNode->visit();
    }

    mRTex->end();
}

void HelloWorld::update(float dt)
{
}

guys? any reply? this forum seems really not so active :-/

You need to add render commands in the overridden draw() method, not in the init() method, if I’m not mistaken.

Tried this already and done it again. I get same exception.

And did you set that up with:

void MyNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    _customCommand.init(_globalZOrder);
    _customCommand.func = CC_CALLBACK_0(MyNode::onDraw, this, transform, flags);
    renderer->addCommand(&_customCommand);
}

void MyNode::onDraw(const Mat4 &transform, uint32_t flags)
{
    Director *director = Director::getInstance();
    director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
    
    CHECK_GL_ERROR_DEBUG();

    // Drawing code here

    CHECK_GL_ERROR_DEBUG();

    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}

First, I want to thank you for your help! I really appreciate it!
But, unfortunately it still does not work :frowning:

I have cleaned up the cpp and h file. Maybe you can try it? Thank you!
Btw, I am using Visual Studio 2013.

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
private:
    cocos2d::RenderTexture* mRTex;
    cocos2d::CustomCommand _customCommand;

public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();

    virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags);

    void onDraw(const cocos2d::Mat4 &transform, uint32_t flags);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

cpp file:

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if (!Layer::init())
    {
        return false;
    }

    auto s = Director::getInstance()->getWinSize();

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

    mRTex = RenderTexture::create(s.width, s.height);
    //mRTex->retain(); // should not be required
    mRTex->setPosition(s / 2);
    this->addChild(mRTex);

    // add "HelloWorld" splash screen"
    auto sprite = Sprite::create("HelloWorld.png");

    // position the sprite on the center of the screen
    sprite->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));

    // add the sprite as a child to this layer
    mRTex->addChild(sprite, 0);
    
    return true;
}

void HelloWorld::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags)
{
    _customCommand.init(mRTex->getGlobalZOrder());
    _customCommand.func = std::bind(&HelloWorld::onDraw, this, transform, flags);
    renderer->addCommand(&_customCommand);
}

void HelloWorld::onDraw(const Mat4 &transform, uint32_t flags)
{
    Director *director = Director::getInstance();
    director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);

    CHECK_GL_ERROR_DEBUG();

    mRTex->beginWithClear(0, 0, 0, 1);

    Vector<Node*>& lChildren = this->getChildren();
    for (int i = 0; i < lChildren.size(); i++)
    {
        cocos2d::Sprite* lNode = (cocos2d::Sprite*)lChildren.at(i);
        lNode->visit();
    }

    mRTex->end();

    CHECK_GL_ERROR_DEBUG();

    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}

Same issue in Xcode 6.4

CCASSERT(!_isRendering, “Cannot add command while rendering”);

I am astounded, there is nothing special on my code, or?

I am no expert in this area, however calling visit() within draw() is probably the cause. What are you trying to achieve as it looks like you want to draw child sprites, which is done automatically?

I want to render my sprites to a rendertexture and apply a shader afterwards.
In cocos v2.2.6 this scenario works without any problems.

Someone else?

I am having the same issue, I moved my visit code into my game loop…it works but it maxes out at 30 fps.
I would like a better solution as I should be looking toward 60fps.
When I find a solution I’ll let you know.