From e4a029e1a7173e344e638d9559956e1c9e4b29c3 Mon Sep 17 00:00:00 2001 From: badlogic Date: Mon, 5 Mar 2018 16:08:17 +0100 Subject: [PATCH] [cpp] Added VertexEffect. --- spine-cpp/spine-cpp/include/spine/MathUtil.h | 40 +++++ .../spine-cpp/include/spine/VertexEffect.h | 106 +++++++++++++ spine-cpp/spine-cpp/include/spine/spine.h | 1 + spine-cpp/spine-cpp/src/spine/MathUtil.cpp | 21 ++- .../spine-cpp/src/spine/PathConstraint.cpp | 2 +- .../spine-cpp/src/spine/VertexEffect.cpp | 146 ++++++++++++++++++ spine-sfml/cpp/example/main.cpp | 15 +- spine-sfml/cpp/src/spine/spine-sfml.cpp | 89 +++++------ spine-sfml/cpp/src/spine/spine-sfml.h | 2 + 9 files changed, 369 insertions(+), 53 deletions(-) create mode 100644 spine-cpp/spine-cpp/include/spine/VertexEffect.h create mode 100644 spine-cpp/spine-cpp/src/spine/VertexEffect.cpp diff --git a/spine-cpp/spine-cpp/include/spine/MathUtil.h b/spine-cpp/spine-cpp/include/spine/MathUtil.h index b5aeafb4f..34b2448fe 100644 --- a/spine-cpp/spine-cpp/include/spine/MathUtil.h +++ b/spine-cpp/spine-cpp/include/spine/MathUtil.h @@ -81,7 +81,47 @@ public: static float fmod(float a, float b); static bool isNan(float v); + + static float random(); + + static float randomTriangular(float min, float max); + + static float randomTriangular(float min, float max, float mode); + + static float pow(float a, float b); }; + +struct Interpolation { + virtual float apply(float a) = 0; + + virtual float interpolate(float start, float end, float a) { + return start + (end - start) * apply(a); + } +}; + +struct PowInterpolation: public Interpolation { + PowInterpolation(int power): power(power) { + } + + float apply(float a) { + if (a <= 0.5f) return MathUtil::pow(a * 2, power) / 2; + return MathUtil::pow((a - 1) * 2, power) / (power % 2 == 0 ? -2 : 2) + 1; + } + + int power; +}; + +struct PowOutInterpolation: public Interpolation { + PowOutInterpolation(int power): power(power) { + } + + float apply(float a) { + return MathUtil::pow(a - 1, power) * (power % 2 == 0 ? -1 : 1) + 1; + } + + int power; +}; + } #endif /* Spine_MathUtil_h */ diff --git a/spine-cpp/spine-cpp/include/spine/VertexEffect.h b/spine-cpp/spine-cpp/include/spine/VertexEffect.h new file mode 100644 index 000000000..ffbdb97dd --- /dev/null +++ b/spine-cpp/spine-cpp/include/spine/VertexEffect.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef Spine_VertexEffect_h +#define Spine_VertexEffect_h + +#include +#include + +namespace Spine { + +class Skeleton; +class Color; + +class VertexEffect: public SpineObject { +public: + virtual void begin(Skeleton& skeleton) = 0; + virtual void transform(float& x, float& y, float &u, float &v, Color &light, Color &dark) = 0; + virtual void end() = 0; +}; + +class JitterVertexEffect: public VertexEffect { +public: + JitterVertexEffect(float jitterX, float jitterY); + + void begin(Skeleton& skeleton); + void transform(float& x, float& y, float &u, float &v, Color &light, Color &dark); + void end(); + + void setJitterX(float jitterX); + float getJitterX(); + + void setJitterY(float jitterY); + float getJitterY(); + +protected: + float _jitterX; + float _jitterY; +}; + +class SwirlVertexEffect: public VertexEffect { +public: + SwirlVertexEffect(float radius, Interpolation &interpolation); + + void begin(Skeleton& skeleton); + void transform(float& x, float& y, float &u, float &v, Color &light, Color &dark); + void end(); + + void setCenterX(float centerX); + float getCenterX(); + + void setCenterY(float centerY); + float getCenterY(); + + void setRadius(float radius); + float getRadius(); + + void setAngle(float angle); + float getAngle(); + + void setWorldX(float worldX); + float getWorldX(); + + void setWorldY(float worldY); + float getWorldY(); + +protected: + float _centerX; + float _centerY; + float _radius; + float _angle; + float _worldX; + float _worldY; + + Interpolation& _interpolation; +}; +} + +#endif /* Spine_VertexEffect_h */ diff --git a/spine-cpp/spine-cpp/include/spine/spine.h b/spine-cpp/spine-cpp/include/spine/spine.h index 3ca0cf266..8194d1abb 100644 --- a/spine-cpp/spine-cpp/include/spine/spine.h +++ b/spine-cpp/spine-cpp/include/spine/spine.h @@ -105,6 +105,7 @@ #include #include #include +#include #include #endif diff --git a/spine-cpp/spine-cpp/src/spine/MathUtil.cpp b/spine-cpp/spine-cpp/src/spine/MathUtil.cpp index 93de78358..59d53ee8b 100644 --- a/spine-cpp/spine-cpp/src/spine/MathUtil.cpp +++ b/spine-cpp/spine-cpp/src/spine/MathUtil.cpp @@ -31,7 +31,8 @@ #include #include -namespace Spine { +using namespace Spine; + float MathUtil::abs(float v) { return ((v) < 0 ? -(v) : (v)); } @@ -91,4 +92,22 @@ static bool _isNan(float value, float zero) { bool MathUtil::isNan(float v) { return _isNan(v, 0); } + +float MathUtil::random() { + return ::rand() / (float)RAND_MAX; +} + +float MathUtil::randomTriangular(float min, float max) { + return randomTriangular(min, max, (min + max) * 0.5f); +} + +float MathUtil::randomTriangular(float min, float max, float mode) { + float u = random(); + float d = max - min; + if (u <= (mode - min) / d) return min + sqrt(u * d * (mode - min)); + return max - sqrt((1 - u) * d * (max - mode)); +} + +float MathUtil::pow(float a, float b) { + return ::pow(a, b); } diff --git a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp index 44506d96a..ae92b79d8 100644 --- a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp @@ -84,7 +84,7 @@ void PathConstraint::update() { return; } - PathConstraintData data = _data; + PathConstraintData &data = _data; SpacingMode spacingMode = data._spacingMode; bool lengthSpacing = spacingMode == SpacingMode_Length; RotateMode rotateMode = data._rotateMode; diff --git a/spine-cpp/spine-cpp/src/spine/VertexEffect.cpp b/spine-cpp/spine-cpp/src/spine/VertexEffect.cpp new file mode 100644 index 000000000..29e7bf35a --- /dev/null +++ b/spine-cpp/spine-cpp/src/spine/VertexEffect.cpp @@ -0,0 +1,146 @@ +/****************************************************************************** + * 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 +#include + +using namespace Spine; + +JitterVertexEffect::JitterVertexEffect(float jitterX, float jitterY): _jitterX(jitterX), _jitterY(jitterY) { +} + +void JitterVertexEffect::begin(Skeleton &skeleton) { +} + +void JitterVertexEffect::transform(float &x, float &y, float &u, float &v, Color &light, Color &dark) { + float jitterX = _jitterX; + float jitterY = _jitterY; + x += MathUtil::randomTriangular(-jitterX, jitterX); + y += MathUtil::randomTriangular(-jitterX, jitterY); +} + +void JitterVertexEffect::end() { +} + +void JitterVertexEffect::setJitterX(float jitterX) { + _jitterX = jitterX; +} + +float JitterVertexEffect::getJitterX() { + return _jitterX; +} + +void JitterVertexEffect::setJitterY(float jitterY) { + _jitterY = jitterY; +} + +float JitterVertexEffect::getJitterY() { + return _jitterY; +} + +SwirlVertexEffect::SwirlVertexEffect(float radius, Interpolation &interpolation): + _radius(radius), + _interpolation(interpolation), + _centerY(0), + _centerX(0), + _worldX(0), + _worldY(0), + _angle(0) { +} + +void SwirlVertexEffect::begin(Skeleton &skeleton) { + _worldX = skeleton.getX() + _centerX; + _worldY = skeleton.getY() + _centerY; +} + +void SwirlVertexEffect::transform(float &positionX, float &positionY, float &u, float &v, Color &light, Color &dark) { + float x = positionX - _worldX; + float y = positionY - _worldY; + float dist = (float)MathUtil::sqrt(x * x + y * y); + if (dist < _radius) { + float theta = _interpolation.interpolate(0, _angle, (_radius - dist) / _radius); + float cos = MathUtil::cos(theta), sin = MathUtil::sin(theta); + positionX = cos * x - sin * y + _worldX; + positionY = sin * x + cos * y + _worldY; + } +} + +void SwirlVertexEffect::end() { + +} + +void SwirlVertexEffect::setCenterX(float centerX) { + _centerX = centerX; +} + +float SwirlVertexEffect::getCenterX() { + return _centerX; +} + +void SwirlVertexEffect::setCenterY(float centerY) { + _centerY = centerY; +} + +float SwirlVertexEffect::getCenterY() { + return _centerY; +} + +void SwirlVertexEffect::setRadius(float radius) { + _radius = radius; +} + +float SwirlVertexEffect::getRadius() { + return _radius; +} + +void SwirlVertexEffect::setAngle(float angle) { + _angle = angle * Spine::DEG_RAD; +} + +float SwirlVertexEffect::getAngle() { + return _angle; +} + +void SwirlVertexEffect::setWorldX(float worldX) { + _worldX = worldX; +} + +float SwirlVertexEffect::getWorldX() { + return _worldX; +} + +void SwirlVertexEffect::setWorldY(float worldY) { + _worldY = worldY; +} + +float SwirlVertexEffect::getWorldY() { + return _worldY; +} diff --git a/spine-sfml/cpp/example/main.cpp b/spine-sfml/cpp/example/main.cpp index 387fb12f3..0aee574ae 100644 --- a/spine-sfml/cpp/example/main.cpp +++ b/spine-sfml/cpp/example/main.cpp @@ -29,11 +29,9 @@ *****************************************************************************/ #include -#include #include #include #include -#include using namespace std; using namespace Spine; @@ -205,9 +203,11 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); drawable->timeScale = 1; - // BOZO spSwirlVertexEffect* effect = spSwirlVertexEffect_create(400); - // effect->centerY = -200; - // drawable->vertexEffect = &effect->super; + PowInterpolation pow2(2); + PowOutInterpolation powOut2(2); + SwirlVertexEffect effect(400, powOut2); + effect.setCenterY(-200); + drawable->vertexEffect = &effect; Skeleton* skeleton = drawable->skeleton; skeleton->setPosition(320, 590); @@ -231,7 +231,7 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) { swirlTime += delta; float percent = MathUtil::fmod(swirlTime, 2); if (percent > 1) percent = 1 - (percent - 1); - // BOZO effect->angle = _spMath_interpolate(_spMath_pow2_apply, -60, 60, percent); + effect.setAngle(pow2.interpolate(-60.0f, 60.0f, percent)); drawable->update(delta); @@ -239,7 +239,6 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) { window.draw(*drawable); window.display(); } - // BOZO spSwirlVertexEffect_dispose(effect); delete drawable; } @@ -452,6 +451,8 @@ void test (SkeletonData* skeletonData, Atlas* atlas) { int main () { DebugExtension dbgExtension; SpineExtension::setInstance(&dbgExtension); + + testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor.atlas", 0.5f); testcase(test, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 1.0f); testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f); testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl.atlas", 0.5f); diff --git a/spine-sfml/cpp/src/spine/spine-sfml.cpp b/spine-sfml/cpp/src/spine/spine-sfml.cpp index ae347d339..18ec32829 100644 --- a/spine-sfml/cpp/src/spine/spine-sfml.cpp +++ b/spine-sfml/cpp/src/spine/spine-sfml.cpp @@ -53,7 +53,7 @@ namespace Spine { SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *stateData) : timeScale(1), vertexArray(new VertexArray(Triangles, skeletonData->getBones().size() * 4)), - worldVertices(), clipper() { + worldVertices(), clipper(), vertexEffect(NULL) { Bone::setYDown(true); worldVertices.ensureCapacity(SPINE_MESH_VERTEX_COUNT_MAX); skeleton = new(__FILE__, __LINE__) Skeleton(skeletonData); @@ -64,6 +64,13 @@ SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateDat if (ownsAnimationStateData) stateData = new(__FILE__, __LINE__) AnimationStateData(skeletonData); state = new(__FILE__, __LINE__) AnimationState(stateData); + + quadIndices.add(0); + quadIndices.add(1); + quadIndices.add(2); + quadIndices.add(2); + quadIndices.add(3); + quadIndices.add(0); } SkeletonDrawable::~SkeletonDrawable() { @@ -83,15 +90,8 @@ void SkeletonDrawable::update(float deltaTime) { void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { vertexArray->clear(); states.texture = NULL; - Vector quadIndices; - quadIndices.add(0); - quadIndices.add(1); - quadIndices.add(2); - quadIndices.add(2); - quadIndices.add(3); - quadIndices.add(0); - // BOZO if (vertexEffect != 0) vertexEffect->begin(vertexEffect, skeleton); + if (vertexEffect != NULL) vertexEffect->begin(*skeleton); sf::Vertex vertex; Texture *texture = NULL; @@ -206,54 +206,55 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { Vector2u size = texture->getSize(); - /* BOZO if (vertexEffect != 0) { - spFloatArray_clear(tempUvs); - spColorArray_clear(tempColors); + if (vertexEffect != 0) { + tempUvs.clear(); + tempColors.clear(); for (int i = 0; i < verticesCount; i++) { - spColor vertexColor = light; - spColor dark; - dark.r = dark.g = dark.b = dark.a = 0; + Color vertexColor = light; + Color dark; + dark._r = dark._g = dark._b = dark._a = 0; int index = i << 1; - float x = vertices[index]; - float y = vertices[index + 1]; - float u = uvs[index]; - float v = uvs[index + 1]; - vertexEffect->transform(vertexEffect, &x, &y, &u, &v, &vertexColor, &dark); - vertices[index] = x; - vertices[index + 1] = y; - spFloatArray_add(tempUvs, u); - spFloatArray_add(tempUvs, v); - spColorArray_add(tempColors, vertexColor); + float x = (*vertices)[index]; + float y = (*vertices)[index + 1]; + float u = (*uvs)[index]; + float v = (*uvs)[index + 1]; + vertexEffect->transform(x, y, u, v, vertexColor, dark); + (*vertices)[index] = x; + (*vertices)[index + 1] = y; + tempUvs.add(u); + tempUvs.add(v); + tempColors.add(vertexColor); } for (int i = 0; i < indicesCount; ++i) { - int index = indices[i] << 1; - vertex.position.x = vertices[index]; - vertex.position.y = vertices[index + 1]; - vertex.texCoords.x = uvs[index] * size.x; - vertex.texCoords.y = uvs[index + 1] * size.y; - spColor vertexColor = tempColors->items[index >> 1]; - vertex.color.r = static_cast(vertexColor.r * 255); - vertex.color.g = static_cast(vertexColor.g * 255); - vertex.color.b = static_cast(vertexColor.b * 255); - vertex.color.a = static_cast(vertexColor.a * 255); + int index = (*indices)[i] << 1; + vertex.position.x = (*vertices)[index]; + vertex.position.y = (*vertices)[index + 1]; + vertex.texCoords.x = (*uvs)[index] * size.x; + vertex.texCoords.y = (*uvs)[index + 1] * size.y; + Color vertexColor = tempColors[index >> 1]; + vertex.color.r = static_cast(vertexColor._r * 255); + vertex.color.g = static_cast(vertexColor._g * 255); + vertex.color.b = static_cast(vertexColor._b * 255); + vertex.color.a = static_cast(vertexColor._a * 255); + vertexArray->append(vertex); + } + } else { + for (int ii = 0; ii < indicesCount; ++ii) { + int index = (*indices)[ii] << 1; + vertex.position.x = (*vertices)[index]; + vertex.position.y = (*vertices)[index + 1]; + vertex.texCoords.x = (*uvs)[index] * size.x; + vertex.texCoords.y = (*uvs)[index + 1] * size.y; vertexArray->append(vertex); } - } else {*/ - for (int ii = 0; ii < indicesCount; ++ii) { - int index = (*indices)[ii] << 1; - vertex.position.x = (*vertices)[index]; - vertex.position.y = (*vertices)[index + 1]; - vertex.texCoords.x = (*uvs)[index] * size.x; - vertex.texCoords.y = (*uvs)[index + 1] * size.y; - vertexArray->append(vertex); } clipper.clipEnd(slot); } target.draw(*vertexArray, states); clipper.clipEnd(); - // BOZO if (vertexEffect != 0) vertexEffect->end(vertexEffect); + if (vertexEffect != 0) vertexEffect->end(); } void SFMLTextureLoader::load(AtlasPage &page, const String &path) { diff --git a/spine-sfml/cpp/src/spine/spine-sfml.h b/spine-sfml/cpp/src/spine/spine-sfml.h index 8f916e541..de9c8784c 100644 --- a/spine-sfml/cpp/src/spine/spine-sfml.h +++ b/spine-sfml/cpp/src/spine/spine-sfml.h @@ -47,6 +47,7 @@ public: AnimationState *state; float timeScale; sf::VertexArray *vertexArray; + VertexEffect* vertexEffect; SkeletonDrawable(SkeletonData *skeleton, AnimationStateData *stateData = 0); @@ -64,6 +65,7 @@ private: mutable Vector worldVertices; mutable Vector tempUvs; mutable Vector tempColors; + mutable Vector quadIndices; mutable SkeletonClipping clipper; mutable bool usePremultipliedAlpha; };