Skip to content

Commit 4ff2432

Browse files
author
Thayer J Andrews
committed
CCEffects - Fix mixing of sprite color / opacity with effects
Some effects handled colors and opacity properly, some did not. And none of them did the right thing if multiple effects were stacked together without stitching. Color would either be multiplied in multiple times or not at all. This change introduces a new code snippet for effect function inputs that is used if the effect function is the first one in a stack. Otherwise, the alternative snippet is used. The initial snippet for all effects multiplies the fragment color by the texture and the alternate snippet just fetches the texture. In plain english this means that the input to an effect stack is the sprite's texture times its color and we insure that the texture times color multiply does not happen again in the stack.
1 parent 2cb233e commit 4ff2432

10 files changed

+53
-38
lines changed

cocos2d/CCEffect.m

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,23 @@ -(NSString*)callStringWithInputs:(NSArray*)inputs
9999

100100
@implementation CCEffectFunctionInput
101101

102-
-(id)initWithType:(NSString*)type name:(NSString*)name snippet:(NSString*)snippet
102+
-(id)initWithType:(NSString*)type name:(NSString*)name initialSnippet:(NSString*)initialSnippet snippet:(NSString*)snippet
103103
{
104104
if((self = [super init]))
105105
{
106106
_type = [type copy];
107107
_name = [name copy];
108+
_initialSnippet = [initialSnippet copy];
108109
_snippet = [snippet copy];
109110
return self;
110111
}
111112

112113
return self;
113114
}
114115

115-
+(id)inputWithType:(NSString*)type name:(NSString*)name snippet:(NSString*)snippet
116+
+(id)inputWithType:(NSString*)type name:(NSString*)name initialSnippet:(NSString*)initialSnippet snippet:(NSString*)snippet
116117
{
117-
return [[self alloc] initWithType:type name:name snippet:snippet];
118+
return [[self alloc] initWithType:type name:name initialSnippet:initialSnippet snippet:snippet];
118119
}
119120

120121
@end
@@ -316,12 +317,22 @@ -(id)initWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunction
316317
{
317318
if((self = [super init]))
318319
{
319-
[self buildEffectWithFragmentFunction:fragmentFunctions vertexFunctions:vertexFunctions fragmentUniforms:fragmentUniforms vertexUniforms:vertexUniforms varyings:varyings];
320+
[self buildEffectWithFragmentFunction:fragmentFunctions vertexFunctions:vertexFunctions fragmentUniforms:fragmentUniforms vertexUniforms:vertexUniforms varyings:varyings firstInStack:YES];
320321
}
321322
return self;
322323
}
323324

324-
- (void)buildEffectWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunctions:(NSMutableArray*)vertexFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings
325+
-(id)initWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunctions:(NSMutableArray*)vertexFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings firstInStack:(BOOL)firstInStack
326+
{
327+
if((self = [super init]))
328+
{
329+
[self buildEffectWithFragmentFunction:fragmentFunctions vertexFunctions:vertexFunctions fragmentUniforms:fragmentUniforms vertexUniforms:vertexUniforms varyings:varyings firstInStack:firstInStack];
330+
}
331+
return self;
332+
}
333+
334+
335+
- (void)buildEffectWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunctions:(NSMutableArray*)vertexFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings firstInStack:(BOOL)firstInStack
325336
{
326337
if (fragmentFunctions)
327338
{
@@ -363,6 +374,7 @@ - (void)buildEffectWithFragmentFunction:(NSMutableArray*) fragmentFunctions vert
363374
[self setVaryings:varyings];
364375

365376
_stitchFlags = CCEffectFunctionStitchBoth;
377+
_firstInStack = firstInStack;
366378

367379
[self buildShaderUniforms:_fragmentUniforms vertexUniforms:_vertexUniforms];
368380
[self buildUniformTranslationTable];
@@ -414,17 +426,17 @@ -(void)setVaryings:(NSArray*)varyings
414426

415427
-(void)buildEffectShader
416428
{
417-
NSString *fragBody = [self buildShaderSourceFromBase:fragBase functions:_fragmentFunctions uniforms:_fragmentUniforms varyings:_varyingVars];
429+
NSString *fragBody = [self buildShaderSourceFromBase:fragBase functions:_fragmentFunctions uniforms:_fragmentUniforms varyings:_varyingVars firstInStack:_firstInStack];
418430
// NSLog(@"\n------------fragBody:\n%@", fragBody);
419431

420-
NSString *vertBody = [self buildShaderSourceFromBase:vertBase functions:_vertexFunctions uniforms:_vertexUniforms varyings:_varyingVars];
432+
NSString *vertBody = [self buildShaderSourceFromBase:vertBase functions:_vertexFunctions uniforms:_vertexUniforms varyings:_varyingVars firstInStack:_firstInStack];
421433
// NSLog(@"\n------------vertBody:\n%@", vertBody);
422434

423435
_shader = [[CCShader alloc] initWithVertexShaderSource:vertBody fragmentShaderSource:fragBody];
424436

425437
}
426438

427-
-(NSString *)buildShaderSourceFromBase:(NSString *)shaderBase functions:(NSArray *)functions uniforms:(NSArray *)uniforms varyings:(NSArray *)varyings
439+
-(NSString *)buildShaderSourceFromBase:(NSString *)shaderBase functions:(NSArray *)functions uniforms:(NSArray *)uniforms varyings:(NSArray *)varyings firstInStack:(BOOL)firstInStack
428440
{
429441
// Build the varying string
430442
NSMutableString* varyingString = [[NSMutableString alloc] init];
@@ -451,9 +463,19 @@ -(NSString *)buildShaderSourceFromBase:(NSString *)shaderBase functions:(NSArray
451463

452464
if([functions firstObject] == curFunction)
453465
{
454-
for (CCEffectFunctionInput *input in curFunction.inputs)
466+
if (firstInStack)
467+
{
468+
for (CCEffectFunctionInput *input in curFunction.inputs)
469+
{
470+
[effectFunctionBody appendFormat:@"tmp = %@;\n", input.initialSnippet];
471+
}
472+
}
473+
else
455474
{
456-
[effectFunctionBody appendFormat:@"tmp = %@;\n", input.snippet];
475+
for (CCEffectFunctionInput *input in curFunction.inputs)
476+
{
477+
[effectFunctionBody appendFormat:@"tmp = %@;\n", input.snippet];
478+
}
457479
}
458480
}
459481

cocos2d/CCEffectBrightness.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ -(void)buildFragmentFunctions
5050
{
5151
self.fragmentFunctions = [[NSMutableArray alloc] init];
5252

53-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
53+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
5454

5555
NSString* effectBody = CC_GLSL(
5656
return vec4((inputValue.rgb + vec3(u_brightness * inputValue.a)), inputValue.a);

cocos2d/CCEffectContrast.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ -(void)buildFragmentFunctions
5151
{
5252
self.fragmentFunctions = [[NSMutableArray alloc] init];
5353

54-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
54+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
5555

5656
NSString* effectBody = CC_GLSL(
5757
return vec4(((inputValue.rgb - vec3(0.5)) * vec3(u_contrast) + vec3(0.5)), inputValue.a);

cocos2d/CCEffectGlass.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ -(void)buildFragmentFunctions
110110
{
111111
self.fragmentFunctions = [[NSMutableArray alloc] init];
112112

113-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
113+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
114114

115115
NSString* effectBody = CC_GLSL(
116116
// Index the normal map and expand the color value from [0..1] to [-1..1]

cocos2d/CCEffectHue.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ -(void)buildFragmentFunctions
103103
{
104104
self.fragmentFunctions = [[NSMutableArray alloc] init];
105105

106-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
106+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
107107

108108
// The non-color matrix shader is based on the hue filter in GPUImage - https://github.com/BradLarson/GPUImage
109109
#if CCEFFECTHUE_USES_COLOR_MATRIX

cocos2d/CCEffectReflection.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ -(void)buildFragmentFunctions
111111
{
112112
self.fragmentFunctions = [[NSMutableArray alloc] init];
113113

114-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
114+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
115115

116116
NSString* effectBody = CC_GLSL(
117117
// Index the normal map and expand the color value from [0..1] to [-1..1]

cocos2d/CCEffectRefraction.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ -(void)buildFragmentFunctions
8080
{
8181
self.fragmentFunctions = [[NSMutableArray alloc] init];
8282

83-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
83+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
8484

8585
NSString* effectBody = CC_GLSL(
8686
// Index the normal map and expand the color value from [0..1] to [-1..1]

cocos2d/CCEffectSaturation.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ -(void)buildFragmentFunctions
8686
{
8787
self.fragmentFunctions = [[NSMutableArray alloc] init];
8888

89-
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
89+
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:@"cc_FragColor * texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)" snippet:@"texture2D(cc_PreviousPassTexture, cc_FragTexCoord1)"];
9090

9191
// Image saturation shader based on saturation filter in GPUImage - https://github.com/BradLarson/GPUImage
9292
NSString* effectBody = CC_GLSL(

cocos2d/CCEffectStack.m

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,6 @@ - (CCEffectPrepareStatus)prepareForRendering
149149
}
150150

151151
NSMutableArray *stitchedEffects = [[NSMutableArray alloc] init];
152-
if ((flattenedEffects.count == 1) || !_stitchingEnabled)
153-
{
154-
// If there's only one effect or if stitching is disabled, just
155-
// use the original effects array.
156-
[stitchedEffects addObjectsFromArray:flattenedEffects];
157-
}
158-
else if (flattenedEffects.count > 1)
159152
{
160153
NSMutableArray *stitchLists = [[NSMutableArray alloc] init];
161154
NSMutableArray *currentStitchList = [[NSMutableArray alloc] initWithArray:@[[flattenedEffects firstObject]]];
@@ -166,7 +159,7 @@ - (CCEffectPrepareStatus)prepareForRendering
166159
for (CCEffect *effect in [flattenedEffects subarrayWithRange:NSMakeRange(1, flattenedEffects.count - 1)])
167160
{
168161
CCEffect *prevEffect = [currentStitchList lastObject];
169-
if ([prevEffect stitchSupported:CCEffectFunctionStitchAfter] && [effect stitchSupported:CCEffectFunctionStitchBefore])
162+
if (_stitchingEnabled && [prevEffect stitchSupported:CCEffectFunctionStitchAfter] && [effect stitchSupported:CCEffectFunctionStitchBefore])
170163
{
171164
[currentStitchList addObject:effect];
172165
}
@@ -177,17 +170,12 @@ - (CCEffectPrepareStatus)prepareForRendering
177170
}
178171
}
179172

173+
int effectIndex = 0;
180174
for (NSArray *stitchList in stitchLists)
181175
{
182176
NSAssert(stitchList.count > 0, @"Encountered an empty stitch list which shouldn't happen.");
183-
if (stitchList.count == 1)
184-
{
185-
[stitchedEffects addObject:[stitchList firstObject]];
186-
}
187-
else
188-
{
189-
[stitchedEffects addObject:[self stitchEffects:stitchList]];
190-
}
177+
[stitchedEffects addObject:[self stitchEffects:stitchList startIndex:effectIndex]];
178+
effectIndex += stitchList.count;
191179
}
192180
}
193181

@@ -216,15 +204,15 @@ - (BOOL)readyForRendering
216204

217205
#pragma mark - Internal
218206

219-
-(CCEffect *)stitchEffects:(NSArray*)effects
207+
-(CCEffect *)stitchEffects:(NSArray*)effects startIndex:(int)startIndex
220208
{
221209
NSMutableArray* allFragFunctions = [[NSMutableArray alloc] init];
222210
NSMutableArray* allFragUniforms = [[NSMutableArray alloc] init];
223211
NSMutableArray* allVertexFunctions = [[NSMutableArray alloc] init];
224212
NSMutableArray* allVertexUniforms = [[NSMutableArray alloc] init];
225213
NSMutableArray* allVaryings = [[NSMutableArray alloc] init];
226214

227-
int effectIndex = 0;
215+
int effectIndex = startIndex;
228216
for(CCEffect* effect in effects)
229217
{
230218
NSString *effectPrefix = [NSString stringWithFormat:@"%@_%d_", effect.debugName, effectIndex];
@@ -268,7 +256,8 @@ -(CCEffect *)stitchEffects:(NSArray*)effects
268256
effectIndex++;
269257
}
270258

271-
CCEffect* stitchedEffect = [[CCEffect alloc] initWithFragmentFunction:allFragFunctions vertexFunctions:allVertexFunctions fragmentUniforms:allFragUniforms vertexUniforms:allVertexUniforms varyings:allVaryings];
259+
BOOL firstInStack = (startIndex == 0) ? YES : NO;
260+
CCEffect* stitchedEffect = [[CCEffect alloc] initWithFragmentFunction:allFragFunctions vertexFunctions:allVertexFunctions fragmentUniforms:allFragUniforms vertexUniforms:allVertexUniforms varyings:allVaryings firstInStack:firstInStack];
272261
stitchedEffect.debugName = @"CCEffectStack_Stitched";
273262

274263
// Set the stitch flags of the resulting effect based on the flags of the first

cocos2d/CCEffect_Private.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ typedef NS_ENUM(NSUInteger, CCEffectPrepareStatus)
5050

5151
@property (nonatomic, readonly) NSString* type;
5252
@property (nonatomic, readonly) NSString* name;
53+
@property (nonatomic, readonly) NSString* initialSnippet;
5354
@property (nonatomic, readonly) NSString* snippet;
5455

55-
-(id)initWithType:(NSString*)type name:(NSString*)name snippet:(NSString*)snippet;
56-
+(id)inputWithType:(NSString*)type name:(NSString*)name snippet:(NSString*)snippet;
56+
-(id)initWithType:(NSString*)type name:(NSString*)name initialSnippet:(NSString*)initialSnippet snippet:(NSString*)snippet;
57+
+(id)inputWithType:(NSString*)type name:(NSString*)name initialSnippet:(NSString*)initialSnippet snippet:(NSString*)snippet;
5758

5859
@end
5960

@@ -131,10 +132,13 @@ typedef void (^CCEffectRenderPassEndBlock)(CCEffectRenderPass *pass);
131132
@property (nonatomic) CCEffectFunctionStitchFlags stitchFlags;
132133
@property (nonatomic) NSMutableDictionary* uniformTranslationTable;
133134

135+
@property (nonatomic, readonly) BOOL firstInStack;
136+
134137

135138
-(id)initWithFragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings;
136139
-(id)initWithFragmentFunction:(NSMutableArray*) fragmentFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings;
137140
-(id)initWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunctions:(NSMutableArray*)vertexFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings;
141+
-(id)initWithFragmentFunction:(NSMutableArray*) fragmentFunctions vertexFunctions:(NSMutableArray*)vertexFunctions fragmentUniforms:(NSArray*)fragmentUniforms vertexUniforms:(NSArray*)vertexUniforms varyings:(NSArray*)varyings firstInStack:(BOOL)firstInStack;
138142

139143
-(CCEffectPrepareStatus)prepareForRendering;
140144
-(CCEffectRenderPass *)renderPassAtIndex:(NSUInteger)passIndex;

0 commit comments

Comments
 (0)