Skip to content

Commit 9b246d0

Browse files
author
Thayer J Andrews
committed
CCEffectStack - Fix a bug in stitching of multi-pass effects like bloom and blur
The passes of these effects would be improperly collapsed into a single pass which cannot be done since they must maintain their multi-pass implementation. Fix this and add a test that exercises this use case.
1 parent ce51c29 commit 9b246d0

File tree

3 files changed

+65
-27
lines changed

3 files changed

+65
-27
lines changed

cocos2d-ui-tests/tests/CCEffectsTest.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,10 +810,12 @@ -(void)setupBloomEffectTest
810810
sampleSprite3.positionType = CCPositionTypeNormalized;
811811

812812
// Blend glow maps test
813+
CCEffectHue *hueEffect = [CCEffectHue effectWithHue:60.0f];
813814
CCEffectBloom* glowEffect3 = [CCEffectBloom effectWithBlurRadius:8 intensity:1.0f luminanceThreshold:1.0f - ((float)i/(float)(steps-1))];
814815
glowEffect3.padding = CGSizeMake(10.0f, 10.0f);
815-
sampleSprite3.effect = glowEffect3;
816816

817+
sampleSprite3.effect = [CCEffectStack effectWithArray:@[glowEffect3, hueEffect]];
818+
817819
[self.contentNode addChild:sampleSprite3];
818820
}
819821
}

cocos2d/CCEffect.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,20 @@ -(id)initWithIndex:(NSUInteger)indexInEffect
250250
return self;
251251
}
252252

253+
-(instancetype)copyWithZone:(NSZone *)zone
254+
{
255+
CCEffectRenderPass *newPass = [[CCEffectRenderPass allocWithZone:zone] initWithIndex:_indexInEffect];
256+
newPass.texCoord1Mapping = _texCoord1Mapping;
257+
newPass.texCoord2Mapping = _texCoord2Mapping;
258+
newPass.blendMode = _blendMode;
259+
newPass.shader = _shader;
260+
newPass.beginBlocks = _beginBlocks;
261+
newPass.updateBlocks = _updateBlocks;
262+
newPass.endBlocks = _endBlocks;
263+
newPass.debugLabel = _debugLabel;
264+
return newPass;
265+
}
266+
253267
-(void)begin:(CCTexture *)previousPassTexture
254268
{
255269
for (CCEffectRenderPassBeginBlock block in _beginBlocks)

cocos2d/CCEffectStack.m

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ - (CCEffectPrepareStatus)prepareForRendering
186186
int effectIndex = 0;
187187
for (NSArray *stitchList in stitchLists)
188188
{
189-
NSAssert(stitchList.count > 0, @"Encountered an empty stitch list which shouldn't happen.");
190189
[stitchedEffects addObject:[CCEffectStack stitchEffects:stitchList startIndex:effectIndex]];
191190
effectIndex += stitchList.count;
192191
}
@@ -222,16 +221,20 @@ - (BOOL)readyForRendering
222221

223222
#pragma mark - Internal
224223

225-
+ (CCEffect *)stitchEffects:(NSArray*)effects startIndex:(int)startIndex
224+
+ (CCEffect *)stitchEffects:(NSArray*)stitchList startIndex:(int)startIndex
226225
{
226+
NSAssert(stitchList.count > 0, @"Encountered an empty stitch list which shouldn't happen.");
227+
227228
NSMutableArray* allFragFunctions = [[NSMutableArray alloc] init];
228229
NSMutableArray* allFragUniforms = [[NSMutableArray alloc] init];
229230
NSMutableArray* allVertexFunctions = [[NSMutableArray alloc] init];
230231
NSMutableArray* allVertexUniforms = [[NSMutableArray alloc] init];
231232
NSMutableArray* allVaryings = [[NSMutableArray alloc] init];
232233

234+
// Even if we're only handed one effect in this stitch list, we have to run it through the
235+
// name mangling code below because all effects in a stack share one uniform namespace.
233236
int effectIndex = startIndex;
234-
for(CCEffect* effect in effects)
237+
for(CCEffect* effect in stitchList)
235238
{
236239
// Construct the prefix to use for name mangling.
237240
NSString *effectPrefix = [NSString stringWithFormat:@"%@_%d_", effect.debugName, effectIndex];
@@ -291,34 +294,53 @@ + (CCEffect *)stitchEffects:(NSArray*)effects startIndex:(int)startIndex
291294
// and last effects in the stitch list. If the "stitch before" flag is set on the
292295
// first effect then set it in the resulting effect. If the "stitch after" flag is
293296
// set in the last effect then set it in the resulting effect.
294-
CCEffect *firstEffect = [effects firstObject];
295-
CCEffect *lastEffect = [effects lastObject];
297+
CCEffect *firstEffect = [stitchList firstObject];
298+
CCEffect *lastEffect = [stitchList lastObject];
296299
stitchedEffect.stitchFlags = (firstEffect.stitchFlags & CCEffectFunctionStitchBefore) | (lastEffect.stitchFlags & CCEffectFunctionStitchAfter);
297300

298-
// Create a new render pass object and set its shader from the stitched effect
299-
// that was created above.
300-
CCEffectRenderPass *newPass = [[CCEffectRenderPass alloc] init];
301-
newPass.debugLabel = @"CCEffectStack_Stitched pass 0";
302-
newPass.shader = stitchedEffect.shader;
303-
304-
NSMutableArray *beginBlocks = [[NSMutableArray alloc] init];
305-
NSMutableArray *endBlocks = [[NSMutableArray alloc] init];
306-
307-
for (CCEffect *effect in effects)
301+
if (stitchList.count == 1)
308302
{
309-
// Copy the begin and end blocks from the input passes into the new pass.
310-
for (CCEffectRenderPass *pass in effect.renderPasses)
303+
// If there was only one effect in the stitch list copy its render
304+
// passes into the output stitched effect. Update the copied passes
305+
// so they point to the new shader in the stitched effect.
306+
307+
NSMutableArray *renderPasses = [[NSMutableArray alloc] init];
308+
for (CCEffectRenderPass *pass in firstEffect.renderPasses)
311309
{
312-
[beginBlocks addObjectsFromArray:pass.beginBlocks];
313-
[endBlocks addObjectsFromArray:pass.endBlocks];
310+
CCEffectRenderPass *newPass = [pass copy];
311+
newPass.shader = stitchedEffect.shader;
312+
[renderPasses addObject:newPass];
314313
}
314+
stitchedEffect.renderPasses = renderPasses;
315315
}
316-
317-
newPass.beginBlocks = beginBlocks;
318-
newPass.endBlocks = endBlocks;
319-
320-
stitchedEffect.renderPasses = @[newPass];
321-
316+
else
317+
{
318+
// If there were multiple effects in the stitch list, create a new render
319+
// pass object, set its shader to the shader from the stitched effect, and
320+
// copy all blocks from the input passes.
321+
CCEffectRenderPass *newPass = [[CCEffectRenderPass alloc] init];
322+
newPass.debugLabel = @"CCEffectStack_Stitched pass 0";
323+
newPass.shader = stitchedEffect.shader;
324+
325+
NSMutableArray *beginBlocks = [[NSMutableArray alloc] init];
326+
NSMutableArray *endBlocks = [[NSMutableArray alloc] init];
327+
328+
for (CCEffect *effect in stitchList)
329+
{
330+
// Copy the begin and end blocks from the input passes into the new pass.
331+
for (CCEffectRenderPass *pass in effect.renderPasses)
332+
{
333+
[beginBlocks addObjectsFromArray:pass.beginBlocks];
334+
[endBlocks addObjectsFromArray:pass.endBlocks];
335+
}
336+
}
337+
338+
newPass.beginBlocks = beginBlocks;
339+
newPass.endBlocks = endBlocks;
340+
341+
stitchedEffect.renderPasses = @[newPass];
342+
}
343+
322344
return stitchedEffect;
323345
}
324346

@@ -328,7 +350,7 @@ + (NSDictionary *)varyingsByApplyingPrefix:(NSString *)prefix toVaryings:(NSArra
328350
for(CCEffectVarying *varying in varyings)
329351
{
330352
NSString *prefixedName = [NSString stringWithFormat:@"%@%@", prefix, varying.name];
331-
CCEffectVarying *prefixedVarying = [[CCEffectVarying alloc] initWithType:varying.type name:prefixedName];
353+
CCEffectVarying *prefixedVarying = [[CCEffectVarying alloc] initWithType:varying.type name:prefixedName count:varying.count];
332354
[varyingReplacements setObject:prefixedVarying forKey:varying.name];
333355
}
334356
return [varyingReplacements copy];

0 commit comments

Comments
 (0)