MemoryTestFixture.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include <spine/extension.h>
  2. #include "MemoryTestFixture.h"
  3. #include "SpineEventMonitor.h"
  4. #include "spine/spine.h"
  5. #include "KMemory.h" // last include
  6. #define SPINEBOY_JSON "testdata/spineboy/spineboy-ess.json"
  7. #define SPINEBOY_ATLAS "testdata/spineboy/spineboy.atlas"
  8. #define MAX_RUN_TIME 6000 // equal to about 100 seconds of execution
  9. MemoryTestFixture::~MemoryTestFixture() {
  10. finalize();
  11. }
  12. void MemoryTestFixture::initialize() {
  13. // on a Per- Fixture Basis, before Test execution
  14. }
  15. void MemoryTestFixture::finalize() {
  16. // on a Per- Fixture Basis, after all tests pass/fail
  17. }
  18. void MemoryTestFixture::setUp() {
  19. // Setup on Per-Test Basis
  20. }
  21. void MemoryTestFixture::tearDown() {
  22. // Tear Down on Per-Test Basis
  23. }
  24. //////////////////////////////////////////////////////////////////////////
  25. // Helper methods
  26. static spSkeletonData *readSkeletonJsonData(const char *filename, spAtlas *atlas) {
  27. spSkeletonJson *json = spSkeletonJson_create(atlas);
  28. ASSERT(json != 0);
  29. spSkeletonData *skeletonData = spSkeletonJson_readSkeletonDataFile(json, filename);
  30. ASSERT(skeletonData != 0);
  31. spSkeletonJson_dispose(json);
  32. return skeletonData;
  33. }
  34. static void LoadSpineboyExample(spAtlas *&atlas, spSkeletonData *&skeletonData, spAnimationStateData *&stateData,
  35. spSkeleton *&skeleton, spAnimationState *&state) {
  36. ///////////////////////////////////////////////////////////////////////////
  37. // Global Animation Information
  38. atlas = spAtlas_createFromFile(SPINEBOY_ATLAS, 0);
  39. ASSERT(atlas != 0);
  40. skeletonData = readSkeletonJsonData(SPINEBOY_JSON, atlas);
  41. ASSERT(skeletonData != 0);
  42. stateData = spAnimationStateData_create(skeletonData);
  43. ASSERT(stateData != 0);
  44. stateData->defaultMix = 0.4f; // force mixing
  45. ///////////////////////////////////////////////////////////////////////////
  46. // Animation Instance
  47. skeleton = spSkeleton_create(skeletonData);
  48. ASSERT(skeleton != 0);
  49. state = spAnimationState_create(stateData);
  50. ASSERT(state != 0);
  51. }
  52. static void
  53. DisposeAll(spSkeleton *skeleton, spAnimationState *state, spAnimationStateData *stateData, spSkeletonData *skeletonData,
  54. spAtlas *atlas) {
  55. ///////////////////////////////////////////////////////////////////////////
  56. // Dispose Instance
  57. spSkeleton_dispose(skeleton);
  58. spAnimationState_dispose(state);
  59. ///////////////////////////////////////////////////////////////////////////
  60. // Dispose Global
  61. spAnimationStateData_dispose(stateData);
  62. spSkeletonData_dispose(skeletonData);
  63. spAtlas_dispose(atlas);
  64. }
  65. //////////////////////////////////////////////////////////////////////////
  66. // Reproduce Memory leak as described in Issue #776
  67. // https://github.com/EsotericSoftware/spine-runtimes/issues/776
  68. void MemoryTestFixture::reproduceIssue_776() {
  69. spAtlas *atlas = 0;
  70. spSkeletonData *skeletonData = 0;
  71. spAnimationStateData *stateData = 0;
  72. spSkeleton *skeleton = 0;
  73. spAnimationState *state = 0;
  74. //////////////////////////////////////////////////////////////////////////
  75. // Initialize Animations
  76. LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
  77. ///////////////////////////////////////////////////////////////////////////
  78. // Run animation
  79. spSkeleton_setToSetupPose(skeleton);
  80. InterruptMonitor eventMonitor(state);
  81. //eventMonitor.SetDebugLogging(true);
  82. // Interrupt the animation on this specific sequence of spEventType(s)
  83. eventMonitor
  84. .AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump")
  85. .AddInterruptEvent(SP_ANIMATION_START);
  86. spAnimationState_setAnimationByName(state, 0, "walk", true);
  87. spAnimationState_addAnimationByName(state, 0, "jump", false, 0.0f);
  88. spAnimationState_addAnimationByName(state, 0, "run", true, 0.0f);
  89. spAnimationState_addAnimationByName(state, 0, "jump", false, 3.0f);
  90. spAnimationState_addAnimationByName(state, 0, "walk", true, 0.0f);
  91. spAnimationState_addAnimationByName(state, 0, "idle", false, 1.0f);
  92. for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i) {
  93. const float timeSlice = 1.0f / 60.0f;
  94. spSkeleton_update(skeleton, timeSlice);
  95. spAnimationState_update(state, timeSlice);
  96. spAnimationState_apply(state, skeleton);
  97. }
  98. //////////////////////////////////////////////////////////////////////////
  99. // Cleanup Animations
  100. DisposeAll(skeleton, state, stateData, skeletonData, atlas);
  101. }
  102. void MemoryTestFixture::reproduceIssue_777() {
  103. spAtlas *atlas = 0;
  104. spSkeletonData *skeletonData = 0;
  105. spAnimationStateData *stateData = 0;
  106. spSkeleton *skeleton = 0;
  107. spAnimationState *state = 0;
  108. //////////////////////////////////////////////////////////////////////////
  109. // Initialize Animations
  110. LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
  111. ///////////////////////////////////////////////////////////////////////////
  112. // Run animation
  113. spSkeleton_setToSetupPose(skeleton);
  114. SpineEventMonitor eventMonitor(state);
  115. //eventMonitor.SetDebugLogging(true);
  116. // Set Animation and Play for 5 frames
  117. spAnimationState_setAnimationByName(state, 0, "walk", true);
  118. for (int i = 0; i < 5; ++i) {
  119. const float timeSlice = 1.0f / 60.0f;
  120. spSkeleton_update(skeleton, timeSlice);
  121. spAnimationState_update(state, timeSlice);
  122. spAnimationState_apply(state, skeleton);
  123. }
  124. // Change animation twice in a row
  125. spAnimationState_setAnimationByName(state, 0, "walk", false);
  126. spAnimationState_setAnimationByName(state, 0, "run", false);
  127. // run normal update
  128. for (int i = 0; i < 5; ++i) {
  129. const float timeSlice = 1.0f / 60.0f;
  130. spSkeleton_update(skeleton, timeSlice);
  131. spAnimationState_update(state, timeSlice);
  132. spAnimationState_apply(state, skeleton);
  133. }
  134. // Now we'd lose mixingFrom (the first "walk" entry we set above) and should leak
  135. spAnimationState_setAnimationByName(state, 0, "run", false);
  136. //////////////////////////////////////////////////////////////////////////
  137. // Cleanup Animations
  138. DisposeAll(skeleton, state, stateData, skeletonData, atlas);
  139. }
  140. spSkeleton *skeleton = 0;
  141. static void spineAnimStateHandler(spAnimationState *state, int type, spTrackEntry *entry, spEvent *event) {
  142. if (type == SP_ANIMATION_COMPLETE) {
  143. spAnimationState_setAnimationByName(state, 0, "walk", false);
  144. spAnimationState_update(state, 0);
  145. spAnimationState_apply(state, skeleton);
  146. }
  147. }
  148. void MemoryTestFixture::reproduceIssue_Loop() {
  149. spAtlas *atlas = 0;
  150. spSkeletonData *skeletonData = 0;
  151. spAnimationStateData *stateData = 0;
  152. spAnimationState *state = 0;
  153. //////////////////////////////////////////////////////////////////////////
  154. // Initialize Animations
  155. LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
  156. ///////////////////////////////////////////////////////////////////////////
  157. if (state)
  158. state->listener = (spAnimationStateListener) &spineAnimStateHandler;
  159. spAnimationState_setAnimationByName(state, 0, "walk", false);
  160. // run normal update
  161. for (int i = 0; i < 50; ++i) {
  162. const float timeSlice = 1.0f / 60.0f;
  163. spSkeleton_update(skeleton, timeSlice);
  164. spAnimationState_update(state, timeSlice);
  165. spAnimationState_apply(state, skeleton);
  166. }
  167. DisposeAll(skeleton, state, stateData, skeletonData, atlas);
  168. }
  169. void MemoryTestFixture::triangulator() {
  170. spTriangulator *triangulator = spTriangulator_create();
  171. spFloatArray *polygon = spFloatArray_create(16);
  172. spFloatArray_add(polygon, 0);
  173. spFloatArray_add(polygon, 0);
  174. spFloatArray_add(polygon, 100);
  175. spFloatArray_add(polygon, 0);
  176. spFloatArray_add(polygon, 100);
  177. spFloatArray_add(polygon, 100);
  178. spFloatArray_add(polygon, 0);
  179. spFloatArray_add(polygon, 100);
  180. spShortArray *triangles = spTriangulator_triangulate(triangulator, polygon);
  181. ASSERT(triangles->size == 6);
  182. ASSERT(triangles->items[0] == 3);
  183. ASSERT(triangles->items[1] == 0);
  184. ASSERT(triangles->items[2] == 1);
  185. ASSERT(triangles->items[3] == 3);
  186. ASSERT(triangles->items[4] == 1);
  187. ASSERT(triangles->items[5] == 2);
  188. spArrayFloatArray *polys = spTriangulator_decompose(triangulator, polygon, triangles);
  189. ASSERT(polys->size == 1);
  190. ASSERT(polys->items[0]->size == 8);
  191. ASSERT(polys->items[0]->items[0] == 0);
  192. ASSERT(polys->items[0]->items[1] == 100);
  193. ASSERT(polys->items[0]->items[2] == 0);
  194. ASSERT(polys->items[0]->items[3] == 0);
  195. ASSERT(polys->items[0]->items[4] == 100);
  196. ASSERT(polys->items[0]->items[5] == 0);
  197. ASSERT(polys->items[0]->items[6] == 100);
  198. ASSERT(polys->items[0]->items[7] == 100);
  199. spFloatArray_dispose(polygon);
  200. spTriangulator_dispose(triangulator);
  201. }
  202. void MemoryTestFixture::skeletonClipper() {
  203. spSkeletonClipping *clipping = spSkeletonClipping_create();
  204. spBoneData *boneData = spBoneData_create(0, "bone", 0);
  205. spBone *bone = spBone_create(boneData, 0, 0);
  206. CONST_CAST(float, bone->a) = 1;
  207. CONST_CAST(float, bone->b) = 0;
  208. CONST_CAST(float, bone->c) = 0;
  209. CONST_CAST(float, bone->d) = 1;
  210. CONST_CAST(float, bone->worldX) = 0;
  211. CONST_CAST(float, bone->worldY) = 0;
  212. spSlotData *slotData = spSlotData_create(0, "slot", 0);
  213. spSlot *slot = spSlot_create(slotData, bone);
  214. spClippingAttachment *clip = spClippingAttachment_create("clipping");
  215. clip->endSlot = slotData;
  216. clip->super.worldVerticesLength = 4 * 2;
  217. clip->super.verticesCount = 4;
  218. clip->super.vertices = MALLOC(float, 4 * 8);
  219. clip->super.vertices[0] = 0;
  220. clip->super.vertices[1] = 50;
  221. clip->super.vertices[2] = 100;
  222. clip->super.vertices[3] = 50;
  223. clip->super.vertices[4] = 100;
  224. clip->super.vertices[5] = 70;
  225. clip->super.vertices[6] = 0;
  226. clip->super.vertices[7] = 70;
  227. spSkeletonClipping_clipStart(clipping, slot, clip);
  228. spFloatArray *vertices = spFloatArray_create(16);
  229. spFloatArray_add(vertices, 0);
  230. spFloatArray_add(vertices, 0);
  231. spFloatArray_add(vertices, 100);
  232. spFloatArray_add(vertices, 0);
  233. spFloatArray_add(vertices, 50);
  234. spFloatArray_add(vertices, 150);
  235. spFloatArray *uvs = spFloatArray_create(16);
  236. spFloatArray_add(uvs, 0);
  237. spFloatArray_add(uvs, 0);
  238. spFloatArray_add(uvs, 1);
  239. spFloatArray_add(uvs, 0);
  240. spFloatArray_add(uvs, 0.5f);
  241. spFloatArray_add(uvs, 1);
  242. spUnsignedShortArray *indices = spUnsignedShortArray_create(16);
  243. spUnsignedShortArray_add(indices, 0);
  244. spUnsignedShortArray_add(indices, 1);
  245. spUnsignedShortArray_add(indices, 2);
  246. spSkeletonClipping_clipTriangles(clipping, vertices->items, vertices->size, indices->items, indices->size,
  247. uvs->items, 2);
  248. float expectedVertices[8] = {83.333328f, 50.000000f, 76.666664f, 70.000000f, 23.333334f, 70.000000f, 16.666672f,
  249. 50.000000f};
  250. ASSERT(clipping->clippedVertices->size == 8);
  251. for (int i = 0; i < clipping->clippedVertices->size; i++) {
  252. ASSERT(ABS(clipping->clippedVertices->items[i] - expectedVertices[i]) < 0.001);
  253. }
  254. float expectedUVs[8] = {0.833333f, 0.333333f, 0.766667f, 0.466667f, 0.233333f, 0.466667f, 0.166667f, 0.333333f};
  255. ASSERT(clipping->clippedUVs->size == 8);
  256. for (int i = 0; i < clipping->clippedUVs->size; i++) {
  257. ASSERT(ABS(clipping->clippedUVs->items[i] - expectedUVs[i]) < 0.001);
  258. }
  259. short expectedIndices[6] = {0, 1, 2, 0, 2, 3};
  260. ASSERT(clipping->clippedTriangles->size == 6);
  261. for (int i = 0; i < clipping->clippedTriangles->size; i++) {
  262. ASSERT(clipping->clippedTriangles->items[i] == expectedIndices[i]);
  263. }
  264. spFloatArray_dispose(vertices);
  265. spFloatArray_dispose(uvs);
  266. spUnsignedShortArray_dispose(indices);
  267. spSlotData_dispose(slotData);
  268. spSlot_dispose(slot);
  269. spBoneData_dispose(boneData);
  270. spBone_dispose(bone);
  271. _spClippingAttachment_dispose(SUPER(SUPER(clip)));
  272. spSkeletonClipping_dispose(clipping);
  273. }