Skip to content

Commit 7e03082

Browse files
committed
Added distance field outline effect.
1 parent 6d5841c commit 7e03082

File tree

5 files changed

+64
-76
lines changed

5 files changed

+64
-76
lines changed

Resources/Images/output.png

72 Bytes
Loading

cocos2d-ui-tests/tests/CCEffectsTest.m

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
#import "CCNodeColor.h"
44
#import "CCEffectNode.h"
55

6-
enum DFTest { DISTANCE_FIELD, OUTLINE };
7-
86
@interface CCEffectsTest : TestBase @end
97
@implementation CCEffectsTest {
108
#if CC_EFFECTS_EXPERIMENTAL
119
CCEffectDistanceField* _distanceFieldEffect;
1210
#endif
1311
CCEffectDFOutline* _outlineEffect;
14-
enum DFTest _currentEffect;
1512
}
1613

1714
-(id)init
@@ -28,15 +25,14 @@ -(id)init
2825

2926
-(void)setupDFOutlineEffectTest
3027
{
31-
_currentEffect = OUTLINE;
3228
self.subTitle = @"Distance Field Outline Test";
3329

3430
CCSprite *environment = [CCSprite spriteWithImageNamed:@"Images/MountainPanorama.jpg"];
3531
environment.positionType = CCPositionTypeNormalized;
3632
environment.anchorPoint = ccp(0.5, 0.5);
3733
environment.position = ccp(0.5f, 0.5f);
3834

39-
_outlineEffect = [CCEffectDFOutline effectWithOutlineColor:[CCColor redColor] fillColor:[CCColor blackColor]];
35+
_outlineEffect = [CCEffectDFOutline effectWithOutlineColor:[CCColor redColor] fillColor:[CCColor blackColor] outlineWidth:3 fieldScale:32];
4036

4137
CCSprite *sampleSprite = [CCSprite spriteWithImageNamed:@"Images/output.png"];
4238
sampleSprite.position = ccp(0.5, 0.5);
@@ -59,31 +55,31 @@ -(void)setupDFOutlineEffectTest
5955
slider.anchorPoint = ccp(0.5f, 0.5f);
6056
slider.scale = 0.8;
6157

62-
[slider setTarget:self selector:@selector(outlineInnerWidthChange:)];
63-
64-
CCSlider* slider2 = [[CCSlider alloc] initWithBackground:background andHandleImage:handle];
65-
[slider2 setBackgroundSpriteFrame:backgroundHilite forState:CCControlStateHighlighted];
66-
slider2.positionType = CCPositionTypeNormalized;
67-
slider2.position = ccp(0.15f, 0.5f);
68-
69-
slider2.preferredSizeType = CCSizeTypeMake(CCSizeUnitNormalized, CCSizeUnitUIPoints);
70-
slider2.preferredSize = CGSizeMake(0.5f, 10);
71-
slider2.rotation = 90;
72-
slider2.anchorPoint = ccp(0.5f, 0.5f);
73-
slider2.scale = 0.8;
58+
[slider setTarget:self selector:@selector(outlineWidthChagne:)];
7459

75-
[slider2 setTarget:self selector:@selector(outlineOuterWidthChange:)];
76-
7760
[self.contentNode addChild:environment];
7861
[self.contentNode addChild:slider];
79-
[self.contentNode addChild:slider2];
8062
[self.contentNode addChild:sampleSprite];
63+
64+
// 6 pixel block used for comparison;
65+
CCNodeColor* block = [CCNodeColor nodeWithColor:[CCColor greenColor]];
66+
block.contentSize = CGSizeMake(6.0, 6.0);
67+
block.position = ccp(0.424, 0.324);
68+
block.positionType = CCPositionTypeNormalized;
69+
block.rotation = 32;
70+
// [self.contentNode addChild:block];
71+
}
72+
73+
- (void)outlineWidthChagne:(id)sender
74+
{
75+
const int outlineWidthMax = 6;
76+
CCSlider* slider = sender;
77+
_outlineEffect.outlineWidth = slider.sliderValue * outlineWidthMax;
8178
}
8279

8380
#if CC_EFFECTS_EXPERIMENTAL
8481
-(void)setupDistanceFieldEffectTest
8582
{
86-
_currentEffect = DISTANCE_FIELD;
8783
self.subTitle = @"Distance Field Effect Test";
8884

8985
// CCNodeColor* environment = [CCNodeColor nodeWithColor:[CCColor whiteColor]];
@@ -166,25 +162,16 @@ -(void)setupDistanceFieldEffectTest
166162
[self.contentNode addChild:slider3];
167163
}
168164

169-
#endif
170-
171165
- (void)outlineInnerWidthChange:(id)sender
172166
{
173167
CCSlider* slider = sender;
174-
if(_currentEffect == DISTANCE_FIELD)
175-
_distanceFieldEffect.outlineInnerWidth = slider.sliderValue;
176-
else if(_currentEffect == OUTLINE)
177-
_outlineEffect.outlineInnerWidth = slider.sliderValue;
178-
168+
_distanceFieldEffect.outlineInnerWidth = slider.sliderValue;
179169
}
180170

181171
- (void)outlineOuterWidthChange:(id)sender
182172
{
183173
CCSlider* slider = sender;
184-
if(_currentEffect == DISTANCE_FIELD)
185-
_distanceFieldEffect.outlineOuterWidth = slider.sliderValue;
186-
else if(_currentEffect == OUTLINE)
187-
_outlineEffect.outlineOuterWidth = slider.sliderValue;
174+
_distanceFieldEffect.outlineOuterWidth = slider.sliderValue;
188175
}
189176

190177
- (void)glowWidthChange:(id)sender
@@ -203,6 +190,8 @@ - (void)enableOutline:(id)sender
203190
_distanceFieldEffect.outline = !_distanceFieldEffect.outline;
204191
}
205192

193+
#endif
194+
206195
#pragma mark DropShadow
207196

208197
-(void)setupDropShadowEffectTest

cocos2d/CCEffectDFOutline.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
/// @name Accessing Effect Attributes
2020
/// -----------------------------------------------------------------------
2121

22+
/** Color of the outline */
2223
@property (nonatomic, strong) CCColor* fillColor;
24+
25+
/** Color of the distance field */
2326
@property (nonatomic, strong) CCColor* outlineColor;
2427

25-
@property (nonatomic) float outlineInnerWidth;
26-
@property (nonatomic) float outlineOuterWidth;
28+
/** Outline width pixel width of the outline */
29+
@property (nonatomic) int outlineWidth;
2730

2831
/// -----------------------------------------------------------------------
2932
/// @name Initializing a CCEffectDFOutline object
@@ -39,11 +42,17 @@
3942
/**
4043
* Initializes a CCEffectDFOutline object with the supplied parameters.
4144
*
42-
* @param glowColor Color of the glow, a [CCColor blackColor] will result in an opaque black drop shadow.
45+
* @param outlineColor Color of the outline, a [CCColor blackColor] will result in an opaque black outline.
46+
* @param fillColor Color of the fillColor, a [CCColor blackColor] will result in an opaque black fillColor.
47+
* @param outlineWidth pixel width of the outline.
48+
* @param fieldScale, defined by the distance field generation proccess, for example a distance field that
49+
* was generated with a 4096/4096 input and output a 128/128 texture would have a fieldScale of 32 (
50+
* input size / output size). Note: this parameter could be automatically calculated if we assume that all
51+
* distance fields are generated from a 4096 input.
4352
*
4453
* @return The CCEffectDFOutline object.
4554
*/
46-
-(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor;
55+
-(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)outlineColor outlineWidth:(int)outlineWidth fieldScale:(float)fieldScale;
4756

4857

4958
/// -----------------------------------------------------------------------
@@ -57,6 +66,6 @@
5766
*
5867
* @return The CCEffectDFOutline object.
5968
*/
60-
+(id)effectWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor;
69+
+(id)effectWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor outlineWidth:(int)outlineWidth fieldScale:(float)fieldScale;
6170

6271
@end

cocos2d/CCEffectDFOutline.m

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
#import "CCRenderer.h"
1212
#import "CCTexture.h"
1313

14-
@implementation CCEffectDFOutline
14+
@implementation CCEffectDFOutline {
15+
float _outerMin;
16+
float _outerMax;
17+
float _fieldScaleFactor;
18+
}
1519

1620
-(id)init
1721
{
18-
return [self initWithOutlineColor:[CCColor redColor] fillColor:[CCColor blackColor]];
22+
return [self initWithOutlineColor:[CCColor redColor] fillColor:[CCColor blackColor] outlineWidth:3 fieldScale:32];
1923
}
2024

21-
-(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor
25+
-(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor outlineWidth:(int)outlineWidth fieldScale:(float)fieldScale
2226
{
2327
NSArray *uniforms = @[
2428
[CCEffectUniform uniform:@"vec4" name:@"u_fillColor" value:[NSValue valueWithGLKVector4:[CCColor blackColor].glkVector4]],
@@ -29,8 +33,8 @@ -(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor
2933

3034
if((self = [super initWithFragmentUniforms:uniforms vertexUniforms:nil varyings:nil]))
3135
{
32-
_outlineInnerWidth = 0.08;
33-
_outlineOuterWidth = 0.08;
36+
_fieldScaleFactor = 32.0f; // 32 4096/128 (input distance field size / output df size)
37+
self.outlineWidth = 3;
3438
_fillColor = fillColor;
3539
_outlineColor = outlineColor;
3640

@@ -39,9 +43,9 @@ -(id)initWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor
3943
return self;
4044
}
4145

42-
+(id)effectWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor
46+
+(id)effectWithOutlineColor:(CCColor*)outlineColor fillColor:(CCColor*)fillColor outlineWidth:(int)outlineWidth fieldScale:(float)fieldScale
4347
{
44-
return [[self alloc] initWithOutlineColor:outlineColor fillColor:fillColor];
48+
return [[self alloc] initWithOutlineColor:outlineColor fillColor:fillColor outlineWidth:outlineWidth fieldScale:fieldScale];
4549
}
4650

4751
-(void)buildFragmentFunctions
@@ -61,15 +65,14 @@ -(void)buildFragmentFunctions
6165

6266
// soft edges
6367
outputColor.a *= smoothstep(min, max, distAlphaMask);
64-
65-
vec4 glowTexel = texture2D(cc_MainTexture, cc_FragTexCoord1);
66-
// min -= 0.2;
67-
// max += 0.2;
68-
68+
6969
min = u_outlineOuterWidth.x;
7070
max = u_outlineOuterWidth.y;
71-
min = 0.3;
72-
max = 0.34;
71+
if(min == 0.5 && max == 0.5)
72+
return outputColor;
73+
74+
vec4 glowTexel = texture2D(cc_MainTexture, cc_FragTexCoord1);
75+
7376

7477
vec4 glowc = u_outlineColor * smoothstep(min, max, glowTexel.r);
7578

@@ -100,38 +103,25 @@ -(void)buildRenderPasses
100103
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_fillColor"]] = [NSValue valueWithGLKVector4:weakSelf.fillColor.glkVector4];
101104
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_outlineColor"]] = [NSValue valueWithGLKVector4:weakSelf.outlineColor.glkVector4];
102105

103-
// 0.5 == center(edge), < 0.5 == outside, > 0.5 == inside
104-
float innerMin = 0.5;
105-
float innerMax = (0.5 * _outlineInnerWidth) + innerMin;
106-
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_outlineInnerWidth"]] = [NSValue valueWithGLKVector2:GLKVector2Make(innerMin, innerMax)];
107-
108-
float outerMin = (0.5 * (1.0 - _outlineOuterWidth));
109-
float outerMax = 0.5;
110-
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_outlineOuterWidth"]] = [NSValue valueWithGLKVector2:GLKVector2Make(outerMin, outerMax)];
111-
112-
// float glowWidthMin = (0.5 * (1.0 - _glowWidth));
113-
// float glowWidthMax = 0.5;
114-
// pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_glowWidth"]] = [NSValue valueWithGLKVector2:GLKVector2Make(glowWidthMin, glowWidthMax)];
115-
//
116-
// pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_outline"]] = _outline ? [NSNumber numberWithFloat:1.0f] : [NSNumber numberWithFloat:0.0f];
117-
// pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_glow"]] = _glow ? [NSNumber numberWithFloat:1.0f] : [NSNumber numberWithFloat:0.0f];
118-
//
119-
// GLKVector2 offset = GLKVector2Make(weakSelf.glowOffset.x / previousPassTexture.contentSize.width, weakSelf.glowOffset.y / previousPassTexture.contentSize.height);
120-
// pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_glowOffset"]] = [NSValue valueWithGLKVector2:offset];
106+
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_outlineOuterWidth"]] = [NSValue valueWithGLKVector2:GLKVector2Make(_outerMin, _outerMax)];
121107

122108
} copy]];
123109

124110
self.renderPasses = @[pass0];
125111
}
126112

127-
-(void)setOutlineInnerWidth:(float)outlineInnerWidth
113+
-(void)setOutlineWidth:(int)outlineWidth
128114
{
129-
_outlineInnerWidth = clampf(outlineInnerWidth, 0.0f, 1.0f);
130-
}
115+
116+
_outlineWidth = outlineWidth;//clampf(outlineOuterWidth, 0.0f, 1.0f);
117+
118+
float outlineWidthNormalized = ((float)outlineWidth)/255.0 * _fieldScaleFactor;
119+
float edgeSoftness = _outlineWidth * 0.1; // randomly chosen number that looks good to me, based on a 200 pixel spread (note: this should adjustable).
120+
121+
// 0.5 == center(edge), < 0.5 == outside, > 0.5 == inside
122+
_outerMin = (0.5 * (1.0 - outlineWidthNormalized));
123+
_outerMax = _outerMin + _outerMin * edgeSoftness;
131124

132-
-(void)setOutlineOuterWidth:(float)outlineOuterWidth
133-
{
134-
_outlineOuterWidth = clampf(outlineOuterWidth, 0.0f, 1.0f);
135125
}
136126

137127
@end

cocos2d/ccConfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,6 @@
155155
#endif
156156

157157
#ifndef CC_EFFECTS_EXPERIMENTAL
158-
#define CC_EFFECTS_EXPERIMENTAL 1
158+
#define CC_EFFECTS_EXPERIMENTAL 0
159159
#endif
160160

0 commit comments

Comments
 (0)