Browse Source

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

badlogic 7 years ago
parent
commit
7c398be3b6
100 changed files with 323 additions and 93 deletions
  1. 6 0
      CHANGELOG.md
  2. 0 0
      examples/alien/export/alien-ess.json
  3. BIN
      examples/alien/export/alien-ess.skel
  4. 0 0
      examples/alien/export/alien-pro.json
  5. BIN
      examples/alien/export/alien-pro.skel
  6. 0 0
      examples/coin/export/coin-pro.json
  7. BIN
      examples/coin/export/coin-pro.skel
  8. 0 0
      examples/dragon/export/dragon-ess.json
  9. BIN
      examples/dragon/export/dragon-ess.skel
  10. 7 7
      examples/export/runtimes.sh
  11. 0 0
      examples/goblins/export/goblins-ess.json
  12. BIN
      examples/goblins/export/goblins-ess.skel
  13. 0 0
      examples/goblins/export/goblins-pro.json
  14. BIN
      examples/goblins/export/goblins-pro.skel
  15. 0 0
      examples/hero/export/hero-ess.json
  16. BIN
      examples/hero/export/hero-ess.skel
  17. 0 0
      examples/hero/export/hero-pro.json
  18. BIN
      examples/hero/export/hero-pro.skel
  19. 0 0
      examples/owl/export/owl-pro.json
  20. BIN
      examples/owl/export/owl-pro.skel
  21. 0 0
      examples/powerup/export/powerup-ess.json
  22. BIN
      examples/powerup/export/powerup-ess.skel
  23. 0 0
      examples/powerup/export/powerup-pro.json
  24. BIN
      examples/powerup/export/powerup-pro.skel
  25. 0 0
      examples/raptor/export/raptor-pro.json
  26. BIN
      examples/raptor/export/raptor-pro.skel
  27. 0 0
      examples/speedy/export/speedy-ess.json
  28. BIN
      examples/speedy/export/speedy-ess.skel
  29. 0 0
      examples/spineboy/export/spineboy-ess.json
  30. BIN
      examples/spineboy/export/spineboy-ess.skel
  31. 0 0
      examples/spineboy/export/spineboy-pro.json
  32. BIN
      examples/spineboy/export/spineboy-pro.skel
  33. BIN
      examples/spineboy/spineboy-pro.spine
  34. 0 0
      examples/spinosaurus/export/spinosaurus-ess.json
  35. BIN
      examples/spinosaurus/export/spinosaurus-ess.skel
  36. 0 0
      examples/stretchyman-stretchy-ik/export/stretchyman-stretchy-ik.json
  37. BIN
      examples/stretchyman-stretchy-ik/export/stretchyman-stretchy-ik.skel
  38. 0 0
      examples/stretchyman/export/stretchyman-pro.json
  39. BIN
      examples/stretchyman/export/stretchyman-pro.skel
  40. 0 0
      examples/tank/export/tank-pro.json
  41. BIN
      examples/tank/export/tank-pro.skel
  42. 0 0
      examples/vine/export/vine-pro.json
  43. BIN
      examples/vine/export/vine-pro.skel
  44. BIN
      spine-as3/spine-as3-example/lib/spine-as3.swc
  45. 0 0
      spine-as3/spine-as3-example/src/spineboy-ess.json
  46. 2 0
      spine-as3/spine-as3/src/spine/Event.as
  47. 4 2
      spine-as3/spine-as3/src/spine/EventData.as
  48. 9 0
      spine-as3/spine-as3/src/spine/SkeletonJson.as
  49. 5 1
      spine-c/spine-c/include/spine/Event.h
  50. 5 1
      spine-c/spine-c/include/spine/EventData.h
  51. 8 0
      spine-c/spine-c/src/spine/SkeletonBinary.c
  52. 11 0
      spine-c/spine-c/src/spine/SkeletonJson.c
  53. 0 0
      spine-cocos2d-objc/Resources/coin-pro.json
  54. 0 0
      spine-cocos2d-objc/Resources/goblins-pro.json
  55. 0 0
      spine-cocos2d-objc/Resources/raptor-pro.json
  56. 0 0
      spine-cocos2d-objc/Resources/spineboy-ess.json
  57. 0 0
      spine-cocos2d-objc/Resources/tank-pro.json
  58. BIN
      spine-cocos2dx/example/Resources/common/coin-pro.skel
  59. 0 0
      spine-cocos2dx/example/Resources/common/goblins-pro.json
  60. 0 0
      spine-cocos2dx/example/Resources/common/raptor-pro.json
  61. 0 0
      spine-cocos2dx/example/Resources/common/spineboy-ess.json
  62. BIN
      spine-cocos2dx/example/Resources/common/tank-pro.skel
  63. 0 0
      spine-corona/data/coin-pro.json
  64. 0 0
      spine-corona/data/goblins-pro.json
  65. 0 0
      spine-corona/data/owl-pro.json
  66. 0 0
      spine-corona/data/raptor-pro.json
  67. 0 0
      spine-corona/data/spineboy-ess.json
  68. 0 0
      spine-corona/data/spineboy-pro.json
  69. 0 0
      spine-corona/data/stretchyman-pro.json
  70. 0 0
      spine-corona/data/stretchyman-stretchy-ik.json
  71. 0 0
      spine-corona/data/tank-pro.json
  72. 0 0
      spine-corona/data/vine-pro.json
  73. 2 2
      spine-corona/main.lua
  74. 10 0
      spine-cpp/spine-cpp/include/spine/Event.h
  75. 15 0
      spine-cpp/spine-cpp/include/spine/EventData.h
  76. 20 1
      spine-cpp/spine-cpp/src/spine/Event.cpp
  77. 31 3
      spine-cpp/spine-cpp/src/spine/EventData.cpp
  78. 10 1
      spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp
  79. 10 0
      spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
  80. 91 65
      spine-csharp/src/AnimationState.cs
  81. 5 0
      spine-csharp/src/Event.cs
  82. 3 0
      spine-csharp/src/EventData.cs
  83. 13 4
      spine-csharp/src/SkeletonBinary.cs
  84. 14 5
      spine-csharp/src/SkeletonJson.cs
  85. 0 0
      spine-libgdx/spine-libgdx-tests/assets/coin/coin-pro.json
  86. BIN
      spine-libgdx/spine-libgdx-tests/assets/coin/coin-pro.skel
  87. 0 0
      spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-ess.json
  88. BIN
      spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-ess.skel
  89. 0 0
      spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-pro.json
  90. BIN
      spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-pro.skel
  91. 0 0
      spine-libgdx/spine-libgdx-tests/assets/raptor/raptor-pro.json
  92. BIN
      spine-libgdx/spine-libgdx-tests/assets/raptor/raptor-pro.skel
  93. 0 0
      spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-ess.json
  94. BIN
      spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-ess.skel
  95. 0 0
      spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-pro.json
  96. BIN
      spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-pro.skel
  97. 0 1
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java
  98. 17 0
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java
  99. 17 0
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java
  100. 8 0
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java

+ 6 - 0
CHANGELOG.md

@@ -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 it is too large
+ 0 - 0
examples/alien/export/alien-ess.json


BIN
examples/alien/export/alien-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/alien/export/alien-pro.json


BIN
examples/alien/export/alien-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/coin/export/coin-pro.json


BIN
examples/coin/export/coin-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/dragon/export/dragon-ess.json


BIN
examples/dragon/export/dragon-ess.skel


+ 7 - 7
examples/export/runtimes.sh

@@ -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-ess.skel ../../spine-sfml/c/data/
+cp -f ../spineboy/export/spineboy-pro.json ../../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-ess.skel ../../spine-sfml/cpp/data/
+cp -f ../spineboy/export/spineboy-pro.json ../../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 it is too large
+ 0 - 0
examples/goblins/export/goblins-ess.json


BIN
examples/goblins/export/goblins-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/goblins/export/goblins-pro.json


BIN
examples/goblins/export/goblins-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/hero/export/hero-ess.json


BIN
examples/hero/export/hero-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/hero/export/hero-pro.json


BIN
examples/hero/export/hero-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/owl/export/owl-pro.json


BIN
examples/owl/export/owl-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/powerup/export/powerup-ess.json


BIN
examples/powerup/export/powerup-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/powerup/export/powerup-pro.json


BIN
examples/powerup/export/powerup-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/raptor/export/raptor-pro.json


BIN
examples/raptor/export/raptor-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/speedy/export/speedy-ess.json


BIN
examples/speedy/export/speedy-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/spineboy/export/spineboy-ess.json


BIN
examples/spineboy/export/spineboy-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/spineboy/export/spineboy-pro.json


BIN
examples/spineboy/export/spineboy-pro.skel


BIN
examples/spineboy/spineboy-pro.spine


File diff suppressed because it is too large
+ 0 - 0
examples/spinosaurus/export/spinosaurus-ess.json


BIN
examples/spinosaurus/export/spinosaurus-ess.skel


File diff suppressed because it is too large
+ 0 - 0
examples/stretchyman-stretchy-ik/export/stretchyman-stretchy-ik.json


BIN
examples/stretchyman-stretchy-ik/export/stretchyman-stretchy-ik.skel


File diff suppressed because it is too large
+ 0 - 0
examples/stretchyman/export/stretchyman-pro.json


BIN
examples/stretchyman/export/stretchyman-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/tank/export/tank-pro.json


BIN
examples/tank/export/tank-pro.skel


File diff suppressed because it is too large
+ 0 - 0
examples/vine/export/vine-pro.json


BIN
examples/vine/export/vine-pro.skel


BIN
spine-as3/spine-as3-example/lib/spine-as3.swc


File diff suppressed because it is too large
+ 0 - 0
spine-as3/spine-as3-example/src/spineboy-ess.json


+ 2 - 0
spine-as3/spine-as3/src/spine/Event.as

@@ -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.");

+ 4 - 2
spine-as3/spine-as3/src/spine/EventData.as

@@ -31,10 +31,12 @@
 package spine {
 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.");

+ 9 - 0
spine-as3/spine-as3/src/spine/SkeletonJson.as

@@ -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;

+ 5 - 1
spine-c/spine-c/include/spine/Event.h

@@ -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;

+ 5 - 1
spine-c/spine-c/include/spine/EventData.h

@@ -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;

+ 8 - 0
spine-c/spine-c/src/spine/SkeletonBinary.c

@@ -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;
 	}
 	}
 
 

+ 11 - 0
spine-c/spine-c/src/spine/SkeletonJson.c

@@ -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 it is too large
+ 0 - 0
spine-cocos2d-objc/Resources/coin-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2d-objc/Resources/goblins-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2d-objc/Resources/raptor-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2d-objc/Resources/spineboy-ess.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2d-objc/Resources/tank-pro.json


BIN
spine-cocos2dx/example/Resources/common/coin-pro.skel


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2dx/example/Resources/common/goblins-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2dx/example/Resources/common/raptor-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-cocos2dx/example/Resources/common/spineboy-ess.json


BIN
spine-cocos2dx/example/Resources/common/tank-pro.skel


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/coin-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/goblins-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/owl-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/raptor-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/spineboy-ess.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/spineboy-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/stretchyman-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/stretchyman-stretchy-ik.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/tank-pro.json


File diff suppressed because it is too large
+ 0 - 0
spine-corona/data/vine-pro.json


+ 2 - 2
spine-corona/main.lua

@@ -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"))

+ 10 - 0
spine-cpp/spine-cpp/include/spine/Event.h

@@ -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;
 };
 };
 }
 }
 
 

+ 15 - 0
spine-cpp/spine-cpp/include/spine/EventData.h

@@ -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;
 };
 };
 }
 }
 
 

+ 20 - 1
spine-cpp/spine-cpp/src/spine/Event.cpp

@@ -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;
+}

+ 31 - 3
spine-cpp/spine-cpp/src/spine/EventData.cpp

@@ -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),
-		_floatValue(0.0f)
-		 {
+		_intValue(0),
+		_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;
+}

+ 10 - 1
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -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);
 		}
 		}
 
 

+ 10 - 0
spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp

@@ -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);

+ 91 - 65
spine-csharp/src/AnimationState.cs

@@ -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 timelineDipMix = from.timelineDipMix.Items;
+				var timelineMode = from.timelineMode.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];
-							alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
+							TrackEntry holdMix = timelineHoldMix[i];
+							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;
-			propertyIDs.Clear();
-			var mixingTo = this.mixingTo;
+			this.propertyIDs.Clear();
 
 
 			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<TrackEntry> timelineDipMix = new ExposedList<TrackEntry>();
+		internal readonly ExposedList<int> timelineMode = new ExposedList<int>();
+		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();
-			timelineDipMix.Clear();
+			timelineMode.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); }

+ 5 - 0
spine-csharp/src/Event.cs

@@ -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;

+ 3 - 0
spine-csharp/src/EventData.cs

@@ -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.");

+ 13 - 4
spine-csharp/src/SkeletonBinary.cs

@@ -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);
-					e.Int = ReadVarint(input, false);
-					e.Float = ReadFloat(input);
-					e.String = ReadBoolean(input) ? ReadString(input) : eventData.String;
+					Event e = new Event(time, eventData) {
+						Int = ReadVarint(input, false),
+						Float = ReadFloat(input),
+						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);

+ 14 - 5
spine-csharp/src/SkeletonJson.cs

@@ -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);
-					e.Int = GetInt(eventMap, "int", eventData.Int);
-					e.Float = GetFloat(eventMap, "float", eventData.Float);
-					e.String = GetString(eventMap, "string", eventData.String);
+					var e = new Event((float)eventMap["time"], eventData) {
+						intValue = GetInt(eventMap, "int", eventData.Int),
+						floatValue = GetFloat(eventMap, "float", eventData.Float),
+						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 it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/coin/coin-pro.json


BIN
spine-libgdx/spine-libgdx-tests/assets/coin/coin-pro.skel


File diff suppressed because it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-ess.json


BIN
spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-ess.skel


File diff suppressed because it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-pro.json


BIN
spine-libgdx/spine-libgdx-tests/assets/goblins/goblins-pro.skel


File diff suppressed because it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/raptor/raptor-pro.json


BIN
spine-libgdx/spine-libgdx-tests/assets/raptor/raptor-pro.skel


File diff suppressed because it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-ess.json


BIN
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-ess.skel


File diff suppressed because it is too large
+ 0 - 0
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-pro.json


BIN
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-pro.skel


+ 0 - 1
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java

@@ -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++) {

+ 17 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java

@@ -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;

+ 17 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java

@@ -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;

+ 8 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java

@@ -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 changed in this diff