From 0abefacf23c6c2792149ee350395c86e7206727b Mon Sep 17 00:00:00 2001 From: badlogic Date: Mon, 26 Jun 2017 15:19:14 +0200 Subject: [PATCH] [cocos2d-objc] Added vertex effects support. See #898 --- spine-cocos2d-objc/example/RaptorExample.m | 5 ++ .../project.pbxproj | 12 ++- .../src/spine/SkeletonRenderer.h | 2 + .../src/spine/SkeletonRenderer.m | 76 ++++++++++++++++--- 4 files changed, 79 insertions(+), 16 deletions(-) diff --git a/spine-cocos2d-objc/example/RaptorExample.m b/spine-cocos2d-objc/example/RaptorExample.m index 3ad8124ec..9e7a7624a 100644 --- a/spine-cocos2d-objc/example/RaptorExample.m +++ b/spine-cocos2d-objc/example/RaptorExample.m @@ -31,6 +31,8 @@ #import "RaptorExample.h" #import "TankExample.h" +spJitterVertexEffect* effect = 0; + @implementation RaptorExample + (CCScene*) scene { @@ -42,9 +44,12 @@ -(id) init { self = [super init]; if (!self) return nil; + + if (!effect) effect = spJitterVertexEffect_create(10, 10); skeletonNode = [SkeletonAnimation skeletonWithFile:@"raptor-pro.json" atlasFile:@"raptor.atlas" scale:0.3f]; [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; + [skeletonNode setEffect:&effect->super]; CGSize windowSize = [[CCDirector sharedDirector] viewSize]; [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; diff --git a/spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj b/spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj index cdfd68ba7..10d05c237 100644 --- a/spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj +++ b/spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj @@ -84,6 +84,7 @@ 76F5BDAD1D2BDFA2005917E5 /* TankExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 76F5BDAC1D2BDFA2005917E5 /* TankExample.m */; }; 76FAC1961E3FA15E001CCC8C /* Color.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC1941E3FA15E001CCC8C /* Color.c */; }; 76FAC1971E3FA15E001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC1951E3FA15E001CCC8C /* PointAttachment.c */; }; + 76FB151A1F01413B00C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB15191F01413B00C5377F /* VertexEffect.c */; }; 83F1A0EF1986955A001F6B44 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83F1A0EE1986955A001F6B44 /* GLKit.framework */; }; 9A5D2499170A94DA0030D4DD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D2498170A94DA0030D4DD /* QuartzCore.framework */; }; 9A5D249B170A94DA0030D4DD /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D249A170A94DA0030D4DD /* OpenGLES.framework */; }; @@ -137,7 +138,7 @@ /* Begin PBXFileReference section */ 43C3282D170B0C19004A9460 /* spine-cocos2d-objc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "spine-cocos2d-objc.m"; path = "src/spine/spine-cocos2d-objc.m"; sourceTree = ""; }; 43C3282E170B0C19004A9460 /* spine-cocos2d-objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "spine-cocos2d-objc.h"; path = "src/spine/spine-cocos2d-objc.h"; sourceTree = ""; }; - 43C32868170B0DA6004A9460 /* spineboy-ess.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = spineboy-ess.json; path = Resources/spineboy-ess.json; sourceTree = ""; }; + 43C32868170B0DA6004A9460 /* spineboy-ess.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "spineboy-ess.json"; path = "Resources/spineboy-ess.json"; sourceTree = ""; }; 43C3286A170B0DA6004A9460 /* spineboy.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = spineboy.atlas; path = Resources/spineboy.atlas; sourceTree = ""; }; 43C3286B170B0DA6004A9460 /* spineboy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = spineboy.png; path = Resources/spineboy.png; sourceTree = ""; }; 43C32871170B0DBE004A9460 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "Resources-ios/Default-568h@2x.png"; sourceTree = ""; }; @@ -175,7 +176,7 @@ 76EE4E441EB36DE6000254F4 /* SkeletonClipping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SkeletonClipping.c; path = "../spine-c/spine-c/src/spine/SkeletonClipping.c"; sourceTree = ""; }; 76EE4E451EB36DE6000254F4 /* Triangulator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Triangulator.c; path = "../spine-c/spine-c/src/spine/Triangulator.c"; sourceTree = ""; }; 76EE4E4E1EB36E53000254F4 /* coin.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = coin.atlas; path = Resources/coin.atlas; sourceTree = ""; }; - 76EE4E4F1EB36E53000254F4 /* coin-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = coin-pro.json; path = Resources/coin-pro.json; sourceTree = ""; }; + 76EE4E4F1EB36E53000254F4 /* coin-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "coin-pro.json"; path = "Resources/coin-pro.json"; sourceTree = ""; }; 76EE4E501EB36E53000254F4 /* coin.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = coin.png; path = Resources/coin.png; sourceTree = ""; }; 76EE4E541EB36E94000254F4 /* CoinExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoinExample.h; path = example/CoinExample.h; sourceTree = ""; }; 76EE4E551EB36E94000254F4 /* CoinExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CoinExample.m; path = example/CoinExample.m; sourceTree = ""; }; @@ -214,10 +215,10 @@ 76F28D141DEC810300CDE54D /* TransformConstraintData.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = TransformConstraintData.c; path = "../spine-c/spine-c/src/spine/TransformConstraintData.c"; sourceTree = ""; }; 76F28D151DEC810300CDE54D /* VertexAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = VertexAttachment.c; path = "../spine-c/spine-c/src/spine/VertexAttachment.c"; sourceTree = ""; }; 76F5BD9C1D2BDE1C005917E5 /* raptor.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = raptor.atlas; path = Resources/raptor.atlas; sourceTree = ""; }; - 76F5BD9D1D2BDE1C005917E5 /* raptor-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = raptor-pro.json; path = Resources/raptor-pro.json; sourceTree = ""; }; + 76F5BD9D1D2BDE1C005917E5 /* raptor-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "raptor-pro.json"; path = "Resources/raptor-pro.json"; sourceTree = ""; }; 76F5BD9E1D2BDE1C005917E5 /* raptor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = raptor.png; path = Resources/raptor.png; sourceTree = ""; }; 76F5BD9F1D2BDE1C005917E5 /* tank.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = tank.atlas; path = Resources/tank.atlas; sourceTree = ""; }; - 76F5BDA01D2BDE1C005917E5 /* tank-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tank-pro.json; path = Resources/tank-pro.json; sourceTree = ""; }; + 76F5BDA01D2BDE1C005917E5 /* tank-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "tank-pro.json"; path = "Resources/tank-pro.json"; sourceTree = ""; }; 76F5BDA11D2BDE1C005917E5 /* tank.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tank.png; path = Resources/tank.png; sourceTree = ""; }; 76F5BDA81D2BDE67005917E5 /* RaptorExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RaptorExample.h; path = example/RaptorExample.h; sourceTree = ""; }; 76F5BDA91D2BDE67005917E5 /* RaptorExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RaptorExample.m; path = example/RaptorExample.m; sourceTree = ""; }; @@ -225,6 +226,7 @@ 76F5BDAC1D2BDFA2005917E5 /* TankExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TankExample.m; path = example/TankExample.m; sourceTree = ""; }; 76FAC1941E3FA15E001CCC8C /* Color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Color.c; path = "../spine-c/spine-c/src/spine/Color.c"; sourceTree = ""; }; 76FAC1951E3FA15E001CCC8C /* PointAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PointAttachment.c; path = "../spine-c/spine-c/src/spine/PointAttachment.c"; sourceTree = ""; }; + 76FB15191F01413B00C5377F /* VertexEffect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = VertexEffect.c; path = "../spine-c/spine-c/src/spine/VertexEffect.c"; sourceTree = ""; }; 83F1A0EE1986955A001F6B44 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; 9A5D2495170A94DA0030D4DD /* SpineExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpineExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9A5D2498170A94DA0030D4DD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; @@ -299,6 +301,7 @@ 43C32822170B0BC2004A9460 /* spine-c */ = { isa = PBXGroup; children = ( + 76FB15191F01413B00C5377F /* VertexEffect.c */, 76EE4E421EB36DE6000254F4 /* Array.c */, 76EE4E431EB36DE6000254F4 /* ClippingAttachment.c */, 76EE4E441EB36DE6000254F4 /* SkeletonClipping.c */, @@ -597,6 +600,7 @@ 76BF7E071E66ED9C00485998 /* GLUtils.c in Sources */, 76EE4E481EB36DE6000254F4 /* SkeletonClipping.c in Sources */, 43C3282F170B0C19004A9460 /* spine-cocos2d-objc.m in Sources */, + 76FB151A1F01413B00C5377F /* VertexEffect.c in Sources */, 76F28D1F1DEC810300CDE54D /* BoundingBoxAttachment.c in Sources */, 76F28D281DEC810300CDE54D /* PathConstraint.c in Sources */, 76F28D2F1DEC810300CDE54D /* SkeletonJson.c in Sources */, diff --git a/spine-cocos2d-objc/src/spine/SkeletonRenderer.h b/spine-cocos2d-objc/src/spine/SkeletonRenderer.h index ce4f6217d..32217ce0e 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonRenderer.h +++ b/spine-cocos2d-objc/src/spine/SkeletonRenderer.h @@ -47,6 +47,7 @@ float* _worldVertices; CCBlendMode* screenMode; spSkeletonClipping* _clipper; + spVertexEffect* _effect; } + (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; @@ -90,5 +91,6 @@ @property (nonatomic) bool debugBones; @property (nonatomic) bool skipVisibilityCheck; @property (nonatomic) spBone* rootBone; +@property (nonatomic) spVertexEffect* effect; @end diff --git a/spine-cocos2d-objc/src/spine/SkeletonRenderer.m b/spine-cocos2d-objc/src/spine/SkeletonRenderer.m index fe8afc220..1b6cfe31d 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonRenderer.m +++ b/spine-cocos2d-objc/src/spine/SkeletonRenderer.m @@ -50,6 +50,7 @@ static bool handlerQueued = false; @synthesize twoColorTint = _twoColorTint; @synthesize debugSlots = _debugSlots; @synthesize debugBones = _debugBones; +@synthesize effect = _effect; + (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease]; @@ -91,6 +92,7 @@ static bool handlerQueued = false; ]; _clipper = spSkeletonClipping_create(); + _effect = 0; } - (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { @@ -173,6 +175,8 @@ static bool handlerQueued = false; handlerQueued = true; } + if (_effect) _effect->begin(_effect, _skeleton); + CCColor* nodeColor = self.color; _skeleton->color.r = nodeColor.red; _skeleton->color.g = nodeColor.green; @@ -288,6 +292,20 @@ static bool handlerQueued = false; vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0); vertex.color = GLKVector4Make(r, g, b, a); vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]); + if (_effect) { + spColor light; + spColor dark; + light.r = r; + light.g = g; + light.b = b; + light.a = a; + dark.r = dark.g = dark.b = dark.a = 0; + _effect->transform(_effect, &vertex.position.x, &vertex.position.y, &vertex.texCoord1.s, &vertex.texCoord1.t, &light, &dark); + vertex.color.r = light.r; + vertex.color.g = light.g; + vertex.color.b = light.b; + vertex.color.a = light.a; + } CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform)); } for (int j = 0; j * 3 < trianglesCount; ++j) { @@ -308,18 +326,50 @@ static bool handlerQueued = false; spVertex* verts = &meshPart.mesh->vertices[meshPart.startVertex]; unsigned short* indices = &meshPart.mesh->indices[meshPart.startIndex]; - for (int i = 0; i * 2 < verticesCount; i++, verts++) { - CCVertex vertex; - vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0); - vertex = CCVertexApplyTransform(vertex, transform); - verts->x = vertex.position.x; - verts->y = vertex.position.y; - verts->z = vertex.position.z; - verts->w = vertex.position.w; - verts->color = ((unsigned short)(r * 255))| ((unsigned short)(g * 255)) << 8 | ((unsigned short)(b * 255)) <<16 | ((unsigned short)(a * 255)) << 24; - verts->color2 = ((unsigned short)(dr * 255)) | ((unsigned short)(dg * 255)) << 8 | ((unsigned short)(db * 255)) << 16 | ((unsigned short)(255)) << 24; - verts->u = uvs[i * 2]; - verts->v = 1 - uvs[i * 2 + 1]; + if (_effect) { + spColor light; + light.r = r; + light.g = g; + light.b = b; + light.a = a; + spColor dark; + dark.r = dr; + dark.g = dg; + dark.b = db; + dark.a = 1; + for (int i = 0; i * 2 < verticesCount; i++, verts++) { + spColor lightCopy = light; + spColor darkCopy = dark; + + CCVertex vertex; + vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0); + verts->u = uvs[i * 2]; + verts->v = 1 - uvs[i * 2 + 1]; + _effect->transform(_effect, &vertex.position.x, &vertex.position.y, &verts->u, &verts->v, &lightCopy, &darkCopy); + + vertex = CCVertexApplyTransform(vertex, transform); + verts->x = vertex.position.x; + verts->y = vertex.position.y; + verts->z = vertex.position.z; + verts->w = vertex.position.w; + verts->color = ((unsigned short)(lightCopy.r * 255))| ((unsigned short)(lightCopy.g * 255)) << 8 | ((unsigned short)(lightCopy.b * 255)) <<16 | ((unsigned short)(lightCopy.a * 255)) << 24; + verts->color2 = ((unsigned short)(darkCopy.r * 255)) | ((unsigned short)(darkCopy.g * 255)) << 8 | ((unsigned short)(darkCopy.b * 255)) << 16 | ((unsigned short)(255)) << 24; + + } + } else { + for (int i = 0; i * 2 < verticesCount; i++, verts++) { + CCVertex vertex; + vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0); + vertex = CCVertexApplyTransform(vertex, transform); + verts->x = vertex.position.x; + verts->y = vertex.position.y; + verts->z = vertex.position.z; + verts->w = vertex.position.w; + verts->color = ((unsigned short)(r * 255))| ((unsigned short)(g * 255)) << 8 | ((unsigned short)(b * 255)) <<16 | ((unsigned short)(a * 255)) << 24; + verts->color2 = ((unsigned short)(dr * 255)) | ((unsigned short)(dg * 255)) << 8 | ((unsigned short)(db * 255)) << 16 | ((unsigned short)(255)) << 24; + verts->u = uvs[i * 2]; + verts->v = 1 - uvs[i * 2 + 1]; + } } for (int j = 0; j < trianglesCount; j++, indices++) { @@ -375,6 +425,8 @@ static bool handlerQueued = false; if (i == 0) [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor blueColor]]; } } + + if (_effect) _effect->end(_effect); } - (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment {