From c3a367de67a32901fc25539b2ce9177529e9d770 Mon Sep 17 00:00:00 2001 From: Lars Birkemose Date: Thu, 14 Aug 2014 14:11:19 +0200 Subject: [PATCH] CCLayerSmoothLine added --- .../CCLayerSmoothLine/CCLayerSmoothLine.h | 60 +++ .../CCLayerSmoothLine/CCLayerSmoothLine.m | 491 ++++++++++++++++++ Extensions/CCLayerSmoothLine/README.md | 19 + cocos2d-iphone-ext.xcodeproj/project.pbxproj | 22 + .../UserInterfaceState.xcuserstate | Bin 29448 -> 29949 bytes .../Classes/Tests/CCLayerSmoothLineTest.m | 37 ++ 6 files changed, 629 insertions(+) create mode 100644 Extensions/CCLayerSmoothLine/CCLayerSmoothLine.h create mode 100644 Extensions/CCLayerSmoothLine/CCLayerSmoothLine.m create mode 100644 Extensions/CCLayerSmoothLine/README.md create mode 100644 cocos2d-iphone-ext/Classes/Tests/CCLayerSmoothLineTest.m diff --git a/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.h b/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.h new file mode 100644 index 0000000..f81020c --- /dev/null +++ b/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.h @@ -0,0 +1,60 @@ +/* + * Smooth drawing: http://merowing.info + * + * Copyright (c) 2012 Krzysztof Zabłocki + * Copyright (c) 2014 Richard Groves + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#import "cocos2d.h" + +typedef struct +{ + CGPoint pos; + float z; + ccColor4F color; +} CCSmoothLineVertex; + +// ----------------------------------------------------------------------- + +@interface CCSmoothLinePoint : NSObject + +@property(nonatomic, assign) CGPoint pos; +@property(nonatomic, assign) float width; + +@end + +// ----------------------------------------------------------------------- + +@interface CCLayerSmoothLine : CCNode + +// ----------------------------------------------------------------------- + ++ (instancetype)layer; +- (instancetype)init; + +- (void)startNewLineFrom:(CGPoint)newPoint withSize:(CGFloat)aSize; +- (void)endLineAt:(CGPoint)aEndPoint withSize:(CGFloat)aSize; +- (void)addPoint:(CGPoint)newPoint withSize:(CGFloat)size; + +// ----------------------------------------------------------------------- + +@end \ No newline at end of file diff --git a/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.m b/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.m new file mode 100644 index 0000000..bdd0486 --- /dev/null +++ b/Extensions/CCLayerSmoothLine/CCLayerSmoothLine.m @@ -0,0 +1,491 @@ +/* + * Smooth drawing: http://merowing.info + * + * Copyright (c) 2012 Krzysztof Zabłocki + * Copyright (c) 2014 Richard Groves + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#import +#import "cocos2d.h" +#import "CCLayerSmoothLine.h" +#import "CCNode_Private.h" // shader stuff +#import "CCRenderer_private.h" // access to get and stash renderer + +// ----------------------------------------------------------------------- + +@implementation CCSmoothLinePoint + +@end + +// ----------------------------------------------------------------------- + +@implementation CCLayerSmoothLine +{ + NSMutableArray *_points; + NSMutableArray *_velocities; + NSMutableArray *_circlesPoints; + + BOOL _connectingLine; + CGPoint _prevC, _prevD; + CGPoint _prevG; + CGPoint _prevI; + float _overdraw; + + CCRenderTexture *_renderTexture; + BOOL _finishingLine; +} + +// ----------------------------------------------------------------------- + ++ (instancetype)layer +{ + return([[self alloc] init]); +} + +// ----------------------------------------------------------------------- + +- (id)init +{ + self = [super init]; + if (self) + { + self.contentSize = [CCDirector sharedDirector].viewSize; + + _points = [NSMutableArray array]; + _velocities = [NSMutableArray array]; + _circlesPoints = [NSMutableArray array]; + + _overdraw = 3.0f; + + CGSize s = [[CCDirector sharedDirector] viewSize]; + _renderTexture = [[CCRenderTexture alloc] initWithWidth:s.width height:s.height pixelFormat:CCTexturePixelFormat_RGBA8888]; + + _renderTexture.positionType = CCPositionTypeNormalized; + _renderTexture.anchorPoint = ccp(0, 0); + _renderTexture.position = ccp(0.5f, 0.5f); + + [_renderTexture clear:1.0f g:1.0f b:1.0f a:1.0f]; + [self addChild:_renderTexture]; + + [[[CCDirector sharedDirector] view] setUserInteractionEnabled:YES]; + + UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; + panGestureRecognizer.maximumNumberOfTouches = 1; + [[[CCDirector sharedDirector] view] addGestureRecognizer:panGestureRecognizer]; + + UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + [[[CCDirector sharedDirector] view] addGestureRecognizer:longPressGestureRecognizer]; + } + return self; +} + +// ----------------------------------------------------------------------- +#pragma mark - Handling points + +- (void)startNewLineFrom:(CGPoint)newPoint withSize:(CGFloat)aSize +{ + _connectingLine = NO; + [self addPoint:newPoint withSize:aSize]; +} + +// ----------------------------------------------------------------------- + +- (void)endLineAt:(CGPoint)aEndPoint withSize:(CGFloat)aSize +{ + [self addPoint:aEndPoint withSize:aSize]; + _finishingLine = YES; +} + +// ----------------------------------------------------------------------- + +- (void)addPoint:(CGPoint)newPoint withSize:(CGFloat)size +{ + CCSmoothLinePoint *point = [[CCSmoothLinePoint alloc] init]; + point.pos = newPoint; + point.width = size; + [_points addObject:point]; +} + +// ----------------------------------------------------------------------- +#pragma mark - Drawing + +#define ADD_TRIANGLE(A, B, C, Z) vertices[index].pos = A, vertices[index++].z = Z, vertices[index].pos = B, vertices[index++].z = Z, vertices[index].pos = C, vertices[index++].z = Z + +- (void)drawLines:(NSArray *)linePoints withColor:(ccColor4F)color +{ + NSUInteger numberOfVertices = ([linePoints count] - 1) * 18; + CCSmoothLineVertex *vertices = calloc(sizeof(CCSmoothLineVertex), numberOfVertices); + + CGPoint prevPoint = [(CCSmoothLinePoint *)[linePoints objectAtIndex:0] pos]; + float prevValue = [(CCSmoothLinePoint *)[linePoints objectAtIndex:0] width]; + float curValue; + int index = 0; + for (int i = 1; i < [linePoints count]; ++i) + { + CCSmoothLinePoint *pointValue = [linePoints objectAtIndex:i]; + CGPoint curPoint = [pointValue pos]; + curValue = [pointValue width]; + + //! equal points, skip them + if (ccpFuzzyEqual(curPoint, prevPoint, 0.0001f)) + { + continue; + } + + CGPoint dir = ccpSub(curPoint, prevPoint); + CGPoint perpendicular = ccpNormalize(ccpPerp(dir)); + CGPoint A = ccpAdd(prevPoint, ccpMult(perpendicular, prevValue / 2)); + CGPoint B = ccpSub(prevPoint, ccpMult(perpendicular, prevValue / 2)); + CGPoint C = ccpAdd(curPoint, ccpMult(perpendicular, curValue / 2)); + CGPoint D = ccpSub(curPoint, ccpMult(perpendicular, curValue / 2)); + + //! continuing line + if (_connectingLine || index > 0) + { + A = _prevC; + B = _prevD; + } + else if (index == 0) + { + //! circle at start of line, revert direction + [_circlesPoints addObject:pointValue]; + [_circlesPoints addObject:[linePoints objectAtIndex:i - 1]]; + } + + ADD_TRIANGLE(A, B, C, 1.0f); + ADD_TRIANGLE(B, C, D, 1.0f); + + _prevD = D; + _prevC = C; + if (_finishingLine && (i == [linePoints count] - 1)) + { + [_circlesPoints addObject:[linePoints objectAtIndex:i - 1]]; + [_circlesPoints addObject:pointValue]; + _finishingLine = NO; + } + prevPoint = curPoint; + prevValue = curValue; + + //! Add overdraw + CGPoint F = ccpAdd(A, ccpMult(perpendicular, _overdraw)); + CGPoint G = ccpAdd(C, ccpMult(perpendicular, _overdraw)); + CGPoint H = ccpSub(B, ccpMult(perpendicular, _overdraw)); + CGPoint I = ccpSub(D, ccpMult(perpendicular, _overdraw)); + + //! end vertices of last line are the start of this one, also for the overdraw + if (_connectingLine || index > 6) + { + F = _prevG; + H = _prevI; + } + + _prevG = G; + _prevI = I; + + ADD_TRIANGLE(F, A, G, 2.0f); + ADD_TRIANGLE(A, G, C, 2.0f); + ADD_TRIANGLE(B, H, D, 2.0f); + ADD_TRIANGLE(H, D, I, 2.0f); + } + [self fillLineTriangles:vertices count:index withColor:color]; + + if (index > 0) + { + _connectingLine = YES; + } + + free(vertices); +} + +// ----------------------------------------------------------------------- + +- (void)fillLineEndPointAt:(CGPoint)center direction:(CGPoint)aLineDir radius:(CGFloat)radius andColor:(ccColor4F)color +{ + int numberOfSegments = 32; + CCSmoothLineVertex *vertices = malloc(sizeof(CCSmoothLineVertex) * numberOfSegments * 9); + float anglePerSegment = (float)(M_PI / (numberOfSegments - 1)); + + //! we need to cover M_PI from this, dot product of normalized vectors is equal to cos angle between them... and if you include rightVec dot you get to know the correct direction :) + CGPoint perpendicular = ccpPerp(aLineDir); + float angle = acosf(ccpDot(perpendicular, CGPointMake(0, 1))); + float rightDot = ccpDot(perpendicular, CGPointMake(1, 0)); + if (rightDot < 0.0f) + { + angle *= -1; + } + + CGPoint prevPoint = center; + CGPoint prevDir = ccp(sinf(0), cosf(0)); + for (unsigned int i = 0; i < numberOfSegments; ++i) + { + CGPoint dir = ccp(sinf(angle), cosf(angle)); + CGPoint curPoint = ccp(center.x + radius * dir.x, center.y + radius * dir.y); + vertices[i * 9 + 0].pos = center; + vertices[i * 9 + 1].pos = prevPoint; + vertices[i * 9 + 2].pos = curPoint; + + //! fill rest of vertex data + for (unsigned int j = 0; j < 9; ++j) + { + vertices[i * 9 + j].z = j < 3 ? 1.0f : 2.0f; + vertices[i * 9 + j].color = color; + } + + //! add overdraw + vertices[i * 9 + 3].pos = ccpAdd(prevPoint, ccpMult(prevDir, _overdraw)); + vertices[i * 9 + 3].color.a = 0; + vertices[i * 9 + 4].pos = prevPoint; + vertices[i * 9 + 5].pos = ccpAdd(curPoint, ccpMult(dir, _overdraw)); + vertices[i * 9 + 5].color.a = 0; + + vertices[i * 9 + 6].pos = prevPoint; + vertices[i * 9 + 7].pos = curPoint; + vertices[i * 9 + 8].pos = ccpAdd(curPoint, ccpMult(dir, _overdraw)); + vertices[i * 9 + 8].color.a = 0; + + prevPoint = curPoint; + prevDir = dir; + angle += anglePerSegment; + } + + CCRenderer *renderer = [CCRenderer currentRenderer]; + GLKMatrix4 projection; + [renderer.globalShaderUniforms[CCShaderUniformProjection] getValue:&projection]; + CCRenderBuffer buffer = [renderer enqueueTriangles:numberOfSegments * 3 andVertexes:numberOfSegments * 9 withState:self.renderState globalSortOrder:1]; + + CCVertex vertex; + for (int i = 0; i < numberOfSegments * 9; i++) + { + vertex.position = GLKVector4Make(vertices[i].pos.x, vertices[i].pos.y, 0.0, 1.0); + vertex.color = GLKVector4Make(vertices[i].color.r, vertices[i].color.g, vertices[i].color.b, vertices[i].color.a); + CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, &projection)); + } + + for (unsigned int i = 0; i < numberOfSegments * 3; i++) + { + CCRenderBufferSetTriangle(buffer, i, i*3, (i*3)+1, (i*3)+2); + } + + free(vertices); +} + +// ----------------------------------------------------------------------- + +- (void)fillLineTriangles:(CCSmoothLineVertex *)vertices count:(NSUInteger)count withColor:(ccColor4F)color +{ + if (!count) + { + return; + } + + ccColor4F fullColor = color; + ccColor4F fadeOutColor = color; + fadeOutColor.a = 0; + + for (int i = 0; i < count / 18; ++i) + { + for (int j = 0; j < 6; ++j) + { + vertices[i * 18 + j].color = color; + } + + //! FAG + vertices[i * 18 + 6].color = fadeOutColor; + vertices[i * 18 + 7].color = fullColor; + vertices[i * 18 + 8].color = fadeOutColor; + + //! AGD + vertices[i * 18 + 9].color = fullColor; + vertices[i * 18 + 10].color = fadeOutColor; + vertices[i * 18 + 11].color = fullColor; + + //! BHC + vertices[i * 18 + 12].color = fullColor; + vertices[i * 18 + 13].color = fadeOutColor; + vertices[i * 18 + 14].color = fullColor; + + //! HCI + vertices[i * 18 + 15].color = fadeOutColor; + vertices[i * 18 + 16].color = fullColor; + vertices[i * 18 + 17].color = fadeOutColor; + } + + CCRenderer *renderer = [CCRenderer currentRenderer]; + GLKMatrix4 projection; + [renderer.globalShaderUniforms[CCShaderUniformProjection] getValue:&projection]; + CCRenderBuffer buffer = [renderer enqueueTriangles:count/3 andVertexes:count withState:self.renderState globalSortOrder:1]; + + CCVertex vertex; + for (unsigned int i = 0; i < count; i++) + { + vertex.position = GLKVector4Make(vertices[i].pos.x, vertices[i].pos.y, 0.0, 1.0); + vertex.color = GLKVector4Make(vertices[i].color.r, vertices[i].color.g, vertices[i].color.b, vertices[i].color.a); + CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, &projection)); + } + + for (unsigned int i = 0; i < count/3; i++) + { + CCRenderBufferSetTriangle(buffer, i, i*3, (i*3)+1, (i*3)+2); + } + + for (unsigned int i = 0; i < [_circlesPoints count] / 2; ++i) + { + CCSmoothLinePoint *prevPoint = [_circlesPoints objectAtIndex:i * 2]; + CCSmoothLinePoint *curPoint = [_circlesPoints objectAtIndex:i * 2 + 1]; + CGPoint dirVector = ccpNormalize(ccpSub(curPoint.pos, prevPoint.pos)); + + [self fillLineEndPointAt:curPoint.pos direction:dirVector radius:curPoint.width * 0.5f andColor:color]; + } + [_circlesPoints removeAllObjects]; +} + +// ----------------------------------------------------------------------- + +- (NSMutableArray *)calculateSmoothLinePoints +{ + if ([_points count] > 2) + { + NSMutableArray *smoothedPoints = [NSMutableArray array]; + for (unsigned int i = 2; i < [_points count]; ++i) + { + CCSmoothLinePoint *prev2 = [_points objectAtIndex:i - 2]; + CCSmoothLinePoint *prev1 = [_points objectAtIndex:i - 1]; + CCSmoothLinePoint *cur = [_points objectAtIndex:i]; + + CGPoint midPoint1 = ccpMult(ccpAdd(prev1.pos, prev2.pos), 0.5f); + CGPoint midPoint2 = ccpMult(ccpAdd(cur.pos, prev1.pos), 0.5f); + + int segmentDistance = 2; + float distance = ccpDistance(midPoint1, midPoint2); + int numberOfSegments = MIN(128, MAX(floorf(distance / segmentDistance), 32)); + + float t = 0.0f; + float step = 1.0f / numberOfSegments; + for (NSUInteger j = 0; j < numberOfSegments; j++) + { + CCSmoothLinePoint *newPoint = [[CCSmoothLinePoint alloc] init]; + newPoint.pos = ccpAdd(ccpAdd(ccpMult(midPoint1, powf(1 - t, 2)), ccpMult(prev1.pos, 2.0f * (1 - t) * t)), ccpMult(midPoint2, t * t)); + newPoint.width = powf(1 - t, 2) * ((prev1.width + prev2.width) * 0.5f) + 2.0f * (1 - t) * t * prev1.width + t * t * ((cur.width + prev1.width) * 0.5f); + + [smoothedPoints addObject:newPoint]; + t += step; + } + CCSmoothLinePoint *finalPoint = [[CCSmoothLinePoint alloc] init]; + finalPoint.pos = midPoint2; + finalPoint.width = (cur.width + prev1.width) * 0.5f; + [smoothedPoints addObject:finalPoint]; + } + //! we need to leave last 2 points for next draw + [_points removeObjectsInRange:NSMakeRange(0, [_points count] - 2)]; + return smoothedPoints; + } else { + return nil; + } +} + +// ----------------------------------------------------------------------- + +- (void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform +{ + ccColor4F color = {0, 0, 0, 1}; + [_renderTexture begin]; + + NSMutableArray *smoothedPoints = [self calculateSmoothLinePoints]; + if (smoothedPoints) + { + [self drawLines:smoothedPoints withColor:color]; + } + [_renderTexture end]; +} + +// ----------------------------------------------------------------------- +#pragma mark - Math + +// ----------------------------------------------------------------------- +#pragma mark - GestureRecognizers + +- (float)extractSize:(UIPanGestureRecognizer *)panGestureRecognizer +{ + //! result of trial & error + float vel = ccpLength([panGestureRecognizer velocityInView:panGestureRecognizer.view]); + float size = vel / 166.0f; + size = clampf(size, 1, 40); + + if ([_velocities count] > 1) + { + size = size * 0.2f + [[_velocities objectAtIndex:[_velocities count] - 1] floatValue] * 0.8f; + } + [_velocities addObject:[NSNumber numberWithFloat:size]]; + return size; +} + +// ----------------------------------------------------------------------- + +- (void)handlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer +{ + const CGPoint point = [[CCDirector sharedDirector] convertToGL:[panGestureRecognizer locationInView:panGestureRecognizer.view]]; + + if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) + { + [_points removeAllObjects]; + [_velocities removeAllObjects]; + + float size = [self extractSize:panGestureRecognizer]; + + [self startNewLineFrom:point withSize:size]; + } + + if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) + { + //! skip points that are too close + float eps = 1.5f; + if ([_points count] > 0) + { + float length = ccpLength(ccpSub([(CCSmoothLinePoint *)[_points lastObject] pos], point)); + + if (length < eps) + { + return; + } + } + float size = [self extractSize:panGestureRecognizer]; + [self addPoint:point withSize:size]; + } + + if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) + { + float size = [self extractSize:panGestureRecognizer]; + [self endLineAt:point withSize:size]; + } +} + +// ----------------------------------------------------------------------- + +- (void)handleLongPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer +{ + [_renderTexture beginWithClear:1.0 g:1.0 b:1.0 a:0]; + [_renderTexture end]; +} + +// ----------------------------------------------------------------------- + +@end diff --git a/Extensions/CCLayerSmoothLine/README.md b/Extensions/CCLayerSmoothLine/README.md new file mode 100644 index 0000000..d8cc95c --- /dev/null +++ b/Extensions/CCLayerSmoothLine/README.md @@ -0,0 +1,19 @@ +CCLayerSmoothLine +================= + +Type of class : Descendant of CCNode +Uses extension : [NONE] + +Authors : Krzysztof Zabłocki, Richard Groves + +Acts like a layer, enabling smooth line drawing. + +Example +======= + +[self addChild:[CCLayerSmoothLine layer]]; + +Known Bugs +========== +Misses round line ends when drawing fast zig zag pattern. + diff --git a/cocos2d-iphone-ext.xcodeproj/project.pbxproj b/cocos2d-iphone-ext.xcodeproj/project.pbxproj index 4066b19..e59290e 100644 --- a/cocos2d-iphone-ext.xcodeproj/project.pbxproj +++ b/cocos2d-iphone-ext.xcodeproj/project.pbxproj @@ -10,7 +10,10 @@ 0E21D306198A47A400E84AB1 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 0E21D305198A47A400E84AB1 /* README.md */; }; 0E21D30C198A484600E84AB1 /* CCSpriteMultiTouch.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E21D30B198A484600E84AB1 /* CCSpriteMultiTouch.m */; }; 0E21D30F198A637900E84AB1 /* CCSpriteMultiTouchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E21D30E198A637900E84AB1 /* CCSpriteMultiTouchTest.m */; }; + 0E9A092A199CDDD10049E409 /* CCLayerSmoothLineTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E9A0929199CDDD10049E409 /* CCLayerSmoothLineTest.m */; }; 0ED73BB51997951A00C83507 /* CCSpineCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 0ED73BB41997951A00C83507 /* CCSpineCurve.m */; }; + 0EF602FD199CDC8F007AEBD9 /* CCLayerSmoothLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EF602FC199CDC8F007AEBD9 /* CCLayerSmoothLine.m */; }; + 0EF602FF199CDD8F007AEBD9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 0EF602FE199CDD8F007AEBD9 /* README.md */; }; A6270E62193757E400196BD3 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6270E61193757E400196BD3 /* QuartzCore.framework */; }; A6270E64193757E400196BD3 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6270E63193757E400196BD3 /* OpenGLES.framework */; }; A6270E66193757E400196BD3 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6270E65193757E400196BD3 /* OpenAL.framework */; }; @@ -125,8 +128,12 @@ 0E21D30A198A484600E84AB1 /* CCSpriteMultiTouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCSpriteMultiTouch.h; path = Extensions/CCSpriteMultiTouch/CCSpriteMultiTouch.h; sourceTree = SOURCE_ROOT; }; 0E21D30B198A484600E84AB1 /* CCSpriteMultiTouch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCSpriteMultiTouch.m; path = Extensions/CCSpriteMultiTouch/CCSpriteMultiTouch.m; sourceTree = SOURCE_ROOT; }; 0E21D30E198A637900E84AB1 /* CCSpriteMultiTouchTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCSpriteMultiTouchTest.m; path = Classes/Tests/CCSpriteMultiTouchTest.m; sourceTree = ""; }; + 0E9A0929199CDDD10049E409 /* CCLayerSmoothLineTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCLayerSmoothLineTest.m; path = Classes/Tests/CCLayerSmoothLineTest.m; sourceTree = ""; }; 0ED73BB31997951A00C83507 /* CCSpineCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCSpineCurve.h; path = Extensions/CCSpine/CCSpineCurve.h; sourceTree = SOURCE_ROOT; }; 0ED73BB41997951A00C83507 /* CCSpineCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCSpineCurve.m; path = Extensions/CCSpine/CCSpineCurve.m; sourceTree = SOURCE_ROOT; }; + 0EF602FB199CDC8F007AEBD9 /* CCLayerSmoothLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCLayerSmoothLine.h; path = Extensions/CCLayerSmoothLine/CCLayerSmoothLine.h; sourceTree = SOURCE_ROOT; }; + 0EF602FC199CDC8F007AEBD9 /* CCLayerSmoothLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCLayerSmoothLine.m; path = Extensions/CCLayerSmoothLine/CCLayerSmoothLine.m; sourceTree = SOURCE_ROOT; }; + 0EF602FE199CDD8F007AEBD9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = Extensions/CCLayerSmoothLine/README.md; sourceTree = SOURCE_ROOT; }; A6254BAF193A1438006BD09E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = Extensions/CCNodeTag/README.md; sourceTree = SOURCE_ROOT; }; A6254BB1193A144A006BD09E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = Extensions/CCDictionary/README.md; sourceTree = SOURCE_ROOT; }; A6254BB3193A145D006BD09E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = Extensions/CCSpine/README.md; sourceTree = SOURCE_ROOT; }; @@ -278,6 +285,16 @@ name = CCSpriteMultiTouch; sourceTree = ""; }; + 0EF602F9199CDC4A007AEBD9 /* CCLayerSmoothLine */ = { + isa = PBXGroup; + children = ( + 0EF602FE199CDD8F007AEBD9 /* README.md */, + 0EF602FB199CDC8F007AEBD9 /* CCLayerSmoothLine.h */, + 0EF602FC199CDC8F007AEBD9 /* CCLayerSmoothLine.m */, + ); + name = CCLayerSmoothLine; + sourceTree = ""; + }; A6270E55193757E300196BD3 = { isa = PBXGroup; children = ( @@ -452,6 +469,7 @@ A6994F83194A2FAC00B97481 /* CCTransformationNodeTest.m */, A6994F80194A2F3D00B97481 /* CCCropNodeTest.m */, 0E21D30E198A637900E84AB1 /* CCSpriteMultiTouchTest.m */, + 0E9A0929199CDDD10049E409 /* CCLayerSmoothLineTest.m */, A6994F7E194A2E2800B97481 /* Test helper classes */, ); name = Tests; @@ -460,6 +478,7 @@ A66C5808193A0C24009D2BD4 /* Extensions */ = { isa = PBXGroup; children = ( + 0EF602F9199CDC4A007AEBD9 /* CCLayerSmoothLine */, 0E21D303198A45F800E84AB1 /* CCSpriteMultiTouch */, A6994F76194A2C8000B97481 /* CCCropNode */, A68895A91949A785002950DD /* CCTransformationNode */, @@ -670,6 +689,7 @@ A6271295193769A900196BD3 /* din-ipad.fnt in Resources */, A6270E82193757E400196BD3 /* Default-Landscape~ipad.png in Resources */, A6270E97193757E400196BD3 /* Icon-Small.png in Resources */, + 0EF602FF199CDD8F007AEBD9 /* README.md in Resources */, A6270E95193757E400196BD3 /* Icon-Small-50.png in Resources */, A62712AA193769A900196BD3 /* Sprites.plist in Resources */, A62712AB193769A900196BD3 /* Sprites.png in Resources */, @@ -731,8 +751,10 @@ A68895AF1949A8B4002950DD /* CCTransformationNode.m in Sources */, A627126D19375F2700196BD3 /* MainMenu.m in Sources */, A66C5830193A0C87009D2BD4 /* CCSpineAnimation.m in Sources */, + 0EF602FD199CDC8F007AEBD9 /* CCLayerSmoothLine.m in Sources */, A66C5835193A0C87009D2BD4 /* CCSpineSkeleton.m in Sources */, A66C5836193A0C87009D2BD4 /* CCSpineSkin.m in Sources */, + 0E9A092A199CDDD10049E409 /* CCLayerSmoothLineTest.m in Sources */, A6271107193757E600196BD3 /* main.m in Sources */, 0E21D30C198A484600E84AB1 /* CCSpriteMultiTouch.m in Sources */, A66C5837193A0C87009D2BD4 /* CCSpineSprite.m in Sources */, diff --git a/cocos2d-iphone-ext.xcodeproj/project.xcworkspace/xcuserdata/Birkemose.xcuserdatad/UserInterfaceState.xcuserstate b/cocos2d-iphone-ext.xcodeproj/project.xcworkspace/xcuserdata/Birkemose.xcuserdatad/UserInterfaceState.xcuserstate index bfee2ff52b739acd8d5cbb5ef23f60b4e3917cfd..cd5f1c83fcef3c1b2b97bcdf75c14c1143eed3de 100644 GIT binary patch delta 16082 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 Y9qoL(OF;aeJBLsV2;AmAQ(&QVvL(OT=oJ!-9W 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 L+waToI^X{fYELil diff --git a/cocos2d-iphone-ext/Classes/Tests/CCLayerSmoothLineTest.m b/cocos2d-iphone-ext/Classes/Tests/CCLayerSmoothLineTest.m new file mode 100644 index 0000000..d3d268c --- /dev/null +++ b/cocos2d-iphone-ext/Classes/Tests/CCLayerSmoothLineTest.m @@ -0,0 +1,37 @@ +// +// CCLayerSmoothLineTest.m +// cocos2d-iphone-ext +// +// Created by Lars Birkemose on 14/08/14. +// Copyright 2014 Cocos2D-iphone. All rights reserved. +// + +#import "TestBase.h" +#import "CCLayerSmoothLine.h" + +//---------------------------------------------------------------------- + +@interface CCLayerSmoothLineTest : TestBase + +@end + +//---------------------------------------------------------------------- + +@implementation CCLayerSmoothLineTest + +- (NSArray *)testConstructors +{ + return [NSArray arrayWithObjects: + @"smoothLineTest", + nil]; +} + +- (void)smoothLineTest +{ + self.subTitle = @"Touch and hold to wipe drawing"; + [self.contentNode addChild:[CCLayerSmoothLine layer]]; +} + +@end + +//----------------------------------------------------------------------