Przeglądaj źródła

[c] Added stride to spSkeletonClipping_clipTriangles. [cocos2dx] Added clipping.

badlogic 8 lat temu
rodzic
commit
676b740269

+ 4 - 0
CHANGELOG.md

@@ -27,6 +27,7 @@
   * Removed `sp_MeshAttachment_computeWorldVertices`, superseded by `spVertexAttachment_computeWorldVertices`.
   * Removed `spBone_worldToLocalRotationX` and `spBone_worldToLocalRotationY`. Replaced by `spBone_worldToLocalRotation` (rotation given relative to x-axis, counter-clockwise, in degrees).
   * Replaced `r`, `g`, `b`, `a` fields with instances of new `spColor` struct in `spRegionAttachment`, `spMeshAttachment`, `spSkeleton`, `spSkeletonData`, `spSlot` and `spSlotData`.
+  * Removed `spVertexIndex`from public API.
  * **Additions**
   * Added support for local and relative transform constraint calculation, including additional fields in `spTransformConstraintData`.  
   * Added `spPointAttachment`, additional method `spAtlasAttachmentLoadeR_newPointAttachment`.
@@ -42,10 +43,12 @@
  * Added support for two color tinting. Tinting is enabled/disabled per `SkeletonRenderer`/`SkeletonAnimation` instance. Use `SkeletonRenderer::setTwoColorTint()`. Note that two color tinting requires the use of a non-standard shader and vertex format. This means that skeletons rendered with two color tinting will break batching. However, skeletons with two color tinting enabled and rendered after each other will be batched.
  * Updated example to use Cocos2d-x 3.14.1.
  * Added mesh debug rendering. Enable/Disable via `SkeletonRenderer::setDebugMeshesEnabled()`.
+ * Added support for clipping.
 
 ### Cocos2d-Objc
  * Fixed renderer to work with 3.6 changes
  * Added support for two color tinting. Tinting is enabled/disabled per `SkeletonRenderer/SkeletonAnimation.twoColorTint = true`. Note that two color tinted skeletons do not batch with other nodes.
+ * Added support for clipping.
 
 ### SFML
  * Fixed renderer to work with 3.6 changes. Sadly, two color tinting does not work, as the vertex format in SFML is fixed.
@@ -53,6 +56,7 @@
 ### Unreal Engine 4
  * Fixed renderer to work with 3.6 changes
  * Added new UPROPERTY to SpineSkeletonRendererComponent called `Color`. This allows to set the tint color of the skeleton in the editor, C++ and Blueprints. Under the hood, the `spSkeleton->color` will be set on every tick of the renderer component.
+ * Added support for clipping.
 
 ## C#
  * **Breaking changes**

+ 0 - 13
spine-c/spine-c/include/spine/RegionAttachment.h

@@ -39,10 +39,6 @@
 extern "C" {
 #endif
 
-typedef enum {
-	SP_VERTEX_X1 = 0, SP_VERTEX_Y1, SP_VERTEX_X2, SP_VERTEX_Y2, SP_VERTEX_X3, SP_VERTEX_Y3, SP_VERTEX_X4, SP_VERTEX_Y4
-} spVertexIndex;
-
 typedef struct spRegionAttachment {
 	spAttachment super;
 	const char* path;
@@ -64,15 +60,6 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self);
 void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices, int offset, int stride);
 
 #ifdef SPINE_SHORT_NAMES
-typedef spVertexIndex VertexIndex;
-#define VERTEX_X1 SP_VERTEX_X1
-#define VERTEX_Y1 SP_VERTEX_Y1
-#define VERTEX_X2 SP_VERTEX_X2
-#define VERTEX_Y2 SP_VERTEX_Y2
-#define VERTEX_X3 SP_VERTEX_X3
-#define VERTEX_Y3 SP_VERTEX_Y3
-#define VERTEX_X4 SP_VERTEX_X4
-#define VERTEX_Y4 SP_VERTEX_Y4
 typedef spRegionAttachment RegionAttachment;
 #define RegionAttachment_create(...) spRegionAttachment_create(__VA_ARGS__)
 #define RegionAttachment_setUVs(...) spRegionAttachment_setUVs(__VA_ARGS__)

+ 1 - 1
spine-c/spine-c/include/spine/SkeletonClipping.h

@@ -57,7 +57,7 @@ int spSkeletonClipping_clipStart(spSkeletonClipping* self, spSlot* slot, spClipp
 void spSkeletonClipping_clipEnd(spSkeletonClipping* self, spSlot* slot);
 void spSkeletonClipping_clipEnd2(spSkeletonClipping* self);
 int /*boolean*/ spSkeletonClipping_isClipping(spSkeletonClipping* self);
-void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices, int verticesLength, unsigned short* triangles, int trianglesLength, float* uvs);
+void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices, int verticesLength, unsigned short* triangles, int trianglesLength, float* uvs, int stride);
 void spSkeletonClipping_dispose(spSkeletonClipping* self);
 
 #ifdef __cplusplus

+ 45 - 32
spine-c/spine-c/src/spine/RegionAttachment.c

@@ -31,6 +31,10 @@
 #include <spine/RegionAttachment.h>
 #include <spine/extension.h>
 
+typedef enum {
+	BLX = 0, BLY, ULX, ULY, URX, URY, BRX, BRY
+} spVertexIndex;
+
 void _spRegionAttachment_dispose (spAttachment* attachment) {
 	spRegionAttachment* self = SUB_CAST(spRegionAttachment, attachment);
 	_spAttachment_deinit(attachment);
@@ -49,23 +53,23 @@ spRegionAttachment* spRegionAttachment_create (const char* name) {
 
 void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate) {
 	if (rotate) {
-		self->uvs[SP_VERTEX_X2] = u;
-		self->uvs[SP_VERTEX_Y2] = v2;
-		self->uvs[SP_VERTEX_X3] = u;
-		self->uvs[SP_VERTEX_Y3] = v;
-		self->uvs[SP_VERTEX_X4] = u2;
-		self->uvs[SP_VERTEX_Y4] = v;
-		self->uvs[SP_VERTEX_X1] = u2;
-		self->uvs[SP_VERTEX_Y1] = v2;
+		self->uvs[URX] = u;
+		self->uvs[URY] = v2;
+		self->uvs[BRX] = u;
+		self->uvs[BRY] = v;
+		self->uvs[BLX] = u2;
+		self->uvs[BLY] = v;
+		self->uvs[ULX] = u2;
+		self->uvs[ULY] = v2;
 	} else {
-		self->uvs[SP_VERTEX_X1] = u;
-		self->uvs[SP_VERTEX_Y1] = v2;
-		self->uvs[SP_VERTEX_X2] = u;
-		self->uvs[SP_VERTEX_Y2] = v;
-		self->uvs[SP_VERTEX_X3] = u2;
-		self->uvs[SP_VERTEX_Y3] = v;
-		self->uvs[SP_VERTEX_X4] = u2;
-		self->uvs[SP_VERTEX_Y4] = v2;
+		self->uvs[ULX] = u;
+		self->uvs[ULY] = v2;
+		self->uvs[URX] = u;
+		self->uvs[URY] = v;
+		self->uvs[BRX] = u2;
+		self->uvs[BRY] = v;
+		self->uvs[BLX] = u2;
+		self->uvs[BLY] = v2;
 	}
 }
 
@@ -86,32 +90,41 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) {
 	float localX2Sin = localX2 * sine;
 	float localY2Cos = localY2 * cosine + self->y;
 	float localY2Sin = localY2 * sine;
-	self->offset[SP_VERTEX_X1] = localXCos - localYSin;
-	self->offset[SP_VERTEX_Y1] = localYCos + localXSin;
-	self->offset[SP_VERTEX_X2] = localXCos - localY2Sin;
-	self->offset[SP_VERTEX_Y2] = localY2Cos + localXSin;
-	self->offset[SP_VERTEX_X3] = localX2Cos - localY2Sin;
-	self->offset[SP_VERTEX_Y3] = localY2Cos + localX2Sin;
-	self->offset[SP_VERTEX_X4] = localX2Cos - localYSin;
-	self->offset[SP_VERTEX_Y4] = localYCos + localX2Sin;
+	self->offset[BLX] = localXCos - localYSin;
+	self->offset[BLY] = localYCos + localXSin;
+	self->offset[ULX] = localXCos - localY2Sin;
+	self->offset[ULY] = localY2Cos + localXSin;
+	self->offset[URX] = localX2Cos - localY2Sin;
+	self->offset[URY] = localY2Cos + localX2Sin;
+	self->offset[BRX] = localX2Cos - localYSin;
+	self->offset[BRY] = localYCos + localX2Sin;
 }
 
 void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices, int offset, int stride) {
 	const float* offsets = self->offset;
 	float x = bone->worldX, y = bone->worldY;
+	float offsetX, offsetY;
 
-	vertices[offset] = offsets[SP_VERTEX_X1] * bone->a + offsets[SP_VERTEX_Y1] * bone->b + x; /* br */
-	vertices[offset + 1] = offsets[SP_VERTEX_X1] * bone->c + offsets[SP_VERTEX_Y1] * bone->d + y;
+	offsetX = offsets[BRX];
+	offsetY = offsets[BRY];
+	vertices[offset] = offsetX * bone->a + offsetY * bone->b + x; /* br */
+	vertices[offset + 1] = offsetX * bone->c + offsetY * bone->d + y;
 	offset += stride;
 
-	vertices[offset] = offsets[SP_VERTEX_X2] * bone->a + offsets[SP_VERTEX_Y2] * bone->b + x; /* bl */
-	vertices[offset + 1] = offsets[SP_VERTEX_X2] * bone->c + offsets[SP_VERTEX_Y2] * bone->d + y;
+	offsetX = offsets[BLX];
+	offsetY = offsets[BLY];
+	vertices[offset] = offsetX * bone->a + offsetY * bone->b + x; /* bl */
+	vertices[offset + 1] = offsetX * bone->c + offsetY * bone->d + y;
 	offset += stride;
 
-	vertices[offset] = offsets[SP_VERTEX_X3] * bone->a + offsets[SP_VERTEX_Y3] * bone->b + x; /* ul */
-	vertices[offset + 1] = offsets[SP_VERTEX_X3] * bone->c + offsets[SP_VERTEX_Y3] * bone->d + y;
+	offsetX = offsets[ULX];
+	offsetY = offsets[ULY];
+	vertices[offset] = offsetX * bone->a + offsetY * bone->b + x; /* ul */
+	vertices[offset + 1] = offsetX * bone->c + offsetY * bone->d + y;
 	offset += stride;
 
-	vertices[offset] = offsets[SP_VERTEX_X4] * bone->a + offsets[SP_VERTEX_Y4] * bone->b + x; /* ur */
-	vertices[offset + 1] = offsets[SP_VERTEX_X4] * bone->c + offsets[SP_VERTEX_Y4] * bone->d + y;
+	offsetX = offsets[URX];
+	offsetY = offsets[URY];
+	vertices[offset] = offsetX * bone->a + offsetY * bone->b + x; /* ur */
+	vertices[offset + 1] = offsetX * bone->c + offsetY * bone->d + y;
 }

+ 8 - 9
spine-c/spine-c/src/spine/SkeletonClipping.c

@@ -206,7 +206,7 @@ int /*boolean*/ _clip(spSkeletonClipping* self, float x1, float y1, float x2, fl
 	return clipped;
 }
 
-void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices, int verticesLength, unsigned short* triangles, int trianglesLength, float* uvs) {
+void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices, int verticesLength, unsigned short* triangles, int trianglesLength, float* uvs, int stride) {
 	int i;
 	spFloatArray* clipOutput = self->clipOutput;
 	spFloatArray* clippedVertices = self->clippedVertices;
@@ -214,7 +214,6 @@ void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices,
 	spUnsignedShortArray* clippedTriangles = self->clippedTriangles;
 	spFloatArray** polygons = self->clippingPolygons->items;
 	int polygonsCount = self->clippingPolygons->size;
-	int vertexSize = 2;
 
 	short index = 0;
 	spFloatArray_clear(clippedVertices);
@@ -223,16 +222,16 @@ void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices,
 	outer:
 	for (i = 0; i < trianglesLength; i += 3) {
 		int p;
-		int vertexOffset = triangles[i] << 1;
+		int vertexOffset = triangles[i] * stride;
 		float x2, y2, u2, v2, x3, y3, u3, v3;
 		float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
 		float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
 
-		vertexOffset = triangles[i + 1] << 1;
+		vertexOffset = triangles[i + 1] * stride;
 		x2 = vertices[vertexOffset]; y2 = vertices[vertexOffset + 1];
 		u2 = uvs[vertexOffset]; v2 = uvs[vertexOffset + 1];
 
-		vertexOffset = triangles[i + 2] << 1;
+		vertexOffset = triangles[i + 2] * stride;
 		x3 = vertices[vertexOffset]; y3 = vertices[vertexOffset + 1];
 		u3 = uvs[vertexOffset]; v3 = uvs[vertexOffset + 1];
 
@@ -254,8 +253,8 @@ void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices,
 
 				clipOutputCount = clipOutputLength >> 1;
 				clipOutputItems = clipOutput->items;
-				clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + clipOutputCount * vertexSize)->items;
-				clippedUVsItems = spFloatArray_setSize(clippedUVs, s + clipOutputCount * vertexSize)->items;
+				clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + (clipOutputCount << 1))->items;
+				clippedUVsItems = spFloatArray_setSize(clippedUVs, s + (clipOutputCount << 1))->items;
 				for (ii = 0; ii < clipOutputLength; ii += 2) {
 					float c0, c1, a, b, c;
 					float x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
@@ -283,8 +282,8 @@ void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices,
 
 			} else {
 				unsigned short* clippedTrianglesItems;
-				float* clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + 3 * vertexSize)->items;
-				float* clippedUVsItems = spFloatArray_setSize(clippedUVs, s + 3 * vertexSize)->items;
+				float* clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + (3 << 1))->items;
+				float* clippedUVsItems = spFloatArray_setSize(clippedUVs, s + (3 << 1))->items;
 				clippedVerticesItems[s] = x1;
 				clippedVerticesItems[s + 1] = y1;
 				clippedVerticesItems[s + 2] = x2;

+ 1 - 1
spine-cocos2d-objc/src/spine/SkeletonRenderer.m

@@ -272,7 +272,7 @@ static bool handlerQueued = false;
 			if (_skipVisibilityCheck || CCRenderCheckVisbility(transform, center, extents)) {
 				
 				if (spSkeletonClipping_isClipping(_clipper)) {
-					spSkeletonClipping_clipTriangles(_clipper, vertices, verticesCount, triangles, trianglesCount, uvs);
+					spSkeletonClipping_clipTriangles(_clipper, vertices, verticesCount, triangles, trianglesCount, uvs, 2);
 					vertices = _clipper->clippedVertices->items;
 					verticesCount = _clipper->clippedVertices->size;
 					uvs = _clipper->clippedUVs->items;

+ 1 - 0
spine-cocos2dx/example/Classes/AppDelegate.cpp

@@ -35,6 +35,7 @@
 
 #include "RaptorExample.h"
 #include "BatchingExample.h"
+#include "CoinExample.h"
 #include "AppMacros.h"
 
 USING_NS_CC;

+ 7 - 4
spine-cocos2dx/example/Classes/BatchingExample.cpp

@@ -34,6 +34,8 @@
 USING_NS_CC;
 using namespace spine;
 
+#define NUM_SKELETONS 50
+
 Scene* BatchingExample::scene () {
 	Scene *scene = Scene::create();
 	scene->addChild(BatchingExample::create());
@@ -65,7 +67,7 @@ bool BatchingExample::init () {
 
 	int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
 	int yMin = 0, yMax = _contentSize.height * 0.7f;
-	for (int i = 0, j = 0; i < 50; i++) {
+	for (int i = 0, j = 0; i < NUM_SKELETONS; i++) {
 		// Each skeleton node shares the same atlas, skeleton data, and mix times.
 		SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
 		skeletonNode->setAnimationStateData(_stateData);
@@ -76,9 +78,10 @@ bool BatchingExample::init () {
 		
 		// alternative setting two color tint for groups of 10 skeletons
 		// should end up with #skeletons / 10 batches
-		if (j++ < 10)
-			skeletonNode->setTwoColorTint(true);
-		if (j == 20) j = 0;
+		// if (j++ < 10)
+//			skeletonNode->setTwoColorTint(true);
+//		if (j == 20) j = 0;
+		// skeletonNode->setTwoColorTint(true);
 
 		skeletonNode->setPosition(Vec2(
 			RandomHelper::random_int(xMin, xMax),

+ 3 - 3
spine-cocos2dx/example/Classes/CoinExample.cpp

@@ -43,10 +43,10 @@ Scene* CoinExample::scene () {
 bool CoinExample::init () {
 	if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false;
 
-	skeletonNode = SkeletonAnimation::createWithJsonFile("coin.json", "coin.atlas", 0.5f);
-	skeletonNode->setAnimation(0, "rotate", true);
+	skeletonNode = SkeletonAnimation::createWithJsonFile("coin.json", "coin.atlas", 1);
+	skeletonNode->setAnimation(0, "rotate", true);	
 
-	skeletonNode->setPosition(Vec2(_contentSize.width / 2, 150));
+	skeletonNode->setPosition(Vec2(_contentSize.width / 2, 100));
 	addChild(skeletonNode);
 
 	scheduleUpdate();

+ 1 - 1
spine-cocos2dx/example/Classes/RaptorExample.cpp

@@ -46,7 +46,7 @@ bool RaptorExample::init () {
 	skeletonNode = SkeletonAnimation::createWithJsonFile("raptor.json", "raptor.atlas", 0.5f);
 	skeletonNode->setAnimation(0, "walk", true);
 	skeletonNode->setAnimation(1, "empty", false);
-	skeletonNode->addAnimation(1, "gungrab", false, 2);
+	skeletonNode->addAnimation(1, "gungrab", false, 2);	
 
 	skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
 	addChild(skeletonNode);

+ 35 - 0
spine-cocos2dx/src/spine/SkeletonBatch.cpp

@@ -58,6 +58,8 @@ SkeletonBatch::SkeletonBatch () {
 		_commandsPool.push_back(new TrianglesCommand());
 	}
 	
+	_indices = spUnsignedShortArray_create(8);
+	
 	reset ();
 		
 	// callback after drawing is finished so we can clear out the batch state
@@ -70,6 +72,8 @@ SkeletonBatch::SkeletonBatch () {
 SkeletonBatch::~SkeletonBatch () {
 	Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
 
+	spUnsignedShortArray_dispose(_indices);
+	
 	for (unsigned int i = 0; i < _commandsPool.size(); i++) {
 		delete _commandsPool[i];
 		_commandsPool[i] = nullptr;
@@ -97,6 +101,36 @@ cocos2d::V3F_C4B_T2F* SkeletonBatch::allocateVertices(uint32_t numVertices) {
 	return vertices;
 }
 	
+void SkeletonBatch::deallocateVertices(uint32_t numVertices) {
+	_numVertices -= numVertices;
+}
+
+	
+unsigned short* SkeletonBatch::allocateIndices(uint32_t numIndices) {	
+	if (_indices->capacity - _indices->size < numIndices) {
+		unsigned short* oldData = _indices->items;
+		int oldSize = _indices->size;
+		spUnsignedShortArray_ensureCapacity(_indices, _indices->size + numIndices);
+		unsigned short* newData = _indices->items;
+		for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
+			TrianglesCommand* command = _commandsPool[i];
+			cocos2d::TrianglesCommand::Triangles& triangles = (cocos2d::TrianglesCommand::Triangles&)command->getTriangles();
+			if (triangles.indices >= oldData && triangles.indices < oldData + oldSize) {
+				triangles.indices = newData + (triangles.indices - oldData);
+			}
+		}
+	}
+	
+	unsigned short* indices = _indices->items + _indices->size;
+	_indices->size += numIndices;
+	return indices;
+}
+
+void SkeletonBatch::deallocateIndices(uint32_t numIndices) {
+	_indices->size -= numIndices;
+}
+
+	
 cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
 	TrianglesCommand* command = nextFreeCommand();
 	command->init(globalOrder, texture, glProgramState, blendType, triangles, mv, flags);
@@ -107,6 +141,7 @@ cocos2d::TrianglesCommand* SkeletonBatch::addCommand(cocos2d::Renderer* renderer
 void SkeletonBatch::reset() {
 	_nextFreeCommand = 0;
 	_numVertices = 0;
+	_indices->size = 0;
 }
 
 cocos2d::TrianglesCommand* SkeletonBatch::nextFreeCommand() {

+ 6 - 0
spine-cocos2dx/src/spine/SkeletonBatch.h

@@ -46,6 +46,9 @@ namespace spine {
         void update (float delta);
 		
 		cocos2d::V3F_C4B_T2F* allocateVertices(uint32_t numVertices);
+		void deallocateVertices(uint32_t numVertices);
+		unsigned short* allocateIndices(uint32_t numIndices);
+		void deallocateIndices(uint32_t numVertices);
 		cocos2d::TrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, cocos2d::Texture2D* texture, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand::Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
         
     protected:
@@ -63,6 +66,9 @@ namespace spine {
 		// pool of vertices
 		std::vector<cocos2d::V3F_C4B_T2F> _vertices;
 		uint32_t _numVertices;
+		
+		// pool of indices
+		spUnsignedShortArray* _indices;
     };
 	
 }

+ 98 - 42
spine-cocos2dx/src/spine/SkeletonRenderer.cpp

@@ -229,15 +229,6 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 			color.b = attachment->color.b;
 			color.a = attachment->color.a;
 			
-			if (slot->darkColor) {
-				darkColor.r = slot->darkColor->r * 255;
-				darkColor.g = slot->darkColor->g * 255;
-				darkColor.b = slot->darkColor->b * 255;
-			} else {
-				darkColor.r = 0;
-				darkColor.g = 0;
-				darkColor.b = 0;
-			}
 			break;
 		}
 		case SP_ATTACHMENT_MESH: {
@@ -262,20 +253,11 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 				spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, (float*)trianglesTwoColor.verts, 0, 7);
 			}
 			
-            color.r = attachment->color.r;
-            color.g = attachment->color.g;
-            color.b = attachment->color.b;
+			color.r = attachment->color.r;
+			color.g = attachment->color.g;
+			color.b = attachment->color.b;
 			color.a = attachment->color.a;
 			
-			if (slot->darkColor) {
-				darkColor.r = slot->darkColor->r * 255;
-				darkColor.g = slot->darkColor->g * 255;
-				darkColor.b = slot->darkColor->b * 255;
-			} else {
-				darkColor.r = 0;
-				darkColor.g = 0;
-				darkColor.b = 0;
-			}
 			break;
 		}
 		case SP_ATTACHMENT_CLIPPING: {
@@ -285,7 +267,17 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 		default:
 			continue;
 		}
-
+		
+		if (slot->darkColor) {
+			darkColor.r = slot->darkColor->r * 255;
+			darkColor.g = slot->darkColor->g * 255;
+			darkColor.b = slot->darkColor->b * 255;
+		} else {
+			darkColor.r = 0;
+			darkColor.g = 0;
+			darkColor.b = 0;
+		}
+		
 		color.a *= _skeleton->color.a * slot->color.a * 255;
 		float multiplier = _premultipliedAlpha ? color.a : 255;
 		color.r *= _skeleton->color.r * slot->color.r * multiplier;
@@ -312,28 +304,92 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 		}
 		
 		if (!isTwoColorTint) {
-			cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
-			
-			for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
-				V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-				vertex->colors.r = (GLubyte)color.r;
-				vertex->colors.g = (GLubyte)color.g;
-				vertex->colors.b = (GLubyte)color.b;
-				vertex->colors.a = (GLubyte)color.a;
+			if (spSkeletonClipping_isClipping(_clipper)) {
+				spSkeletonClipping_clipTriangles(_clipper, (float*)&triangles.verts[0].vertices, triangles.vertCount * sizeof(cocos2d::V3F_C4B_T2F) / 4, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, 6);
+				batch->deallocateVertices(triangles.vertCount);
+				
+				if (_clipper->clippedTriangles->size == 0)
+					continue;
+				
+				triangles.vertCount = _clipper->clippedVertices->size >> 1;
+				triangles.verts = batch->allocateVertices(triangles.vertCount);
+				triangles.indexCount = _clipper->clippedTriangles->size;
+				triangles.indices = batch->allocateIndices(triangles.indexCount);
+				memcpy(triangles.indices, _clipper->clippedTriangles->items, sizeof(unsigned short) * _clipper->clippedTriangles->size);
+				
+				cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
+				
+				float* verts = _clipper->clippedVertices->items;
+				float* uvs = _clipper->clippedUVs->items;
+				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
+					V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+					vertex->vertices.x = verts[vv];
+					vertex->vertices.y = verts[vv + 1];
+					vertex->texCoords.u = uvs[vv];
+					vertex->texCoords.v = uvs[vv + 1];
+					vertex->colors.r = (GLubyte)color.r;
+					vertex->colors.g = (GLubyte)color.g;
+					vertex->colors.b = (GLubyte)color.b;
+					vertex->colors.a = (GLubyte)color.a;
+				}
+			} else {
+				cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
+				
+				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+					V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+					vertex->colors.r = (GLubyte)color.r;
+					vertex->colors.g = (GLubyte)color.g;
+					vertex->colors.b = (GLubyte)color.b;
+					vertex->colors.a = (GLubyte)color.a;
+				}
 			}
 		} else {
-			TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
-			
-			for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
-				V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-				vertex->color.r = (GLubyte)color.r;
-				vertex->color.g = (GLubyte)color.g;
-				vertex->color.b = (GLubyte)color.b;
-				vertex->color.a = (GLubyte)color.a;
-				vertex->color2.r = (GLubyte)darkColor.r;
-				vertex->color2.g = (GLubyte)darkColor.g;
-				vertex->color2.b = (GLubyte)darkColor.b;
-				vertex->color2.a = 1;
+			if (spSkeletonClipping_isClipping(_clipper)) {
+				spSkeletonClipping_clipTriangles(_clipper, (float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, 7);
+				twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount);
+				
+				if (_clipper->clippedTriangles->size == 0)
+					continue;
+				
+				trianglesTwoColor.vertCount = _clipper->clippedVertices->size >> 1;
+				trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount);
+				trianglesTwoColor.indexCount = _clipper->clippedTriangles->size;
+				trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount);
+				memcpy(trianglesTwoColor.indices, _clipper->clippedTriangles->items, sizeof(unsigned short) * _clipper->clippedTriangles->size);
+				
+				TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
+				
+				float* verts = _clipper->clippedVertices->items;
+				float* uvs = _clipper->clippedUVs->items;
+				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
+					V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+					vertex->position.x = verts[vv];
+					vertex->position.y = verts[vv + 1];
+					vertex->texCoords.u = uvs[vv];
+					vertex->texCoords.v = uvs[vv + 1];
+					vertex->color.r = (GLubyte)color.r;
+					vertex->color.g = (GLubyte)color.g;
+					vertex->color.b = (GLubyte)color.b;
+					vertex->color.a = (GLubyte)color.a;
+					vertex->color2.r = (GLubyte)darkColor.r;
+					vertex->color2.g = (GLubyte)darkColor.g;
+					vertex->color2.b = (GLubyte)darkColor.b;
+					vertex->color2.a = 1;
+				}
+			} else {
+				TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
+				
+				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+					V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+					vertex->color.r = (GLubyte)color.r;
+					vertex->color.g = (GLubyte)color.g;
+					vertex->color.b = (GLubyte)color.b;
+					vertex->color.a = (GLubyte)color.a;
+					vertex->color2.r = (GLubyte)darkColor.r;
+					vertex->color2.g = (GLubyte)darkColor.g;
+					vertex->color2.b = (GLubyte)darkColor.b;
+					vertex->color2.a = 1;
+				}
 			}
 		}
 		spSkeletonClipping_clipEnd(_clipper, slot);

+ 35 - 0
spine-cocos2dx/src/spine/SkeletonTwoColorBatch.cpp

@@ -168,6 +168,8 @@ SkeletonTwoColorBatch::SkeletonTwoColorBatch () {
 		_commandsPool.push_back(new TwoColorTrianglesCommand());
 	}
 	
+	_indices = spUnsignedShortArray_create(8);
+	
 	reset ();
 	
 	// callback after drawing is finished so we can clear out the batch state
@@ -193,6 +195,8 @@ SkeletonTwoColorBatch::SkeletonTwoColorBatch () {
 SkeletonTwoColorBatch::~SkeletonTwoColorBatch () {
 	Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION);
 	
+	spUnsignedShortArray_dispose(_indices);
+	
 	for (unsigned int i = 0; i < _commandsPool.size(); i++) {
 		delete _commandsPool[i];
 		_commandsPool[i] = nullptr;
@@ -222,6 +226,36 @@ V3F_C4B_C4B_T2F* SkeletonTwoColorBatch::allocateVertices(uint32_t numVertices) {
 	_numVertices += numVertices;
 	return vertices;
 }
+	
+	
+void SkeletonTwoColorBatch::deallocateVertices(uint32_t numVertices) {
+	_numVertices -= numVertices;
+}
+
+
+unsigned short* SkeletonTwoColorBatch::allocateIndices(uint32_t numIndices) {
+	if (_indices->capacity - _indices->size < numIndices) {
+		unsigned short* oldData = _indices->items;
+		int oldSize =_indices->size;
+		spUnsignedShortArray_ensureCapacity(_indices, _indices->size + numIndices);
+		unsigned short* newData = _indices->items;
+		for (uint32_t i = 0; i < this->_nextFreeCommand; i++) {
+			TwoColorTrianglesCommand* command = _commandsPool[i];
+			TwoColorTriangles& triangles = (TwoColorTriangles&)command->getTriangles();
+			if (triangles.indices >= oldData && triangles.indices < oldData + oldSize) {
+				triangles.indices = newData + (triangles.indices - oldData);
+			}
+		}
+	}
+	
+	unsigned short* indices = _indices->items + _indices->size;
+	_indices->size += numIndices;
+	return indices;
+}
+
+void SkeletonTwoColorBatch::deallocateIndices(uint32_t numIndices) {
+	_indices->size -= numIndices;
+}
 
 TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
 	TwoColorTrianglesCommand* command = nextFreeCommand();
@@ -293,6 +327,7 @@ void SkeletonTwoColorBatch::flush (TwoColorTrianglesCommand* materialCommand) {
 void SkeletonTwoColorBatch::reset() {
 	_nextFreeCommand = 0;
 	_numVertices = 0;
+	_indices->size = 0;
 	_numVerticesBuffer = 0;
 	_numIndicesBuffer = 0;
 	_lastCommand = nullptr;

+ 7 - 0
spine-cocos2dx/src/spine/SkeletonTwoColorBatch.h

@@ -108,6 +108,10 @@ namespace spine {
         void update (float delta);
 
 		V3F_C4B_C4B_T2F* allocateVertices(uint32_t numVertices);
+		void deallocateVertices(uint32_t numVertices);
+		
+		unsigned short* allocateIndices(uint32_t numIndices);
+		void deallocateIndices(uint32_t numIndices);
 
 		TwoColorTrianglesCommand* addCommand(cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags);
 
@@ -135,6 +139,9 @@ namespace spine {
 		std::vector<V3F_C4B_C4B_T2F> _vertices;
 		uint32_t _numVertices;
 		
+		// pool of indices
+		spUnsignedShortArray* _indices;
+		
 		// two color tint shader and state
 		cocos2d::GLProgram* _twoColorTintShader;
 		cocos2d::GLProgramState* _twoColorTintShaderState;

+ 1 - 1
spine-sfml/src/spine/spine-sfml.cpp

@@ -169,7 +169,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 		}
 
 		if (spSkeletonClipping_isClipping(clipper)) {
-			spSkeletonClipping_clipTriangles(clipper, vertices, verticesCount << 1, indices, indicesCount, uvs);
+			spSkeletonClipping_clipTriangles(clipper, vertices, verticesCount << 1, indices, indicesCount, uvs, 2);
 			vertices = clipper->clippedVertices->items;
 			verticesCount = clipper->clippedVertices->size >> 1;
 			uvs = clipper->clippedUVs->items;

+ 1 - 1
spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp

@@ -264,7 +264,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(spSkeleton* Skeleton) {
 		}
 
 		if (spSkeletonClipping_isClipping(clipper)) {
-			spSkeletonClipping_clipTriangles(clipper, attachmentVertices, numVertices << 1, attachmentIndices, numIndices, attachmentUvs);
+			spSkeletonClipping_clipTriangles(clipper, attachmentVertices, numVertices << 1, attachmentIndices, numIndices, attachmentUvs, 2);
 			attachmentVertices = clipper->clippedVertices->items;
 			numVertices = clipper->clippedVertices->size >> 1;
 			attachmentIndices = clipper->clippedTriangles->items;