AnimatedSprite2D.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. //
  2. // Copyright (c) 2008-2016 the Urho3D project.
  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 deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // 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 FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../IO/Log.h"
  25. #include "../Resource/ResourceCache.h"
  26. #include "../Scene/Scene.h"
  27. #include "../Scene/SceneEvents.h"
  28. #include "../Atomic2D/AnimatedSprite2D.h"
  29. #include "../Atomic2D/AnimationSet2D.h"
  30. #include "../Atomic2D/Sprite2D.h"
  31. #include "../Atomic2D/SpriterInstance2D.h"
  32. #include "../DebugNew.h"
  33. #ifdef ATOMIC_SPINE
  34. #include <spine/spine.h>
  35. #endif
  36. namespace Atomic
  37. {
  38. extern const char* ATOMIC2D_CATEGORY;
  39. extern const char* blendModeNames[];
  40. const char* loopModeNames[] =
  41. {
  42. "Default",
  43. "ForceLooped",
  44. "ForceClamped",
  45. 0
  46. };
  47. AnimatedSprite2D::AnimatedSprite2D(Context* context) :
  48. StaticSprite2D(context),
  49. #ifdef ATOMIC_SPINE
  50. skeleton_(0),
  51. animationStateData_(0),
  52. animationState_(0),
  53. #endif
  54. spriterInstance_(0),
  55. speed_(1.0f),
  56. loopMode_(LM_DEFAULT)
  57. {
  58. }
  59. AnimatedSprite2D::~AnimatedSprite2D()
  60. {
  61. Dispose();
  62. }
  63. void AnimatedSprite2D::RegisterObject(Context* context)
  64. {
  65. context->RegisterFactory<AnimatedSprite2D>(ATOMIC2D_CATEGORY);
  66. ATOMIC_COPY_BASE_ATTRIBUTES(StaticSprite2D);
  67. ATOMIC_REMOVE_ATTRIBUTE("Sprite");
  68. ATOMIC_ACCESSOR_ATTRIBUTE("Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
  69. ATOMIC_ACCESSOR_ATTRIBUTE("Entity", GetEntity, SetEntity, String, String::EMPTY, AM_DEFAULT);
  70. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Animation Set", GetAnimationSetAttr, SetAnimationSetAttr, ResourceRef,
  71. ResourceRef(AnimatedSprite2D::GetTypeStatic()), AM_DEFAULT);
  72. ATOMIC_ACCESSOR_ATTRIBUTE("Animation", GetAnimation, SetAnimationAttr, String, String::EMPTY, AM_DEFAULT);
  73. ATOMIC_ENUM_ACCESSOR_ATTRIBUTE("Loop Mode", GetLoopMode, SetLoopMode, LoopMode2D, loopModeNames, LM_DEFAULT, AM_DEFAULT);
  74. }
  75. void AnimatedSprite2D::OnSetEnabled()
  76. {
  77. StaticSprite2D::OnSetEnabled();
  78. bool enabled = IsEnabledEffective();
  79. Scene* scene = GetScene();
  80. if (scene)
  81. {
  82. if (enabled)
  83. SubscribeToEvent(scene, E_SCENEPOSTUPDATE, ATOMIC_HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
  84. else
  85. UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
  86. }
  87. }
  88. void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
  89. {
  90. if (animationSet == animationSet_)
  91. return;
  92. Dispose();
  93. animationSet_ = animationSet;
  94. if (!animationSet_)
  95. return;
  96. SetSprite(animationSet_->GetSprite());
  97. #ifdef ATOMIC_SPINE
  98. if (animationSet_->GetSkeletonData())
  99. {
  100. spSkeletonData* skeletonData = animationSet->GetSkeletonData();
  101. // Create skeleton
  102. skeleton_ = spSkeleton_create(skeletonData);
  103. skeleton_->flipX = flipX_;
  104. skeleton_->flipY = flipY_;
  105. if (skeleton_->data->skinsCount > 0)
  106. {
  107. // If entity is empty use first skin in spine
  108. if (entity_.Empty())
  109. entity_ = skeleton_->data->skins[0]->name;
  110. spSkeleton_setSkinByName(skeleton_, entity_.CString());
  111. }
  112. spSkeleton_updateWorldTransform(skeleton_);
  113. }
  114. #endif
  115. if (animationSet_->GetSpriterData())
  116. {
  117. spriterInstance_ = new Spriter::SpriterInstance(this, animationSet_->GetSpriterData());
  118. if (!animationSet_->GetSpriterData()->entities_.Empty())
  119. {
  120. // If entity is empty use first entity in spriter
  121. if (entity_.Empty())
  122. entity_ = animationSet_->GetSpriterData()->entities_[0]->name_;
  123. spriterInstance_->SetEntity(entity_);
  124. }
  125. }
  126. // Clear animation name
  127. animationName_.Clear();
  128. loopMode_ = LM_DEFAULT;
  129. }
  130. void AnimatedSprite2D::SetEntity(const String& entity)
  131. {
  132. if (entity == entity_)
  133. return;
  134. entity_ = entity;
  135. #ifdef ATOMIC_SPINE
  136. if (skeleton_)
  137. spSkeleton_setSkinByName(skeleton_, entity_.CString());
  138. #endif
  139. if (spriterInstance_)
  140. spriterInstance_->SetEntity(entity_.CString());
  141. }
  142. void AnimatedSprite2D::SetAnimation(const String& name, LoopMode2D loopMode)
  143. {
  144. animationName_ = name;
  145. loopMode_ = loopMode;
  146. if (!animationSet_ || !animationSet_->HasAnimation(animationName_))
  147. return;
  148. #ifdef ATOMIC_SPINE
  149. if (skeleton_)
  150. SetSpineAnimation();
  151. #endif
  152. if (spriterInstance_)
  153. SetSpriterAnimation();
  154. }
  155. void AnimatedSprite2D::SetLoopMode(LoopMode2D loopMode)
  156. {
  157. loopMode_ = loopMode;
  158. }
  159. void AnimatedSprite2D::SetSpeed(float speed)
  160. {
  161. speed_ = speed;
  162. MarkNetworkUpdate();
  163. }
  164. AnimationSet2D* AnimatedSprite2D::GetAnimationSet() const
  165. {
  166. return animationSet_;
  167. }
  168. void AnimatedSprite2D::SetAnimationSetAttr(const ResourceRef& value)
  169. {
  170. ResourceCache* cache = GetSubsystem<ResourceCache>();
  171. SetAnimationSet(cache->GetResource<AnimationSet2D>(value.name_));
  172. }
  173. ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
  174. {
  175. return GetResourceRef(animationSet_, AnimationSet2D::GetTypeStatic());
  176. }
  177. void AnimatedSprite2D::OnSceneSet(Scene* scene)
  178. {
  179. StaticSprite2D::OnSceneSet(scene);
  180. if (scene)
  181. {
  182. if (scene == node_)
  183. ATOMIC_LOGWARNING(GetTypeName() + " should not be created to the root scene node");
  184. if (IsEnabledEffective())
  185. SubscribeToEvent(scene, E_SCENEPOSTUPDATE, ATOMIC_HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
  186. }
  187. else
  188. UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
  189. }
  190. void AnimatedSprite2D::SetAnimationAttr(const String& name)
  191. {
  192. animationName_ = name;
  193. SetAnimation(animationName_, loopMode_);
  194. }
  195. void AnimatedSprite2D::UpdateSourceBatches()
  196. {
  197. #ifdef ATOMIC_SPINE
  198. if (skeleton_ && animationState_)
  199. UpdateSourceBatchesSpine();
  200. #endif
  201. if (spriterInstance_ && spriterInstance_->GetAnimation())
  202. UpdateSourceBatchesSpriter();
  203. sourceBatchesDirty_ = false;
  204. }
  205. void AnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
  206. {
  207. using namespace ScenePostUpdate;
  208. float timeStep = eventData[P_TIMESTEP].GetFloat();
  209. UpdateAnimation(timeStep);
  210. }
  211. void AnimatedSprite2D::UpdateAnimation(float timeStep)
  212. {
  213. #ifdef ATOMIC_SPINE
  214. if (skeleton_ && animationState_)
  215. UpdateSpineAnimation(timeStep);
  216. #endif
  217. if (spriterInstance_ && spriterInstance_->GetAnimation())
  218. UpdateSpriterAnimation(timeStep);
  219. }
  220. #ifdef ATOMIC_SPINE
  221. void AnimatedSprite2D::SetSpineAnimation()
  222. {
  223. if (!animationStateData_)
  224. {
  225. animationStateData_ = spAnimationStateData_create(animationSet_->GetSkeletonData());
  226. if (!animationStateData_)
  227. {
  228. ATOMIC_LOGERROR("Create animation state data failed");
  229. return;
  230. }
  231. }
  232. if (!animationState_)
  233. {
  234. animationState_ = spAnimationState_create(animationStateData_);
  235. if (!animationState_)
  236. {
  237. ATOMIC_LOGERROR("Create animation state failed");
  238. return;
  239. }
  240. }
  241. // Reset slots to setup pose, fix issue #932
  242. spSkeleton_setSlotsToSetupPose(skeleton_);
  243. spAnimationState_setAnimationByName(animationState_, 0, animationName_.CString(), loopMode_ != LM_FORCE_CLAMPED ? true : false);
  244. UpdateAnimation(0.0f);
  245. MarkNetworkUpdate();
  246. }
  247. void AnimatedSprite2D::UpdateSpineAnimation(float timeStep)
  248. {
  249. timeStep *= speed_;
  250. skeleton_->flipX = flipX_;
  251. skeleton_->flipY = flipY_;
  252. spSkeleton_update(skeleton_, timeStep);
  253. spAnimationState_update(animationState_, timeStep);
  254. spAnimationState_apply(animationState_, skeleton_);
  255. spSkeleton_updateWorldTransform(skeleton_);
  256. sourceBatchesDirty_ = true;
  257. worldBoundingBoxDirty_ = true;
  258. }
  259. void AnimatedSprite2D::UpdateSourceBatchesSpine()
  260. {
  261. const Matrix3x4& worldTransform = GetNode()->GetWorldTransform();
  262. SourceBatch2D& sourceBatch = sourceBatches_[0];
  263. sourceBatches_[0].vertices_.Clear();
  264. const int SLOT_VERTEX_COUNT_MAX = 1024;
  265. float slotVertices[SLOT_VERTEX_COUNT_MAX];
  266. for (int i = 0; i < skeleton_->slotsCount; ++i)
  267. {
  268. spSlot* slot = skeleton_->drawOrder[i];
  269. spAttachment* attachment = slot->attachment;
  270. if (!attachment)
  271. continue;
  272. unsigned color = Color(color_.r_ * slot->r,
  273. color_.g_ * slot->g,
  274. color_.b_ * slot->b,
  275. color_.a_ * slot->a).ToUInt();
  276. if (attachment->type == SP_ATTACHMENT_REGION)
  277. {
  278. spRegionAttachment* region = (spRegionAttachment*)attachment;
  279. spRegionAttachment_computeWorldVertices(region, slot->bone, slotVertices);
  280. Vertex2D vertices[4];
  281. vertices[0].position_ = worldTransform * Vector3(slotVertices[SP_VERTEX_X1], slotVertices[SP_VERTEX_Y1]);
  282. vertices[1].position_ = worldTransform * Vector3(slotVertices[SP_VERTEX_X2], slotVertices[SP_VERTEX_Y2]);
  283. vertices[2].position_ = worldTransform * Vector3(slotVertices[SP_VERTEX_X3], slotVertices[SP_VERTEX_Y3]);
  284. vertices[3].position_ = worldTransform * Vector3(slotVertices[SP_VERTEX_X4], slotVertices[SP_VERTEX_Y4]);
  285. vertices[0].color_ = color;
  286. vertices[1].color_ = color;
  287. vertices[2].color_ = color;
  288. vertices[3].color_ = color;
  289. vertices[0].uv_ = Vector2(region->uvs[SP_VERTEX_X1], region->uvs[SP_VERTEX_Y1]);
  290. vertices[1].uv_ = Vector2(region->uvs[SP_VERTEX_X2], region->uvs[SP_VERTEX_Y2]);
  291. vertices[2].uv_ = Vector2(region->uvs[SP_VERTEX_X3], region->uvs[SP_VERTEX_Y3]);
  292. vertices[3].uv_ = Vector2(region->uvs[SP_VERTEX_X4], region->uvs[SP_VERTEX_Y4]);
  293. sourceBatches_[0].vertices_.Push(vertices[0]);
  294. sourceBatches_[0].vertices_.Push(vertices[1]);
  295. sourceBatches_[0].vertices_.Push(vertices[2]);
  296. sourceBatches_[0].vertices_.Push(vertices[3]);
  297. }
  298. else if (attachment->type == SP_ATTACHMENT_MESH)
  299. {
  300. spMeshAttachment* mesh = (spMeshAttachment*)attachment;
  301. if (mesh->verticesCount > SLOT_VERTEX_COUNT_MAX)
  302. continue;
  303. spMeshAttachment_computeWorldVertices(mesh, slot, slotVertices);
  304. Vertex2D vertex;
  305. vertex.color_ = color;
  306. for (int j = 0; j < mesh->trianglesCount; ++j)
  307. {
  308. int index = mesh->triangles[j] << 1;
  309. vertex.position_ = worldTransform * Vector3(slotVertices[index], slotVertices[index + 1]);
  310. vertex.uv_ = Vector2(mesh->uvs[index], mesh->uvs[index + 1]);
  311. sourceBatches_[0].vertices_.Push(vertex);
  312. // Add padding vertex
  313. if (j % 3 == 2)
  314. sourceBatches_[0].vertices_.Push(vertex);
  315. }
  316. }
  317. else if (attachment->type == SP_ATTACHMENT_SKINNED_MESH)
  318. {
  319. spSkinnedMeshAttachment* skinnedMesh = (spSkinnedMeshAttachment*)attachment;
  320. if (skinnedMesh->uvsCount > SLOT_VERTEX_COUNT_MAX)
  321. continue;
  322. spSkinnedMeshAttachment_computeWorldVertices(skinnedMesh, slot, slotVertices);
  323. Vertex2D vertex;
  324. vertex.color_ = color;
  325. for (int j = 0; j < skinnedMesh->trianglesCount; ++j)
  326. {
  327. int index = skinnedMesh->triangles[j] << 1;
  328. vertex.position_ = worldTransform * Vector3(slotVertices[index], slotVertices[index + 1]);
  329. vertex.uv_ = Vector2(skinnedMesh->uvs[index], skinnedMesh->uvs[index + 1]);
  330. sourceBatches_[0].vertices_.Push(vertex);
  331. // Add padding vertex
  332. if (j % 3 == 2)
  333. sourceBatches_[0].vertices_.Push(vertex);
  334. }
  335. }
  336. }
  337. }
  338. #endif
  339. void AnimatedSprite2D::SetSpriterAnimation()
  340. {
  341. if (!spriterInstance_)
  342. spriterInstance_ = new Spriter::SpriterInstance(this, animationSet_->GetSpriterData());
  343. // Use entity is empty first entity
  344. if (entity_.Empty())
  345. entity_ = animationSet_->GetSpriterData()->entities_[0]->name_;
  346. if (!spriterInstance_->SetEntity(entity_.CString()))
  347. {
  348. ATOMIC_LOGERROR("Set entity failed");
  349. return;
  350. }
  351. if (!spriterInstance_->SetAnimation(animationName_.CString(), (Spriter::LoopMode)loopMode_))
  352. {
  353. ATOMIC_LOGERROR("Set animation failed");
  354. return;
  355. }
  356. UpdateAnimation(0.0f);
  357. MarkNetworkUpdate();
  358. }
  359. void AnimatedSprite2D::UpdateSpriterAnimation(float timeStep)
  360. {
  361. spriterInstance_->Update(timeStep * speed_);
  362. sourceBatchesDirty_ = true;
  363. worldBoundingBoxDirty_ = true;
  364. }
  365. void AnimatedSprite2D::UpdateSourceBatchesSpriter()
  366. {
  367. const Matrix3x4& nodeWorldTransform = GetNode()->GetWorldTransform();
  368. Vector<Vertex2D>& vertices = sourceBatches_[0].vertices_;
  369. vertices.Clear();
  370. Rect drawRect;
  371. Rect textureRect;
  372. unsigned color = color_.ToUInt();
  373. Vertex2D vertex0;
  374. Vertex2D vertex1;
  375. Vertex2D vertex2;
  376. Vertex2D vertex3;
  377. const PODVector<Spriter::SpatialTimelineKey*>& timelineKeys = spriterInstance_->GetTimelineKeys();
  378. for (size_t i = 0; i < timelineKeys.Size(); ++i)
  379. {
  380. if (timelineKeys[i]->GetObjectType() != Spriter::SPRITE)
  381. continue;
  382. Spriter::SpriteTimelineKey* timelineKey = (Spriter::SpriteTimelineKey*)timelineKeys[i];
  383. Spriter::SpatialInfo& info = timelineKey->info_;
  384. Vector3 position(info.x_, info.y_, 0.0f);
  385. if (flipX_)
  386. position.x_ = -position.x_;
  387. if (flipY_)
  388. position.y_ = -position.y_;
  389. float angle = info.angle_;
  390. if (flipX_ != flipY_)
  391. angle = -angle;
  392. Matrix3x4 localTransform(position * PIXEL_SIZE,
  393. Quaternion(angle),
  394. Vector3(info.scaleX_, info.scaleY_, 1.0f));
  395. Matrix3x4 worldTransform = nodeWorldTransform * localTransform;
  396. Sprite2D* sprite = animationSet_->GetSpriterFileSprite(timelineKey->folderId_, timelineKey->fileId_);
  397. if (!sprite)
  398. return;
  399. if (timelineKey->useDefaultPivot_)
  400. sprite->GetDrawRectangle(drawRect, flipX_, flipY_);
  401. else
  402. sprite->GetDrawRectangle(drawRect, Vector2(timelineKey->pivotX_, timelineKey->pivotY_), flipX_, flipY_);
  403. if (!sprite->GetTextureRectangle(textureRect, flipX_, flipY_))
  404. return;
  405. vertex0.position_ = worldTransform * Vector3(drawRect.min_.x_, drawRect.min_.y_, 0.0f);
  406. vertex1.position_ = worldTransform * Vector3(drawRect.min_.x_, drawRect.max_.y_, 0.0f);
  407. vertex2.position_ = worldTransform * Vector3(drawRect.max_.x_, drawRect.max_.y_, 0.0f);
  408. vertex3.position_ = worldTransform * Vector3(drawRect.max_.x_, drawRect.min_.y_, 0.0f);
  409. vertex0.uv_ = textureRect.min_;
  410. vertex1.uv_ = Vector2(textureRect.min_.x_, textureRect.max_.y_);
  411. vertex2.uv_ = textureRect.max_;
  412. vertex3.uv_ = Vector2(textureRect.max_.x_, textureRect.min_.y_);
  413. vertex0.color_ = vertex1.color_ = vertex2.color_ = vertex3.color_ = color;
  414. vertices.Push(vertex0);
  415. vertices.Push(vertex1);
  416. vertices.Push(vertex2);
  417. vertices.Push(vertex3);
  418. }
  419. }
  420. void AnimatedSprite2D::Dispose()
  421. {
  422. #ifdef ATOMIC_SPINE
  423. if (animationState_)
  424. {
  425. spAnimationState_dispose(animationState_);
  426. animationState_ = 0;
  427. }
  428. if (animationStateData_)
  429. {
  430. spAnimationStateData_dispose(animationStateData_);
  431. animationStateData_ = 0;
  432. }
  433. if (skeleton_)
  434. {
  435. spSkeleton_dispose(skeleton_);
  436. skeleton_ = 0;
  437. }
  438. #endif
  439. if (spriterInstance_)
  440. {
  441. delete spriterInstance_;
  442. spriterInstance_ = 0;
  443. }
  444. }
  445. }