From 90180dafbbe223df6c2344523e5f57e0f949eec7 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Sat, 27 Apr 2013 16:58:22 +0200 Subject: [PATCH] CCSkeletonAnimation separated from CCSkeleton. Has convenience methods to apply multiple AnimationStates and queue animations. --- .gitignore | 3 + .../Resources-ios/AppDelegate.mm | 162 ++++++++++++ spine-cocos2d-iphone/example/ExampleLayer.h | 2 +- spine-cocos2d-iphone/example/ExampleLayer.m | 32 +-- .../project.pbxproj | 20 +- spine-cocos2d-iphone/src/spine/CCSkeleton.h | 60 +++++ spine-cocos2d-iphone/src/spine/CCSkeleton.m | 245 ++++++++++++++++++ .../src/spine/CCSkeletonAnimation.h | 69 +++++ .../src/spine/CCSkeletonAnimation.m | 177 +++++++++++++ .../src/spine/spine-cocos2d-iphone.h | 47 +--- .../src/spine/spine-cocos2d-iphone.m | 226 ---------------- .../example/Classes/ExampleLayer.cpp | 21 +- spine-cocos2dx/example/Classes/ExampleLayer.h | 2 +- .../example/proj.win32/spine-cocos2dx.vcxproj | 4 + .../proj.win32/spine-cocos2dx.vcxproj.filters | 12 + spine-cocos2dx/src/spine/CCSkeleton.cpp | 229 ++++++++++++++++ spine-cocos2dx/src/spine/CCSkeleton.h | 69 +++++ .../src/spine/CCSkeletonAnimation.cpp | 139 ++++++++++ .../src/spine/CCSkeletonAnimation.h | 70 +++++ spine-cocos2dx/src/spine/spine-cocos2dx.cpp | 197 +------------- spine-cocos2dx/src/spine/spine-cocos2dx.h | 32 +-- 21 files changed, 1290 insertions(+), 528 deletions(-) create mode 100644 spine-cocos2d-iphone/Resources-ios/AppDelegate.mm create mode 100644 spine-cocos2d-iphone/src/spine/CCSkeleton.h create mode 100644 spine-cocos2d-iphone/src/spine/CCSkeleton.m create mode 100644 spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.h create mode 100644 spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.m create mode 100644 spine-cocos2dx/src/spine/CCSkeleton.cpp create mode 100644 spine-cocos2dx/src/spine/CCSkeleton.h create mode 100644 spine-cocos2dx/src/spine/CCSkeletonAnimation.cpp create mode 100644 spine-cocos2dx/src/spine/CCSkeletonAnimation.h diff --git a/.gitignore b/.gitignore index 4756dabad..bfc1f9e69 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ target *.sdf *.opensdf *.suo +*.ipch spine-cocos2dx/cocos2dx/ !spine-cocos2dx/cocos2dx/Place cocos2dx here.txt @@ -31,6 +32,8 @@ spine-xna/obj spine-xna/example/bin spine-xna/example/obj +spine-unity/Assets/Plugins/Spine/spine-csharp +!spine-unity/Assets/Plugins/Spine/spine-csharp/Place spine-csharp here.txt spine-unity/ProjectSettings spine-unity/Temp spine-unity/Library diff --git a/spine-cocos2d-iphone/Resources-ios/AppDelegate.mm b/spine-cocos2d-iphone/Resources-ios/AppDelegate.mm new file mode 100644 index 000000000..d24b37b2e --- /dev/null +++ b/spine-cocos2d-iphone/Resources-ios/AppDelegate.mm @@ -0,0 +1,162 @@ + +#import "cocos2d.h" +#import "AppDelegate.h" +#import "ExampleLayer.h" + +@implementation MyNavigationController + +// The available orientations should be defined in the Info.plist file. +// And in iOS 6+ only, you can override it in the Root View controller in the "supportedInterfaceOrientations" method. +// Only valid for iOS 6+. NOT VALID for iOS 4 / 5. +-(NSUInteger)supportedInterfaceOrientations { + // iPhone only + if( [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ) + return UIInterfaceOrientationMaskLandscape; + + // iPad only + return UIInterfaceOrientationMaskLandscape; +} + +// Supported orientations. Customize it for your own needs +// Only valid on iOS 4 / 5. NOT VALID for iOS 6. +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + // iPhone only + if( [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ) + return UIInterfaceOrientationIsLandscape(interfaceOrientation); + + // iPad only + // iPhone only + return UIInterfaceOrientationIsLandscape(interfaceOrientation); +} + +// This is needed for iOS4 and iOS5 in order to ensure +// that the 1st scene has the correct dimensions +// This is not needed on iOS6 and could be added to the application:didFinish... +-(void) directorDidReshapeProjection:(CCDirector*)director { + if(director.runningScene == nil) { + // Add the first scene to the stack. The director will draw it immediately into the framebuffer. (Animation is started automatically when the view is displayed.) + // and add the scene to the stack. The director will run it when it automatically when the view is displayed. + [director runWithScene: [ExampleLayer scene]]; + } +} +@end + + +@implementation AppController + +@synthesize window=window_, navController=navController_, director=director_; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Create the main window + window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + + // Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits + CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds] + pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8 + depthFormat:0 //GL_DEPTH_COMPONENT24_OES + preserveBackbuffer:NO + sharegroup:nil + multiSampling:NO + numberOfSamples:0]; + + director_ = (CCDirectorIOS*) [CCDirector sharedDirector]; + + director_.wantsFullScreenLayout = YES; + + // Display FSP and SPF + [director_ setDisplayStats:YES]; + + // set FPS at 60 + [director_ setAnimationInterval:1.0/60]; + + // attach the openglView to the director + [director_ setView:glView]; + + // 2D projection + [director_ setProjection:kCCDirectorProjection2D]; + // [director setProjection:kCCDirectorProjection3D]; + + // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices + if( ! [director_ enableRetinaDisplay:YES] ) + CCLOG(@"Retina Display Not supported"); + + // Default texture format for PNG/BMP/TIFF/JPEG/GIF images + // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565 + // You can change this setting at any time. + [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888]; + + // If the 1st suffix is not found and if fallback is enabled then fallback suffixes are going to searched. If none is found, it will try with the name without suffix. + // On iPad HD : "-ipadhd", "-ipad", "-hd" + // On iPad : "-ipad", "-hd" + // On iPhone HD: "-hd" + CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils]; + [sharedFileUtils setEnableFallbackSuffixes:NO]; // Default: NO. No fallback suffixes are going to be used + [sharedFileUtils setiPhoneRetinaDisplaySuffix:@"-hd"]; // Default on iPhone RetinaDisplay is "-hd" + [sharedFileUtils setiPadSuffix:@"-ipad"]; // Default on iPad is "ipad" + [sharedFileUtils setiPadRetinaDisplaySuffix:@"-ipadhd"]; // Default on iPad RetinaDisplay is "-ipadhd" + + // Assume that PVR images have premultiplied alpha + [CCTexture2D PVRImagesHavePremultipliedAlpha:YES]; + + // Create a Navigation Controller with the Director + navController_ = [[MyNavigationController alloc] initWithRootViewController:director_]; + navController_.navigationBarHidden = YES; + + // for rotation and other messages + [director_ setDelegate:navController_]; + + // set the Navigation Controller as the root view controller + [window_ setRootViewController:navController_]; + + // make main window visible + [window_ makeKeyAndVisible]; + + return YES; +} + +// getting a call, pause the game +-(void) applicationWillResignActive:(UIApplication *)application { + if( [navController_ visibleViewController] == director_ ) + [director_ pause]; +} + +// call got rejected +-(void) applicationDidBecomeActive:(UIApplication *)application { + [[CCDirector sharedDirector] setNextDeltaTimeZero:YES]; + if( [navController_ visibleViewController] == director_ ) + [director_ resume]; +} + +-(void) applicationDidEnterBackground:(UIApplication*)application { + if( [navController_ visibleViewController] == director_ ) + [director_ stopAnimation]; +} + +-(void) applicationWillEnterForeground:(UIApplication*)application { + if( [navController_ visibleViewController] == director_ ) + [director_ startAnimation]; +} + +// application will be killed +- (void)applicationWillTerminate:(UIApplication *)application { + CC_DIRECTOR_END(); +} + +// purge memory +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application +{ + [[CCDirector sharedDirector] purgeCachedData]; +} + +// next delta time will be zero +-(void) applicationSignificantTimeChange:(UIApplication *)application { + [[CCDirector sharedDirector] setNextDeltaTimeZero:YES]; +} + +- (void) dealloc { + [window_ release]; + [navController_ release]; + + [super dealloc]; +} +@end diff --git a/spine-cocos2d-iphone/example/ExampleLayer.h b/spine-cocos2d-iphone/example/ExampleLayer.h index ba50e6fcc..854696bd4 100644 --- a/spine-cocos2d-iphone/example/ExampleLayer.h +++ b/spine-cocos2d-iphone/example/ExampleLayer.h @@ -27,7 +27,7 @@ #import @interface ExampleLayer : CCLayer { - CCSkeleton* skeletonNode; + CCSkeletonAnimation* animationNode; } +(CCScene*) scene; diff --git a/spine-cocos2d-iphone/example/ExampleLayer.m b/spine-cocos2d-iphone/example/ExampleLayer.m index 380d06238..2a86f3730 100644 --- a/spine-cocos2d-iphone/example/ExampleLayer.m +++ b/spine-cocos2d-iphone/example/ExampleLayer.m @@ -37,18 +37,18 @@ self = [super init]; if (!self) return nil; - skeletonNode = [CCSkeleton skeletonWithFile:@"spineboy.json" atlasFile:@"spineboy.atlas"]; - AnimationStateData_setMixByName(skeletonNode->state->data, "walk", "jump", 0.4f); - AnimationStateData_setMixByName(skeletonNode->state->data, "jump", "walk", 0.4f); - AnimationState_setAnimationByName(skeletonNode->state, "walk", true); - skeletonNode->timeScale = 0.3f; - skeletonNode->debugBones = true; + animationNode = [CCSkeletonAnimation skeletonWithFile:@"spineboy.json" atlasFile:@"spineboy.atlas" scale:1]; + [animationNode setMixFrom:@"walk" to:@"jump" duration:0.2f]; + [animationNode setMixFrom:@"jump" to:@"walk" duration:0.4f]; + [animationNode setAnimation:@"walk" loop:NO]; + [animationNode addAnimation:@"jump" loop:NO afterDelay:0]; + [animationNode addAnimation:@"walk" loop:YES afterDelay:0]; + animationNode.timeScale = 0.3f; + animationNode.debugBones = true; CGSize windowSize = [[CCDirector sharedDirector] winSize]; - [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; - [self addChild:skeletonNode]; - - [self scheduleUpdate]; + [animationNode setPosition:ccp(windowSize.width / 2, 20)]; + [self addChild:animationNode]; #if __CC_PLATFORM_MAC [self setMouseEnabled:YES]; @@ -57,22 +57,14 @@ return self; } -- (void) update:(ccTime)delta { - if (skeletonNode->state->loop) { - if (skeletonNode->state->time > 2) AnimationState_setAnimationByName(skeletonNode->state, "jump", false); - } else { - if (skeletonNode->state->time > 1) AnimationState_setAnimationByName(skeletonNode->state, "walk", true); - } -} - #if __CC_PLATFORM_MAC - (BOOL) ccMouseDown:(NSEvent*)event { CCDirector* director = [CCDirector sharedDirector]; NSPoint location = [director convertEventToGL:event]; location.x -= [[director runningScene]position].x; location.y -= [[director runningScene]position].y; - location.x -= skeletonNode.position.x; - location.y -= skeletonNode.position.y; + location.x -= animationNode.position.x; + location.y -= animationNode.position.y; if (CGRectContainsPoint(skeletonNode.boundingBox, location)) NSLog(@"Clicked!"); return YES; } diff --git a/spine-cocos2d-iphone/spine-cocos2d-iphone-ios.xcodeproj/project.pbxproj b/spine-cocos2d-iphone/spine-cocos2d-iphone-ios.xcodeproj/project.pbxproj index 7e1410ea9..9b9cb95fa 100644 --- a/spine-cocos2d-iphone/spine-cocos2d-iphone-ios.xcodeproj/project.pbxproj +++ b/spine-cocos2d-iphone/spine-cocos2d-iphone-ios.xcodeproj/project.pbxproj @@ -158,7 +158,9 @@ 43C32A03170B0F15004A9460 /* vec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C32992170B0F14004A9460 /* vec3.c */; }; 43C32A04170B0F15004A9460 /* vec4.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C32993170B0F14004A9460 /* vec4.c */; }; 43C32A06170B0F93004A9460 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C32A05170B0F93004A9460 /* main.m */; }; - 43C32A09170B10FF004A9460 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C32A08170B10FF004A9460 /* AppDelegate.m */; }; + 43C32A09170B10FF004A9460 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 43C32A08170B10FF004A9460 /* AppDelegate.mm */; }; + 43DB2A3D172C16BC003045C5 /* CCSkeleton.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DB2A3A172C16BC003045C5 /* CCSkeleton.m */; }; + 43DB2A3E172C16BC003045C5 /* CCSkeletonAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DB2A3C172C16BC003045C5 /* CCSkeletonAnimation.m */; }; 9A5D2499170A94DA0030D4DD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D2498170A94DA0030D4DD /* QuartzCore.framework */; }; 9A5D249B170A94DA0030D4DD /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D249A170A94DA0030D4DD /* OpenGLES.framework */; }; 9A5D249D170A94DA0030D4DD /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D249C170A94DA0030D4DD /* OpenAL.framework */; }; @@ -481,7 +483,11 @@ 43C32993170B0F14004A9460 /* vec4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vec4.c; sourceTree = ""; }; 43C32A05170B0F93004A9460 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = "Resources-ios/main.m"; sourceTree = ""; }; 43C32A07170B10FF004A9460 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = "Resources-ios/AppDelegate.h"; sourceTree = ""; }; - 43C32A08170B10FF004A9460 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = "Resources-ios/AppDelegate.m"; sourceTree = ""; }; + 43C32A08170B10FF004A9460 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = "Resources-ios/AppDelegate.mm"; sourceTree = ""; }; + 43DB2A39172C16BC003045C5 /* CCSkeleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCSkeleton.h; path = src/spine/CCSkeleton.h; sourceTree = ""; }; + 43DB2A3A172C16BC003045C5 /* CCSkeleton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCSkeleton.m; path = src/spine/CCSkeleton.m; sourceTree = ""; }; + 43DB2A3B172C16BC003045C5 /* CCSkeletonAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCSkeletonAnimation.h; path = src/spine/CCSkeletonAnimation.h; sourceTree = ""; }; + 43DB2A3C172C16BC003045C5 /* CCSkeletonAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCSkeletonAnimation.m; path = src/spine/CCSkeletonAnimation.m; sourceTree = ""; }; 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; }; 9A5D249A170A94DA0030D4DD /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -522,7 +528,7 @@ 43C32826170B0BF6004A9460 /* ExampleLayer.h */, 43C32827170B0BF6004A9460 /* ExampleLayer.m */, 43C32A07170B10FF004A9460 /* AppDelegate.h */, - 43C32A08170B10FF004A9460 /* AppDelegate.m */, + 43C32A08170B10FF004A9460 /* AppDelegate.mm */, 43C32A05170B0F93004A9460 /* main.m */, 43C32889170B0E9F004A9460 /* Prefix.pch */, ); @@ -578,6 +584,10 @@ children = ( 43C3282D170B0C19004A9460 /* spine-cocos2d-iphone.m */, 43C3282E170B0C19004A9460 /* spine-cocos2d-iphone.h */, + 43DB2A39172C16BC003045C5 /* CCSkeleton.h */, + 43DB2A3A172C16BC003045C5 /* CCSkeleton.m */, + 43DB2A3B172C16BC003045C5 /* CCSkeletonAnimation.h */, + 43DB2A3C172C16BC003045C5 /* CCSkeletonAnimation.m */, ); name = "spine-cocos2d-iphone"; sourceTree = ""; @@ -1217,7 +1227,9 @@ 43C32A03170B0F15004A9460 /* vec3.c in Sources */, 43C32A04170B0F15004A9460 /* vec4.c in Sources */, 43C32A06170B0F93004A9460 /* main.m in Sources */, - 43C32A09170B10FF004A9460 /* AppDelegate.m in Sources */, + 43C32A09170B10FF004A9460 /* AppDelegate.mm in Sources */, + 43DB2A3D172C16BC003045C5 /* CCSkeleton.m in Sources */, + 43DB2A3E172C16BC003045C5 /* CCSkeletonAnimation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/spine-cocos2d-iphone/src/spine/CCSkeleton.h b/spine-cocos2d-iphone/src/spine/CCSkeleton.h new file mode 100644 index 000000000..0dc0a5f6d --- /dev/null +++ b/spine-cocos2d-iphone/src/spine/CCSkeleton.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#import +#import "cocos2d.h" + +#ifdef __cplusplus +using namespace spine; +#endif + +/** +Draws a skeleton. +*/ +@interface CCSkeleton : CCNodeRGBA { + Skeleton* _skeleton; + float _timeScale; + bool _debugSlots; + bool _debugBones; + + ccBlendFunc _blendFunc; + bool _ownsSkeletonData; + Atlas* _atlas; +} + ++ (id) skeletonWithData:(SkeletonData*)skeletonData; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (id) initWithData:(SkeletonData*)skeletonData; +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale; +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +@property (nonatomic, readonly) Skeleton* skeleton; +@property (nonatomic) float timeScale; +@property (nonatomic) bool debugSlots; +@property (nonatomic) bool debugBones; + +@end diff --git a/spine-cocos2d-iphone/src/spine/CCSkeleton.m b/spine-cocos2d-iphone/src/spine/CCSkeleton.m new file mode 100644 index 000000000..52618bdf2 --- /dev/null +++ b/spine-cocos2d-iphone/src/spine/CCSkeleton.m @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#import +#import + +@interface CCSkeleton (Private) +- (void) initialize:(SkeletonData*)skeletonData; +@end + +@implementation CCSkeleton + +@synthesize skeleton = _skeleton; +@synthesize timeScale = _timeScale; +@synthesize debugSlots = _debugSlots; +@synthesize debugBones = _debugBones; + ++ (id) skeletonWithData:(SkeletonData*)skeletonData { + return [[[CCSkeleton alloc] initWithData:skeletonData] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale { + return [[[CCSkeleton alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + return [[[CCSkeleton alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; +} + +- (void) initialize:(SkeletonData*)skeletonData { + _skeleton = Skeleton_create(skeletonData); + + _blendFunc.src = GL_ONE; + _blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + + _timeScale = 1; + + [self setShaderProgram:[[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTextureColor]]; + [self scheduleUpdate]; +} + +- (id) initWithData:(SkeletonData*)skeletonData { + NSAssert(skeletonData, @"skeletonData cannot be null."); + + self = [super init]; + if (!self) return nil; + + [self initialize:skeletonData]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale { + self = [super init]; + if (!self) return nil; + + SkeletonJson* json = SkeletonJson_create(atlas); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); + NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); + SkeletonJson_dispose(json); + if (!skeletonData) return 0; + + [self initialize:skeletonData]; + _ownsSkeletonData = YES; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + self = [super init]; + if (!self) return nil; + + _atlas = Atlas_readAtlasFile([atlasFile UTF8String]); + NSAssert(_atlas, ([NSString stringWithFormat:@"Error reading atlas file: %@", atlasFile])); + if (!_atlas) return 0; + + SkeletonJson* json = SkeletonJson_create(_atlas); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); + NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); + SkeletonJson_dispose(json); + if (!skeletonData) return 0; + + [self initialize:skeletonData]; + _ownsSkeletonData = YES; + + return self; +} + +- (void) dealloc { + if (_ownsSkeletonData) SkeletonData_dispose(_skeleton->data); + if (_atlas) Atlas_dispose(_atlas); + Skeleton_dispose(_skeleton); + [super dealloc]; +} + +- (void) update:(ccTime)deltaTime { + Skeleton_update(_skeleton, deltaTime * _timeScale); +} + +- (void) draw { + CC_NODE_DRAW_SETUP(); + + ccGLBlendFunc(_blendFunc.src, _blendFunc.dst); + ccColor3B color = self.color; + _skeleton->r = color.r / (float)255; + _skeleton->g = color.g / (float)255; + _skeleton->b = color.b / (float)255; + _skeleton->a = self.opacity / (float)255; + + CCTextureAtlas* textureAtlas = 0; + ccV3F_C4B_T2F_Quad quad; + quad.tl.vertices.z = 0; + quad.tr.vertices.z = 0; + quad.bl.vertices.z = 0; + quad.br.vertices.z = 0; + for (int i = 0, n = _skeleton->slotCount; i < n; i++) { + Slot* slot = _skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->texture; + if (regionTextureAtlas != textureAtlas) { + if (textureAtlas) { + [textureAtlas drawQuads]; + [textureAtlas removeAllQuads]; + } + } + textureAtlas = regionTextureAtlas; + if (textureAtlas.capacity == textureAtlas.totalQuads && + ![textureAtlas resizeCapacity:textureAtlas.capacity * 2]) return; + RegionAttachment_updateQuad(attachment, slot, &quad); + [textureAtlas updateQuad:&quad atIndex:textureAtlas.totalQuads]; + } + if (textureAtlas) { + [textureAtlas drawQuads]; + [textureAtlas removeAllQuads]; + } + + if (_debugSlots) { + // Slots. + ccDrawColor4B(0, 0, 255, 255); + glLineWidth(1); + CGPoint points[4]; + ccV3F_C4B_T2F_Quad quad; + for (int i = 0, n = _skeleton->slotCount; i < n; i++) { + Slot* slot = _skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + RegionAttachment_updateQuad(attachment, slot, &quad); + points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y); + points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y); + points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y); + points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y); + ccDrawPoly(points, 4, true); + } + } + if (_debugBones) { + // Bone lengths. + glLineWidth(2); + ccDrawColor4B(255, 0, 0, 255); + for (int i = 0, n = _skeleton->boneCount; i < n; i++) { + Bone *bone = _skeleton->bones[i]; + float x = bone->data->length * bone->m00 + bone->worldX; + float y = bone->data->length * bone->m10 + bone->worldY; + ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y)); + } + // Bone origins. + ccPointSize(4); + ccDrawColor4B(0, 0, 255, 255); // Root bone is blue. + for (int i = 0, n = _skeleton->boneCount; i < n; i++) { + Bone *bone = _skeleton->bones[i]; + ccDrawPoint(ccp(bone->worldX, bone->worldY)); + if (i == 0) ccDrawColor4B(0, 255, 0, 255); + } + } +} + +- (CGRect) boundingBox { + float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; + float scaleX = self.scaleX; + float scaleY = self.scaleY; + ccV3F_C4B_T2F_Quad quad; + for (int i = 0; i < _skeleton->slotCount; ++i) { + Slot* slot = _skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + RegionAttachment_updateQuad(attachment, slot, &quad); + minX = fmin(minX, quad.bl.vertices.x * scaleX); + minY = fmin(minY, quad.bl.vertices.y * scaleY); + maxX = fmax(maxX, quad.bl.vertices.x * scaleX); + maxY = fmax(maxY, quad.bl.vertices.y * scaleY); + minX = fmin(minX, quad.br.vertices.x * scaleX); + minY = fmin(minY, quad.br.vertices.y * scaleY); + maxX = fmax(maxX, quad.br.vertices.x * scaleX); + maxY = fmax(maxY, quad.br.vertices.y * scaleY); + minX = fmin(minX, quad.tl.vertices.x * scaleX); + minY = fmin(minY, quad.tl.vertices.y * scaleY); + maxX = fmax(maxX, quad.tl.vertices.x * scaleX); + maxY = fmax(maxY, quad.tl.vertices.y * scaleY); + minX = fmin(minX, quad.tr.vertices.x * scaleX); + minY = fmin(minY, quad.tr.vertices.y * scaleY); + maxX = fmax(maxX, quad.tr.vertices.x * scaleX); + maxY = fmax(maxY, quad.tr.vertices.y * scaleY); + } + minX = self.position.x + minX; + minY = self.position.y + minY; + maxX = self.position.x + maxX; + maxY = self.position.y + maxY; + return CGRectMake(minX, minY, maxX - minX, maxY - minY); +} + +// CCBlendProtocol + +- (void) setBlendFunc:(ccBlendFunc)func { + self.blendFunc = func; +} + +- (ccBlendFunc) blendFunc { + return _blendFunc; +} + +@end diff --git a/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.h b/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.h new file mode 100644 index 000000000..96aa57c65 --- /dev/null +++ b/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.h @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#import +#import +#import "cocos2d.h" + +#ifdef __cplusplus +using namespace spine; +#endif + +/** +Draws an animated skeleton, providing a simple API for applying one or more animations and queuing animations to be played later. +*/ +@interface CCSkeletonAnimation : CCSkeleton { + NSMutableArray* _states; + + NSMutableArray* _stateDatas; +} + ++ (id) skeletonWithData:(SkeletonData*)skeletonData; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (id) initWithData:(SkeletonData*)skeletonData; +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale; +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (void) addAnimationState; +- (void) addAnimationState:(AnimationStateData*)stateData; +- (void) setAnimationStateData:(AnimationStateData*)stateData forState:(int)stateIndex; + +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration; +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration forState:(int)stateIndex; + +- (void) setAnimation:(NSString*)name loop:(bool)loop; +- (void) setAnimation:(NSString*)name loop:(bool)loop forState:(int)stateIndex; + +- (void) addAnimation:(NSString*)name loop:(bool)loop afterDelay:(float)delay; +- (void) addAnimation:(NSString*)name loop:(bool)loop afterDelay:(float)delay forState:(int)stateIndex; + +- (void) clearAnimation; +- (void) clearAnimationForState:(int)stateIndex; + +@property (retain, nonatomic, readonly) NSMutableArray* states; + +@end diff --git a/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.m b/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.m new file mode 100644 index 000000000..c7d19d6a3 --- /dev/null +++ b/spine-cocos2d-iphone/src/spine/CCSkeletonAnimation.m @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#import +#import + +@interface CCSkeletonAnimation (Private) +- (void) initialize; +@end + +@implementation CCSkeletonAnimation + +@synthesize states = _states; + ++ (id) skeletonWithData:(SkeletonData*)skeletonData { + return [[[CCSkeletonAnimation alloc] initWithData:skeletonData] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale { + return [[[CCSkeletonAnimation alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + return [[[CCSkeletonAnimation alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; +} + +- (void) initialize { + _states = [[NSMutableArray arrayWithCapacity:2] retain]; + _stateDatas = [[NSMutableArray arrayWithCapacity:2] retain]; + [self addAnimationState]; +} + +- (id) initWithData:(SkeletonData*)skeletonData { + self = [super initWithData:skeletonData]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale { + self = [super initWithFile:skeletonDataFile atlas:atlas scale:scale]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + self = [super initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (void) dealloc { + for (NSValue* value in _stateDatas) + AnimationStateData_dispose([value pointerValue]); + [_stateDatas release]; + + for (NSValue* value in _states) + AnimationState_dispose([value pointerValue]); + [_states release]; + + [super dealloc]; +} + +- (void) update:(ccTime)deltaTime { + [super update:deltaTime]; + + deltaTime *= _timeScale; + for (NSValue* value in _states) { + AnimationState* state = [value pointerValue]; + AnimationState_update(state, deltaTime); + AnimationState_apply(state, _skeleton); + } + Skeleton_updateWorldTransform(_skeleton); +} + +- (void) addAnimationState { + AnimationStateData* stateData = AnimationStateData_create(_skeleton->data); + [_stateDatas addObject:[NSValue valueWithPointer:stateData]]; + [self addAnimationState:stateData]; +} + +- (void) addAnimationState:(AnimationStateData*)stateData { + NSAssert(stateData, @"stateData cannot be null."); + AnimationState* state = AnimationState_create(stateData); + [_states addObject:[NSValue valueWithPointer:state]]; +} + +- (void) setAnimationStateData:(AnimationStateData*)stateData forState:(int)stateIndex { + NSAssert(stateData, @"stateData cannot be null."); + NSAssert(stateIndex >= 0 && stateIndex < (int)_states.count, @"stateIndex out of range."); + + AnimationState* state = [[_states objectAtIndex:stateIndex] pointerValue]; + for (NSValue* value in _stateDatas) { + if (state->data == [value pointerValue]) { + AnimationStateData_dispose(state->data); + [_stateDatas removeObject:value]; + break; + } + } + [_states removeObject:[NSValue valueWithPointer:state]]; + AnimationState_dispose(state); + + state = AnimationState_create(stateData); + [_states setObject:[NSValue valueWithPointer:state] atIndexedSubscript:stateIndex]; +} + +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration { + [self setMixFrom:fromAnimation to:toAnimation duration:duration forState:0]; +} + +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration forState:(int)stateIndex { + NSAssert(stateIndex >= 0 && stateIndex < (int)_states.count, @"stateIndex out of range."); + AnimationState* state = [[_states objectAtIndex:stateIndex] pointerValue]; + AnimationStateData_setMixByName(state->data, [fromAnimation UTF8String], [toAnimation UTF8String], duration); +} + +- (void) setAnimation:(NSString*)name loop:(bool)loop { + [self setAnimation:name loop:loop forState:0]; +} + +- (void) setAnimation:(NSString*)name loop:(bool)loop forState:(int)stateIndex { + NSAssert(stateIndex >= 0 && stateIndex < (int)_states.count, @"stateIndex out of range."); + AnimationState* state = [[_states objectAtIndex:stateIndex] pointerValue]; + AnimationState_setAnimationByName(state, [name UTF8String], loop); +} + +- (void) addAnimation:(NSString*)name loop:(bool)loop afterDelay:(float)delay { + [self addAnimation:name loop:loop afterDelay:delay forState:0]; +} + +- (void) addAnimation:(NSString*)name loop:(bool)loop afterDelay:(float)delay forState:(int)stateIndex { + NSAssert(stateIndex >= 0 && stateIndex < (int)_states.count, @"stateIndex out of range."); + AnimationState* state = [[_states objectAtIndex:stateIndex] pointerValue]; + AnimationState_addAnimationByName(state, [name UTF8String], loop, delay); +} + +- (void) clearAnimation { + [self clearAnimationForState:0]; +} + +- (void) clearAnimationForState:(int)stateIndex { + NSAssert(stateIndex >= 0 && stateIndex < (int)_states.count, @"stateIndex out of range."); + AnimationState* state = [[_states objectAtIndex:stateIndex] pointerValue]; + AnimationState_clearAnimation(state); +} + +@end diff --git a/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.h b/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.h index a12c98743..bf9bd62c0 100644 --- a/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.h +++ b/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.h @@ -23,47 +23,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -#ifndef SPINE_COCOS2D_H_ -#define SPINE_COCOS2D_H_ - -#include -#include "cocos2d.h" - -#ifdef __cplusplus -using namespace spine; -#endif - -@interface CCSkeleton : CCNodeRGBA { -@private - bool ownsSkeleton; - bool ownsStateData; - Atlas* atlas; - -@public - Skeleton* const skeleton; - AnimationState* const state; - float timeScale; - bool debugSlots; - bool debugBones; - - ccBlendFunc blendFunc; -} - -+ (CCSkeleton*) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas; -+ (CCSkeleton*) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale; - -+ (CCSkeleton*) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile; -+ (CCSkeleton*) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; - -+ (CCSkeleton*) skeletonWithData:(SkeletonData*)skeletonData; -+ (CCSkeleton*) skeletonWithData:(SkeletonData*)skeletonData stateData:(AnimationStateData*)stateData; - -- initWithData:(SkeletonData*)skeletonData; -- initWithData:(SkeletonData*)skeletonData stateData:(AnimationStateData*)stateData; - -@end - -/**/ +#import +#import "cocos2d.h" +#import "CCSkeleton.h" +#import "CCSkeletonAnimation.h" #ifdef __cplusplus namespace spine { @@ -76,5 +39,3 @@ void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_ } } #endif - -#endif /* SPINE_COCOS2D_H_ */ diff --git a/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.m b/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.m index a5434568a..dbffa5c2e 100644 --- a/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.m +++ b/spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.m @@ -96,229 +96,3 @@ void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_ #ifdef __cplusplus } #endif - -/**/ - -@implementation CCSkeleton - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas { - return [CCSkeleton skeletonWithFile:skeletonDataFile atlas:atlas scale:1]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale { - NSAssert(skeletonDataFile, @"skeletonDataFile cannot be nil."); - NSAssert(atlas, @"atlas cannot be nil."); - - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = scale; - SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); - NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); - SkeletonJson_dispose(json); - - CCSkeleton* node = skeletonData ? [CCSkeleton skeletonWithData:skeletonData] : 0; - node->ownsSkeleton = true; - return node; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile { - return [CCSkeleton skeletonWithFile:skeletonDataFile atlasFile:atlasFile scale:1]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { - NSAssert(skeletonDataFile, @"skeletonDataFile cannot be nil."); - NSAssert(atlasFile, @"atlasFile cannot be nil."); - - Atlas* atlas = Atlas_readAtlasFile([atlasFile UTF8String]); - NSAssert(atlas, ([NSString stringWithFormat:@"Error reading atlas file: %@", atlasFile])); - if (!atlas) return 0; - - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = scale; - SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); - NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); - SkeletonJson_dispose(json); - if (!skeletonData) { - Atlas_dispose(atlas); - return 0; - } - - CCSkeleton* node = [CCSkeleton skeletonWithData:skeletonData]; - node->ownsSkeleton = true; - node->atlas = atlas; - return node; -} - -+ (id) skeletonWithData:(SkeletonData*)skeletonData { - return [CCSkeleton skeletonWithData:skeletonData stateData:0]; -} - -+ (id) skeletonWithData:(SkeletonData*)skeletonData stateData:(AnimationStateData*)stateData { - return [[[CCSkeleton alloc] initWithData:skeletonData stateData:stateData] autorelease]; -} - -- (id) initWithData:(SkeletonData*)skeletonData { - return [self initWithData:skeletonData stateData:0]; -} - -- (id) initWithData:(SkeletonData*)skeletonData stateData:(AnimationStateData*)stateData { - NSAssert(skeletonData, @"skeletonData cannot be nil."); - - self = [super init]; - if (!self) return nil; - - CONST_CAST(Skeleton*, skeleton) = Skeleton_create(skeletonData); - - if (!stateData) { - stateData = AnimationStateData_create(skeletonData); - ownsStateData = true; - } - CONST_CAST(AnimationState*, state) = AnimationState_create(stateData); - - blendFunc.src = GL_ONE; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - - timeScale = 1; - - [self setShaderProgram:[[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTextureColor]]; - [self scheduleUpdate]; - - return self; -} - -- (void) dealloc { - if (ownsSkeleton) Skeleton_dispose(skeleton); - if (ownsStateData) AnimationStateData_dispose(state->data); - if (atlas) Atlas_dispose(atlas); - AnimationState_dispose(state); - [super dealloc]; -} - -- (void) update:(ccTime)deltaTime { - Skeleton_update(skeleton, deltaTime * timeScale); - AnimationState_update(state, deltaTime * timeScale); - AnimationState_apply(state, skeleton); - Skeleton_updateWorldTransform(skeleton); -} - -- (void) draw { - CC_NODE_DRAW_SETUP(); - - ccGLBlendFunc(blendFunc.src, blendFunc.dst); - ccColor3B color = self.color; - skeleton->r = color.r / (float)255; - skeleton->g = color.g / (float)255; - skeleton->b = color.b / (float)255; - skeleton->a = self.opacity / (float)255; - - CCTextureAtlas* textureAtlas = 0; - ccV3F_C4B_T2F_Quad quad; - quad.tl.vertices.z = 0; - quad.tr.vertices.z = 0; - quad.bl.vertices.z = 0; - quad.br.vertices.z = 0; - for (int i = 0, n = skeleton->slotCount; i < n; i++) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->texture; - if (regionTextureAtlas != textureAtlas) { - if (textureAtlas) { - [textureAtlas drawQuads]; - [textureAtlas removeAllQuads]; - } - } - textureAtlas = regionTextureAtlas; - if (textureAtlas.capacity == textureAtlas.totalQuads && - ![textureAtlas resizeCapacity:textureAtlas.capacity * 2]) return; - RegionAttachment_updateQuad(attachment, slot, &quad); - [textureAtlas updateQuad:&quad atIndex:textureAtlas.totalQuads]; - } - if (textureAtlas) { - [textureAtlas drawQuads]; - [textureAtlas removeAllQuads]; - } - - if (debugSlots) { - // Slots. - ccDrawColor4B(0, 0, 255, 255); - glLineWidth(1); - CGPoint points[4]; - ccV3F_C4B_T2F_Quad quad; - for (int i = 0, n = skeleton->slotCount; i < n; i++) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - RegionAttachment_updateQuad(attachment, slot, &quad); - points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y); - points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y); - points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y); - points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y); - ccDrawPoly(points, 4, true); - } - } - if (debugBones) { - // Bone lengths. - glLineWidth(2); - ccDrawColor4B(255, 0, 0, 255); - for (int i = 0, n = skeleton->boneCount; i < n; i++) { - Bone *bone = skeleton->bones[i]; - float x = bone->data->length * bone->m00 + bone->worldX; - float y = bone->data->length * bone->m10 + bone->worldY; - ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y)); - } - // Bone origins. - ccPointSize(4); - ccDrawColor4B(0, 0, 255, 255); // Root bone is blue. - for (int i = 0, n = skeleton->boneCount; i < n; i++) { - Bone *bone = skeleton->bones[i]; - ccDrawPoint(ccp(bone->worldX, bone->worldY)); - if (i == 0) ccDrawColor4B(0, 255, 0, 255); - } - } -} - -- (CGRect) boundingBox { - float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; - float scaleX = self.scaleX; - float scaleY = self.scaleY; - ccV3F_C4B_T2F_Quad quad; - for (int i = 0; i < skeleton->slotCount; ++i) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - RegionAttachment_updateQuad(attachment, slot, &quad); - minX = fmin(minX, quad.bl.vertices.x * scaleX); - minY = fmin(minY, quad.bl.vertices.y * scaleY); - maxX = fmax(maxX, quad.bl.vertices.x * scaleX); - maxY = fmax(maxY, quad.bl.vertices.y * scaleY); - minX = fmin(minX, quad.br.vertices.x * scaleX); - minY = fmin(minY, quad.br.vertices.y * scaleY); - maxX = fmax(maxX, quad.br.vertices.x * scaleX); - maxY = fmax(maxY, quad.br.vertices.y * scaleY); - minX = fmin(minX, quad.tl.vertices.x * scaleX); - minY = fmin(minY, quad.tl.vertices.y * scaleY); - maxX = fmax(maxX, quad.tl.vertices.x * scaleX); - maxY = fmax(maxY, quad.tl.vertices.y * scaleY); - minX = fmin(minX, quad.tr.vertices.x * scaleX); - minY = fmin(minY, quad.tr.vertices.y * scaleY); - maxX = fmax(maxX, quad.tr.vertices.x * scaleX); - maxY = fmax(maxY, quad.tr.vertices.y * scaleY); - } - minX = self.position.x + minX; - minY = self.position.y + minY; - maxX = self.position.x + maxX; - maxY = self.position.y + maxY; - return CGRectMake(minX, minY, maxX - minX, maxY - minY); -} - -// CCBlendProtocol - -- (void) setBlendFunc:(ccBlendFunc)func { - self.blendFunc = func; -} - -- (ccBlendFunc) blendFunc { - return blendFunc; -} - -@end diff --git a/spine-cocos2dx/example/Classes/ExampleLayer.cpp b/spine-cocos2dx/example/Classes/ExampleLayer.cpp index 233b4ed09..519a9cecd 100644 --- a/spine-cocos2dx/example/Classes/ExampleLayer.cpp +++ b/spine-cocos2dx/example/Classes/ExampleLayer.cpp @@ -41,10 +41,17 @@ CCScene* ExampleLayer::scene () { bool ExampleLayer::init () { if (!CCLayer::init()) return false; - skeletonNode = CCSkeleton::createWithFile("spineboy.json", "spineboy.atlas"); - AnimationStateData_setMixByName(skeletonNode->state->data, "walk", "jump", 0.4f); - AnimationStateData_setMixByName(skeletonNode->state->data, "jump", "walk", 0.4f); - AnimationState_setAnimationByName(skeletonNode->state, "walk", true); + skeletonNode = new CCSkeletonAnimation("spineboy.json", "spineboy.atlas"); + skeletonNode->addAnimationState(); + skeletonNode->setMix("walk", "jump", 0.2f); + skeletonNode->setMix("jump", "walk", 0.4f); + + skeletonNode->setAnimation("walk", true); + // This shows how to setup animations to play back to back. + //skeletonNode->addAnimation("jump", true); + //skeletonNode->addAnimation("walk", true); + //skeletonNode->addAnimation("jump", true); + skeletonNode->timeScale = 0.3f; skeletonNode->debugBones = true; @@ -63,9 +70,9 @@ bool ExampleLayer::init () { } void ExampleLayer::update (float deltaTime) { - if (skeletonNode->state->loop) { - if (skeletonNode->state->time > 2) AnimationState_setAnimationByName(skeletonNode->state, "jump", false); + if (skeletonNode->states[0]->loop) { + if (skeletonNode->states[0]->time > 2) skeletonNode->setAnimation("jump", false); } else { - if (skeletonNode->state->time > 1) AnimationState_setAnimationByName(skeletonNode->state, "walk", true); + if (skeletonNode->states[0]->time > 1) skeletonNode->setAnimation("walk", true); } } diff --git a/spine-cocos2dx/example/Classes/ExampleLayer.h b/spine-cocos2dx/example/Classes/ExampleLayer.h index dc3b8d08e..e9ebc3545 100644 --- a/spine-cocos2dx/example/Classes/ExampleLayer.h +++ b/spine-cocos2dx/example/Classes/ExampleLayer.h @@ -31,7 +31,7 @@ class ExampleLayer: public cocos2d::CCLayer { private: - spine::CCSkeleton* skeletonNode; + spine::CCSkeletonAnimation* skeletonNode; public: static cocos2d::CCScene* scene (); diff --git a/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj b/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj index 2754577f1..0605836d3 100644 --- a/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj +++ b/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj @@ -143,6 +143,8 @@ + + @@ -168,6 +170,8 @@ + + diff --git a/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj.filters b/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj.filters index afab79138..697cef5e7 100644 --- a/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj.filters +++ b/spine-cocos2dx/example/proj.win32/spine-cocos2dx.vcxproj.filters @@ -87,6 +87,12 @@ Classes\spine-c + + Classes\spine-cocos2dx + + + Classes\spine-cocos2dx + @@ -155,5 +161,11 @@ Classes\spine-c + + Classes\spine-cocos2dx + + + Classes\spine-cocos2dx + \ No newline at end of file diff --git a/spine-cocos2dx/src/spine/CCSkeleton.cpp b/spine-cocos2dx/src/spine/CCSkeleton.cpp new file mode 100644 index 000000000..fb1a56042 --- /dev/null +++ b/spine-cocos2dx/src/spine/CCSkeleton.cpp @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#include +#include + +USING_NS_CC; +using std::min; +using std::max; + +namespace spine { + +static CCSkeleton* createWithData (SkeletonData* skeletonData) { + CCSkeleton* node = new CCSkeleton(skeletonData); + node->autorelease(); + return node; +} + +static CCSkeleton* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) { + CCSkeleton* node = new CCSkeleton(skeletonDataFile, atlas, scale); + node->autorelease(); + return node; +} + +static CCSkeleton* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) { + CCSkeleton* node = new CCSkeleton(skeletonDataFile, atlasFile, scale); + node->autorelease(); + return node; +} + +void CCSkeleton::initialize (SkeletonData *skeletonData) { + ownsSkeletonData = false; + atlas = 0; + debugSlots = false; + debugBones = false; + + skeleton = Skeleton_create(skeletonData); + + blendFunc.src = GL_ONE; + blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + + setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor)); + scheduleUpdate(); +} + +CCSkeleton::CCSkeleton (SkeletonData *skeletonData) { + initialize(skeletonData); +} + +CCSkeleton::CCSkeleton (const char* skeletonDataFile, Atlas* atlas, float scale) { + SkeletonJson* json = SkeletonJson_create(atlas); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile); + CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data."); + SkeletonJson_dispose(json); + + initialize(skeletonData); + ownsSkeletonData = true; +} + +CCSkeleton::CCSkeleton (const char* skeletonDataFile, const char* atlasFile, float scale) { + atlas = Atlas_readAtlasFile(atlasFile); + CCAssert(atlas, "Error reading atlas file."); + + SkeletonJson* json = SkeletonJson_create(atlas); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile); + CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data file."); + SkeletonJson_dispose(json); + + initialize(skeletonData); + ownsSkeletonData = true; +} + +CCSkeleton::~CCSkeleton () { + if (ownsSkeletonData) SkeletonData_dispose(skeleton->data); + if (atlas) Atlas_dispose(atlas); + Skeleton_dispose(skeleton); +} + +void CCSkeleton::update (float deltaTime) { + Skeleton_update(skeleton, deltaTime * timeScale); +} + +void CCSkeleton::draw () { + CC_NODE_DRAW_SETUP(); + + ccGLBlendFunc(blendFunc.src, blendFunc.dst); + ccColor3B color = getColor(); + skeleton->r = color.r / (float)255; + skeleton->g = color.g / (float)255; + skeleton->b = color.b / (float)255; + skeleton->a = getOpacity() / (float)255; + + CCTextureAtlas* textureAtlas = 0; + ccV3F_C4B_T2F_Quad quad; + quad.tl.vertices.z = 0; + quad.tr.vertices.z = 0; + quad.bl.vertices.z = 0; + quad.br.vertices.z = 0; + for (int i = 0, n = skeleton->slotCount; i < n; i++) { + Slot* slot = skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->texture; + if (regionTextureAtlas != textureAtlas) { + if (textureAtlas) { + textureAtlas->drawQuads(); + textureAtlas->removeAllQuads(); + } + } + textureAtlas = regionTextureAtlas; + if (textureAtlas->getCapacity() == textureAtlas->getTotalQuads() && + !textureAtlas->resizeCapacity(textureAtlas->getCapacity() * 2)) return; + RegionAttachment_updateQuad(attachment, slot, &quad); + textureAtlas->updateQuad(&quad, textureAtlas->getTotalQuads()); + } + if (textureAtlas) { + textureAtlas->drawQuads(); + textureAtlas->removeAllQuads(); + } + + if (debugSlots) { + // Slots. + ccDrawColor4B(0, 0, 255, 255); + glLineWidth(1); + CCPoint points[4]; + ccV3F_C4B_T2F_Quad quad; + for (int i = 0, n = skeleton->slotCount; i < n; i++) { + Slot* slot = skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + RegionAttachment_updateQuad(attachment, slot, &quad); + points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y); + points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y); + points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y); + points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y); + ccDrawPoly(points, 4, true); + } + } + if (debugBones) { + // Bone lengths. + glLineWidth(2); + ccDrawColor4B(255, 0, 0, 255); + for (int i = 0, n = skeleton->boneCount; i < n; i++) { + Bone *bone = skeleton->bones[i]; + float x = bone->data->length * bone->m00 + bone->worldX; + float y = bone->data->length * bone->m10 + bone->worldY; + ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y)); + } + // Bone origins. + ccPointSize(4); + ccDrawColor4B(0, 0, 255, 255); // Root bone is blue. + for (int i = 0, n = skeleton->boneCount; i < n; i++) { + Bone *bone = skeleton->bones[i]; + ccDrawPoint(ccp(bone->worldX, bone->worldY)); + if (i == 0) ccDrawColor4B(0, 255, 0, 255); + } + } +} + +CCRect CCSkeleton::boundingBox () { + float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; + float scaleX = getScaleX(); + float scaleY = getScaleY(); + ccV3F_C4B_T2F_Quad quad; + for (int i = 0; i < skeleton->slotCount; ++i) { + Slot* slot = skeleton->slots[i]; + if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; + RegionAttachment* attachment = (RegionAttachment*)slot->attachment; + RegionAttachment_updateQuad(attachment, slot, &quad); + minX = min(minX, quad.bl.vertices.x * scaleX); + minY = min(minY, quad.bl.vertices.y * scaleY); + maxX = max(maxX, quad.bl.vertices.x * scaleX); + maxY = max(maxY, quad.bl.vertices.y * scaleY); + minX = min(minX, quad.br.vertices.x * scaleX); + minY = min(minY, quad.br.vertices.y * scaleY); + maxX = max(maxX, quad.br.vertices.x * scaleX); + maxY = max(maxY, quad.br.vertices.y * scaleY); + minX = min(minX, quad.tl.vertices.x * scaleX); + minY = min(minY, quad.tl.vertices.y * scaleY); + maxX = max(maxX, quad.tl.vertices.x * scaleX); + maxY = max(maxY, quad.tl.vertices.y * scaleY); + minX = min(minX, quad.tr.vertices.x * scaleX); + minY = min(minY, quad.tr.vertices.y * scaleY); + maxX = max(maxX, quad.tr.vertices.x * scaleX); + maxY = max(maxY, quad.tr.vertices.y * scaleY); + } + CCPoint position = getPosition(); + minX = position.x + minX; + minY = position.y + minY; + maxX = position.x + maxX; + maxY = position.y + maxY; + return CCRectMake(minX, minY, maxX - minX, maxY - minY); +} + +// CCBlendProtocol + +ccBlendFunc CCSkeleton::getBlendFunc () { + return blendFunc; +} + +void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) { + this->blendFunc = blendFunc; +} + +} diff --git a/spine-cocos2dx/src/spine/CCSkeleton.h b/spine-cocos2dx/src/spine/CCSkeleton.h new file mode 100644 index 000000000..c5373c33f --- /dev/null +++ b/spine-cocos2dx/src/spine/CCSkeleton.h @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef SPINE_CCSKELETON_H_ +#define SPINE_CCSKELETON_H_ + +#include +#include "cocos2d.h" + +namespace spine { + +/** +Draws a skeleton. +*/ +class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol { +public: + Skeleton* skeleton; + float timeScale; + bool debugSlots; + bool debugBones; + + static CCSkeleton* createWithData (SkeletonData* skeletonData); + static CCSkeleton* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1); + static CCSkeleton* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1); + + CCSkeleton (SkeletonData* skeletonData); + CCSkeleton (const char* skeletonDataFile, Atlas* atlas, float scale = 1); + CCSkeleton (const char* skeletonDataFile, const char* atlasFile, float scale = 1); + + virtual ~CCSkeleton (); + + virtual void update (float deltaTime); + virtual void draw (); + virtual cocos2d::CCRect boundingBox (); + + // CCBlendProtocol + CC_PROPERTY(cocos2d::ccBlendFunc, blendFunc, BlendFunc); + +private: + bool ownsSkeletonData; + Atlas* atlas; + void initialize (SkeletonData *skeletonData); +}; + +} + +#endif /* SPINE_CCSKELETON_H_ */ diff --git a/spine-cocos2dx/src/spine/CCSkeletonAnimation.cpp b/spine-cocos2dx/src/spine/CCSkeletonAnimation.cpp new file mode 100644 index 000000000..03012d7c5 --- /dev/null +++ b/spine-cocos2dx/src/spine/CCSkeletonAnimation.cpp @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#include +#include +#include + +USING_NS_CC; +using std::min; +using std::max; +using std::vector; + +namespace spine { + +static CCSkeletonAnimation* createWithData (SkeletonData* skeletonData) { + CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonData); + node->autorelease(); + return node; +} + +static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) { + CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonDataFile, atlas, scale); + node->autorelease(); + return node; +} + +static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) { + CCSkeletonAnimation* node = new CCSkeletonAnimation(skeletonDataFile, atlasFile, scale); + node->autorelease(); + return node; +} + +CCSkeletonAnimation::CCSkeletonAnimation (SkeletonData *skeletonData) + : CCSkeleton(skeletonData) { +} + +CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, Atlas* atlas, float scale) + : CCSkeleton(skeletonDataFile, atlas, scale) { +} + +CCSkeletonAnimation::CCSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale) + : CCSkeleton(skeletonDataFile, atlasFile, scale) { +} + +CCSkeletonAnimation::~CCSkeletonAnimation () { + for (std::vector::iterator iter = stateDatas.begin(); iter != stateDatas.end(); ++iter) + AnimationStateData_dispose(*iter); + + for (std::vector::iterator iter = states.begin(); iter != states.end(); ++iter) + AnimationState_dispose(*iter); +} + +void CCSkeletonAnimation::update (float deltaTime) { + super::update(deltaTime); + + deltaTime *= timeScale; + for (std::vector::iterator iter = states.begin(); iter != states.end(); ++iter) { + AnimationState_update(*iter, deltaTime); + AnimationState_apply(*iter, skeleton); + } + Skeleton_updateWorldTransform(skeleton); +} + +void CCSkeletonAnimation::addAnimationState (AnimationStateData* stateData) { + if (!stateData) { + stateData = AnimationStateData_create(skeleton->data); + stateDatas.push_back(stateData); + } + AnimationState* state = AnimationState_create(stateData); + states.push_back(state); +} + +void CCSkeletonAnimation::setAnimationStateData (AnimationStateData* stateData, int stateIndex) { + CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range."); + CCAssert(stateData, "stateData cannot be null."); + + AnimationState* state = states[stateIndex]; + for (std::vector::iterator iter = stateDatas.begin(); iter != stateDatas.end(); ++iter) { + if (state->data == *iter) { + AnimationStateData_dispose(state->data); + stateDatas.erase(iter); + break; + } + } + for (std::vector::iterator iter = states.begin(); iter != states.end(); ++iter) { + if (state == *iter) { + states.erase(iter); + break; + } + } + AnimationState_dispose(state); + + state = AnimationState_create(stateData); + states.push_back(state); +} + +void CCSkeletonAnimation::setMix (char* fromAnimation, char* toAnimation, float duration, int stateIndex) { + CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range."); + AnimationStateData_setMixByName(states[stateIndex]->data, fromAnimation, toAnimation, duration); +} + +void CCSkeletonAnimation::setAnimation (char* name, bool loop, int stateIndex) { + CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range."); + AnimationState_setAnimationByName(states[stateIndex], name, loop); +} + +void CCSkeletonAnimation::addAnimation (char* name, bool loop, float delay, int stateIndex) { + CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range."); + AnimationState_addAnimationByName(states[stateIndex], name, loop, delay); +} + +void CCSkeletonAnimation::clearAnimation (int stateIndex) { + CCAssert(stateIndex >= 0 && stateIndex < (int)states.size(), "stateIndex out of range."); + AnimationState_clearAnimation(states[stateIndex]); +} + +} diff --git a/spine-cocos2dx/src/spine/CCSkeletonAnimation.h b/spine-cocos2dx/src/spine/CCSkeletonAnimation.h new file mode 100644 index 000000000..fd468acac --- /dev/null +++ b/spine-cocos2dx/src/spine/CCSkeletonAnimation.h @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef SPINE_CCSKELETONANIMATION_H_ +#define SPINE_CCSKELETONANIMATION_H_ + +#include +#include +#include "cocos2d.h" + +namespace spine { + +/** +Draws an animated skeleton, providing a simple API for applying one or more animations and queuing animations to be played later. +*/ +class CCSkeletonAnimation: public CCSkeleton { +public: + std::vector states; + + static CCSkeletonAnimation* createWithData (SkeletonData* skeletonData); + static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1); + static CCSkeletonAnimation* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1); + + CCSkeletonAnimation (SkeletonData* skeletonData); + CCSkeletonAnimation (const char* skeletonDataFile, Atlas* atlas, float scale = 1); + CCSkeletonAnimation (const char* skeletonDataFile, const char* atlasFile, float scale = 1); + + virtual ~CCSkeletonAnimation (); + + virtual void update (float deltaTime); + + void addAnimationState (AnimationStateData* stateData = 0); + void setAnimationStateData (AnimationStateData* stateData, int stateIndex = 0); + void setMix (char* fromAnimation, char* toAnimation, float duration, int stateIndex = 0); + void setAnimation (char* name, bool loop, int stateIndex = 0); + void addAnimation (char* name, bool loop, float delay = 0, int stateIndex = 0); + void clearAnimation (int stateIndex = 0); + +private: + typedef CCSkeleton super; + std::vector stateDatas; + + void initialize (); +}; + +} + +#endif /* SPINE_CCSKELETONANIMATION_H_ */ diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp index 55b43ca4d..41098443a 100644 --- a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp +++ b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp @@ -27,8 +27,7 @@ #include USING_NS_CC; -using std::min; -using std::max; + namespace spine { void _AtlasPage_createTexture (AtlasPage* self, const char* path) { @@ -97,198 +96,4 @@ void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_ quad->br.texCoords.v = self->uvs[VERTEX_Y4]; } -/**/ - -CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale) { - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = scale; - SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile); - CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data."); - SkeletonJson_dispose(json); - CCSkeleton* node = skeletonData ? createWithData(skeletonData) : 0; - node->ownsSkeleton = true; - return node; -} - -CCSkeleton* CCSkeleton::createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale) { - Atlas* atlas = Atlas_readAtlasFile(atlasFile); - CCAssert(atlas, "Error reading atlas file."); - if (!atlas) return 0; - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = scale; - SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, skeletonDataFile); - CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data file."); - SkeletonJson_dispose(json); - if (!skeletonData) { - Atlas_dispose(atlas); - return 0; - } - CCSkeleton* node = createWithData(skeletonData); - node->ownsSkeleton = true; - node->atlas = atlas; - return node; -} - -CCSkeleton* CCSkeleton::createWithData (SkeletonData* skeletonData, AnimationStateData* stateData) { - CCSkeleton* node = new CCSkeleton(skeletonData, stateData); - node->autorelease(); - return node; -} - -CCSkeleton::CCSkeleton (SkeletonData *skeletonData, AnimationStateData *stateData) : - ownsSkeleton(false), ownsStateData(false), atlas(0), - skeleton(0), state(0), debugSlots(false), debugBones(false) { - CONST_CAST(Skeleton*, skeleton) = Skeleton_create(skeletonData); - - if (!stateData) { - stateData = AnimationStateData_create(skeletonData); - ownsStateData = true; - } - CONST_CAST(AnimationState*, state) = AnimationState_create(stateData); - - blendFunc.src = GL_ONE; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - - timeScale = 1; - - setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor)); - scheduleUpdate(); -} - -CCSkeleton::~CCSkeleton () { - if (ownsSkeleton) Skeleton_dispose(skeleton); - if (ownsStateData) AnimationStateData_dispose(state->data); - if (atlas) Atlas_dispose(atlas); - AnimationState_dispose(state); -} - -void CCSkeleton::update (float deltaTime) { - Skeleton_update(skeleton, deltaTime); - AnimationState_update(state, deltaTime * timeScale); - AnimationState_apply(state, skeleton); - Skeleton_updateWorldTransform(skeleton); -} - -void CCSkeleton::draw () { - CC_NODE_DRAW_SETUP(); - - ccGLBlendFunc(blendFunc.src, blendFunc.dst); - ccColor3B color = getColor(); - skeleton->r = color.r / (float)255; - skeleton->g = color.g / (float)255; - skeleton->b = color.b / (float)255; - skeleton->a = getOpacity() / (float)255; - - CCTextureAtlas* textureAtlas = 0; - ccV3F_C4B_T2F_Quad quad; - quad.tl.vertices.z = 0; - quad.tr.vertices.z = 0; - quad.bl.vertices.z = 0; - quad.br.vertices.z = 0; - for (int i = 0, n = skeleton->slotCount; i < n; i++) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->texture; - if (regionTextureAtlas != textureAtlas) { - if (textureAtlas) { - textureAtlas->drawQuads(); - textureAtlas->removeAllQuads(); - } - } - textureAtlas = regionTextureAtlas; - if (textureAtlas->getCapacity() == textureAtlas->getTotalQuads() && - !textureAtlas->resizeCapacity(textureAtlas->getCapacity() * 2)) return; - RegionAttachment_updateQuad(attachment, slot, &quad); - textureAtlas->updateQuad(&quad, textureAtlas->getTotalQuads()); - } - if (textureAtlas) { - textureAtlas->drawQuads(); - textureAtlas->removeAllQuads(); - } - - if (debugSlots) { - // Slots. - ccDrawColor4B(0, 0, 255, 255); - glLineWidth(1); - CCPoint points[4]; - ccV3F_C4B_T2F_Quad quad; - for (int i = 0, n = skeleton->slotCount; i < n; i++) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - RegionAttachment_updateQuad(attachment, slot, &quad); - points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y); - points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y); - points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y); - points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y); - ccDrawPoly(points, 4, true); - } - } - if (debugBones) { - // Bone lengths. - glLineWidth(2); - ccDrawColor4B(255, 0, 0, 255); - for (int i = 0, n = skeleton->boneCount; i < n; i++) { - Bone *bone = skeleton->bones[i]; - float x = bone->data->length * bone->m00 + bone->worldX; - float y = bone->data->length * bone->m10 + bone->worldY; - ccDrawLine(ccp(bone->worldX, bone->worldY), ccp(x, y)); - } - // Bone origins. - ccPointSize(4); - ccDrawColor4B(0, 0, 255, 255); // Root bone is blue. - for (int i = 0, n = skeleton->boneCount; i < n; i++) { - Bone *bone = skeleton->bones[i]; - ccDrawPoint(ccp(bone->worldX, bone->worldY)); - if (i == 0) ccDrawColor4B(0, 255, 0, 255); - } - } -} - -CCRect CCSkeleton::boundingBox () { - float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; - float scaleX = getScaleX(); - float scaleY = getScaleY(); - ccV3F_C4B_T2F_Quad quad; - for (int i = 0; i < skeleton->slotCount; ++i) { - Slot* slot = skeleton->slots[i]; - if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue; - RegionAttachment* attachment = (RegionAttachment*)slot->attachment; - RegionAttachment_updateQuad(attachment, slot, &quad); - minX = min(minX, quad.bl.vertices.x * scaleX); - minY = min(minY, quad.bl.vertices.y * scaleY); - maxX = max(maxX, quad.bl.vertices.x * scaleX); - maxY = max(maxY, quad.bl.vertices.y * scaleY); - minX = min(minX, quad.br.vertices.x * scaleX); - minY = min(minY, quad.br.vertices.y * scaleY); - maxX = max(maxX, quad.br.vertices.x * scaleX); - maxY = max(maxY, quad.br.vertices.y * scaleY); - minX = min(minX, quad.tl.vertices.x * scaleX); - minY = min(minY, quad.tl.vertices.y * scaleY); - maxX = max(maxX, quad.tl.vertices.x * scaleX); - maxY = max(maxY, quad.tl.vertices.y * scaleY); - minX = min(minX, quad.tr.vertices.x * scaleX); - minY = min(minY, quad.tr.vertices.y * scaleY); - maxX = max(maxX, quad.tr.vertices.x * scaleX); - maxY = max(maxY, quad.tr.vertices.y * scaleY); - } - CCPoint position = getPosition(); - minX = position.x + minX; - minY = position.y + minY; - maxX = position.x + maxX; - maxY = position.y + maxY; - return CCRectMake(minX, minY, maxX - minX, maxY - minY); -} - -// CCBlendProtocol - -ccBlendFunc CCSkeleton::getBlendFunc () { - return blendFunc; -} - -void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) { - this->blendFunc = blendFunc; -} - } diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.h b/spine-cocos2dx/src/spine/spine-cocos2dx.h index 8551640ad..cadf3ab03 100644 --- a/spine-cocos2dx/src/spine/spine-cocos2dx.h +++ b/spine-cocos2dx/src/spine/spine-cocos2dx.h @@ -28,39 +28,11 @@ #include #include "cocos2d.h" +#include +#include namespace spine { -class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol { -private: - bool ownsSkeleton; - bool ownsStateData; - Atlas* atlas; - -public: - Skeleton* const skeleton; - AnimationState* const state; - float timeScale; - bool debugSlots; - bool debugBones; - - static CCSkeleton* createWithFile (const char* skeletonDataFile, Atlas* atlas, float scale = 1); - static CCSkeleton* createWithFile (const char* skeletonDataFile, const char* atlasFile, float scale = 1); - static CCSkeleton* createWithData (SkeletonData* skeletonData, AnimationStateData* stateData = 0); - - CCSkeleton (SkeletonData* skeletonData, AnimationStateData* stateData = 0); - virtual ~CCSkeleton (); - - virtual void update (float deltaTime); - virtual void draw (); - virtual cocos2d::CCRect boundingBox (); - - // CCBlendProtocol - CC_PROPERTY(cocos2d::ccBlendFunc, blendFunc, BlendFunc); -}; - -/**/ - void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, cocos2d::ccV3F_C4B_T2F_Quad* quad); }