123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- #include <spine/extension.h>
- #include "MemoryTestFixture.h"
- #include "SpineEventMonitor.h"
- #include "spine/spine.h"
- #include "KMemory.h" // last include
- #define SPINEBOY_JSON "testdata/spineboy/spineboy-ess.json"
- #define SPINEBOY_ATLAS "testdata/spineboy/spineboy.atlas"
- #define MAX_RUN_TIME 6000 // equal to about 100 seconds of execution
- MemoryTestFixture::~MemoryTestFixture() {
- finalize();
- }
- void MemoryTestFixture::initialize() {
- // on a Per- Fixture Basis, before Test execution
- }
- void MemoryTestFixture::finalize() {
- // on a Per- Fixture Basis, after all tests pass/fail
- }
- void MemoryTestFixture::setUp() {
- // Setup on Per-Test Basis
- }
- void MemoryTestFixture::tearDown() {
- // Tear Down on Per-Test Basis
- }
- //////////////////////////////////////////////////////////////////////////
- // Helper methods
- static spSkeletonData *readSkeletonJsonData(const char *filename, spAtlas *atlas) {
- spSkeletonJson *json = spSkeletonJson_create(atlas);
- ASSERT(json != 0);
- spSkeletonData *skeletonData = spSkeletonJson_readSkeletonDataFile(json, filename);
- ASSERT(skeletonData != 0);
- spSkeletonJson_dispose(json);
- return skeletonData;
- }
- static void LoadSpineboyExample(spAtlas *&atlas, spSkeletonData *&skeletonData, spAnimationStateData *&stateData,
- spSkeleton *&skeleton, spAnimationState *&state) {
- ///////////////////////////////////////////////////////////////////////////
- // Global Animation Information
- atlas = spAtlas_createFromFile(SPINEBOY_ATLAS, 0);
- ASSERT(atlas != 0);
- skeletonData = readSkeletonJsonData(SPINEBOY_JSON, atlas);
- ASSERT(skeletonData != 0);
- stateData = spAnimationStateData_create(skeletonData);
- ASSERT(stateData != 0);
- stateData->defaultMix = 0.4f; // force mixing
- ///////////////////////////////////////////////////////////////////////////
- // Animation Instance
- skeleton = spSkeleton_create(skeletonData);
- ASSERT(skeleton != 0);
- state = spAnimationState_create(stateData);
- ASSERT(state != 0);
- }
- static void
- DisposeAll(spSkeleton *skeleton, spAnimationState *state, spAnimationStateData *stateData, spSkeletonData *skeletonData,
- spAtlas *atlas) {
- ///////////////////////////////////////////////////////////////////////////
- // Dispose Instance
- spSkeleton_dispose(skeleton);
- spAnimationState_dispose(state);
- ///////////////////////////////////////////////////////////////////////////
- // Dispose Global
- spAnimationStateData_dispose(stateData);
- spSkeletonData_dispose(skeletonData);
- spAtlas_dispose(atlas);
- }
- //////////////////////////////////////////////////////////////////////////
- // Reproduce Memory leak as described in Issue #776
- // https://github.com/EsotericSoftware/spine-runtimes/issues/776
- void MemoryTestFixture::reproduceIssue_776() {
- spAtlas *atlas = 0;
- spSkeletonData *skeletonData = 0;
- spAnimationStateData *stateData = 0;
- spSkeleton *skeleton = 0;
- spAnimationState *state = 0;
- //////////////////////////////////////////////////////////////////////////
- // Initialize Animations
- LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
- ///////////////////////////////////////////////////////////////////////////
- // Run animation
- spSkeleton_setToSetupPose(skeleton);
- InterruptMonitor eventMonitor(state);
- //eventMonitor.SetDebugLogging(true);
- // Interrupt the animation on this specific sequence of spEventType(s)
- eventMonitor
- .AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump")
- .AddInterruptEvent(SP_ANIMATION_START);
- spAnimationState_setAnimationByName(state, 0, "walk", true);
- spAnimationState_addAnimationByName(state, 0, "jump", false, 0.0f);
- spAnimationState_addAnimationByName(state, 0, "run", true, 0.0f);
- spAnimationState_addAnimationByName(state, 0, "jump", false, 3.0f);
- spAnimationState_addAnimationByName(state, 0, "walk", true, 0.0f);
- spAnimationState_addAnimationByName(state, 0, "idle", false, 1.0f);
- for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i) {
- const float timeSlice = 1.0f / 60.0f;
- spSkeleton_update(skeleton, timeSlice);
- spAnimationState_update(state, timeSlice);
- spAnimationState_apply(state, skeleton);
- }
- //////////////////////////////////////////////////////////////////////////
- // Cleanup Animations
- DisposeAll(skeleton, state, stateData, skeletonData, atlas);
- }
- void MemoryTestFixture::reproduceIssue_777() {
- spAtlas *atlas = 0;
- spSkeletonData *skeletonData = 0;
- spAnimationStateData *stateData = 0;
- spSkeleton *skeleton = 0;
- spAnimationState *state = 0;
- //////////////////////////////////////////////////////////////////////////
- // Initialize Animations
- LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
- ///////////////////////////////////////////////////////////////////////////
- // Run animation
- spSkeleton_setToSetupPose(skeleton);
- SpineEventMonitor eventMonitor(state);
- //eventMonitor.SetDebugLogging(true);
- // Set Animation and Play for 5 frames
- spAnimationState_setAnimationByName(state, 0, "walk", true);
- for (int i = 0; i < 5; ++i) {
- const float timeSlice = 1.0f / 60.0f;
- spSkeleton_update(skeleton, timeSlice);
- spAnimationState_update(state, timeSlice);
- spAnimationState_apply(state, skeleton);
- }
- // Change animation twice in a row
- spAnimationState_setAnimationByName(state, 0, "walk", false);
- spAnimationState_setAnimationByName(state, 0, "run", false);
- // run normal update
- for (int i = 0; i < 5; ++i) {
- const float timeSlice = 1.0f / 60.0f;
- spSkeleton_update(skeleton, timeSlice);
- spAnimationState_update(state, timeSlice);
- spAnimationState_apply(state, skeleton);
- }
- // Now we'd lose mixingFrom (the first "walk" entry we set above) and should leak
- spAnimationState_setAnimationByName(state, 0, "run", false);
- //////////////////////////////////////////////////////////////////////////
- // Cleanup Animations
- DisposeAll(skeleton, state, stateData, skeletonData, atlas);
- }
- spSkeleton *skeleton = 0;
- static void spineAnimStateHandler(spAnimationState *state, int type, spTrackEntry *entry, spEvent *event) {
- if (type == SP_ANIMATION_COMPLETE) {
- spAnimationState_setAnimationByName(state, 0, "walk", false);
- spAnimationState_update(state, 0);
- spAnimationState_apply(state, skeleton);
- }
- }
- void MemoryTestFixture::reproduceIssue_Loop() {
- spAtlas *atlas = 0;
- spSkeletonData *skeletonData = 0;
- spAnimationStateData *stateData = 0;
- spAnimationState *state = 0;
- //////////////////////////////////////////////////////////////////////////
- // Initialize Animations
- LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
- ///////////////////////////////////////////////////////////////////////////
- if (state)
- state->listener = (spAnimationStateListener) &spineAnimStateHandler;
- spAnimationState_setAnimationByName(state, 0, "walk", false);
- // run normal update
- for (int i = 0; i < 50; ++i) {
- const float timeSlice = 1.0f / 60.0f;
- spSkeleton_update(skeleton, timeSlice);
- spAnimationState_update(state, timeSlice);
- spAnimationState_apply(state, skeleton);
- }
- DisposeAll(skeleton, state, stateData, skeletonData, atlas);
- }
- void MemoryTestFixture::triangulator() {
- spTriangulator *triangulator = spTriangulator_create();
- spFloatArray *polygon = spFloatArray_create(16);
- spFloatArray_add(polygon, 0);
- spFloatArray_add(polygon, 0);
- spFloatArray_add(polygon, 100);
- spFloatArray_add(polygon, 0);
- spFloatArray_add(polygon, 100);
- spFloatArray_add(polygon, 100);
- spFloatArray_add(polygon, 0);
- spFloatArray_add(polygon, 100);
- spShortArray *triangles = spTriangulator_triangulate(triangulator, polygon);
- ASSERT(triangles->size == 6);
- ASSERT(triangles->items[0] == 3);
- ASSERT(triangles->items[1] == 0);
- ASSERT(triangles->items[2] == 1);
- ASSERT(triangles->items[3] == 3);
- ASSERT(triangles->items[4] == 1);
- ASSERT(triangles->items[5] == 2);
- spArrayFloatArray *polys = spTriangulator_decompose(triangulator, polygon, triangles);
- ASSERT(polys->size == 1);
- ASSERT(polys->items[0]->size == 8);
- ASSERT(polys->items[0]->items[0] == 0);
- ASSERT(polys->items[0]->items[1] == 100);
- ASSERT(polys->items[0]->items[2] == 0);
- ASSERT(polys->items[0]->items[3] == 0);
- ASSERT(polys->items[0]->items[4] == 100);
- ASSERT(polys->items[0]->items[5] == 0);
- ASSERT(polys->items[0]->items[6] == 100);
- ASSERT(polys->items[0]->items[7] == 100);
- spFloatArray_dispose(polygon);
- spTriangulator_dispose(triangulator);
- }
- void MemoryTestFixture::skeletonClipper() {
- spSkeletonClipping *clipping = spSkeletonClipping_create();
- spBoneData *boneData = spBoneData_create(0, "bone", 0);
- spBone *bone = spBone_create(boneData, 0, 0);
- CONST_CAST(float, bone->a) = 1;
- CONST_CAST(float, bone->b) = 0;
- CONST_CAST(float, bone->c) = 0;
- CONST_CAST(float, bone->d) = 1;
- CONST_CAST(float, bone->worldX) = 0;
- CONST_CAST(float, bone->worldY) = 0;
- spSlotData *slotData = spSlotData_create(0, "slot", 0);
- spSlot *slot = spSlot_create(slotData, bone);
- spClippingAttachment *clip = spClippingAttachment_create("clipping");
- clip->endSlot = slotData;
- clip->super.worldVerticesLength = 4 * 2;
- clip->super.verticesCount = 4;
- clip->super.vertices = MALLOC(float, 4 * 8);
- clip->super.vertices[0] = 0;
- clip->super.vertices[1] = 50;
- clip->super.vertices[2] = 100;
- clip->super.vertices[3] = 50;
- clip->super.vertices[4] = 100;
- clip->super.vertices[5] = 70;
- clip->super.vertices[6] = 0;
- clip->super.vertices[7] = 70;
- spSkeletonClipping_clipStart(clipping, slot, clip);
- spFloatArray *vertices = spFloatArray_create(16);
- spFloatArray_add(vertices, 0);
- spFloatArray_add(vertices, 0);
- spFloatArray_add(vertices, 100);
- spFloatArray_add(vertices, 0);
- spFloatArray_add(vertices, 50);
- spFloatArray_add(vertices, 150);
- spFloatArray *uvs = spFloatArray_create(16);
- spFloatArray_add(uvs, 0);
- spFloatArray_add(uvs, 0);
- spFloatArray_add(uvs, 1);
- spFloatArray_add(uvs, 0);
- spFloatArray_add(uvs, 0.5f);
- spFloatArray_add(uvs, 1);
- spUnsignedShortArray *indices = spUnsignedShortArray_create(16);
- spUnsignedShortArray_add(indices, 0);
- spUnsignedShortArray_add(indices, 1);
- spUnsignedShortArray_add(indices, 2);
- spSkeletonClipping_clipTriangles(clipping, vertices->items, vertices->size, indices->items, indices->size,
- uvs->items, 2);
- float expectedVertices[8] = {83.333328f, 50.000000f, 76.666664f, 70.000000f, 23.333334f, 70.000000f, 16.666672f,
- 50.000000f};
- ASSERT(clipping->clippedVertices->size == 8);
- for (int i = 0; i < clipping->clippedVertices->size; i++) {
- ASSERT(ABS(clipping->clippedVertices->items[i] - expectedVertices[i]) < 0.001);
- }
- float expectedUVs[8] = {0.833333f, 0.333333f, 0.766667f, 0.466667f, 0.233333f, 0.466667f, 0.166667f, 0.333333f};
- ASSERT(clipping->clippedUVs->size == 8);
- for (int i = 0; i < clipping->clippedUVs->size; i++) {
- ASSERT(ABS(clipping->clippedUVs->items[i] - expectedUVs[i]) < 0.001);
- }
- short expectedIndices[6] = {0, 1, 2, 0, 2, 3};
- ASSERT(clipping->clippedTriangles->size == 6);
- for (int i = 0; i < clipping->clippedTriangles->size; i++) {
- ASSERT(clipping->clippedTriangles->items[i] == expectedIndices[i]);
- }
- spFloatArray_dispose(vertices);
- spFloatArray_dispose(uvs);
- spUnsignedShortArray_dispose(indices);
- spSlotData_dispose(slotData);
- spSlot_dispose(slot);
- spBoneData_dispose(boneData);
- spBone_dispose(bone);
- _spClippingAttachment_dispose(SUPER(SUPER(clip)));
- spSkeletonClipping_dispose(clipping);
- }
|