Yay, now the C++ Runtime passes all the same tests as the C Runtime!

This commit is contained in:
Stephen Gowen 2017-12-08 14:15:30 -05:00
parent c1995586aa
commit e24b061c61
12 changed files with 862 additions and 346 deletions

View File

@ -281,6 +281,7 @@
BB6017F01FD92A5B009BD546 /* SimpleTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleTest.h; sourceTree = "<group>"; }; BB6017F01FD92A5B009BD546 /* SimpleTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleTest.h; sourceTree = "<group>"; };
BB6017FC1FD92AF3009BD546 /* SpineEventMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpineEventMonitor.h; sourceTree = "<group>"; }; BB6017FC1FD92AF3009BD546 /* SpineEventMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpineEventMonitor.h; sourceTree = "<group>"; };
BB6017FD1FD92AF3009BD546 /* SpineEventMonitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpineEventMonitor.cpp; sourceTree = "<group>"; }; BB6017FD1FD92AF3009BD546 /* SpineEventMonitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpineEventMonitor.cpp; sourceTree = "<group>"; };
BBFB507F1FDAF6CD005B22B6 /* MemoryTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MemoryTest.h; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -326,6 +327,7 @@
children = ( children = (
BB6017121FD9289A009BD546 /* main.cpp */, BB6017121FD9289A009BD546 /* main.cpp */,
BB6017F01FD92A5B009BD546 /* SimpleTest.h */, BB6017F01FD92A5B009BD546 /* SimpleTest.h */,
BBFB507F1FDAF6CD005B22B6 /* MemoryTest.h */,
); );
path = spine_unit_test; path = spine_unit_test;
sourceTree = "<group>"; sourceTree = "<group>";

View File

@ -0,0 +1,444 @@
//
// MemoryTest.h
// spine_unit_test
//
// Created by Stephen Gowen on 12/8/17.
// Copyright © 2017 Noctis Games. All rights reserved.
//
#ifndef MemoryTest_h
#define MemoryTest_h
#include "SpineEventMonitor.h"
#include <spine/SkeletonJson.h>
#include <spine/SkeletonData.h>
#include <spine/Atlas.h>
#include <spine/AnimationStateData.h>
#include <spine/Skeleton.h>
#include <spine/AnimationState.h>
#include <spine/Animation.h>
#include <vector>
#include <spine/Extension.h>
#include <spine/TextureLoader.h>
#include <spine/Vector.h>
#include <spine/CurveTimeline.h>
#include <spine/VertexAttachment.h>
#include <spine/Json.h>
#include <spine/AttachmentLoader.h>
#include <spine/AtlasAttachmentLoader.h>
#include <spine/LinkedMesh.h>
#include <spine/Triangulator.h>
#include <spine/SkeletonClipping.h>
#include <spine/BoneData.h>
#include <spine/Bone.h>
#include <spine/SlotData.h>
#include <spine/Slot.h>
#include <spine/ClippingAttachment.h>
#include <new>
#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
namespace Spine
{
class MemoryTest
{
public:
class MyTextureLoader : public TextureLoader
{
virtual void load(AtlasPage& page, std::string path)
{
page.rendererObject = NULL;
page.width = 2048;
page.height = 2048;
}
virtual void unload(void* texture)
{
// TODO
}
};
//////////////////////////////////////////////////////////////////////////
// Helper methods
static SkeletonData* readSkeletonJsonData(const char* filename, Atlas* atlas)
{
Vector<Atlas*> atlasArray;
atlasArray.push_back(atlas);
SkeletonJson* skeletonJson = NEW(SkeletonJson);
new (skeletonJson) SkeletonJson(atlasArray);
assert(skeletonJson != 0);
SkeletonData* skeletonData = skeletonJson->readSkeletonDataFile(filename);
assert(skeletonData != 0);
DESTROY(SkeletonJson, skeletonJson);
return skeletonData;
}
static void loadSpineboyExample(Atlas* &atlas, SkeletonData* &skeletonData, AnimationStateData* &stateData, Skeleton* &skeleton, AnimationState* &state)
{
///////////////////////////////////////////////////////////////////////////
// Global Animation Information
static MyTextureLoader myTextureLoader;
atlas = NEW(Atlas);
new (atlas) Atlas(SPINEBOY_ATLAS, myTextureLoader);
assert(atlas != 0);
skeletonData = readSkeletonJsonData(SPINEBOY_JSON, atlas);
assert(skeletonData != 0);
stateData = NEW(AnimationStateData);
new (stateData) AnimationStateData(*skeletonData);
assert(stateData != 0);
stateData->setDefaultMix(0.2f); // force mixing
///////////////////////////////////////////////////////////////////////////
// Animation Instance
skeleton = NEW(Skeleton);
new (skeleton) Skeleton(*skeletonData);
assert(skeleton != 0);
state = NEW(AnimationState);
new (state) AnimationState(*stateData);
assert(state != 0);
}
static void disposeAll(Skeleton* skeleton, AnimationState* state, AnimationStateData* stateData, SkeletonData* skeletonData, Atlas* atlas)
{
///////////////////////////////////////////////////////////////////////////
// Dispose Instance
DESTROY(Skeleton, skeleton);
DESTROY(AnimationState, state);
///////////////////////////////////////////////////////////////////////////
// Dispose Global
DESTROY(AnimationStateData, stateData);
DESTROY(SkeletonData, skeletonData);
DESTROY(Atlas, atlas);
}
//////////////////////////////////////////////////////////////////////////
// Reproduce Memory leak as described in Issue #776
// https://github.com/EsotericSoftware/spine-runtimes/issues/776
static void reproduceIssue_776()
{
Atlas* atlas = NULL;
SkeletonData* skeletonData = NULL;
AnimationStateData* stateData = NULL;
Skeleton* skeleton = NULL;
AnimationState* state = NULL;
//////////////////////////////////////////////////////////////////////////
// Initialize Animations
loadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
///////////////////////////////////////////////////////////////////////////
// Run animation
skeleton->setToSetupPose();
InterruptMonitor eventMonitor(state);
// Interrupt the animation on this specific sequence of spEventType(s)
eventMonitor
.AddInterruptEvent(EventType_Interrupt, "jump")
.AddInterruptEvent(EventType_Start);
state->setAnimation(0, "walk", true);
state->addAnimation(0, "jump", false, 0.0f);
state->addAnimation(0, "run", true, 0.0f);
state->addAnimation(0, "jump", false, 3.0f);
state->addAnimation(0, "walk", true, 0.0f);
state->addAnimation(0, "idle", false, 1.0f);
for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i)
{
const float timeSlice = 1.0f / 60.0f;
skeleton->update(timeSlice);
state->update(timeSlice);
state->apply(*skeleton);
}
//////////////////////////////////////////////////////////////////////////
// Cleanup Animations
disposeAll(skeleton, state, stateData, skeletonData, atlas);
}
static void reproduceIssue_777()
{
Atlas* atlas = NULL;
SkeletonData* skeletonData = NULL;
AnimationStateData* stateData = NULL;
Skeleton* skeleton = NULL;
AnimationState* state = NULL;
//////////////////////////////////////////////////////////////////////////
// Initialize Animations
loadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
///////////////////////////////////////////////////////////////////////////
// Run animation
skeleton->setToSetupPose();
SpineEventMonitor eventMonitor(state);
// Set Animation and Play for 5 frames
state->setAnimation(0, "walk", true);
for (int i = 0; i < 5; ++i)
{
const float timeSlice = 1.0f / 60.0f;
skeleton->update(timeSlice);
state->update(timeSlice);
state->apply(*skeleton);
}
// Change animation twice in a row
state->setAnimation(0, "walk", false);
state->setAnimation(0, "run", false);
// run normal update
for (int i = 0; i < 5; ++i)
{
const float timeSlice = 1.0f / 60.0f;
skeleton->update(timeSlice);
state->update(timeSlice);
state->apply(*skeleton);
}
// Now we'd lose mixingFrom (the first "walk" entry we set above) and should leak
state->setAnimation(0, "run", false);
//////////////////////////////////////////////////////////////////////////
// Cleanup Animations
disposeAll(skeleton, state, stateData, skeletonData, atlas);
}
static void spineAnimStateHandler(AnimationState* state, EventType type, TrackEntry* entry, Event* event)
{
if (type == EventType_Complete)
{
state->setAnimation(0, "walk", false);
state->update(0);
state->apply(*skeleton);
}
}
static void reproduceIssue_Loop()
{
Atlas* atlas = NULL;
SkeletonData* skeletonData = NULL;
AnimationStateData* stateData = NULL;
AnimationState* state = NULL;
//////////////////////////////////////////////////////////////////////////
// Initialize Animations
loadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
///////////////////////////////////////////////////////////////////////////
if (state)
{
state->setOnAnimationEventFunc(spineAnimStateHandler);
}
state->setAnimation(0, "walk", false);
// run normal update
for (int i = 0; i < 50; ++i)
{
const float timeSlice = 1.0f / 60.0f;
skeleton->update(timeSlice);
state->update(timeSlice);
state->apply(*skeleton);
}
disposeAll(skeleton, state, stateData, skeletonData, atlas);
}
static void triangulator()
{
Triangulator* triangulator = NEW(Triangulator);
new (triangulator) Triangulator();
Vector<float> polygon;
polygon.reserve(16);
polygon.push_back(0);
polygon.push_back(0);
polygon.push_back(100);
polygon.push_back(0);
polygon.push_back(100);
polygon.push_back(100);
polygon.push_back(0);
polygon.push_back(100);
Vector<int> triangles = triangulator->triangulate(polygon);
assert(triangles.size() == 6);
assert(triangles[0] == 3);
assert(triangles[1] == 0);
assert(triangles[2] == 1);
assert(triangles[3] == 3);
assert(triangles[4] == 1);
assert(triangles[5] == 2);
Vector< Vector<float> *> polys = triangulator->decompose(polygon, triangles);
assert(polys.size() == 1);
assert(polys[0]->size() == 8);
assert(polys[0]->operator[](0) == 0);
assert(polys[0]->operator[](1) == 100);
assert(polys[0]->operator[](2) == 0);
assert(polys[0]->operator[](3) == 0);
assert(polys[0]->operator[](4) == 100);
assert(polys[0]->operator[](5) == 0);
assert(polys[0]->operator[](6) == 100);
assert(polys[0]->operator[](7) == 100);
DESTROY(Triangulator, triangulator);
}
static void skeletonClipper()
{
Atlas* atlas = NULL;
SkeletonData* skeletonData = NULL;
AnimationStateData* stateData = NULL;
Skeleton* skeleton = NULL;
AnimationState* state = NULL;
//////////////////////////////////////////////////////////////////////////
// Initialize Animations
loadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
SkeletonClipping* clipping = NEW(SkeletonClipping);
new (clipping) SkeletonClipping();
BoneData* boneData = NEW(BoneData);
new (boneData) BoneData(0, "bone", 0);
Bone* bone = NEW(Bone);
new(bone) Bone(*boneData, *skeleton, NULL);
bone->setA(1);
bone->setB(0);
bone->setC(0);
bone->setD(1);
bone->setWorldX(0);
bone->setWorldY(0);
SlotData* slotData = NEW(SlotData);
new (slotData) SlotData(0, "slot", *boneData);
Slot* slot = NEW(Slot);
new(slot) Slot(*slotData, *bone);
ClippingAttachment* clip = NEW(ClippingAttachment);
new(clip) ClippingAttachment("clipping");
clip->setEndSlot(slotData);
clip->setWorldVerticesLength(4 * 2);
Vector<float> clipVertices;
clipVertices.reserve(8);
clipVertices.setSize(8);
clip->setVertices(clipVertices);
clip->getVertices()[0] = 0;
clip->getVertices()[1] = 50;
clip->getVertices()[2] = 100;
clip->getVertices()[3] = 50;
clip->getVertices()[4] = 100;
clip->getVertices()[5] = 70;
clip->getVertices()[6] = 0;
clip->getVertices()[7] = 70;
clipping->clipStart(*slot, clip);
Vector<float> vertices;
vertices.reserve(16);
vertices.push_back(0);
vertices.push_back(0);
vertices.push_back(100);
vertices.push_back(0);
vertices.push_back(50);
vertices.push_back(150);
Vector<float> uvs;
uvs.reserve(16);
uvs.push_back(0);
uvs.push_back(0);
uvs.push_back(1);
uvs.push_back(0);
uvs.push_back(0.5f);
uvs.push_back(1);
Vector<int> indices;
indices.reserve(16);
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
clipping->clipTriangles(vertices, static_cast<int>(vertices.size()), indices, static_cast<int>(indices.size()), uvs);
float expectedVertices[8] = { 83.333328, 50.000000, 76.666664, 70.000000, 23.333334, 70.000000, 16.666672, 50.000000 };
assert(clipping->getClippedVertices().size() == 8);
for (int i = 0; i < clipping->getClippedVertices().size(); i++)
{
assert(abs(clipping->getClippedVertices()[i] - expectedVertices[i]) < 0.001);
}
float expectedUVs[8] = { 0.833333f, 0.333333, 0.766667, 0.466667, 0.233333, 0.466667, 0.166667, 0.333333 };
assert(clipping->getClippedUVs().size() == 8);
for (int i = 0; i < clipping->getClippedUVs().size(); i++)
{
assert(abs(clipping->getClippedUVs()[i] - expectedUVs[i]) < 0.001);
}
short expectedIndices[6] = { 0, 1, 2, 0, 2, 3 };
assert(clipping->getClippedTriangles().size() == 6);
for (int i = 0; i < clipping->getClippedTriangles().size(); i++)
{
assert(clipping->getClippedTriangles()[i] == expectedIndices[i]);
}
DESTROY(SlotData, slotData);
DESTROY(Slot, slot);
DESTROY(BoneData, boneData);
DESTROY(Bone, bone);
DESTROY(ClippingAttachment, clip);
DESTROY(SkeletonClipping, clipping);
//////////////////////////////////////////////////////////////////////////
// Cleanup Animations
disposeAll(skeleton, state, stateData, skeletonData, atlas);
}
static void test()
{
reproduceIssue_776();
reproduceIssue_777();
reproduceIssue_Loop();
triangulator();
skeletonClipper();
}
private:
static Skeleton* skeleton;
// ctor, copy ctor, and assignment should be private in a Singleton
MemoryTest();
MemoryTest(const MemoryTest&);
MemoryTest& operator=(const MemoryTest&);
};
}
Skeleton* MemoryTest::skeleton = NULL;
#endif /* MemoryTest_h */

View File

@ -1,6 +1,6 @@
// //
// SimpleTest.h // SimpleTest.h
// TestHarness // spine_unit_test
// //
// Created by Stephen Gowen on 11/9/17. // Created by Stephen Gowen on 11/9/17.
// Copyright © 2017 Noctis Games. All rights reserved. // Copyright © 2017 Noctis Games. All rights reserved.

View File

@ -19,6 +19,7 @@
#include "spine/Extension.h" #include "spine/Extension.h"
#include "SimpleTest.h" #include "SimpleTest.h"
#include "MemoryTest.h"
#include "KMemory.h" // last include #include "KMemory.h" // last include
@ -101,6 +102,7 @@ int main(int argc, char* argv[])
#endif #endif
SimpleTest::test(); SimpleTest::test();
MemoryTest::test();
// End Timing // End Timing
time(&end_time); time(&end_time);

View File

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

View File

@ -116,7 +116,7 @@ InterruptMonitor& InterruptMonitor::AddInterruptEvent(int theEventType, TrackEnt
InterruptMonitor& InterruptMonitor::AddInterruptEventTrigger(const std::string & theEventTriggerName) InterruptMonitor& InterruptMonitor::AddInterruptEventTrigger(const std::string & theEventTriggerName)
{ {
InterruptEvent ev; InterruptEvent ev;
// ev.mEventType = SP_ANIMATION_EVENT; ev.mEventType = EventType_Event;
ev.mEventName = theEventTriggerName; ev.mEventName = theEventTriggerName;
mEventStack.push_back(ev); mEventStack.push_back(ev);
return *this; return *this;
@ -143,7 +143,7 @@ void InterruptMonitor::OnSpineAnimationStateEvent(AnimationState * state, EventT
inline bool InterruptMonitor::InterruptEvent::matches(AnimationState * state, EventType type, TrackEntry * trackEntry, Event * event) inline bool InterruptMonitor::InterruptEvent::matches(AnimationState * state, EventType type, TrackEntry * trackEntry, Event * event)
{ {
// Must match spEventType {SP_ANIMATION_START, SP_ANIMATION_INTERRUPT, SP_ANIMATION_END, SP_ANIMATION_COMPLETE, SP_ANIMATION_DISPOSE, SP_ANIMATION_EVENT } // Must match EventType {EventType_Start, EventType_Interrupt, EventType_End, EventType_Complete, EventType_Dispose, EventType_Event }
if (mEventType == type) if (mEventType == type)
{ {
// Looking for specific TrackEntry by pointer // Looking for specific TrackEntry by pointer

View File

@ -162,12 +162,18 @@ namespace Spine
void setAShearY(float inValue); void setAShearY(float inValue);
float getA(); float getA();
void setA(float inValue);
float getB(); float getB();
void setB(float inValue);
float getC(); float getC();
void setC(float inValue);
float getD(); float getD();
void setD(float inValue);
float getWorldX(); float getWorldX();
void setWorldX(float inValue);
float getWorldY(); float getWorldY();
void setWorldY(float inValue);
float getWorldRotationX(); float getWorldRotationX();
float getWorldRotationY(); float getWorldRotationY();

View File

@ -54,6 +54,10 @@ namespace Spine
bool isClipping(); bool isClipping();
Vector<float>& getClippedVertices();
Vector<int>& getClippedTriangles();
Vector<float>& getClippedUVs();
private: private:
Triangulator _triangulator; Triangulator _triangulator;
Vector<float> _clippingPolygon; Vector<float> _clippingPolygon;

View File

@ -66,6 +66,7 @@ namespace Spine
{ {
clear(); clear();
deallocate(_buffer); deallocate(_buffer);
_buffer = NULL;
_size = inVector._size; _size = inVector._size;
_capacity = inVector._capacity; _capacity = inVector._capacity;
@ -194,6 +195,8 @@ namespace Spine
void setSize(size_t inValue) void setSize(size_t inValue)
{ {
assert(inValue <= _capacity);
_size = inValue; _size = inValue;
} }

View File

@ -230,7 +230,7 @@ namespace Spine
_timelineDipMix.clear(); _timelineDipMix.clear();
_timelinesRotation.clear(); _timelinesRotation.clear();
_onAnimationEventFunc = NULL; _onAnimationEventFunc = dummyOnAnimationEventFunc;
} }
EventQueueEntry::EventQueueEntry(EventType eventType, TrackEntry* trackEntry, Event* event) : EventQueueEntry::EventQueueEntry(EventType eventType, TrackEntry* trackEntry, Event* event) :

View File

@ -521,31 +521,61 @@ namespace Spine
return _a; return _a;
} }
void Bone::setA(float inValue)
{
_a = inValue;
}
float Bone::getB() float Bone::getB()
{ {
return _b; return _b;
} }
void Bone::setB(float inValue)
{
_b = inValue;
}
float Bone::getC() float Bone::getC()
{ {
return _c; return _c;
} }
void Bone::setC(float inValue)
{
_c = inValue;
}
float Bone::getD() float Bone::getD()
{ {
return _d; return _d;
} }
void Bone::setD(float inValue)
{
_d = inValue;
}
float Bone::getWorldX() float Bone::getWorldX()
{ {
return _worldX; return _worldX;
} }
void Bone::setWorldX(float inValue)
{
_worldX = inValue;
}
float Bone::getWorldY() float Bone::getWorldY()
{ {
return _worldY; return _worldY;
} }
void Bone::setWorldY(float inValue)
{
_worldY = inValue;
}
float Bone::getWorldRotationX() float Bone::getWorldRotationX()
{ {
return MathUtil::atan2(_c, _a) * RadDeg; return MathUtil::atan2(_c, _a) * RadDeg;

View File

@ -54,6 +54,7 @@ namespace Spine
int n = clip->getWorldVerticesLength(); int n = clip->getWorldVerticesLength();
_clippingPolygon.reserve(n); _clippingPolygon.reserve(n);
_clippingPolygon.setSize(n);
clip->computeWorldVertices(slot, 0, n, _clippingPolygon, 0, 2); clip->computeWorldVertices(slot, 0, n, _clippingPolygon, 0, 2);
makeClockwise(_clippingPolygon); makeClockwise(_clippingPolygon);
Vector< Vector<float>* > clippingPolygons = _triangulator.decompose(_clippingPolygon, _triangulator.triangulate(_clippingPolygon)); Vector< Vector<float>* > clippingPolygons = _triangulator.decompose(_clippingPolygon, _triangulator.triangulate(_clippingPolygon));
@ -96,7 +97,8 @@ namespace Spine
void SkeletonClipping::clipTriangles(Vector<float>& vertices, int verticesLength, Vector<int>& triangles, int trianglesLength, Vector<float>& uvs) void SkeletonClipping::clipTriangles(Vector<float>& vertices, int verticesLength, Vector<int>& triangles, int trianglesLength, Vector<float>& uvs)
{ {
Vector<float>& clipOutput = _clipOutput, clippedVertices = _clippedVertices; Vector<float>& clipOutput = _clipOutput;
Vector<float>& clippedVertices = _clippedVertices;
Vector<int>& clippedTriangles = _clippedTriangles; Vector<int>& clippedTriangles = _clippedTriangles;
Vector< Vector<float>* >& polygons = _clippingPolygons; Vector< Vector<float>* >& polygons = _clippingPolygons;
int polygonsCount = static_cast<int>(_clippingPolygons.size()); int polygonsCount = static_cast<int>(_clippingPolygons.size());
@ -135,7 +137,9 @@ namespace Spine
int clipOutputCount = clipOutputLength >> 1; int clipOutputCount = clipOutputLength >> 1;
clippedVertices.reserve(s + clipOutputCount * 2); clippedVertices.reserve(s + clipOutputCount * 2);
clippedVertices.setSize(s + clipOutputCount * 2);
_clippedUVs.reserve(s + clipOutputCount * 2); _clippedUVs.reserve(s + clipOutputCount * 2);
_clippedUVs.setSize(s + clipOutputCount * 2);
for (int ii = 0; ii < clipOutputLength; ii += 2) for (int ii = 0; ii < clipOutputLength; ii += 2)
{ {
float x = clipOutput[ii], y = clipOutput[ii + 1]; float x = clipOutput[ii], y = clipOutput[ii + 1];
@ -152,6 +156,7 @@ namespace Spine
s = static_cast<int>(clippedTriangles.size()); s = static_cast<int>(clippedTriangles.size());
clippedTriangles.reserve(s + 3 * (clipOutputCount - 2)); clippedTriangles.reserve(s + 3 * (clipOutputCount - 2));
clippedTriangles.setSize(s + 3 * (clipOutputCount - 2));
clipOutputCount--; clipOutputCount--;
for (int ii = 1; ii < clipOutputCount; ii++) for (int ii = 1; ii < clipOutputCount; ii++)
{ {
@ -165,7 +170,9 @@ namespace Spine
else else
{ {
clippedVertices.reserve(s + 3 * 2); clippedVertices.reserve(s + 3 * 2);
clippedVertices.setSize(s + 3 * 2);
_clippedUVs.reserve(s + 3 * 2); _clippedUVs.reserve(s + 3 * 2);
_clippedUVs.setSize(s + 3 * 2);
clippedVertices[s] = x1; clippedVertices[s] = x1;
clippedVertices[s + 1] = y1; clippedVertices[s + 1] = y1;
clippedVertices[s + 2] = x2; clippedVertices[s + 2] = x2;
@ -182,6 +189,7 @@ namespace Spine
s = static_cast<int>(clippedTriangles.size()); s = static_cast<int>(clippedTriangles.size());
clippedTriangles.reserve(s + 3); clippedTriangles.reserve(s + 3);
clippedTriangles.setSize(s + 3);
clippedTriangles[s] = index; clippedTriangles[s] = index;
clippedTriangles[s + 1] = index + 1; clippedTriangles[s + 1] = index + 1;
clippedTriangles[s + 2] = index + 2; clippedTriangles[s + 2] = index + 2;
@ -197,9 +205,24 @@ namespace Spine
return _clipAttachment != NULL; return _clipAttachment != NULL;
} }
Vector<float>& SkeletonClipping::getClippedVertices()
{
return _clippedVertices;
}
Vector<int>& SkeletonClipping::getClippedTriangles()
{
return _clippedTriangles;
}
Vector<float>& SkeletonClipping::getClippedUVs()
{
return _clippedUVs;
}
bool SkeletonClipping::clip(float x1, float y1, float x2, float y2, float x3, float y3, Vector<float>& clippingArea, Vector<float>& output) bool SkeletonClipping::clip(float x1, float y1, float x2, float y2, float x3, float y3, Vector<float>& clippingArea, Vector<float>& output)
{ {
Vector<float> originalOutput = output; Vector<float>& originalOutput = output;
bool clipped = false; bool clipped = false;
// Avoid copy at the end. // Avoid copy at the end.
@ -225,7 +248,7 @@ namespace Spine
input.push_back(y1); input.push_back(y1);
output.clear(); output.clear();
Vector<float> clippingVertices = clippingArea; Vector<float>& clippingVertices = clippingArea;
int clippingVerticesLast = static_cast<int>(clippingArea.size()) - 4; int clippingVerticesLast = static_cast<int>(clippingArea.size()) - 4;
for (int i = 0; ; i += 2) for (int i = 0; ; i += 2)
{ {
@ -233,7 +256,7 @@ namespace Spine
float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
Vector<float> inputVertices = input; Vector<float>& inputVertices = input;
int inputVerticesLength = static_cast<int>(input.size()) - 2, outputStart = static_cast<int>(output.size()); int inputVerticesLength = static_cast<int>(input.size()) - 2, outputStart = static_cast<int>(output.size());
for (int ii = 0; ii < inputVerticesLength; ii += 2) for (int ii = 0; ii < inputVerticesLength; ii += 2)
{ {
@ -299,6 +322,7 @@ namespace Spine
else else
{ {
originalOutput.reserve(originalOutput.size() - 2); originalOutput.reserve(originalOutput.size() - 2);
originalOutput.setSize(originalOutput.size() - 2);
} }
return clipped; return clipped;