SpineObject.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _SPINE_OBJECT_H_
  23. #define _SPINE_OBJECT_H_
  24. #ifndef _FRAMEALLOCATOR_H_
  25. #include "memory/frameAllocator.h"
  26. #endif
  27. #ifndef _SPRITE_BATCH_H_
  28. #include "2d/core/SpriteBatch.h"
  29. #endif
  30. #ifndef _SCENE_OBJECT_H_
  31. #include "2d/sceneobject/SceneObject.h"
  32. #endif
  33. #ifndef _SPINE_ASSET_H_
  34. #include "2d/assets/SpineAsset.h"
  35. #endif
  36. #ifndef _SPINE_COLLISION_PROXY_H_
  37. #include "2d/sceneobject/SpineCollisionProxy.h"
  38. #endif
  39. //------------------------------------------------------------------------------
  40. // Spine events support
  41. static void spineAnimationEventCallbackHandler(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event);
  42. //------------------------------------------------------------------------------
  43. static const b2Transform B2_IDENTITY_TRANSFORM = b2Transform(b2Vec2(0.0f, 0.0f), b2Rot(0.0f));
  44. class SpineObject : public SceneObject, public SpriteBatch
  45. {
  46. protected:
  47. typedef SceneObject Parent;
  48. public:
  49. // Smart pointer support
  50. struct SkeletonDeleter { void operator()(spSkeleton* p) { spSkeleton_dispose(p); } };
  51. struct AnimationStateDeleter { void operator()(spAnimationState* p) { p->listener = NULL; spAnimationState_disposeStatics(); spAnimationState_dispose(p); } };
  52. struct SkeletonClippingDeleter { void operator()(spSkeletonClipping* p) { spSkeletonClipping_dispose(p); } };
  53. struct SkeletonBoundsDeleter { void operator()(spSkeletonBounds* p) { spSkeletonBounds_dispose(p); } };
  54. struct JitterVertexDeleter { void operator()(spJitterVertexEffect* p) { spJitterVertexEffect_dispose(p); } };
  55. struct SwirlVertexDeleter { void operator()(spSwirlVertexEffect* p) { spSwirlVertexEffect_dispose(p); } };
  56. using skeleton_ptr = unique_ptr<spSkeleton, SkeletonDeleter>;
  57. using animationState_ptr = unique_ptr<spAnimationState, AnimationStateDeleter>;
  58. using skeletonClipping_ptr = unique_ptr<spSkeletonClipping, SkeletonClippingDeleter>;
  59. using skeletonBounds_ptr = unique_ptr<spSkeletonBounds, SkeletonBoundsDeleter>;
  60. using jitterEffect_ptr = unique_ptr<spJitterVertexEffect, JitterVertexDeleter>;
  61. using swirlEffect_ptr = unique_ptr<spSwirlVertexEffect, SwirlVertexDeleter>;
  62. // Can't use smart pointers for this because HashTable calls delete on the value members in its destructor.
  63. using SpineCollisionProxyMapType = HashMap<spAttachment*, SpineCollisionProxy*>;
  64. enum VertexEffect {
  65. INVALID_VERTEX_EFFECT,
  66. NONE,
  67. JITTER,
  68. SWIRL
  69. };
  70. private:
  71. AssetPtr<SpineAsset> mSpineAsset; /* SpineObject holds instance data, SpineAsset holds template data. */
  72. skeleton_ptr mSkeleton;
  73. animationState_ptr mAnimationState;
  74. skeletonClipping_ptr mSkeletonClipping;
  75. skeletonBounds_ptr mSkeletonBounds;
  76. // Special vertex effects provided by Spine
  77. spVertexEffect *mVertexEffect; // Only one effect can be active at a time. This points to it. Null if none active.
  78. VertexEffect mActiveEffect;
  79. jitterEffect_ptr mJitterControl;
  80. swirlEffect_ptr mSwirlControl;
  81. F32 mPreTickTime;
  82. F32 mPostTickTime;
  83. F32 mLastFrameTime;
  84. bool mFlipX;
  85. bool mFlipY;
  86. // OOBB calculation support
  87. F32 mPriorRootBoneWorldX;
  88. F32 mPriorRootBoneWorldY;
  89. bool mPriorFlipX;
  90. bool mPriorFlipY;
  91. // Auto-Center support
  92. Vector2 mAutoCenterOffset;
  93. // Collision support
  94. SpineCollisionProxyMapType mCollisionProxies;
  95. public:
  96. SpineObject() { resetState(); };
  97. // Use CopyTo() if need to replicate.
  98. SpineObject(const SpineObject&) = delete;
  99. SpineObject& SpineObject::operator=(const SpineObject&) = delete;
  100. // Add 'move' support if/when needed.
  101. SpineObject(SpineObject&& other) = delete;
  102. SpineObject& SpineObject::operator=(SpineObject&&) = delete;
  103. virtual void copyTo(SimObject* object);
  104. bool setSpineAsset(const char* pSpineAssetId);
  105. inline StringTableEntry getSpineAsset(void) const { return mSpineAsset.getAssetId(); }
  106. // Render flipping.
  107. void setFlip(const bool flipX, const bool flipY);
  108. void setFlipX(const bool flipX) { setFlip(flipX, mFlipY); }
  109. void setFlipY(const bool flipY) { setFlip(mFlipX, flipY); }
  110. inline bool getFlipX(void) const { return mFlipX; }
  111. inline bool getFlipY(void) const { return mFlipY; }
  112. // Render special effects
  113. inline VertexEffect getActiveEffect(void) const { return mActiveEffect; }
  114. // -- Jitter
  115. void enableJitter(const F32 x, const F32 y);
  116. void disableJitter(void);
  117. // -- These can be used by script at run time to vary the effect.
  118. inline F32 getJitterX(void) const { return mJitterControl ? mJitterControl->jitterX : 0.0f; }
  119. inline void setJitterX(const F32 x) { if (mJitterControl) mJitterControl->jitterX = x; }
  120. inline F32 getJitterY(void) const { return mJitterControl ? mJitterControl->jitterY : 0.0f; }
  121. inline void setJitterY(const F32 y) { if (mJitterControl) mJitterControl->jitterY = y; }
  122. // -- Swirl
  123. void enableSwirl(const F32 radius);
  124. void disableSwirl(void);
  125. // -- These can be used by script at run time to vary the effect.
  126. inline F32 getSwirlX(void) const { return mSwirlControl ? mSwirlControl->centerX : 0.0f; }
  127. inline void setSwirlX(const F32 x) { if (mSwirlControl) mSwirlControl->centerX = x; }
  128. inline F32 getSwirlY(void) const { return mSwirlControl ? mSwirlControl->centerY : 0.0f; }
  129. inline void setSwirlY(const F32 y) { if (mSwirlControl) mSwirlControl->centerY = y; }
  130. inline F32 getSwirlRadius(void) const { return mSwirlControl ? mSwirlControl->radius : 0.0f; }
  131. inline void setSwirlRadius(const F32 r) { if (mSwirlControl) mSwirlControl->radius = r; }
  132. inline F32 getSwirlAngle(void) const { return mSwirlControl ? mSwirlControl->angle : 0.0f; }
  133. inline void setSwirlAngle(const F32 a) { if (mSwirlControl) mSwirlControl->angle = a; }
  134. // Appearance
  135. void setScale(const Vector2& scale);
  136. inline void setScale(const F32 x, const F32 y) { setScale(Vector2(x, y)); }
  137. inline Vector2 getScale(void) const { return mSkeleton ? Vector2(mSkeleton->scaleX, mSkeleton->scaleY) : Vector2(0.0f, 0.0f); }
  138. bool setSkin(const char* pSkin);
  139. inline StringTableEntry getSkinName(void) const;
  140. // Animation
  141. inline F32 setTimeScale(const F32 timeScale);
  142. inline F32 getTimeScale(void) const { return mAnimationState ? mAnimationState->timeScale : 0.0f; }
  143. bool setAnimation(const char* pName, const int track = 0, const bool shouldLoop = false, const F32 mixDuration = -1.0f);
  144. bool setEmptyAnimation(const int track = 0, const F32 mixDuration = 0.0f);
  145. bool queueAnimation(const char* pName, const int track = 0, const bool shouldLoop = false, const F32 mixDuration = -1.0f, const F32 delay = 0.0f);
  146. bool queueEmptyAnimation(const int track = 0, const F32 mixDuration = 0.0f, const F32 delay = 0.0f);
  147. void clearAnimations(const int track, const bool mixToSetupPose = false, const F32 mixDuration = 0.0f);
  148. void clearAllAnimations(const bool mixToSetupPose = false, const F32 mixDuration = 0.0f);
  149. StringTableEntry getAnimationName(const int track = 0) const;
  150. bool getIsLooping(const int track = 0) const;
  151. bool setMix(const char* pFromName, const char* pToName, const F32 mixDuration);
  152. // Events
  153. void SpineObject::enableEventCallbacks(void);
  154. void SpineObject::disableEventCallbacks(void);
  155. // Collision Support
  156. const SpineCollisionProxy* getCollisionProxy(
  157. const char* anAttachmentName,
  158. const char* aSlotName,
  159. const char* aSkinName = "default",
  160. const F32 sizerWidth = 1.0f,
  161. const F32 sizerHeight = 1.0f,
  162. const char* objectName = NULL);
  163. bool deleteCollisionProxy(const char *proxyId);
  164. // This needs to be available to the Console for use during object instantiation.
  165. static void initPersistFields();
  166. /// Declare Console Object.
  167. DECLARE_CONOBJECT(SpineObject);
  168. protected:
  169. // Render suport
  170. void updateSpine(const F32 time);
  171. void prepareSpineForRender();
  172. void calculateSpineOOBB(const vector<Vector2> pointSoup);
  173. virtual void preIntegrate(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats);
  174. virtual void interpolateObject(const F32 timeDelta);
  175. virtual bool canPrepareRender(void) const { return true; }
  176. virtual bool validRender(void) const { return mSpineAsset.notNull(); }
  177. virtual bool shouldRender(void) const { return true; }
  178. virtual void scenePrepareRender(const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue);
  179. virtual void sceneRender(const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer);
  180. // Render special effects - support
  181. // Set indirectly via enable methods. However, need this to support TAML reading of object.
  182. void setActiveEffect(const VertexEffect e);
  183. static VertexEffect getVertexEffectTypeEnum(const char* label);
  184. static const char* getVertexEffectTypeDescription(const VertexEffect vertexEffectType);
  185. // Internal management
  186. void SpineObject::resetState();
  187. virtual void OnRegisterScene(Scene *scene);
  188. virtual void OnUnregisterScene(Scene *scene);
  189. private:
  190. // Utility
  191. // Cope with spine reflecting about an axis to accomplish a flip, while the SceneObject doesn't support such flipping.
  192. inline F32 setPerFlipState(const F32 value) { return mFlipY ? (mFlipX ? value : -value) : (mFlipX ? -value : value); }
  193. // Object Persistence Support
  194. //
  195. // This determines if there is any animation data to write and returns true if there is.
  196. bool writeAnimationData(void) const;
  197. bool writeCollisionData(void) const;
  198. // This encodes and returns the information required to restart the currently running animations. It is returned
  199. // in a string for writing to the TAML file.
  200. const char *getAnimationData(void) const;
  201. // This encodes and returns the information required to recreate the Spine object's collision boxes.
  202. const char *getCollisionData(void) const;
  203. // This attempts to start the animation(s) defined in the animation data string passed in.
  204. void setAnimationData(const char *animationData);
  205. // This attempts to create the collision boxes defined in the data passed in.
  206. void setCollisionData(const char *collisionData);
  207. protected:
  208. static bool setSpineAsset(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSpineAsset(data); return false; }
  209. static bool writeSpineAsset(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->mSpineAsset.notNull(); }
  210. static bool setAnimationData(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setAnimationData(data); return false; }
  211. static const char* getAnimationData(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getAnimationData(); }
  212. static bool writeAnimationData(void*obj, const char* data) { return static_cast<SpineObject*>(obj)->writeAnimationData(); }
  213. static bool setCollisionData(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setCollisionData(data); return false; }
  214. static const char* getCollisionData(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getCollisionData(); }
  215. static bool writeCollisionData(void*obj, const char* data) { return static_cast<SpineObject*>(obj)->writeCollisionData(); }
  216. static bool setSkin(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSkin(data); return false; }
  217. static const char* getSkinName(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getSkinName(); }
  218. static bool writeCurrentSkin(void*obj, StringTableEntry pSkin) { return true; }
  219. static bool setScale(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setScale(Vector2(data)); return false; }
  220. static const char* getScale(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getScale().scriptThis(); }
  221. static bool writeScale(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getScale().notZero(); }
  222. static bool setFlipX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setFlipX(dAtob(data)); return false; }
  223. static bool writeFlipX(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getFlipX() == true; }
  224. static bool setFlipY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setFlipY(dAtob(data)); return false; }
  225. static bool writeFlipY(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getFlipY() == true; }
  226. static bool setTimeScale(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setTimeScale(dAtof(data)); return false; }
  227. static const char* getTimeScale(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getTimeScale()); }
  228. static bool writeTimeScale(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getTimeScale() != 1.0f; }
  229. static bool setActiveEffectType(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setActiveEffect(getVertexEffectTypeEnum(data)); return false; }
  230. static bool writeActiveEffectType(void* obj, StringTableEntry pFieldName) { VertexEffect ve = static_cast<SpineObject*>(obj)->getActiveEffect(); return ve != NONE && ve != INVALID_VERTEX_EFFECT; }
  231. static bool setJitterX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setJitterX(dAtof(data)); return false; }
  232. static const char* getJitterX(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getJitterX()); }
  233. static bool setJitterY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setJitterY(dAtof(data)); return false; }
  234. static const char* getJitterY(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getJitterY()); }
  235. static bool writeJitterEffectValues(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getActiveEffect() == VertexEffect::JITTER; }
  236. static bool setSwirlX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlX(dAtof(data)); return false; }
  237. static const char* getSwirlX(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlX()); }
  238. static bool setSwirlY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlY(dAtof(data)); return false; }
  239. static const char* getSwirlY(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlY()); }
  240. static bool setSwirlRadius(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlRadius(dAtof(data)); return false; }
  241. static const char* getSwirlRadius(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlRadius()); }
  242. static bool setSwirlAngle(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlAngle(dAtof(data)); return false; }
  243. static const char* getSwirlAngle(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlAngle()); }
  244. static bool writeSwirlEffectValues(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getActiveEffect() == VertexEffect::SWIRL; }
  245. static bool setEventCallbacksEnabled(void* obj, const char* data) { if (dAtob(data)) { static_cast<SpineObject*>(obj)->enableEventCallbacks(); } else { static_cast<SpineObject*>(obj)->disableEventCallbacks(); } return false; }
  246. static bool writeEventCallbacksEnabled(void* obj, StringTableEntry pFieldName) { SpineObject *me = static_cast<SpineObject*>(obj); return me->mAnimationState && me->mAnimationState->listener; }
  247. };
  248. #endif // _SPINE_OBJECT_H_