Merge branch '3.7-beta' into 3.7-beta-cpp

This commit is contained in:
badlogic 2018-09-06 16:01:12 +02:00
commit 7c398be3b6
214 changed files with 11729 additions and 11257 deletions

View File

@ -8,6 +8,7 @@
* **Additions** * **Additions**
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### Starling ### Starling
* Added support for vertex effects. See `RaptorExample.as` * Added support for vertex effects. See `RaptorExample.as`
@ -40,6 +41,7 @@
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `spTrackEntry->mixBlend = SP_MIXBLEND_ADD)` on each track. To specify the blend percentage, set `spTrackEntry->alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `spTrackEntry->mixBlend = SP_MIXBLEND_ADD)` on each track. To specify the blend percentage, set `spTrackEntry->alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
* Optimized attachment lookup to give a 40x speed-up. See https://github.com/EsotericSoftware/spine-runtimes/commit/cab81276263890b65d07fa2329ace16db1e365ff * Optimized attachment lookup to give a 40x speed-up. See https://github.com/EsotericSoftware/spine-runtimes/commit/cab81276263890b65d07fa2329ace16db1e365ff
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### Cocos2d-Objc ### Cocos2d-Objc
* Added vertex effect support to modify vertices of skeletons on the CPU. See `RaptorExample.m`. * Added vertex effect support to modify vertices of skeletons on the CPU. See `RaptorExample.m`.
@ -97,6 +99,7 @@
* **Additions** * **Additions**
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#MixBlend = MixBlend.add` on each track. To specify the blend percentage, set `TrackEntry#Alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#MixBlend = MixBlend.add` on each track. To specify the blend percentage, set `TrackEntry#Alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### Unity ### Unity
* **Runtime and Editor, and Assembly Definition** Files and folders have been reorganized into "Runtime" and "Editor". Each of these have an `.asmdef` file that defines these separately as their own assembly in Unity. For projects not using assembly definition, you may delete the `.asmdef` files. These assembly definitions will be ignored by older versions of Unity that don't support it. * **Runtime and Editor, and Assembly Definition** Files and folders have been reorganized into "Runtime" and "Editor". Each of these have an `.asmdef` file that defines these separately as their own assembly in Unity. For projects not using assembly definition, you may delete the `.asmdef` files. These assembly definitions will be ignored by older versions of Unity that don't support it.
@ -137,6 +140,7 @@
* Added convenience method to add all attachments from one skin to another, see https://github.com/EsotericSoftware/spine-runtimes/commit/a0b7bb6c445efdfac12b0cdee2057afa3eff3ead * Added convenience method to add all attachments from one skin to another, see https://github.com/EsotericSoftware/spine-runtimes/commit/a0b7bb6c445efdfac12b0cdee2057afa3eff3ead
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### libGDX ### libGDX
* Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect` and `VertexEffectTest`. * Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect` and `VertexEffectTest`.
@ -154,6 +158,7 @@
* Added `JitterEffect` and `SwirlEffect` and support for vertex effects in Corona and Love * Added `JitterEffect` and `SwirlEffect` and support for vertex effects in Corona and Love
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry:setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry.alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry:setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry.alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion.
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### Love2D ### Love2D
* Added support for vertex effects. Set an implementation like "JitterEffect" on `Skeleton.vertexEffect`. See `main.lua` for an example. * Added support for vertex effects. Set an implementation like "JitterEffect" on `Skeleton.vertexEffect`. See `main.lua` for an example.
@ -170,6 +175,7 @@
* Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. See https://github.com/EsotericSoftware/spine-runtimes/blob/f045d221836fa56191ccda73dd42ae884d4731b8/spine-ts/webgl/tests/test-additive-animation-blending.html for an example. * Added additive animation blending. When playing back multiple animations on different tracks, where each animation modifies the same skeleton property, the results of tracks with lower indices are discarded, and only the result from the track with the highest index is used. With animation blending, the results of all tracks are mixed together. This allows effects like mixing multiple facial expressions (angry, happy, sad) with percentage mixes. By default the old behaviour is retained (results from lower tracks are discarded). To enable additive blending across animation tracks, call `TrackEntry#setMixBlend(MixBlend.add)` on each track. To specify the blend percentage, set `TrackEntry#alpha`. See http://esotericsoftware.com/forum/morph-target-track-animation-mix-mode-9459 for a discussion. See https://github.com/EsotericSoftware/spine-runtimes/blob/f045d221836fa56191ccda73dd42ae884d4731b8/spine-ts/webgl/tests/test-additive-animation-blending.html for an example.
* Added work-around for iOS WebKit JIT bug, see https://github.com/EsotericSoftware/spine-runtimes/commit/c28bbebf804980f55cdd773fed9ff145e0e7e76c * Added work-around for iOS WebKit JIT bug, see https://github.com/EsotericSoftware/spine-runtimes/commit/c28bbebf804980f55cdd773fed9ff145e0e7e76c
* Support for stretchy IK * Support for stretchy IK
* Support for audio events, see `audioPath`, `volume` and `balance` fields on event (data).
### WebGL backend ### WebGL backend
* Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`, and the example which allows to set effects. * Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`, and the example which allows to set effects.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -90,7 +90,7 @@ cp -f ../raptor/export/raptor-pro.json ../../spine-corona/data
cp -f ../raptor/export/raptor.atlas ../../spine-corona/data cp -f ../raptor/export/raptor.atlas ../../spine-corona/data
cp -f ../raptor/export/raptor.png ../../spine-corona/data cp -f ../raptor/export/raptor.png ../../spine-corona/data
cp -f ../spineboy/export/spineboy-ess.json ../../spine-corona/data cp -f ../spineboy/export/spineboy-pro.json ../../spine-corona/data
cp -f ../spineboy/export/spineboy.atlas ../../spine-corona/data cp -f ../spineboy/export/spineboy.atlas ../../spine-corona/data
cp -f ../spineboy/export/spineboy.png ../../spine-corona/data cp -f ../spineboy/export/spineboy.png ../../spine-corona/data
@ -126,7 +126,7 @@ cp -f ../raptor/export/raptor-pro.json ../../spine-love/data
cp -f ../raptor/export/raptor.atlas ../../spine-love/data cp -f ../raptor/export/raptor.atlas ../../spine-love/data
cp -f ../raptor/export/raptor.png ../../spine-love/data cp -f ../raptor/export/raptor.png ../../spine-love/data
cp -f ../spineboy/export/spineboy-ess.json ../../spine-love/data cp -f ../spineboy/export/spineboy-pro.json ../../spine-love/data
cp -f ../spineboy/export/spineboy.atlas ../../spine-love/data cp -f ../spineboy/export/spineboy.atlas ../../spine-love/data
cp -f ../spineboy/export/spineboy.png ../../spine-love/data cp -f ../spineboy/export/spineboy.png ../../spine-love/data
@ -161,8 +161,8 @@ cp -f ../raptor/export/raptor-pro.skel ../../spine-sfml/c/data/
cp -f ../raptor/export/raptor.atlas ../../spine-sfml/c/data/ cp -f ../raptor/export/raptor.atlas ../../spine-sfml/c/data/
cp -f ../raptor/export/raptor.png ../../spine-sfml/c/data/ cp -f ../raptor/export/raptor.png ../../spine-sfml/c/data/
cp -f ../spineboy/export/spineboy-ess.json ../../spine-sfml/c/data/ cp -f ../spineboy/export/spineboy-pro.json ../../spine-sfml/c/data/
cp -f ../spineboy/export/spineboy-ess.skel ../../spine-sfml/c/data/ cp -f ../spineboy/export/spineboy-pro.skel ../../spine-sfml/c/data/
cp -f ../spineboy/export/spineboy.atlas ../../spine-sfml/c/data/ cp -f ../spineboy/export/spineboy.atlas ../../spine-sfml/c/data/
cp -f ../spineboy/export/spineboy.png ../../spine-sfml/c/data/ cp -f ../spineboy/export/spineboy.png ../../spine-sfml/c/data/
@ -206,8 +206,8 @@ cp -f ../raptor/export/raptor-pro.skel ../../spine-sfml/cpp/data/
cp -f ../raptor/export/raptor.atlas ../../spine-sfml/cpp/data/ cp -f ../raptor/export/raptor.atlas ../../spine-sfml/cpp/data/
cp -f ../raptor/export/raptor.png ../../spine-sfml/cpp/data/ cp -f ../raptor/export/raptor.png ../../spine-sfml/cpp/data/
cp -f ../spineboy/export/spineboy-ess.json ../../spine-sfml/cpp/data/ cp -f ../spineboy/export/spineboy-pro.json ../../spine-sfml/cpp/data/
cp -f ../spineboy/export/spineboy-ess.skel ../../spine-sfml/cpp/data/ cp -f ../spineboy/export/spineboy-pro.skel ../../spine-sfml/cpp/data/
cp -f ../spineboy/export/spineboy.atlas ../../spine-sfml/cpp/data/ cp -f ../spineboy/export/spineboy.atlas ../../spine-sfml/cpp/data/
cp -f ../spineboy/export/spineboy.png ../../spine-sfml/cpp/data/ cp -f ../spineboy/export/spineboy.png ../../spine-sfml/cpp/data/
@ -248,7 +248,7 @@ cp -f ../raptor/export/raptor-pro.json ../../spine-starling/spine-starling-examp
cp -f ../raptor/export/raptor.atlas ../../spine-starling/spine-starling-example/src/ cp -f ../raptor/export/raptor.atlas ../../spine-starling/spine-starling-example/src/
cp -f ../raptor/export/raptor.png ../../spine-starling/spine-starling-example/src/ cp -f ../raptor/export/raptor.png ../../spine-starling/spine-starling-example/src/
cp -f ../spineboy/export/spineboy-ess.json ../../spine-starling/spine-starling-example/src/ cp -f ../spineboy/export/spineboy-pro.json ../../spine-starling/spine-starling-example/src/
cp -f ../spineboy/export/spineboy.atlas ../../spine-starling/spine-starling-example/src/ cp -f ../spineboy/export/spineboy.atlas ../../spine-starling/spine-starling-example/src/
cp -f ../spineboy/export/spineboy.png ../../spine-starling/spine-starling-example/src/ cp -f ../spineboy/export/spineboy.png ../../spine-starling/spine-starling-example/src/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1 +1 @@
{"skeleton":{"hash":"B2ZPp7lIxBrN+g+ALWuTw4IWKYE","spine":"3.7.28-beta","width":1680,"height":1782.28,"images":"./images/","audio":""},"bones":[{"name":"root","y":-526.32},{"name":"leaves","parent":"root","x":-0.17,"y":1310.1},{"name":"logo","parent":"root","y":1332.03},{"name":"play","parent":"root","x":3.02,"y":-83.61},{"name":"quit","parent":"root","x":-2.86,"y":-201.21},{"name":"settings","parent":"root","x":3.02,"y":-144.37}],"slots":[{"name":"background","bone":"root"},{"name":"leaves","bone":"leaves","attachment":"leaves"},{"name":"logo","bone":"logo","attachment":"logo"},{"name":"play","bone":"play","color":"fff99dff","attachment":"play"},{"name":"quit","bone":"quit","color":"fff99dff","attachment":"quit"},{"name":"settings","bone":"settings","color":"fff99dff","attachment":"settings"}],"skins":{"default":{"leaves":{"leaves":{"y":-28.54,"width":1042,"height":522}},"logo":{"logo":{"y":-20.4,"width":917,"height":323}},"play":{"play":{"width":218,"height":77}},"quit":{"quit":{"width":216,"height":77}},"settings":{"settings":{"width":446,"height":76}}}},"animations":{"animation":{"slots":{"leaves":{"color":[{"time":0,"color":"ffffff00"},{"time":0.3333,"color":"ffffffff"}]},"logo":{"color":[{"time":0,"color":"ffffff00"},{"time":0.3333,"color":"ffffffff"}]},"play":{"color":[{"time":1.3333,"color":"fff99dff"},{"time":1.5667,"color":"ffffffff","curve":"stepped"},{"time":1.8333,"color":"ffffffff"},{"time":2.0667,"color":"fff99dff"}]},"quit":{"color":[{"time":2.4,"color":"fff99dff"},{"time":2.6333,"color":"ffffffff"}]},"settings":{"color":[{"time":1.8667,"color":"fff99dff"},{"time":2.1,"color":"ffffffff","curve":"stepped"},{"time":2.3667,"color":"ffffffff"},{"time":2.6,"color":"fff99dff"}]}},"bones":{"logo":{"translate":[{"time":0,"x":0,"y":40.8,"curve":[0.043,0.15,0.345,1.27]},{"time":0.3333,"x":0,"y":-597.72,"curve":[0.425,0.17,0.592,1]},{"time":1,"x":0,"y":-583.72,"curve":[0.402,0,0.603,1]},{"time":1.6667,"x":0,"y":-592.12,"curve":[0.408,0.01,0.655,0.99]},{"time":2.3333,"x":0,"y":-583.72,"curve":[0.402,0,0.603,1]},{"time":3,"x":0,"y":-592.12,"curve":[0.408,0.01,0.655,0.99]},{"time":3.6667,"x":0,"y":-583.72}],"scale":[{"time":0,"x":0.342,"y":0.342,"curve":[0,0,0.744,0.4]},{"time":0.3333,"x":1,"y":1,"curve":[0.19,0.38,0.658,0.99]},{"time":1,"x":1.02,"y":1.03,"curve":[0.371,0,0.661,1]},{"time":1.6667,"x":1,"y":1,"curve":[0.388,0.01,0.687,1]},{"time":2.3333,"x":1.02,"y":1.03,"curve":[0.371,0,0.661,1]},{"time":3,"x":1,"y":1,"curve":[0.388,0.01,0.687,1]},{"time":3.6667,"x":1.02,"y":1.03}]},"play":{"translate":[{"time":0.6667,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":0.8667,"x":0,"y":480.2}],"scale":[{"time":1.3333,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":1.5667,"x":1.231,"y":1.231,"curve":"stepped"},{"time":1.8333,"x":1.231,"y":1.231,"curve":[0,0,0.526,2.46]},{"time":2.0667,"x":1,"y":1}]},"settings":{"translate":[{"time":0.8,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":1,"x":0,"y":431.2}],"scale":[{"time":1.8667,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":2.1,"x":1.23,"y":1.23,"curve":"stepped"},{"time":2.3667,"x":1.23,"y":1.23,"curve":[0,0,0.526,2.46]},{"time":2.6,"x":1,"y":1}]},"quit":{"translate":[{"time":0.9333,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":1.1333,"x":0,"y":376.32}],"scale":[{"time":2.4,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":2.6333,"x":1.23,"y":1.23}]},"leaves":{"translate":[{"time":0,"x":0,"y":0,"curve":[0.043,0.15,0.345,1.27]},{"time":0.3333,"x":0.17,"y":-601.24,"curve":[0.425,0.17,0.592,1]},{"time":1.3333,"x":0.17,"y":-580.84,"curve":[0.402,0,0.603,1]},{"time":2,"x":0.17,"y":-595.12},{"time":2.6667,"x":0.17,"y":-580.84,"curve":[0.402,0,0.603,1]},{"time":3.3333,"x":0.17,"y":-595.12}],"scale":[{"time":0,"x":0.34,"y":0.34,"curve":[0,0,0.744,0.4]},{"time":0.3333,"x":1,"y":1},{"time":1.3333,"x":1.03,"y":1.02},{"time":2,"x":1,"y":1},{"time":2.6667,"x":1.03,"y":1.02},{"time":3.3333,"x":1,"y":1}]}}}}} {"skeleton":{"hash":"B2ZPp7lIxBrN+g+ALWuTw4IWKYE","spine":"3.7.29-beta","width":1680,"height":1782.28,"images":"./images/","audio":""},"bones":[{"name":"root","y":-526.32},{"name":"leaves","parent":"root","x":-0.17,"y":1310.1},{"name":"logo","parent":"root","y":1332.03},{"name":"play","parent":"root","x":3.02,"y":-83.61},{"name":"quit","parent":"root","x":-2.86,"y":-201.21},{"name":"settings","parent":"root","x":3.02,"y":-144.37}],"slots":[{"name":"background","bone":"root"},{"name":"leaves","bone":"leaves","attachment":"leaves"},{"name":"logo","bone":"logo","attachment":"logo"},{"name":"play","bone":"play","color":"fff99dff","attachment":"play"},{"name":"quit","bone":"quit","color":"fff99dff","attachment":"quit"},{"name":"settings","bone":"settings","color":"fff99dff","attachment":"settings"}],"skins":{"default":{"leaves":{"leaves":{"y":-28.54,"width":1042,"height":522}},"logo":{"logo":{"y":-20.4,"width":917,"height":323}},"play":{"play":{"width":218,"height":77}},"quit":{"quit":{"width":216,"height":77}},"settings":{"settings":{"width":446,"height":76}}}},"animations":{"animation":{"slots":{"leaves":{"color":[{"time":0,"color":"ffffff00"},{"time":0.3333,"color":"ffffffff"}]},"logo":{"color":[{"time":0,"color":"ffffff00"},{"time":0.3333,"color":"ffffffff"}]},"play":{"color":[{"time":1.3333,"color":"fff99dff"},{"time":1.5667,"color":"ffffffff","curve":"stepped"},{"time":1.8333,"color":"ffffffff"},{"time":2.0667,"color":"fff99dff"}]},"quit":{"color":[{"time":2.4,"color":"fff99dff"},{"time":2.6333,"color":"ffffffff"}]},"settings":{"color":[{"time":1.8667,"color":"fff99dff"},{"time":2.1,"color":"ffffffff","curve":"stepped"},{"time":2.3667,"color":"ffffffff"},{"time":2.6,"color":"fff99dff"}]}},"bones":{"logo":{"translate":[{"time":0,"x":0,"y":40.8,"curve":[0.043,0.15,0.345,1.27]},{"time":0.3333,"x":0,"y":-597.72,"curve":[0.425,0.17,0.592,1]},{"time":1,"x":0,"y":-583.72,"curve":[0.402,0,0.603,1]},{"time":1.6667,"x":0,"y":-592.12,"curve":[0.408,0.01,0.655,0.99]},{"time":2.3333,"x":0,"y":-583.72,"curve":[0.402,0,0.603,1]},{"time":3,"x":0,"y":-592.12,"curve":[0.408,0.01,0.655,0.99]},{"time":3.6667,"x":0,"y":-583.72}],"scale":[{"time":0,"x":0.342,"y":0.342,"curve":[0,0,0.744,0.4]},{"time":0.3333,"x":1,"y":1,"curve":[0.19,0.38,0.658,0.99]},{"time":1,"x":1.02,"y":1.03,"curve":[0.371,0,0.661,1]},{"time":1.6667,"x":1,"y":1,"curve":[0.388,0.01,0.687,1]},{"time":2.3333,"x":1.02,"y":1.03,"curve":[0.371,0,0.661,1]},{"time":3,"x":1,"y":1,"curve":[0.388,0.01,0.687,1]},{"time":3.6667,"x":1.02,"y":1.03}]},"play":{"translate":[{"time":0.6667,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":0.8667,"x":0,"y":480.2}],"scale":[{"time":1.3333,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":1.5667,"x":1.231,"y":1.231,"curve":"stepped"},{"time":1.8333,"x":1.231,"y":1.231,"curve":[0,0,0.526,2.46]},{"time":2.0667,"x":1,"y":1}]},"settings":{"translate":[{"time":0.8,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":1,"x":0,"y":431.2}],"scale":[{"time":1.8667,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":2.1,"x":1.23,"y":1.23,"curve":"stepped"},{"time":2.3667,"x":1.23,"y":1.23,"curve":[0,0,0.526,2.46]},{"time":2.6,"x":1,"y":1}]},"quit":{"translate":[{"time":0.9333,"x":0,"y":0,"curve":[0,0,0.448,1.63]},{"time":1.1333,"x":0,"y":376.32}],"scale":[{"time":2.4,"x":1,"y":1,"curve":[0,0,0.526,2.46]},{"time":2.6333,"x":1.23,"y":1.23}]},"leaves":{"translate":[{"time":0,"x":0,"y":0,"curve":[0.043,0.15,0.345,1.27]},{"time":0.3333,"x":0.17,"y":-601.24,"curve":[0.425,0.17,0.592,1]},{"time":1.3333,"x":0.17,"y":-580.84,"curve":[0.402,0,0.603,1]},{"time":2,"x":0.17,"y":-595.12},{"time":2.6667,"x":0.17,"y":-580.84,"curve":[0.402,0,0.603,1]},{"time":3.3333,"x":0.17,"y":-595.12}],"scale":[{"time":0,"x":0.34,"y":0.34,"curve":[0,0,0.744,0.4]},{"time":0.3333,"x":1,"y":1},{"time":1.3333,"x":1.03,"y":1.02},{"time":2,"x":1,"y":1},{"time":2.6667,"x":1.03,"y":1.02},{"time":3.3333,"x":1,"y":1}]}}}}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,8 @@ package spine {
public var intValue : int; public var intValue : int;
public var floatValue : Number; public var floatValue : Number;
public var stringValue : String; public var stringValue : String;
public var volume: Number = 1;
public var balance: Number = 0;
public function Event(time : Number, data : EventData) { public function Event(time : Number, data : EventData) {
if (data == null) throw new ArgumentError("data cannot be null."); if (data == null) throw new ArgumentError("data cannot be null.");

View File

@ -32,9 +32,11 @@ package spine {
public class EventData { public class EventData {
internal var _name : String; internal var _name : String;
public var intValue : int; public var intValue : int;
;
public var floatValue : Number; public var floatValue : Number;
public var stringValue : String; public var stringValue : String;
public var audioPath: String;
public var volume: Number = 1;
public var balance: Number = 0;
public function EventData(name : String) { public function EventData(name : String) {
if (name == null) throw new ArgumentError("name cannot be null."); if (name == null) throw new ArgumentError("name cannot be null.");

View File

@ -266,6 +266,11 @@ package spine {
eventData.intValue = eventMap["int"] || 0; eventData.intValue = eventMap["int"] || 0;
eventData.floatValue = eventMap["float"] || 0; eventData.floatValue = eventMap["float"] || 0;
eventData.stringValue = eventMap["string"] || ""; eventData.stringValue = eventMap["string"] || "";
eventData.audioPath = eventMap["audio"] || null;
if (eventData.audioPath != null) {
eventData.volume = eventMap["volume"] || 1;
eventData.balance = eventMap["balance"] || 0;
}
skeletonData.events.push(eventData); skeletonData.events.push(eventData);
} }
} }
@ -714,6 +719,10 @@ package spine {
event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue;
event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue;
event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue;
if (eventData.audioPath != null) {
event.volume = eventMap.hasOwnProperty("volume") ? eventMap["volume"] : 1;
event.balance = eventMap.hasOwnProperty("balance") ? eventMap["balance"] : 0;
}
eventTimeline.setFrame(frameIndex++, event); eventTimeline.setFrame(frameIndex++, event);
} }
timelines[timelines.length] = eventTimeline; timelines[timelines.length] = eventTimeline;

View File

@ -44,6 +44,8 @@ typedef struct spEvent {
int intValue; int intValue;
float floatValue; float floatValue;
const char* stringValue; const char* stringValue;
float volume;
float balance;
#ifdef __cplusplus #ifdef __cplusplus
spEvent() : spEvent() :
@ -51,7 +53,9 @@ typedef struct spEvent {
time(0), time(0),
intValue(0), intValue(0),
floatValue(0), floatValue(0),
stringValue(0) { stringValue(0),
volume(0),
balance(0) {
} }
#endif #endif
} spEvent; } spEvent;

View File

@ -43,6 +43,8 @@ typedef struct spEventData {
float floatValue; float floatValue;
const char* stringValue; const char* stringValue;
const char* audioPath; const char* audioPath;
float volume;
float balance;
#ifdef __cplusplus #ifdef __cplusplus
spEventData() : spEventData() :
@ -50,7 +52,9 @@ typedef struct spEventData {
intValue(0), intValue(0),
floatValue(0), floatValue(0),
stringValue(0), stringValue(0),
audioPath(0) { audioPath(0),
volume(0),
balance(0) {
} }
#endif #endif
} spEventData; } spEventData;

View File

@ -592,6 +592,10 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
event->stringValue = readString(input); event->stringValue = readString(input);
else else
MALLOC_STR(event->stringValue, eventData->stringValue); MALLOC_STR(event->stringValue, eventData->stringValue);
if (eventData->audioPath) {
event->volume = readFloat(input);
event->balance = readFloat(input);
}
spEventTimeline_setFrame(timeline, i, event); spEventTimeline_setFrame(timeline, i, event);
} }
spTimelineArray_add(timelines, (spTimeline*)timeline); spTimelineArray_add(timelines, (spTimeline*)timeline);
@ -1077,6 +1081,10 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
eventData->floatValue = readFloat(input); eventData->floatValue = readFloat(input);
eventData->stringValue = readString(input); eventData->stringValue = readString(input);
eventData->audioPath = readString(input); eventData->audioPath = readString(input);
if (eventData->audioPath) {
eventData->volume = readFloat(input);
eventData->balance = readFloat(input);
}
skeletonData->events[i] = eventData; skeletonData->events[i] = eventData;
} }

View File

@ -502,6 +502,10 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
event->floatValue = Json_getFloat(valueMap, "float", eventData->floatValue); event->floatValue = Json_getFloat(valueMap, "float", eventData->floatValue);
stringValue = Json_getString(valueMap, "string", eventData->stringValue); stringValue = Json_getString(valueMap, "string", eventData->stringValue);
if (stringValue) MALLOC_STR(event->stringValue, stringValue); if (stringValue) MALLOC_STR(event->stringValue, stringValue);
if (eventData->audioPath) {
event->volume = Json_getFloat(valueMap, "volume", 1);
event->balance = Json_getFloat(valueMap, "volume", 0);
}
spEventTimeline_setFrame(timeline, frameIndex, event); spEventTimeline_setFrame(timeline, frameIndex, event);
} }
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
@ -1081,6 +1085,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
if (events) { if (events) {
Json *eventMap; Json *eventMap;
const char* stringValue; const char* stringValue;
const char* audioPath;
skeletonData->eventsCount = events->size; skeletonData->eventsCount = events->size;
skeletonData->events = MALLOC(spEventData*, events->size); skeletonData->events = MALLOC(spEventData*, events->size);
for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) { for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) {
@ -1089,6 +1094,12 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
eventData->floatValue = Json_getFloat(eventMap, "float", 0); eventData->floatValue = Json_getFloat(eventMap, "float", 0);
stringValue = Json_getString(eventMap, "string", 0); stringValue = Json_getString(eventMap, "string", 0);
if (stringValue) MALLOC_STR(eventData->stringValue, stringValue); if (stringValue) MALLOC_STR(eventData->stringValue, stringValue);
audioPath = Json_getString(eventMap, "audio", 0);
if (audioPath) {
MALLOC_STR(eventData->audioPath, audioPath);
eventData->volume = Json_getFloat(eventMap, "volume", 1);
eventData->balance = Json_getFloat(eventMap, "balance", 0);
}
skeletonData->events[i] = eventData; skeletonData->events[i] = eventData;
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,7 @@ function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
print(entry.trackIndex.." dispose: "..entry.animation.name) print(entry.trackIndex.." dispose: "..entry.animation.name)
end end
animationState.onEvent = function (entry, event) animationState.onEvent = function (entry, event)
print(entry.trackIndex.." event: "..entry.animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'") print(entry.trackIndex.." event: "..entry.animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'" .. ", " .. event.volume .. ", " .. event.balance)
end end
if atlasFile == "spineboy.atlas" then if atlasFile == "spineboy.atlas" then
@ -81,9 +81,9 @@ function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
return { skeleton = skeleton, state = animationState } return { skeleton = skeleton, state = animationState }
end end
table.insert(skeletons, loadSkeleton("spineboy.atlas", "spineboy-pro.json", 240, 300, 0.4, "walk"))
table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-stretchy-ik.json", 40, 300, 0.5, "sneak")) table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-stretchy-ik.json", 40, 300, 0.5, "sneak"))
table.insert(skeletons, loadSkeleton("coin.atlas", "coin-pro.json", 240, 300, 0.4, "rotate")) table.insert(skeletons, loadSkeleton("coin.atlas", "coin-pro.json", 240, 300, 0.4, "rotate"))
table.insert(skeletons, loadSkeleton("spineboy.atlas", "spineboy-ess.json", 240, 300, 0.4, "walk"))
table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor-pro.json", 200, 300, 0.25, "walk")) table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor-pro.json", 200, 300, 0.25, "walk"))
table.insert(skeletons, loadSkeleton("goblins.atlas", "goblins-pro.json", 240, 300, 0.8, "walk", "goblin")) table.insert(skeletons, loadSkeleton("goblins.atlas", "goblins-pro.json", 240, 300, 0.8, "walk", "goblin"))
table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-pro.json", 40, 300, 0.5, "sneak")) table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-pro.json", 40, 300, 0.5, "sneak"))

View File

@ -65,12 +65,22 @@ public:
void setStringValue(const String &inValue); void setStringValue(const String &inValue);
float getVolume();
void setVolume(float inValue);
float getBalance();
void setBalance(float inValue);
private: private:
const EventData &_data; const EventData &_data;
const float _time; const float _time;
int _intValue; int _intValue;
float _floatValue; float _floatValue;
String _stringValue; String _stringValue;
float _volume;
float _balance;
}; };
} }

View File

@ -61,11 +61,26 @@ public:
void setStringValue(const String &inValue); void setStringValue(const String &inValue);
const String &getAudioPath();
void setAudioPath(const String &inValue);
float getVolume();
void setVolume(float inValue);
float getBalance();
void setBalance(float inValue);
private: private:
const String _name; const String _name;
int _intValue; int _intValue;
float _floatValue; float _floatValue;
String _stringValue; String _stringValue;
String _audioPath;
float _volume;
float _balance;
}; };
} }

View File

@ -41,7 +41,9 @@ spine::Event::Event(float time, const spine::EventData &data) :
_time(time), _time(time),
_intValue(0), _intValue(0),
_floatValue(0), _floatValue(0),
_stringValue() { _stringValue(),
_volume(1),
_balance(0) {
} }
const spine::EventData &spine::Event::getData() { const spine::EventData &spine::Event::getData() {
@ -75,3 +77,20 @@ const spine::String &spine::Event::getStringValue() {
void spine::Event::setStringValue(const spine::String &inValue) { void spine::Event::setStringValue(const spine::String &inValue) {
_stringValue = inValue; _stringValue = inValue;
} }
float Event::getVolume() {
return _volume;
}
void Event::setVolume(float inValue) {
_volume = inValue;
}
float Event::getBalance() {
return _balance;
}
void Event::setBalance(float inValue) {
_balance = inValue;
}

View File

@ -38,9 +38,12 @@
spine::EventData::EventData(const spine::String &name) : spine::EventData::EventData(const spine::String &name) :
_name(name), _name(name),
_intValue((int)0), _intValue(0),
_floatValue(0.0f) _floatValue(0),
{ _stringValue(),
_audioPath(),
_volume(1),
_balance(0) {
assert(_name.length() > 0); assert(_name.length() > 0);
} }
@ -72,3 +75,28 @@ const spine::String &spine::EventData::getStringValue() {
void spine::EventData::setStringValue(const spine::String &inValue) { void spine::EventData::setStringValue(const spine::String &inValue) {
this->_stringValue = inValue; this->_stringValue = inValue;
} }
const String &EventData::getAudioPath() {
return _audioPath;
}
void EventData::setAudioPath(const String &inValue) {
_audioPath = inValue;
}
float EventData::getVolume() {
return _volume;
}
void EventData::setVolume(float inValue) {
_volume = inValue;
}
float EventData::getBalance() {
return _balance;
}
void EventData::setBalance(float inValue) {
_balance = inValue;
}

View File

@ -315,7 +315,11 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
eventData->_intValue = readVarint(input, false); eventData->_intValue = readVarint(input, false);
eventData->_floatValue = readFloat(input); eventData->_floatValue = readFloat(input);
eventData->_stringValue.own(readString(input)); eventData->_stringValue.own(readString(input));
String(readString(input), true); // skip audio path eventData->_audioPath.own(readString(input)); // skip audio path
if (!eventData->_audioPath.isEmpty()) {
eventData->_volume = readFloat(input);
eventData->_balance = readFloat(input);
}
skeletonData->_events[i] = eventData; skeletonData->_events[i] = eventData;
} }
@ -1016,6 +1020,11 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
if (freeString) { if (freeString) {
SpineExtension::free(event_stringValue, __FILE__, __LINE__); SpineExtension::free(event_stringValue, __FILE__, __LINE__);
} }
if (!eventData->_audioPath.isEmpty()) {
event->_volume = readFloat(input);
event->_balance = readFloat(input);
}
timeline->setFrame(i, event); timeline->setFrame(i, event);
} }

View File

@ -678,6 +678,12 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
eventData->_floatValue = Json::getFloat(eventMap, "float", 0); eventData->_floatValue = Json::getFloat(eventMap, "float", 0);
const char *stringValue = Json::getString(eventMap, "string", 0); const char *stringValue = Json::getString(eventMap, "string", 0);
eventData->_stringValue = stringValue; eventData->_stringValue = stringValue;
const char *audioPath = Json::getString(eventMap, "audio", 0);
eventData->_audioPath = audioPath;
if (audioPath) {
eventData->_volume = Json::getFloat(eventMap, "volume", 1);
eventData->_balance = Json::getFloat(eventMap, "balance", 0);
}
skeletonData->_events[i] = eventData; skeletonData->_events[i] = eventData;
} }
} }
@ -1175,6 +1181,10 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
event->_intValue = Json::getInt(valueMap, "int", eventData->_intValue); event->_intValue = Json::getInt(valueMap, "int", eventData->_intValue);
event->_floatValue = Json::getFloat(valueMap, "float", eventData->_floatValue); event->_floatValue = Json::getFloat(valueMap, "float", eventData->_floatValue);
event->_stringValue = Json::getString(valueMap, "string", eventData->_stringValue.buffer()); event->_stringValue = Json::getString(valueMap, "string", eventData->_stringValue.buffer());
if (!eventData->_audioPath.isEmpty()) {
event->_volume = Json::getFloat(valueMap, "volume", 1);
event->_balance = Json::getFloat(valueMap, "balance", 0);
}
timeline->setFrame(frameIndex, event); timeline->setFrame(frameIndex, event);
} }
timelines.add(timeline); timelines.add(timeline);

View File

@ -34,17 +34,16 @@ using System.Collections.Generic;
namespace Spine { namespace Spine {
public class AnimationState { public class AnimationState {
static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0); static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
internal const int Subsequent = 0, First = 1, Dip = 2, DipMix = 3; internal const int Subsequent = 0, First = 1, Hold = 2, HoldMix = 3;
private AnimationStateData data; private AnimationStateData data;
Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>(); private readonly Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>(); private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
private readonly ExposedList<Event> events = new ExposedList<Event>(); private readonly ExposedList<Event> events = new ExposedList<Event>();
private readonly EventQueue queue; // Initialized by constructor. private readonly EventQueue queue; // Initialized by constructor.
private readonly HashSet<int> propertyIDs = new HashSet<int>(); private readonly HashSet<int> propertyIDs = new HashSet<int>();
private readonly ExposedList<TrackEntry> mixingTo = new ExposedList<TrackEntry>();
private bool animationsChanged; private bool animationsChanged;
private float timeScale = 1; private float timeScale = 1;
@ -119,6 +118,7 @@ namespace Spine {
// End mixing from entries once all have completed. // End mixing from entries once all have completed.
var from = current.mixingFrom; var from = current.mixingFrom;
current.mixingFrom = null; current.mixingFrom = null;
if (from != null) from.mixingTo = null;
while (from != null) { while (from != null) {
queue.End(from); queue.End(from);
from = from.mixingFrom; from = from.mixingFrom;
@ -146,6 +146,7 @@ namespace Spine {
// Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame). // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
if (from.totalAlpha == 0 || to.mixDuration == 0) { if (from.totalAlpha == 0 || to.mixDuration == 0) {
to.mixingFrom = from.mixingFrom; to.mixingFrom = from.mixingFrom;
if (from.mixingFrom != null) from.mixingFrom.mixingTo = to;
to.interruptAlpha = from.interruptAlpha; to.interruptAlpha = from.interruptAlpha;
queue.End(from); queue.End(from);
} }
@ -187,11 +188,11 @@ namespace Spine {
int timelineCount = current.animation.timelines.Count; int timelineCount = current.animation.timelines.Count;
var timelines = current.animation.timelines; var timelines = current.animation.timelines;
var timelinesItems = timelines.Items; var timelinesItems = timelines.Items;
if (mix == 1 || blend == MixBlend.Add) { if (i == 0 && (mix == 1 || blend == MixBlend.Add)) {
for (int ii = 0; ii < timelineCount; ii++) for (int ii = 0; ii < timelineCount; ii++)
timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In); timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In);
} else { } else {
var timelineData = current.timelineData.Items; var timelineMode = current.timelineMode.Items;
bool firstFrame = current.timelinesRotation.Count == 0; bool firstFrame = current.timelinesRotation.Count == 0;
if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1); if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
@ -199,7 +200,7 @@ namespace Spine {
for (int ii = 0; ii < timelineCount; ii++) { for (int ii = 0; ii < timelineCount; ii++) {
Timeline timeline = timelinesItems[ii]; Timeline timeline = timelinesItems[ii];
MixBlend timelineBlend = timelineData[ii] >= AnimationState.Subsequent ? blend : MixBlend.Setup; MixBlend timelineBlend = timelineMode[ii] >= AnimationState.Subsequent ? blend : MixBlend.Setup;
var rotateTimeline = timeline as RotateTimeline; var rotateTimeline = timeline as RotateTimeline;
if (rotateTimeline != null) if (rotateTimeline != null)
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
@ -237,14 +238,14 @@ namespace Spine {
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
int timelineCount = timelines.Count; int timelineCount = timelines.Count;
var timelinesItems = timelines.Items; var timelinesItems = timelines.Items;
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix); float alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix);
if (blend == MixBlend.Add) { if (blend == MixBlend.Add) {
for (int i = 0; i < timelineCount; i++) for (int i = 0; i < timelineCount; i++)
(timelinesItems[i]).Apply(skeleton, animationLast, animationTime, eventBuffer, alphaMix, blend, MixDirection.Out); (timelinesItems[i]).Apply(skeleton, animationLast, animationTime, eventBuffer, alphaMix, blend, MixDirection.Out);
} else { } else {
var timelineData = from.timelineData.Items; var timelineMode = from.timelineMode.Items;
var timelineDipMix = from.timelineDipMix.Items; var timelineHoldMix = from.timelineHoldMix.Items;
bool firstFrame = from.timelinesRotation.Count == 0; bool firstFrame = from.timelinesRotation.Count == 0;
if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
@ -255,7 +256,7 @@ namespace Spine {
Timeline timeline = timelinesItems[i]; Timeline timeline = timelinesItems[i];
MixBlend timelineBlend; MixBlend timelineBlend;
float alpha; float alpha;
switch (timelineData[i]) { switch (timelineMode[i]) {
case AnimationState.Subsequent: case AnimationState.Subsequent:
if (!attachments && timeline is AttachmentTimeline) if (!attachments && timeline is AttachmentTimeline)
continue; continue;
@ -268,14 +269,14 @@ namespace Spine {
timelineBlend = MixBlend.Setup; timelineBlend = MixBlend.Setup;
alpha = alphaMix; alpha = alphaMix;
break; break;
case AnimationState.Dip: case AnimationState.Hold:
timelineBlend = MixBlend.Setup; timelineBlend = MixBlend.Setup;
alpha = alphaDip; alpha = alphaHold;
break; break;
default: default:
timelineBlend = MixBlend.Setup; timelineBlend = MixBlend.Setup;
TrackEntry dipMix = timelineDipMix[i]; TrackEntry holdMix = timelineHoldMix[i];
alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration); alpha = alphaHold * Math.Max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
break; break;
} }
from.totalAlpha += alpha; from.totalAlpha += alpha;
@ -428,6 +429,7 @@ namespace Spine {
if (from == null) break; if (from == null) break;
queue.End(from); queue.End(from);
entry.mixingFrom = null; entry.mixingFrom = null;
entry.mixingTo = null;
entry = from; entry = from;
} }
@ -444,6 +446,7 @@ namespace Spine {
if (from != null) { if (from != null) {
if (interrupt) queue.Interrupt(from); if (interrupt) queue.Interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixingTo = current;
current.mixTime = 0; current.mixTime = 0;
// Store interrupted mix percentage. // Store interrupted mix percentage.
@ -599,6 +602,7 @@ namespace Spine {
entry.trackIndex = trackIndex; entry.trackIndex = trackIndex;
entry.animation = animation; entry.animation = animation;
entry.loop = loop; entry.loop = loop;
entry.holdPrevious = false;
entry.eventThreshold = 0; entry.eventThreshold = 0;
entry.attachmentThreshold = 0; entry.attachmentThreshold = 0;
@ -636,17 +640,71 @@ namespace Spine {
private void AnimationsChanged () { private void AnimationsChanged () {
animationsChanged = false; animationsChanged = false;
var propertyIDs = this.propertyIDs; this.propertyIDs.Clear();
propertyIDs.Clear();
var mixingTo = this.mixingTo;
var tracksItems = tracks.Items; var tracksItems = tracks.Items;
for (int i = 0, n = tracks.Count; i < n; i++) { for (int i = 0, n = tracks.Count; i < n; i++) {
var entry = tracksItems[i]; var entry = tracksItems[i];
if (entry != null && (i == 0 || entry.mixBlend != MixBlend.Add)) entry.SetTimelineData(null, mixingTo, propertyIDs); if (entry == null) continue;
// Move to last entry, then iterate in reverse (the order animations are applied).
while (entry.mixingFrom != null)
entry = entry.mixingFrom;
do {
if (entry.mixingTo == null || entry.mixBlend != MixBlend.Add) SetTimelineModes(entry);
entry = entry.mixingTo;
} while (entry != null);
} }
} }
private void SetTimelineModes (TrackEntry entry) {
var to = entry.mixingTo;
var timelines = entry.animation.timelines.Items;
int timelinesCount = entry.animation.timelines.Count;
var timelineMode = entry.timelineMode.Resize(timelinesCount).Items; //timelineMode.setSize(timelinesCount);
entry.timelineHoldMix.Clear();
var timelineHoldMix = entry.timelineHoldMix.Resize(timelinesCount).Items; //timelineHoldMix.setSize(timelinesCount);
var propertyIDs = this.propertyIDs;
if (to != null && to.holdPrevious) {
for (int i = 0; i < timelinesCount; i++) {
propertyIDs.Add(timelines[i].PropertyId);
timelineMode[i] = AnimationState.Hold;
}
return;
}
// outer:
for (int i = 0; i < timelinesCount; i++) {
int id = timelines[i].PropertyId;
if (!propertyIDs.Add(id))
timelineMode[i] = AnimationState.Subsequent;
else if (to == null || !HasTimeline(to, id))
timelineMode[i] = AnimationState.First;
else {
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {
if (HasTimeline(next, id)) continue;
if (next.mixDuration > 0) {
timelineMode[i] = AnimationState.HoldMix;
timelineHoldMix[i] = next;
goto continue_outer; // continue outer;
}
break;
}
timelineMode[i] = AnimationState.Hold;
}
continue_outer: {}
}
}
static bool HasTimeline (TrackEntry entry, int id) {
var timelines = entry.animation.timelines.Items;
for (int i = 0, n = entry.animation.timelines.Count; i < n; i++)
if (timelines[i].PropertyId == id) return true;
return false;
}
/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns> /// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
public TrackEntry GetCurrent (int trackIndex) { public TrackEntry GetCurrent (int trackIndex) {
return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex]; return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex];
@ -675,17 +733,17 @@ namespace Spine {
public class TrackEntry : Pool<TrackEntry>.IPoolable { public class TrackEntry : Pool<TrackEntry>.IPoolable {
internal Animation animation; internal Animation animation;
internal TrackEntry next, mixingFrom; internal TrackEntry next, mixingFrom, mixingTo;
internal int trackIndex; internal int trackIndex;
internal bool loop; internal bool loop, holdPrevious;
internal float eventThreshold, attachmentThreshold, drawOrderThreshold; internal float eventThreshold, attachmentThreshold, drawOrderThreshold;
internal float animationStart, animationEnd, animationLast, nextAnimationLast; internal float animationStart, animationEnd, animationLast, nextAnimationLast;
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f; internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
internal float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha; internal float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha;
internal MixBlend mixBlend = MixBlend.Replace; internal MixBlend mixBlend = MixBlend.Replace;
internal readonly ExposedList<int> timelineData = new ExposedList<int>(); internal readonly ExposedList<int> timelineMode = new ExposedList<int>();
internal readonly ExposedList<TrackEntry> timelineDipMix = new ExposedList<TrackEntry>(); internal readonly ExposedList<TrackEntry> timelineHoldMix = new ExposedList<TrackEntry>();
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>(); internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
// IPoolable.Reset() // IPoolable.Reset()
@ -693,8 +751,8 @@ namespace Spine {
next = null; next = null;
mixingFrom = null; mixingFrom = null;
animation = null; animation = null;
timelineData.Clear(); timelineMode.Clear();
timelineDipMix.Clear(); timelineHoldMix.Clear();
timelinesRotation.Clear(); timelinesRotation.Clear();
Start = null; Start = null;
@ -705,47 +763,6 @@ namespace Spine {
Event = null; Event = null;
} }
/// <summary>Sets the timeline data.</summary>
/// <param name="to">May be null.</param>
internal TrackEntry SetTimelineData (TrackEntry to, ExposedList<TrackEntry> mixingToArray, HashSet<int> propertyIDs) {
if (to != null) mixingToArray.Add(to);
var lastEntry = mixingFrom != null ? mixingFrom.SetTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null) mixingToArray.Pop();
var mixingTo = mixingToArray.Items;
int mixingToLast = mixingToArray.Count - 1;
var timelines = animation.timelines.Items;
int timelinesCount = animation.timelines.Count;
var timelineDataItems = timelineData.Resize(timelinesCount).Items; // timelineData.setSize(timelinesCount);
timelineDipMix.Clear();
var timelineDipMixItems = timelineDipMix.Resize(timelinesCount).Items; //timelineDipMix.setSize(timelinesCount);
// outer:
for (int i = 0; i < timelinesCount; i++) {
int id = timelines[i].PropertyId;
if (!propertyIDs.Add(id)) {
timelineDataItems[i] = AnimationState.Subsequent;
} else if (to == null || !to.HasTimeline(id)) {
timelineDataItems[i] = AnimationState.First;
} else {
for (int ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.HasTimeline(id)) {
if (entry.mixDuration > 0) {
timelineDataItems[i] = AnimationState.DipMix;
timelineDipMixItems[i] = entry;
goto continue_outer; // continue outer;
}
break;
}
}
timelineDataItems[i] = AnimationState.Dip;
}
continue_outer: {}
}
return lastEntry;
}
bool HasTimeline (int id) { bool HasTimeline (int id) {
var timelines = animation.timelines.Items; var timelines = animation.timelines.Items;
for (int i = 0, n = animation.timelines.Count; i < n; i++) for (int i = 0, n = animation.timelines.Count; i < n; i++)
@ -903,6 +920,15 @@ namespace Spine {
/// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list.</summary> /// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list.</summary>
public TrackEntry MixingFrom { get { return mixingFrom; } } public TrackEntry MixingFrom { get { return mixingFrom; } }
/// <summary>
/// If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead of being mixed out.
///
/// When mixing between animations that key the same property, if a lower track also keys that property then the value will briefly dip toward the lower track value during the mix. This happens because the first animation mixes from 100% to 0% while the second animation mixes from 0% to 100%. Setting HoldPrevious to true applies the first animation at 100% during the mix so the lower track value is overwritten. Such dipping does not occur on the lowest track which keys the property, only when a higher track also keys the property.
///
/// Snapping will occur if HoldPrevious is true and this animation does not key all the same properties as the previous animation.
/// </summary>
public bool HoldPrevious { get { return holdPrevious; } set { holdPrevious = value; } }
public event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete; public event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
public event AnimationState.TrackEntryEventDelegate Event; public event AnimationState.TrackEntryEventDelegate Event;
internal void OnStart () { if (Start != null) Start(this); } internal void OnStart () { if (Start != null) Start(this); }

View File

@ -38,6 +38,8 @@ namespace Spine {
internal int intValue; internal int intValue;
internal float floatValue; internal float floatValue;
internal string stringValue; internal string stringValue;
internal float volume;
internal float balance;
public EventData Data { get { return data; } } public EventData Data { get { return data; } }
/// <summary>The animation time this event was keyed.</summary> /// <summary>The animation time this event was keyed.</summary>
@ -47,6 +49,9 @@ namespace Spine {
public float Float { get { return floatValue; } set { floatValue = value; } } public float Float { get { return floatValue; } set { floatValue = value; } }
public string String { get { return stringValue; } set { stringValue = value; } } public string String { get { return stringValue; } set { stringValue = value; } }
public float Volume { get { return volume; } set { volume = value; } }
public float Balance { get { return balance; } set { balance = value; } }
public Event (float time, EventData data) { public Event (float time, EventData data) {
if (data == null) throw new ArgumentNullException("data", "data cannot be null."); if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
this.time = time; this.time = time;

View File

@ -40,7 +40,10 @@ namespace Spine {
public int Int { get; set; } public int Int { get; set; }
public float Float { get; set; } public float Float { get; set; }
public string @String { get; set; } public string @String { get; set; }
public string AudioPath { get; set; } public string AudioPath { get; set; }
public float Volume { get; set; }
public float Balance { get; set; }
public EventData (string name) { public EventData (string name) {
if (name == null) throw new ArgumentNullException("name", "name cannot be null."); if (name == null) throw new ArgumentNullException("name", "name cannot be null.");

View File

@ -288,6 +288,10 @@ namespace Spine {
data.Float = ReadFloat(input); data.Float = ReadFloat(input);
data.String = ReadString(input); data.String = ReadString(input);
data.AudioPath = ReadString(input); data.AudioPath = ReadString(input);
if (data.AudioPath != null) {
data.Volume = ReadFloat(input);
data.Balance = ReadFloat(input);
}
skeletonData.events.Add(data); skeletonData.events.Add(data);
} }
@ -804,10 +808,15 @@ namespace Spine {
for (int i = 0; i < eventCount; i++) { for (int i = 0; i < eventCount; i++) {
float time = ReadFloat(input); float time = ReadFloat(input);
EventData eventData = skeletonData.events.Items[ReadVarint(input, true)]; EventData eventData = skeletonData.events.Items[ReadVarint(input, true)];
Event e = new Event(time, eventData); Event e = new Event(time, eventData) {
e.Int = ReadVarint(input, false); Int = ReadVarint(input, false),
e.Float = ReadFloat(input); Float = ReadFloat(input),
e.String = ReadBoolean(input) ? ReadString(input) : eventData.String; String = ReadBoolean(input) ? ReadString(input) : eventData.String
};
if (e.data.AudioPath != null) {
e.volume = ReadFloat(input);
e.balance = ReadFloat(input);
}
timeline.SetFrame(i, e); timeline.SetFrame(i, e);
} }
timelines.Add(timeline); timelines.Add(timeline);

View File

@ -296,7 +296,11 @@ namespace Spine {
data.Int = GetInt(entryMap, "int", 0); data.Int = GetInt(entryMap, "int", 0);
data.Float = GetFloat(entryMap, "float", 0); data.Float = GetFloat(entryMap, "float", 0);
data.String = GetString(entryMap, "string", string.Empty); data.String = GetString(entryMap, "string", string.Empty);
data.AudioPath = GetString(entryMap, "audio", string.Empty); data.AudioPath = GetString(entryMap, "audio", null);
if (data.AudioPath != null) {
data.Volume = GetFloat(entryMap, "volume", 1);
data.Balance = GetFloat(entryMap, "balance", 0);
}
skeletonData.events.Add(data); skeletonData.events.Add(data);
} }
} }
@ -779,10 +783,15 @@ namespace Spine {
foreach (Dictionary<string, Object> eventMap in eventsMap) { foreach (Dictionary<string, Object> eventMap in eventsMap) {
EventData eventData = skeletonData.FindEvent((string)eventMap["name"]); EventData eventData = skeletonData.FindEvent((string)eventMap["name"]);
if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]); if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]);
var e = new Event((float)eventMap["time"], eventData); var e = new Event((float)eventMap["time"], eventData) {
e.Int = GetInt(eventMap, "int", eventData.Int); intValue = GetInt(eventMap, "int", eventData.Int),
e.Float = GetFloat(eventMap, "float", eventData.Float); floatValue = GetFloat(eventMap, "float", eventData.Float),
e.String = GetString(eventMap, "string", eventData.String); stringValue = GetString(eventMap, "string", eventData.String)
};
if (e.data.AudioPath != null) {
e.volume = GetFloat(eventMap, "volume", eventData.Volume);
e.balance = GetFloat(eventMap, "balance", eventData.Balance);
}
timeline.SetFrame(frameIndex++, e); timeline.SetFrame(frameIndex++, e);
} }
timelines.Add(timeline); timelines.Add(timeline);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -666,7 +666,6 @@ public class AnimationState {
private void animationsChanged () { private void animationsChanged () {
animationsChanged = false; animationsChanged = false;
IntSet propertyIDs = this.propertyIDs;
propertyIDs.clear(2048); propertyIDs.clear(2048);
for (int i = 0, n = tracks.size; i < n; i++) { for (int i = 0, n = tracks.size; i < n; i++) {

View File

@ -44,6 +44,7 @@ public class Event {
int intValue; int intValue;
float floatValue; float floatValue;
String stringValue; String stringValue;
float volume, balance;
final float time; final float time;
public Event (float time, EventData data) { public Event (float time, EventData data) {
@ -76,6 +77,22 @@ public class Event {
this.stringValue = stringValue; this.stringValue = stringValue;
} }
public float getVolume () {
return volume;
}
public void setVolume (float volume) {
this.volume = volume;
}
public float getBalance () {
return balance;
}
public void setBalance (float balance) {
this.balance = balance;
}
/** The animation time this event was keyed. */ /** The animation time this event was keyed. */
public float getTime () { public float getTime () {
return time; return time;

View File

@ -38,6 +38,7 @@ public class EventData {
int intValue; int intValue;
float floatValue; float floatValue;
String stringValue, audioPath; String stringValue, audioPath;
float volume, balance;
public EventData (String name) { public EventData (String name) {
if (name == null) throw new IllegalArgumentException("name cannot be null."); if (name == null) throw new IllegalArgumentException("name cannot be null.");
@ -76,6 +77,22 @@ public class EventData {
this.audioPath = audioPath; this.audioPath = audioPath;
} }
public float getVolume () {
return volume;
}
public void setVolume (float volume) {
this.volume = volume;
}
public float getBalance () {
return balance;
}
public void setBalance (float balance) {
this.balance = balance;
}
/** The name of the event, which is unique within the skeleton. */ /** The name of the event, which is unique within the skeleton. */
public String getName () { public String getName () {
return name; return name;

View File

@ -310,6 +310,10 @@ public class SkeletonBinary {
data.floatValue = input.readFloat(); data.floatValue = input.readFloat();
data.stringValue = input.readString(); data.stringValue = input.readString();
data.audioPath = input.readString(); data.audioPath = input.readString();
if (data.audioPath != null) {
data.volume = input.readFloat();
data.balance = input.readFloat();
}
skeletonData.events.add(data); skeletonData.events.add(data);
} }
@ -821,6 +825,10 @@ public class SkeletonBinary {
event.intValue = input.readInt(false); event.intValue = input.readInt(false);
event.floatValue = input.readFloat(); event.floatValue = input.readFloat();
event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue;
if (event.getData().audioPath != null) {
event.volume = input.readFloat();
event.balance = input.readFloat();
}
timeline.setFrame(i, event); timeline.setFrame(i, event);
} }
timelines.add(timeline); timelines.add(timeline);

Some files were not shown because too many files have changed in this diff Show More