Using custom shaders with CCRenderTexture and manual glUseProgram(), any better way to do this with cocos2d?

To use my custom shader with CCRenderTexture, I was doing:

  glUseProgram(myProgramHandle);
  //other code to update program variables
  //..
  myCCRenderTexture->beginWithClear(1,1,1,1);
  glBindTexture(GL_TEXTURE_2D, texName);
  glUniform1fv(paramHandle, 12, paramValue);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  myCCRenderTexture->end();

But my use of glUseProgram confuses cocos2d later. I could fix it by adding these lines to first manually save GL_CURRENT_PROGRAM and GL_ARRAY_BUFFER_BINDING values and then restore them later:

  GLint savedPreviousProgram, savedPreviousArrayBuffer; //temp variables to save gl state
  glGetIntegerv(GL_CURRENT_PROGRAM,&savedPreviousProgram); //save current program 
  glGetIntegerv(GL_ARRAY_BUFFER_BINDING,&savedPreviousArrayBuffer); //save array buffer binding

  glUseProgram(myProgramHandle);
  //other code to update program variables
  //..
  myCCRenderTexture->beginWithClear(1,1,1,1);
  glBindTexture(GL_TEXTURE_2D, texName);
  glUniform1fv(paramHandle, 12, paramValue);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  myCCRenderTexture->end();

  glUseProgram(savedPreviousProgram); //restore previous gl program
  glBindBuffer(GL_ARRAY_BUFFER, savedPreviousArrayBuffer); //restore previous array buffer binding

Why do I need to manually save and restore GL program and array buffer value? Is there any other way to do this with cocos2d without using direct openGL functions?

Hi!
I don’t know if this could help, but here’s the code I used to draw CCRenderTexture:

void MetaballFrame::draw()
{
    glActiveTexture(GL_TEXTURE1);
    ccGLBindTexture2DN(1, _colorRampTexture->getName());
    glActiveTexture(GL_TEXTURE0);
    CCSprite::draw();
}

void MetaballFrame::Begin(float r, float g, float b, float a)
{
    _renderTarget->beginWithClear(r, g, b, a);
}

void MetaballFrame::End()
{
    _renderTarget->end();
}

where _renderTarget is a pointer to CCRenderTarget instance.
Note that I’m using two textures / samplers in my shader.

Where/How do you set your shader? Do you need to set any uniform parameters for your shader?

I am using a direct glUseProgram call, and maybe I need to use a cocos2d function to set my shader?

CCSprite::draw sets the shader for you. You only need to call CCNode::setShaderProgram with your shader program in the initialization function or elsewhere.
If you need to set uniforms you can try the following code:

CC_NODE_DRAW_SETUP();
this->getShaderProgram()->setUniformLocationWith1f(location, value);
CCSprite::draw();

Actually, CCSprite::draw does two things:

  1. it make your shader program active and sets builtin uniform parameters;
  2. it sets various attribute pointers, binds the main texture etc-etc.
    But you have to set your uniform between these two things somehow, which is imposimple since a single call to CCSprite::draw. Thus, you have to call CC_NODE_DRAW_SETUP by yourself. Note that there is a minimal overhead of invocation of this function is CCSprite::draw since Cocos2d won’t set the shader program again if it’s alread set.