Search code examples
objective-copengl-escocos2d-iphoneblending

How to dynamically color CCSprite but preserve black, white and transparent pixels


Is there a way, possibly a ccBlendFunc, that will allow me to dynamically color sprites without affecting the pure white (255, 255, 255), pure black (0, 0, 0), and purely transparent (alpha=255) pixels?

Using the default blend function and setting sprite.color on a CCSprite will re-color the white pixels to whatever value is ccColor3B value is specified, and that is undesirable for me.


Solution

  • Use a shader. If you are using cocos2d version 2.1, start with ccShader_PositionTextureColor_frag (used by CCSprite to render textures, and other classes), copied here

    #ifdef GL_ES    
        precision lowp float;   
    #endif
    
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    uniform sampler2D CC_Texture0;
    
    void main()
    {
        gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
    }
    

    You want to change that line in main() to skip the fragments you want to skip. CCSprite writes the 'sprite.color' property into v_fragmentColor (look at the code , there are 'premultiplied alpha' variants). You want to modify the v_fragmentColor when texture2D(CC_Texture0, v_texCoord).a == 0, and other circumstances.

    I would extend CCSprite to use this new shader (ie avoid toying directly with the shaders builtin to cocos2d, have your own trial and error place). Once you have the shader doing what you want, add the logic in your class to place the new shader program in CCShaderCache, and retrieve it from there.