Skeleton.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /******************************************************************************
  2. * Spine Runtimes Software License v2.5
  3. *
  4. * Copyright (c) 2013-2016, Esoteric Software
  5. * All rights reserved.
  6. *
  7. * You are granted a perpetual, non-exclusive, non-sublicensable, and
  8. * non-transferable license to use, install, execute, and perform the Spine
  9. * Runtimes software and derivative works solely for personal or internal
  10. * use. Without the written permission of Esoteric Software (see Section 2 of
  11. * the Spine Software License Agreement), you may not (a) modify, translate,
  12. * adapt, or develop new applications using the Spine Runtimes or otherwise
  13. * create derivative works or improvements of the Spine Runtimes or (b) remove,
  14. * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
  15. * or other intellectual property or proprietary rights notices on or in the
  16. * Software, including any copy thereof. Redistributions in binary or source
  17. * form must include this license and terms.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  22. * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
  25. * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *****************************************************************************/
  30. #include <spine/Skeleton.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <spine/extension.h>
  34. typedef enum {
  35. SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_PATH_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT
  36. } _spUpdateType;
  37. typedef struct {
  38. _spUpdateType type;
  39. void* object;
  40. } _spUpdate;
  41. typedef struct {
  42. spSkeleton super;
  43. int updateCacheCount;
  44. int updateCacheCapacity;
  45. _spUpdate* updateCache;
  46. int updateCacheResetCount;
  47. int updateCacheResetCapacity;
  48. spBone** updateCacheReset;
  49. } _spSkeleton;
  50. spSkeleton* spSkeleton_create (spSkeletonData* data) {
  51. int i;
  52. int* childrenCounts;
  53. _spSkeleton* internal = NEW(_spSkeleton);
  54. spSkeleton* self = SUPER(internal);
  55. CONST_CAST(spSkeletonData*, self->data) = data;
  56. self->bonesCount = self->data->bonesCount;
  57. self->bones = MALLOC(spBone*, self->bonesCount);
  58. childrenCounts = CALLOC(int, self->bonesCount);
  59. for (i = 0; i < self->bonesCount; ++i) {
  60. spBoneData* boneData = self->data->bones[i];
  61. spBone* newBone;
  62. if (!boneData->parent)
  63. newBone = spBone_create(boneData, self, 0);
  64. else {
  65. spBone* parent = self->bones[boneData->parent->index];
  66. newBone = spBone_create(boneData, self, parent);
  67. ++childrenCounts[boneData->parent->index];
  68. }
  69. self->bones[i] = newBone;
  70. }
  71. for (i = 0; i < self->bonesCount; ++i) {
  72. spBoneData* boneData = self->data->bones[i];
  73. spBone* bone = self->bones[i];
  74. CONST_CAST(spBone**, bone->children) = MALLOC(spBone*, childrenCounts[boneData->index]);
  75. }
  76. for (i = 0; i < self->bonesCount; ++i) {
  77. spBone* bone = self->bones[i];
  78. spBone* parent = bone->parent;
  79. if (parent)
  80. parent->children[parent->childrenCount++] = bone;
  81. }
  82. CONST_CAST(spBone*, self->root) = (self->bonesCount > 0 ? self->bones[0] : NULL);
  83. self->slotsCount = data->slotsCount;
  84. self->slots = MALLOC(spSlot*, self->slotsCount);
  85. for (i = 0; i < self->slotsCount; ++i) {
  86. spSlotData *slotData = data->slots[i];
  87. spBone* bone = self->bones[slotData->boneData->index];
  88. self->slots[i] = spSlot_create(slotData, bone);
  89. }
  90. self->drawOrder = MALLOC(spSlot*, self->slotsCount);
  91. memcpy(self->drawOrder, self->slots, sizeof(spSlot*) * self->slotsCount);
  92. self->ikConstraintsCount = data->ikConstraintsCount;
  93. self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount);
  94. for (i = 0; i < self->data->ikConstraintsCount; ++i)
  95. self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self);
  96. self->transformConstraintsCount = data->transformConstraintsCount;
  97. self->transformConstraints = MALLOC(spTransformConstraint*, self->transformConstraintsCount);
  98. for (i = 0; i < self->data->transformConstraintsCount; ++i)
  99. self->transformConstraints[i] = spTransformConstraint_create(self->data->transformConstraints[i], self);
  100. self->pathConstraintsCount = data->pathConstraintsCount;
  101. self->pathConstraints = MALLOC(spPathConstraint*, self->pathConstraintsCount);
  102. for (i = 0; i < self->data->pathConstraintsCount; i++)
  103. self->pathConstraints[i] = spPathConstraint_create(self->data->pathConstraints[i], self);
  104. self->r = 1; self->g = 1; self->b = 1; self->a = 1;
  105. spSkeleton_updateCache(self);
  106. FREE(childrenCounts);
  107. return self;
  108. }
  109. void spSkeleton_dispose (spSkeleton* self) {
  110. int i;
  111. _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
  112. FREE(internal->updateCache);
  113. FREE(internal->updateCacheReset);
  114. for (i = 0; i < self->bonesCount; ++i)
  115. spBone_dispose(self->bones[i]);
  116. FREE(self->bones);
  117. for (i = 0; i < self->slotsCount; ++i)
  118. spSlot_dispose(self->slots[i]);
  119. FREE(self->slots);
  120. for (i = 0; i < self->ikConstraintsCount; ++i)
  121. spIkConstraint_dispose(self->ikConstraints[i]);
  122. FREE(self->ikConstraints);
  123. for (i = 0; i < self->transformConstraintsCount; ++i)
  124. spTransformConstraint_dispose(self->transformConstraints[i]);
  125. FREE(self->transformConstraints);
  126. for (i = 0; i < self->pathConstraintsCount; i++)
  127. spPathConstraint_dispose(self->pathConstraints[i]);
  128. FREE(self->pathConstraints);
  129. FREE(self->drawOrder);
  130. FREE(self);
  131. }
  132. static void _addToUpdateCache(_spSkeleton* const internal, _spUpdateType type, void *object) {
  133. _spUpdate* update;
  134. if (internal->updateCacheCount == internal->updateCacheCapacity) {
  135. internal->updateCacheCapacity *= 2;
  136. internal->updateCache = realloc(internal->updateCache, sizeof(_spUpdate) * internal->updateCacheCapacity);
  137. }
  138. update = internal->updateCache + internal->updateCacheCount;
  139. update->type = type;
  140. update->object = object;
  141. ++internal->updateCacheCount;
  142. }
  143. static void _addToUpdateCacheReset(_spSkeleton* const internal, spBone* bone) {
  144. if (internal->updateCacheResetCount == internal->updateCacheResetCapacity) {
  145. internal->updateCacheResetCapacity *= 2;
  146. internal->updateCacheReset = realloc(internal->updateCacheReset, sizeof(spBone*) * internal->updateCacheResetCapacity);
  147. }
  148. internal->updateCacheReset[internal->updateCacheResetCount] = bone;
  149. ++internal->updateCacheResetCount;
  150. }
  151. static void _sortBone(_spSkeleton* const internal, spBone* bone) {
  152. if (bone->sorted) return;
  153. if (bone->parent) _sortBone(internal, bone->parent);
  154. bone->sorted = 1;
  155. _addToUpdateCache(internal, SP_UPDATE_BONE, bone);
  156. }
  157. static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAttachment* attachment, spBone* slotBone) {
  158. spPathAttachment* pathAttachment = (spPathAttachment*)attachment;
  159. int* pathBones;
  160. int pathBonesCount;
  161. if (pathAttachment->super.super.type != SP_ATTACHMENT_PATH) return;
  162. pathBones = pathAttachment->super.bones;
  163. pathBonesCount = pathAttachment->super.bonesCount;
  164. if (pathBones == 0)
  165. _sortBone(internal, slotBone);
  166. else {
  167. spBone** bones = internal->super.bones;
  168. int i = 0, n;
  169. while (i < pathBonesCount) {
  170. int boneCount = pathBones[i++];
  171. for (n = i + boneCount; i < n; i++)
  172. _sortBone(internal, bones[pathBones[i]]);
  173. }
  174. }
  175. }
  176. static void _sortPathConstraintAttachment(_spSkeleton* const internal, spSkin* skin, int slotIndex, spBone* slotBone) {
  177. _Entry* entry = SUB_CAST(_spSkin, skin)->entries;
  178. while (entry) {
  179. if (entry->slotIndex == slotIndex) _sortPathConstraintAttachmentBones(internal, entry->attachment, slotBone);
  180. entry = entry->next;
  181. }
  182. }
  183. static void _sortReset(spBone** bones, int bonesCount) {
  184. int i;
  185. for (i = 0; i < bonesCount; ++i) {
  186. spBone* bone = bones[i];
  187. if (bone->sorted) _sortReset(bone->children, bone->childrenCount);
  188. bone->sorted = 0;
  189. }
  190. }
  191. static void _sortIkConstraint (_spSkeleton* const internal, spIkConstraint* constraint) {
  192. int /*bool*/ contains = 0;
  193. int i;
  194. spBone* target = constraint->target;
  195. spBone** constrained;
  196. spBone* parent;
  197. _sortBone(internal, target);
  198. constrained = constraint->bones;
  199. parent = constrained[0];
  200. _sortBone(internal, parent);
  201. if (constraint->bonesCount > 1) {
  202. spBone* child = constrained[constraint->bonesCount - 1];
  203. contains = 0;
  204. for (i = 0; i < internal->updateCacheCount; i++) {
  205. _spUpdate update = internal->updateCache[i];
  206. if (update.object == child) {
  207. contains = -1;
  208. break;
  209. }
  210. }
  211. if (!contains)
  212. _addToUpdateCacheReset(internal, child);
  213. }
  214. _addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
  215. _sortReset(parent->children, parent->childrenCount);
  216. constrained[constraint->bonesCount-1]->sorted = 1;
  217. }
  218. static void _sortPathConstraint(_spSkeleton* const internal, spPathConstraint* constraint) {
  219. spSlot* slot = constraint->target;
  220. int slotIndex = slot->data->index;
  221. spBone* slotBone = slot->bone;
  222. int ii, nn, boneCount;
  223. spAttachment* attachment;
  224. spBone** constrained;
  225. spSkeleton* skeleton = SUPER_CAST(spSkeleton, internal);
  226. if (skeleton->skin) _sortPathConstraintAttachment(internal, skeleton->skin, slotIndex, slotBone);
  227. if (skeleton->data->defaultSkin && skeleton->data->defaultSkin != skeleton->skin)
  228. _sortPathConstraintAttachment(internal, skeleton->data->defaultSkin, slotIndex, slotBone);
  229. for (ii = 0, nn = skeleton->data->skinsCount; ii < nn; ii++)
  230. _sortPathConstraintAttachment(internal, skeleton->data->skins[ii], slotIndex, slotBone);
  231. attachment = slot->attachment;
  232. if (attachment->type == SP_ATTACHMENT_PATH) _sortPathConstraintAttachmentBones(internal, attachment, slotBone);
  233. constrained = constraint->bones;
  234. boneCount = constraint->bonesCount;
  235. for (ii = 0; ii < boneCount; ii++)
  236. _sortBone(internal, constrained[ii]);
  237. _addToUpdateCache(internal, SP_UPDATE_PATH_CONSTRAINT, constraint);
  238. for (ii = 0; ii < boneCount; ii++)
  239. _sortReset(constrained[ii]->children, constrained[ii]->childrenCount);
  240. for (ii = 0; ii < boneCount; ii++)
  241. constrained[ii]->sorted = 1;
  242. }
  243. static void _sortTransformConstraint(_spSkeleton* const internal, spTransformConstraint* constraint) {
  244. int ii, boneCount;
  245. spBone** constrained;
  246. _sortBone(internal, constraint->target);
  247. constrained = constraint->bones;
  248. boneCount = constraint->bonesCount;
  249. for (ii = 0; ii < boneCount; ii++)
  250. _sortBone(internal, constrained[ii]);
  251. _addToUpdateCache(internal, SP_UPDATE_TRANSFORM_CONSTRAINT, constraint);
  252. for (ii = 0; ii < boneCount; ii++)
  253. _sortReset(constrained[ii]->children, constrained[ii]->childrenCount);
  254. for (ii = 0; ii < boneCount; ii++)
  255. constrained[ii]->sorted = 1;
  256. }
  257. void spSkeleton_updateCache (spSkeleton* self) {
  258. int i, ii;
  259. spBone** bones;
  260. spIkConstraint** ikConstraints;
  261. spPathConstraint** pathConstraints;
  262. spTransformConstraint** transformConstraints;
  263. int ikCount, transformCount, pathCount, constraintCount;
  264. _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
  265. internal->updateCacheCapacity = self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount;
  266. FREE(internal->updateCache);
  267. internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity);
  268. internal->updateCacheCount = 0;
  269. internal->updateCacheResetCapacity = self->bonesCount;
  270. FREE(internal->updateCacheReset);
  271. internal->updateCacheReset = MALLOC(spBone*, internal->updateCacheResetCapacity);
  272. internal->updateCacheResetCount = 0;
  273. bones = self->bones;
  274. for (i = 0; i < self->bonesCount; ++i)
  275. bones[i]->sorted = 0;
  276. /* IK first, lowest hierarchy depth first. */
  277. ikConstraints = self->ikConstraints;
  278. transformConstraints = self->transformConstraints;
  279. pathConstraints = self->pathConstraints;
  280. ikCount = self->ikConstraintsCount; transformCount = self->transformConstraintsCount; pathCount = self->pathConstraintsCount;
  281. constraintCount = ikCount + transformCount + pathCount;
  282. i = 0;
  283. outer:
  284. for (; i < constraintCount; i++) {
  285. for (ii = 0; ii < ikCount; ii++) {
  286. spIkConstraint* ikConstraint = ikConstraints[ii];
  287. if (ikConstraint->data->order == i) {
  288. _sortIkConstraint(internal, ikConstraint);
  289. i++;
  290. goto outer;
  291. }
  292. }
  293. for (ii = 0; ii < transformCount; ii++) {
  294. spTransformConstraint* transformConstraint = transformConstraints[ii];
  295. if (transformConstraint->data->order == i) {
  296. _sortTransformConstraint(internal, transformConstraint);
  297. i++;
  298. goto outer;
  299. }
  300. }
  301. for (ii = 0; ii < pathCount; ii++) {
  302. spPathConstraint* pathConstraint = pathConstraints[ii];
  303. if (pathConstraint->data->order == i) {
  304. _sortPathConstraint(internal, pathConstraint);
  305. i++;
  306. goto outer;
  307. }
  308. }
  309. }
  310. for (i = 0; i < self->bonesCount; ++i)
  311. _sortBone(internal, self->bones[i]);
  312. }
  313. void spSkeleton_updateWorldTransform (const spSkeleton* self) {
  314. int i;
  315. _spSkeleton* internal = SUB_CAST(_spSkeleton, self);
  316. spBone** updateCacheReset = internal->updateCacheReset;
  317. for (i = 0; i < internal->updateCacheResetCount; i++) {
  318. spBone* bone = updateCacheReset[i];
  319. CONST_CAST(float, bone->ax) = bone->x;
  320. CONST_CAST(float, bone->ay) = bone->y;
  321. CONST_CAST(float, bone->arotation) = bone->rotation;
  322. CONST_CAST(float, bone->ascaleX) = bone->scaleX;
  323. CONST_CAST(float, bone->ascaleY) = bone->scaleY;
  324. CONST_CAST(float, bone->ashearX) = bone->shearX;
  325. CONST_CAST(float, bone->ashearY) = bone->shearY;
  326. CONST_CAST(int, bone->appliedValid) = 1;
  327. }
  328. for (i = 0; i < internal->updateCacheCount; ++i) {
  329. _spUpdate* update = internal->updateCache + i;
  330. switch (update->type) {
  331. case SP_UPDATE_BONE:
  332. spBone_updateWorldTransform((spBone*)update->object);
  333. break;
  334. case SP_UPDATE_IK_CONSTRAINT:
  335. spIkConstraint_apply((spIkConstraint*)update->object);
  336. break;
  337. case SP_UPDATE_TRANSFORM_CONSTRAINT:
  338. spTransformConstraint_apply((spTransformConstraint*)update->object);
  339. break;
  340. case SP_UPDATE_PATH_CONSTRAINT:
  341. spPathConstraint_apply((spPathConstraint*)update->object);
  342. break;
  343. }
  344. }
  345. }
  346. void spSkeleton_setToSetupPose (const spSkeleton* self) {
  347. spSkeleton_setBonesToSetupPose(self);
  348. spSkeleton_setSlotsToSetupPose(self);
  349. }
  350. void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
  351. int i;
  352. for (i = 0; i < self->bonesCount; ++i)
  353. spBone_setToSetupPose(self->bones[i]);
  354. for (i = 0; i < self->ikConstraintsCount; ++i) {
  355. spIkConstraint* ikConstraint = self->ikConstraints[i];
  356. ikConstraint->bendDirection = ikConstraint->data->bendDirection;
  357. ikConstraint->mix = ikConstraint->data->mix;
  358. }
  359. for (i = 0; i < self->transformConstraintsCount; ++i) {
  360. spTransformConstraint* constraint = self->transformConstraints[i];
  361. spTransformConstraintData* data = constraint->data;
  362. constraint->rotateMix = data->rotateMix;
  363. constraint->translateMix = data->translateMix;
  364. constraint->scaleMix = data->scaleMix;
  365. constraint->shearMix = data->shearMix;
  366. }
  367. for (i = 0; i < self->pathConstraintsCount; ++i) {
  368. spPathConstraint* constraint = self->pathConstraints[i];
  369. spPathConstraintData* data = constraint->data;
  370. constraint->position = data->position;
  371. constraint->spacing = data->spacing;
  372. constraint->rotateMix = data->rotateMix;
  373. constraint->translateMix = data->translateMix;
  374. }
  375. }
  376. void spSkeleton_setSlotsToSetupPose (const spSkeleton* self) {
  377. int i;
  378. memcpy(self->drawOrder, self->slots, self->slotsCount * sizeof(spSlot*));
  379. for (i = 0; i < self->slotsCount; ++i)
  380. spSlot_setToSetupPose(self->slots[i]);
  381. }
  382. spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName) {
  383. int i;
  384. for (i = 0; i < self->bonesCount; ++i)
  385. if (strcmp(self->data->bones[i]->name, boneName) == 0) return self->bones[i];
  386. return 0;
  387. }
  388. int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName) {
  389. int i;
  390. for (i = 0; i < self->bonesCount; ++i)
  391. if (strcmp(self->data->bones[i]->name, boneName) == 0) return i;
  392. return -1;
  393. }
  394. spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName) {
  395. int i;
  396. for (i = 0; i < self->slotsCount; ++i)
  397. if (strcmp(self->data->slots[i]->name, slotName) == 0) return self->slots[i];
  398. return 0;
  399. }
  400. int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName) {
  401. int i;
  402. for (i = 0; i < self->slotsCount; ++i)
  403. if (strcmp(self->data->slots[i]->name, slotName) == 0) return i;
  404. return -1;
  405. }
  406. int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName) {
  407. spSkin *skin;
  408. if (!skinName) {
  409. spSkeleton_setSkin(self, 0);
  410. return 1;
  411. }
  412. skin = spSkeletonData_findSkin(self->data, skinName);
  413. if (!skin) return 0;
  414. spSkeleton_setSkin(self, skin);
  415. return 1;
  416. }
  417. void spSkeleton_setSkin (spSkeleton* self, spSkin* newSkin) {
  418. if (newSkin) {
  419. if (self->skin)
  420. spSkin_attachAll(newSkin, self, self->skin);
  421. else {
  422. /* No previous skin, attach setup pose attachments. */
  423. int i;
  424. for (i = 0; i < self->slotsCount; ++i) {
  425. spSlot* slot = self->slots[i];
  426. if (slot->data->attachmentName) {
  427. spAttachment* attachment = spSkin_getAttachment(newSkin, i, slot->data->attachmentName);
  428. if (attachment) spSlot_setAttachment(slot, attachment);
  429. }
  430. }
  431. }
  432. }
  433. CONST_CAST(spSkin*, self->skin) = newSkin;
  434. }
  435. spAttachment* spSkeleton_getAttachmentForSlotName (const spSkeleton* self, const char* slotName, const char* attachmentName) {
  436. int slotIndex = spSkeletonData_findSlotIndex(self->data, slotName);
  437. return spSkeleton_getAttachmentForSlotIndex(self, slotIndex, attachmentName);
  438. }
  439. spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int slotIndex, const char* attachmentName) {
  440. if (slotIndex == -1) return 0;
  441. if (self->skin) {
  442. spAttachment *attachment = spSkin_getAttachment(self->skin, slotIndex, attachmentName);
  443. if (attachment) return attachment;
  444. }
  445. if (self->data->defaultSkin) {
  446. spAttachment *attachment = spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName);
  447. if (attachment) return attachment;
  448. }
  449. return 0;
  450. }
  451. int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName) {
  452. int i;
  453. for (i = 0; i < self->slotsCount; ++i) {
  454. spSlot *slot = self->slots[i];
  455. if (strcmp(slot->data->name, slotName) == 0) {
  456. if (!attachmentName)
  457. spSlot_setAttachment(slot, 0);
  458. else {
  459. spAttachment* attachment = spSkeleton_getAttachmentForSlotIndex(self, i, attachmentName);
  460. if (!attachment) return 0;
  461. spSlot_setAttachment(slot, attachment);
  462. }
  463. return 1;
  464. }
  465. }
  466. return 0;
  467. }
  468. spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName) {
  469. int i;
  470. for (i = 0; i < self->ikConstraintsCount; ++i)
  471. if (strcmp(self->ikConstraints[i]->data->name, constraintName) == 0) return self->ikConstraints[i];
  472. return 0;
  473. }
  474. spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName) {
  475. int i;
  476. for (i = 0; i < self->transformConstraintsCount; ++i)
  477. if (strcmp(self->transformConstraints[i]->data->name, constraintName) == 0) return self->transformConstraints[i];
  478. return 0;
  479. }
  480. spPathConstraint* spSkeleton_findPathConstraint (const spSkeleton* self, const char* constraintName) {
  481. int i;
  482. for (i = 0; i < self->pathConstraintsCount; ++i)
  483. if (strcmp(self->pathConstraints[i]->data->name, constraintName) == 0) return self->pathConstraints[i];
  484. return 0;
  485. }
  486. void spSkeleton_update (spSkeleton* self, float deltaTime) {
  487. self->time += deltaTime;
  488. }