@araker, thanks for the sharing! I added the extra property because I would like to see if I can use the alpha value in this ccc4 color to set the opacity of the tint while the original opacity value will be used to set the overall opacity of the sprite.
I tried to drop the updateColor override and yes the tinting can be achieved by setColor and the opacity of the sprite (with just some minor color difference). But I found that I still can't change the opacity of the sprite anymore, although the updateColor method now is using the opacity_ value of the sprite.

I think this is caused by the gltexenv setting in my draw method instead. Maybe I need to combine the alpha in another way but I just can't figure it out. I am really new to opengl. I think my code now set the alpha value to fully opaque no matter what the sprite's opacity setting is. I need to set the alpha back to the sprite's opacity without affecting the tinting. Below is the full code of my draw method in my subclassed ccsprite and ccspritebatchnode:
ccSprite:
-(void) draw
{
//[super draw];
NSAssert(!usesBatchNode_, @"If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called");
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Unneeded states: -
BOOL newBlend = NO;
if( blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST ) {
newBlend = YES;
glBlendFunc( blendFunc_.src, blendFunc_.dst );
}
#define kQuadSize sizeof(quad_.bl)
//set blend function...
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //you can force it here or set it on the sprite
//the magic
// Using texture unit 0
glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// The vertex color set by setColor will cover the sprite's texture
// GL_PREVIOUS equals the vertex color
// GL_TEXTURE equals the sprite's texture
// We will use the vertex's color's primary color to control the blending
// The vertex color's alpha value can be set by the new colorA property
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_PRIMARY_COLOR); // primary color is the actual vertex colors
// the vertex color including the added alpha value will control how much the set color will affect the sprite
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, [texture_ name]);
// The address of the quad array
long offset = (long)&quad_;
// vertex
NSInteger diff = offsetof( ccV3F_C4B_T2F, vertices);
glVertexPointer(3, GL_FLOAT, kQuadSize, (void*) (offset + diff) );
// color
diff = offsetof( ccV3F_C4B_T2F, colors);
glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff));
// tex coords
diff = offsetof( ccV3F_C4B_T2F, texCoords);
glTexCoordPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if( newBlend )
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
#if CC_SPRITE_DEBUG_DRAW
CGSize s = [self contentSize];
CGPoint vertices[4]={
ccp(0,0),ccp(s.width,0),
ccp(s.width,s.height),ccp(0,s.height),
};
ccDrawPoly(vertices, 4, YES);
#endif // CC_TEXTURENODE_DEBUG_DRAW
//go back to default
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
CCSpriteBatchNode:
-(void) draw
{
//[super draw];
// Optimization: Fast Dispatch
if( textureAtlas_.totalQuads == 0 )
return;
//CCSprite *child;
MyCCSprite *child;
ccArray *array = descendants_->data;
NSUInteger i = array->num;
id *arr = array->arr;
if( i > 0 ) {
while (i-- > 0) {
child = *arr++;
// fast dispatch
child->updateMethod(child, selUpdate);
#if CC_SPRITEBATCHNODE_DEBUG_DRAW
//Issue #528
CGRect rect = [child boundingBox];
CGPoint vertices[4]={
ccp(rect.origin.x,rect.origin.y),
ccp(rect.origin.x+rect.size.width,rect.origin.y),
ccp(rect.origin.x+rect.size.width,rect.origin.y+rect.size.height),
ccp(rect.origin.x,rect.origin.y+rect.size.height),
};
ccDrawPoly(vertices, 4, YES);
#endif // CC_SPRITEBATCHNODE_DEBUG_DRAW
}
}
//the magic
// Using texture unit 0
glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// The vertex color set by setColor will cover the sprite's texture
// GL_PREVIOUS equals the vertex color
// GL_TEXTURE equals the sprite's texture
// We will use the vertex's color's primary color to control the blending
// The vertex color's alpha value can be set by the new colorA property
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_PRIMARY_COLOR); // primary color is the actual vertex colors
// the vertex color including the added alpha value will control how much the set color will affect the sprite
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST;
if( newBlend )
glBlendFunc( blendFunc_.src, blendFunc_.dst );
[textureAtlas_ drawQuads];
if( newBlend )
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
//go back to default
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}