AnimatedSprite2D.cpp 16 KB

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