From 7488383b151f63b7d3e95247d9a973751ff82fff Mon Sep 17 00:00:00 2001 From: badlogic Date: Mon, 26 Jun 2017 15:00:59 +0200 Subject: [PATCH] [cocos2dx] Added support for vertex effects. See #898 --- CHANGELOG.md | 3 + spine-c/spine-c/include/spine/extension.h | 2 +- .../example/Classes/RaptorExample.cpp | 18 +- .../example/Classes/RaptorExample.h | 3 + .../example/proj.android/jni/Android.mk | 1 + .../example/proj.ios_mac/VertexEffect.c | 98 +++++++++ .../spine-cocos2d-x.xcodeproj/project.pbxproj | 6 + .../proj.win32/spine-cocos2d-x.vcxproj | 1 + spine-cocos2dx/src/spine/SkeletonRenderer.cpp | 200 ++++++++++++++---- spine-cocos2dx/src/spine/SkeletonRenderer.h | 6 +- 10 files changed, 291 insertions(+), 47 deletions(-) create mode 100644 spine-cocos2dx/example/proj.ios_mac/VertexEffect.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9ff6683..d88f246d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ * Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments. * `AnimationState#apply` returns boolean indicating if any timeline was applied or not. * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans + * Added `spVertexEffect` and corresponding implementations `spJitterVertexEffect` and `spSwirlVertexEffect`. Create/dispose through the corresponding `spXXXVertexEffect_create()/dispose()` functions. Set on framework/engine specific renderer. See changes for spine-c based frameworks/engines below. ### Cocos2d-X * Fixed renderer to work with 3.6 changes @@ -55,6 +56,7 @@ * Added mesh debug rendering. Enable/Disable via `SkeletonRenderer::setDebugMeshesEnabled()`. * Added support for clipping. * SkeletonRenderer now combines the displayed color of the Node (cascaded from all parents) with the skeleton color for tinting. + * Added support for vertex effects. See `RaptorExample.cpp`. ### Cocos2d-Objc * Fixed renderer to work with 3.6 changes @@ -64,6 +66,7 @@ ### SFML * Fixed renderer to work with 3.6 changes. Sadly, two color tinting does not work, as the vertex format in SFML is fixed. * Added support for clipping. + * Added support for vertex effects. See raptor example. ### Unreal Engine 4 * Fixed renderer to work with 3.6 changes diff --git a/spine-c/spine-c/include/spine/extension.h b/spine-c/spine-c/include/spine/extension.h index 021027217..60d8aa803 100644 --- a/spine-c/spine-c/include/spine/extension.h +++ b/spine-c/spine-c/include/spine/extension.h @@ -103,7 +103,7 @@ #define COS(A) cosf(A) #define SQRT(A) sqrtf(A) #define ACOS(A) acosf(A) -#define POW(A,B) pow(A, B); +#define POW(A,B) pow(A, B) #else #define FMOD(A,B) (float)fmod(A, B) #define ATAN2(A,B) (float)atan2(A, B) diff --git a/spine-cocos2dx/example/Classes/RaptorExample.cpp b/spine-cocos2dx/example/Classes/RaptorExample.cpp index d421dfe1d..cfd610a88 100644 --- a/spine-cocos2dx/example/Classes/RaptorExample.cpp +++ b/spine-cocos2dx/example/Classes/RaptorExample.cpp @@ -30,10 +30,13 @@ #include "RaptorExample.h" #include "TankExample.h" +#include USING_NS_CC; using namespace spine; +spSwirlVertexEffect* effect = spSwirlVertexEffect_create(400); + Scene* RaptorExample::scene () { Scene *scene = Scene::create(); scene->addChild(RaptorExample::create()); @@ -46,7 +49,13 @@ bool RaptorExample::init () { skeletonNode = SkeletonAnimation::createWithJsonFile("raptor-pro.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->setTwoColorTint(true); + + effect->centerY = 200; + swirlTime = 0; + + skeletonNode->setVertexEffect(&effect->super); skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); addChild(skeletonNode); @@ -68,3 +77,10 @@ bool RaptorExample::init () { return true; } + +void RaptorExample::update(float fDelta) { + swirlTime += fDelta; + float percent = fmod(swirlTime, 2); + if (percent > 1) percent = 1 - (percent - 1); + effect->angle = _spMath_interpolate(_spMath_pow2_apply, -60, 60, percent); +} diff --git a/spine-cocos2dx/example/Classes/RaptorExample.h b/spine-cocos2dx/example/Classes/RaptorExample.h index c3c2be041..2eadb9022 100644 --- a/spine-cocos2dx/example/Classes/RaptorExample.h +++ b/spine-cocos2dx/example/Classes/RaptorExample.h @@ -41,9 +41,12 @@ public: CREATE_FUNC(RaptorExample); virtual bool init (); + + virtual void update(float fDelta); private: spine::SkeletonAnimation* skeletonNode; + float swirlTime; }; #endif // _RAPTOREXAMPLE_H_ diff --git a/spine-cocos2dx/example/proj.android/jni/Android.mk b/spine-cocos2dx/example/proj.android/jni/Android.mk index 4503f15d5..876195d72 100755 --- a/spine-cocos2dx/example/proj.android/jni/Android.mk +++ b/spine-cocos2dx/example/proj.android/jni/Android.mk @@ -59,6 +59,7 @@ LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../../../spine-c/spine-c/src/spine/TransformConstraint.c \ ../../../../spine-c/spine-c/src/spine/TransformConstraintData.c \ ../../../../spine-c/spine-c/src/spine/VertexAttachment.c \ + ../../../../spine-c/spine-c/src/spine/VertexEffect.c \ ../../../../spine-c/spine-c/src/spine/extension.c diff --git a/spine-cocos2dx/example/proj.ios_mac/VertexEffect.c b/spine-cocos2dx/example/proj.ios_mac/VertexEffect.c new file mode 100644 index 000000000..68d4d1f68 --- /dev/null +++ b/spine-cocos2dx/example/proj.ios_mac/VertexEffect.c @@ -0,0 +1,98 @@ +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include + +void _spJitterVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) { +} + +void _spJitterVertexEffect_transform(spVertexEffect* self, float* x, float* y, float* u, float* v, spColor* light, spColor* dark) { + spJitterVertexEffect* internal = (spJitterVertexEffect*)self; + float jitterX = internal->jitterX; + float jitterY = internal->jitterY; + (*x) += _spMath_randomTriangular(-jitterX, jitterY); + (*y) += _spMath_randomTriangular(-jitterX, jitterY); +} + +void _spJitterVertexEffect_end(spVertexEffect* self) { +} + +spJitterVertexEffect* spJitterVertexEffect_create(float jitterX, float jitterY) { + spJitterVertexEffect* effect = CALLOC(spJitterVertexEffect, 1); + effect->super.begin = _spJitterVertexEffect_begin; + effect->super.transform = _spJitterVertexEffect_transform; + effect->super.end = _spJitterVertexEffect_end; + effect->jitterX = jitterX; + effect->jitterY = jitterY; + return effect; +} + +void spJitterVertexEffect_dispose(spJitterVertexEffect* effect) { + FREE(effect); +} + +void _spSwirlVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) { + spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self; + internal->worldX = skeleton->x + internal->centerX; + internal->worldY = skeleton->y + internal->centerY; +} + +void _spSwirlVertexEffect_transform(spVertexEffect* self, float* positionX, float* positionY, float* u, float* v, spColor* light, spColor* dark) { + spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self; + float radAngle = internal->angle * DEG_RAD; + float x = *positionX - internal->worldX; + float y = *positionY - internal->worldY; + float dist = SQRT(x * x + y * y); + if (dist < internal->radius) { + float theta = _spMath_interpolate(_spMath_pow2_apply, 0, radAngle, (internal->radius - dist) / internal->radius); + float cosine = COS(theta); + float sine = SIN(theta); + (*positionX) = cosine * x - sine * y + internal->worldX; + (*positionY) = sine * x + cosine * y + internal->worldY; + } +} + +void _spSwirlVertexEffect_end(spVertexEffect* self) { +} + +spSwirlVertexEffect* spSwirlVertexEffect_create(float radius) { + spSwirlVertexEffect* effect = CALLOC(spSwirlVertexEffect, 1); + effect->super.begin = _spSwirlVertexEffect_begin; + effect->super.transform = _spSwirlVertexEffect_transform; + effect->super.end = _spSwirlVertexEffect_end; + effect->radius = radius; + return effect; +} + +void spSwirlVertexEffect_dispose(spSwirlVertexEffect* effect) { + FREE(effect); +} + diff --git a/spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj b/spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj index f3ca62892..8b6a40892 100644 --- a/spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj +++ b/spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj @@ -170,6 +170,8 @@ 76FAC18D1E3F97D2001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */; }; 76FAC18F1E3F98A0001CCC8C /* Color.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18A1E3F97D2001CCC8C /* Color.c */; }; 76FAC1901E3F98A0001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */; }; + 76FB150F1F01377200C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB150E1F01377200C5377F /* VertexEffect.c */; }; + 76FB15111F0139B400C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB150E1F01377200C5377F /* VertexEffect.c */; }; 8262943E1AAF051F00CB7CF7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8262943D1AAF051F00CB7CF7 /* Security.framework */; }; BF171245129291EC00B8313A /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF170DB012928DE900B8313A /* OpenGLES.framework */; }; BF1712471292920000B8313A /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BF170DB412928DE900B8313A /* libz.dylib */; }; @@ -335,6 +337,7 @@ 76F5BD541D2BD7D3005917E5 /* TankExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TankExample.h; sourceTree = ""; }; 76FAC18A1E3F97D2001CCC8C /* Color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Color.c; path = "../../../spine-c/spine-c/src/spine/Color.c"; sourceTree = ""; }; 76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PointAttachment.c; path = "../../../spine-c/spine-c/src/spine/PointAttachment.c"; sourceTree = ""; }; + 76FB150E1F01377200C5377F /* VertexEffect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = VertexEffect.c; sourceTree = ""; }; 8262943D1AAF051F00CB7CF7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; BF170DB012928DE900B8313A /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; BF170DB412928DE900B8313A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; @@ -552,6 +555,7 @@ 76AAA3B21D180F7300C54FCB /* spine */ = { isa = PBXGroup; children = ( + 76FB150E1F01377200C5377F /* VertexEffect.c */, 76D520E11EB3625700572471 /* Array.c */, 76D520D71EB3611300572471 /* ClippingAttachment.c */, 76D520D81EB3611300572471 /* SkeletonClipping.c */, @@ -803,6 +807,7 @@ 76F28CB81DEC7EBB00CDE54D /* Bone.c in Sources */, 76F28CB61DEC7EBB00CDE54D /* Attachment.c in Sources */, 503AE10217EB989F00D1A890 /* RootViewController.mm in Sources */, + 76FB150F1F01377200C5377F /* VertexEffect.c in Sources */, 503AE10117EB989F00D1A890 /* main.m in Sources */, 76D520DB1EB3611300572471 /* SkeletonClipping.c in Sources */, 76F28CCB1DEC7EBB00CDE54D /* Skin.c in Sources */, @@ -820,6 +825,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 76FB15111F0139B400C5377F /* VertexEffect.c in Sources */, 76D520E71EB3634600572471 /* CoinExample.cpp in Sources */, 76D520E31EB3625B00572471 /* Array.c in Sources */, 76D520DE1EB3619800572471 /* ClippingAttachment.c in Sources */, diff --git a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj index 917041d6a..3711efd27 100644 --- a/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj +++ b/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj @@ -179,6 +179,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y + diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index 271d6a30b..e9fdfa13b 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -77,21 +77,21 @@ void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsS } SkeletonRenderer::SkeletonRenderer () - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) { + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) { } SkeletonRenderer::SkeletonRenderer (spSkeletonData *skeletonData, bool ownsSkeletonData) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) { + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) { initWithData(skeletonData, ownsSkeletonData); } SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) { + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) { initWithJsonFile(skeletonDataFile, atlas, scale); } SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) { + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) { initWithJsonFile(skeletonDataFile, atlasFile, scale); } @@ -183,6 +183,8 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t SkeletonBatch* batch = SkeletonBatch::getInstance(); SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance(); bool isTwoColorTint = this->isTwoColorTint(); + + if (_effect) _effect->begin(_effect, _skeleton); Color4F nodeColor; nodeColor.r = getDisplayedColor().r / (float)255; @@ -321,26 +323,70 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t 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; + if (_effect) { + spColor light; + spColor dark; + light.r = color.r / 255.0f; + light.g = color.g / 255.0f; + light.b = color.b / 255.0f; + light.a = color.a / 255.0f; + dark.r = dark.g = dark.b = dark.a = 0; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) { + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v; + spColor lightCopy = light; + spColor darkCopy = dark; + vertex->vertices.x = verts[vv]; + vertex->vertices.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + _effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy); + vertex->colors.r = (GLubyte)(lightCopy.r * 255); + vertex->colors.g = (GLubyte)(lightCopy.g * 255); + vertex->colors.b = (GLubyte)(lightCopy.b * 255); + vertex->colors.a = (GLubyte)(lightCopy.a * 255); + } + } else { + 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; + if (_effect) { + spColor light; + spColor dark; + light.r = color.r / 255.0f; + light.g = color.g / 255.0f; + light.b = color.b / 255.0f; + light.a = color.a / 255.0f; + dark.r = dark.g = dark.b = dark.a = 0; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) { + V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v; + spColor lightCopy = light; + spColor darkCopy = dark; + _effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy); + vertex->colors.r = (GLubyte)(lightCopy.r * 255); + vertex->colors.g = (GLubyte)(lightCopy.g * 255); + vertex->colors.b = (GLubyte)(lightCopy.b * 255); + vertex->colors.a = (GLubyte)(lightCopy.a * 255); + } + } else { + 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 { @@ -361,34 +407,94 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t 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; + + if (_effect) { + spColor light; + spColor dark; + light.r = color.r / 255.0f; + light.g = color.g / 255.0f; + light.b = color.b / 255.0f; + light.a = color.a / 255.0f; + dark.r = darkColor.r / 255.0f; + dark.g = darkColor.g / 255.0f; + dark.b = darkColor.b / 255.0f; + dark.a = darkColor.a / 255.0f; + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v; + spColor lightCopy = light; + spColor darkCopy = dark; + vertex->position.x = verts[vv]; + vertex->position.y = verts[vv + 1]; + vertex->texCoords.u = uvs[vv]; + vertex->texCoords.v = uvs[vv + 1]; + _effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy); + vertex->color.r = (GLubyte)(lightCopy.r * 255); + vertex->color.g = (GLubyte)(lightCopy.g * 255); + vertex->color.b = (GLubyte)(lightCopy.b * 255); + vertex->color.a = (GLubyte)(lightCopy.a * 255); + vertex->color2.r = (GLubyte)(darkCopy.r * 255); + vertex->color2.g = (GLubyte)(darkCopy.g * 255); + vertex->color2.b = (GLubyte)(darkCopy.b * 255); + vertex->color2.a = 1; + } + } else { + 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; + if (_effect) { + spColor light; + spColor dark; + light.r = color.r / 255.0f; + light.g = color.g / 255.0f; + light.b = color.b / 255.0f; + light.a = color.a / 255.0f; + dark.r = darkColor.r / 255.0f; + dark.g = darkColor.g / 255.0f; + dark.b = darkColor.b / 255.0f; + dark.a = darkColor.a / 255.0f; + + for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) { + V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v; + spColor lightCopy = light; + spColor darkCopy = dark; + _effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy); + vertex->color.r = (GLubyte)(lightCopy.r * 255); + vertex->color.g = (GLubyte)(lightCopy.g * 255); + vertex->color.b = (GLubyte)(lightCopy.b * 255); + vertex->color.a = (GLubyte)(lightCopy.a * 255); + vertex->color2.r = (GLubyte)(darkCopy.r * 255); + vertex->color2.g = (GLubyte)(darkCopy.g * 255); + vertex->color2.b = (GLubyte)(darkCopy.b * 255); + vertex->color2.a = 1; + } + } else { + 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; + } } } } @@ -432,6 +538,8 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t } } } + + if (_effect) _effect->end(_effect); if (_debugSlots || _debugBones || _debugMeshes) { drawDebug(renderer, transform, transformFlags); @@ -595,6 +703,10 @@ void SkeletonRenderer::setTwoColorTint(bool enabled) { bool SkeletonRenderer::isTwoColorTint() { return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState(); } + +void SkeletonRenderer::setVertexEffect(spVertexEffect *effect) { + this->_effect = effect; +} spSkeleton* SkeletonRenderer::getSkeleton () { return _skeleton; diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.h b/spine-cocos2dx/src/spine/SkeletonRenderer.h index 99988af93..a8a2d9df1 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.h +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.h @@ -99,6 +99,9 @@ public: void setTwoColorTint(bool enabled); /* Whether two color tinting is enabled */ bool isTwoColorTint(); + + /* Sets the vertex effect to be used, set to 0 to disable vertex effects */ + void setVertexEffect(spVertexEffect* effect); // --- BlendProtocol virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override; @@ -125,7 +128,7 @@ CC_CONSTRUCTOR_ACCESS: protected: void setSkeletonData (spSkeletonData* skeletonData, bool ownsSkeletonData); virtual AttachmentVertices* getAttachmentVertices (spRegionAttachment* attachment) const; - virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const; + virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const; bool _ownsSkeletonData; spAtlas* _atlas; @@ -140,6 +143,7 @@ protected: bool _debugBones; bool _debugMeshes; spSkeletonClipping* _clipper; + spVertexEffect* _effect; }; }