"soft light" blend mode?

Hi,

if I have a texture image that I’d like to display as it would in Photoshop/Gimp using “soft light” blend mode, how would I do that with cocos2d-x?

Is this even possible to implement in a performant way if the sprite would be an overlay for the entire screen?

For example, starting with a Sprite,

Sprite* noise = Sprite::create("noise.png");

how can I display that sprite in “soft light” blend mode? Do I need to look into using glBlendFunc ? Or do I need to look into shaders? Sorry, both of these concepts are still fairly new to me

Thanks for any help

check out the ShadeTestSprite maybe it will help.

Ok,

I am trying out some custom shaders based of the ShaderTestSprite suite and following this tutorial: http://www.raywenderlich.com/4428/how-to-mask-a-sprite-with-cocos2d-2-0

I dont get the result shown in that tutorial page though. The tutorial shows a sprite image masked by a secondary image. My result is that only one or the other of the images are being rendered depending on the order that the texture is bound in the shader draw call. Can anyone see what I am doing wrong in the code below (MaskSprite is based off the ShaderSprite from the test suite, the code follows at the bottom)?

My result is that the mask image (CalendarMask.png) is rendered with the portion that should be transparent as opaque, and the portion that should be opaque is transparent. The actual sprite image that was to be masked is not rendered at all (Calendar1.png)

My custom MaskSprite (ported from the linked tutorial above)

class MaskSprite : public ShaderSprite, public ShaderSpriteCreator
{
public:
    MaskSprite();
    void draw();

private:
    GLuint _maskLocation;

protected:
    virtual void buildCustomUniforms();
    virtual void setCustomUniforms();
    Texture2D* _maskTexture;
};

MaskSprite::MaskSprite() {
    _fragSourceFile = "Mask.frag";
    _maskTexture = TextureCache::getInstance()->addImage("CalendarMask.png");
}

void MaskSprite::buildCustomUniforms() {
    _maskLocation = glGetUniformLocation( getShaderProgram()->getProgram(), "u_mask");
}

void MaskSprite::setCustomUniforms() {
    glActiveTexture(GL_TEXTURE1);
    GL::bindTexture2D(_maskTexture->getName());
    getShaderProgram()->setUniformLocationWith1i(_maskLocation, 1);
}

void MaskSprite::draw() {
    GL::enableVertexAttribs(cocos2d::GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX );
    BlendFunc blend = getBlendFunc();
    GL::blendFunc(blend.src, blend.dst);

    getShaderProgram()->use();
    getShaderProgram()->setUniformsForBuiltins();
    setCustomUniforms();

    //
    // Attributes
    //
#define kQuadSize sizeof(_quad.bl)
    long offset = (long)&_quad;

    // vertex
    int diff = offsetof( V3F_C4B_T2F, vertices);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));

    // texCoods
    diff = offsetof( V3F_C4B_T2F, texCoords);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));

    // color
    diff = offsetof( V3F_C4B_T2F, colors);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));


    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glActiveTexture(GL_TEXTURE0);
    CC_INCREMENT_GL_DRAWS(1);
}

The mask shader:

#ifdef GL_ES
precision lowp float;
#endif

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform sampler2D CC_Texture0;
uniform sampler2D u_mask;

void main()
{
    vec4 texColor = texture2D(CC_Texture0, v_texCoord);
    vec4 maskColor = texture2D(u_mask, v_texCoord);
    vec4 finalColor = vec4(texColor.r, texColor.g, texColor.b, maskColor.a * texColor.a);
    gl_FragColor = v_fragmentColor * finalColor;
}

The ShaderSprite from the test suite:

template 
class ShaderSpriteCreator
{
public:
    static spriteType* createSprite(const char* pszFileName)
    {
        spriteType* pRet = new spriteType();
        if (pRet && pRet->initWithFile(pszFileName))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_DELETE(pRet);
        }
        return pRet;
    }
};

class ShaderSprite : public Sprite
{
public:
    ShaderSprite();
    ~ShaderSprite();

    bool initWithTexture(Texture2D* texture, const Rect&  rect);
    void draw();
    void initProgram();
    void listenBackToForeground(Object *obj);

protected:
    virtual void buildCustomUniforms() = 0;
    virtual void setCustomUniforms() = 0;
protected:
    std::string _fragSourceFile;

};

ShaderSprite::ShaderSprite()
{
}

ShaderSprite::~ShaderSprite()
{
    NotificationCenter::getInstance()->removeObserver(this, EVNET_COME_TO_FOREGROUND);
}

void ShaderSprite::listenBackToForeground(Object *obj)
{
    setShaderProgram(NULL);
    initProgram();
}

bool ShaderSprite::initWithTexture(Texture2D* texture, const Rect& rect)
{
    if( Sprite::initWithTexture(texture, rect) )
    {
        NotificationCenter::getInstance()->addObserver(this,
                                                       callfuncO_selector(ShaderSprite::listenBackToForeground),
                                                       EVNET_COME_TO_FOREGROUND,
                                                       NULL);

        this->initProgram();

        return true;
    }

    return false;
}

void ShaderSprite::initProgram()
{
    GLchar * fragSource = (GLchar*) String::createWithContentsOfFile(
                                                                     FileUtils::getInstance()->fullPathForFilename(_fragSourceFile.c_str()).c_str())->getCString();
    auto pProgram = new GLProgram();
    pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert, fragSource);
    setShaderProgram(pProgram);
    pProgram->release();

    CHECK_GL_ERROR_DEBUG();

    getShaderProgram()->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    getShaderProgram()->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
    getShaderProgram()->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);

    CHECK_GL_ERROR_DEBUG();

    getShaderProgram()->link();

    CHECK_GL_ERROR_DEBUG();

    getShaderProgram()->updateUniforms();

    CHECK_GL_ERROR_DEBUG();

    buildCustomUniforms();

    CHECK_GL_ERROR_DEBUG();
}

void ShaderSprite::draw()
{
    GL::enableVertexAttribs(cocos2d::GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX );
    BlendFunc blend = getBlendFunc();
    GL::blendFunc(blend.src, blend.dst);

    getShaderProgram()->use();
    getShaderProgram()->setUniformsForBuiltins();
    setCustomUniforms();

    GL::bindTexture2D( getTexture()->getName());

    //
    // Attributes
    //
#define kQuadSize sizeof(_quad.bl)
    long offset = (long)&_quad;

    // vertex
    int diff = offsetof( V3F_C4B_T2F, vertices);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));

    // texCoods
    diff = offsetof( V3F_C4B_T2F, texCoords);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));

    // color
    diff = offsetof( V3F_C4B_T2F, colors);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));


    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    CC_INCREMENT_GL_DRAWS(1);
}

I am still trying to wrap my head around OpenGL and the cocos2d implementation, but so far I am haven’t even been able to replicate this tutorial in the v3 cocos2d-x branch:
http://www.raywenderlich.com/4428/how-to-mask-a-sprite-with-cocos2d-2-0

Does anyone have a working port of that tutorial? For me, just the mask image is rendered with the inner white portion visible and the outer border transparent. The underlying background texture isn’t rendered at all. This is pretty much the opposite of that should happen but I am so far unsuccessful at figuring it out. If any experts out there has a working port of the above tutorial that would be a big help my understanding how things work and I’d be very appreciative.

Thanks