Преглед на файлове

[haxe] Physics porting - Missing Skeleton loaders, examples and TODO

Davide Tantillo преди 1 година
родител
ревизия
bb9d23c4d0
променени са 62 файла, в които са добавени 2867 реда и са изтрити 528 реда
  1. 3 0
      spine-haxe/.vscode/settings.json
  2. 116 0
      spine-haxe/example/assets/cloud-pot.atlas
  3. 779 0
      spine-haxe/example/assets/cloud-pot.json
  4. BIN
      spine-haxe/example/assets/cloud-pot.png
  5. 11 0
      spine-haxe/example/assets/sack-pma.atlas
  6. BIN
      spine-haxe/example/assets/sack-pma.png
  7. 203 0
      spine-haxe/example/assets/sack-pro.json
  8. BIN
      spine-haxe/example/assets/sack-pro.skel
  9. 1 0
      spine-haxe/example/src/Main.hx
  10. 22 6
      spine-haxe/example/src/VineExample.hx
  11. 165 109
      spine-haxe/spine-haxe/spine/Bone.hx
  12. 4 2
      spine-haxe/spine-haxe/spine/BoneData.hx
  13. 25 13
      spine-haxe/spine-haxe/spine/IkConstraint.hx
  14. 2 2
      spine-haxe/spine-haxe/spine/IkConstraintData.hx
  15. 56 0
      spine-haxe/spine-haxe/spine/Inherit.hx
  16. 5 0
      spine-haxe/spine-haxe/spine/MathUtils.hx
  17. 13 8
      spine-haxe/spine-haxe/spine/PathConstraint.hx
  18. 7 8
      spine-haxe/spine-haxe/spine/Physics.hx
  19. 322 0
      spine-haxe/spine-haxe/spine/PhysicsConstraint.hx
  20. 60 0
      spine-haxe/spine-haxe/spine/PhysicsConstraintData.hx
  21. 72 39
      spine-haxe/spine-haxe/spine/Skeleton.hx
  22. 2 1
      spine-haxe/spine-haxe/spine/SkeletonBinary.hx
  23. 27 0
      spine-haxe/spine-haxe/spine/SkeletonData.hx
  24. 123 2
      spine-haxe/spine-haxe/spine/SkeletonJson.hx
  25. 7 0
      spine-haxe/spine-haxe/spine/Skin.hx
  26. 2 0
      spine-haxe/spine-haxe/spine/SlotData.hx
  27. 13 11
      spine-haxe/spine-haxe/spine/TransformConstraint.hx
  28. 1 1
      spine-haxe/spine-haxe/spine/Updatable.hx
  29. 1 2
      spine-haxe/spine-haxe/spine/animation/AlphaTimeline.hx
  30. 43 31
      spine-haxe/spine-haxe/spine/animation/AnimationState.hx
  31. 87 0
      spine-haxe/spine-haxe/spine/animation/CurveTimeline1.hx
  32. 1 2
      spine-haxe/spine-haxe/spine/animation/DeformTimeline.hx
  33. 2 5
      spine-haxe/spine-haxe/spine/animation/EventTimeline.hx
  34. 4 4
      spine-haxe/spine-haxe/spine/animation/IkConstraintTimeline.hx
  35. 73 0
      spine-haxe/spine-haxe/spine/animation/InheritTimeline.hx
  36. 4 4
      spine-haxe/spine-haxe/spine/animation/PathConstraintMixTimeline.hx
  37. 6 23
      spine-haxe/spine-haxe/spine/animation/PathConstraintPositionTimeline.hx
  38. 5 23
      spine-haxe/spine-haxe/spine/animation/PathConstraintSpacingTimeline.hx
  39. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintDampingTimeline.hx
  40. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintGravityTimeline.hx
  41. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintInertiaTimeline.hx
  42. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintMassTimeline.hx
  43. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintMixTimeline.hx
  44. 86 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintResetTimeline.hx
  45. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintStrengthTimeline.hx
  46. 70 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintTimeline.hx
  47. 54 0
      spine-haxe/spine-haxe/spine/animation/PhysicsConstraintWindTimeline.hx
  48. 23 13
      spine-haxe/spine-haxe/spine/animation/Property.hx
  49. 2 24
      spine-haxe/spine-haxe/spine/animation/RotateTimeline.hx
  50. 1 46
      spine-haxe/spine-haxe/spine/animation/ScaleXTimeline.hx
  51. 1 45
      spine-haxe/spine-haxe/spine/animation/ScaleYTimeline.hx
  52. 1 1
      spine-haxe/spine-haxe/spine/animation/SequenceTimeline.hx
  53. 1 22
      spine-haxe/spine-haxe/spine/animation/ShearXTimeline.hx
  54. 1 22
      spine-haxe/spine-haxe/spine/animation/ShearYTimeline.hx
  55. 21 3
      spine-haxe/spine-haxe/spine/animation/TrackEntry.hx
  56. 3 3
      spine-haxe/spine-haxe/spine/animation/TransformConstraintTimeline.hx
  57. 1 22
      spine-haxe/spine-haxe/spine/animation/TranslateXTimeline.hx
  58. 1 22
      spine-haxe/spine-haxe/spine/animation/TranslateYTimeline.hx
  59. 3 3
      spine-haxe/spine-haxe/spine/attachments/MeshAttachment.hx
  60. 2 3
      spine-haxe/spine-haxe/spine/attachments/PointAttachment.hx
  61. 1 1
      spine-haxe/spine-haxe/spine/attachments/RegionAttachment.hx
  62. 4 2
      spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx

+ 3 - 0
spine-haxe/.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+    "cmake.configureOnOpen": false
+}

+ 116 - 0
spine-haxe/example/assets/cloud-pot.atlas

@@ -0,0 +1,116 @@
+cloud-pot.png
+size:4096,512
+filter:MipMapLinearLinear,MipMapLinearLinear
+cloud-base-1
+bounds:1109,8,458,415
+offsets:5,1,465,420
+cloud-base-10
+bounds:279,175,190,199
+offsets:2,1,193,201
+cloud-base-2
+bounds:1575,10,416,413
+offsets:3,1,420,415
+cloud-base-3
+bounds:2331,91,332,324
+offsets:16,1,349,327
+rotate:90
+cloud-base-4
+bounds:1999,78,345,324
+offsets:6,1,352,326
+rotate:90
+cloud-base-5
+bounds:3496,137,286,248
+offsets:2,1,289,250
+rotate:90
+cloud-base-6
+bounds:2663,104,319,269
+offsets:2,1,322,272
+rotate:90
+cloud-base-7
+bounds:2940,128,287,295
+offsets:12,1,300,297
+cloud-base-8
+bounds:3235,123,300,253
+offsets:6,1,307,256
+rotate:90
+cloud-base-9
+bounds:3752,209,211,214
+offsets:2,1,214,216
+cloud-cheeks
+bounds:548,227,433,156
+offsets:1,1,435,158
+cloud-eyes-closed
+bounds:279,382,261,41
+offsets:1,1,263,43
+cloud-eyes-open
+bounds:8,374,263,49
+offsets:1,1,265,51
+cloud-eyes-reflex
+bounds:548,391,237,32
+offsets:1,1,239,34
+cloud-mouth-closed
+bounds:166,336,95,30
+offsets:1,1,97,32
+cloud-mouth-open
+bounds:3971,307,116,68
+offsets:1,1,118,70
+rotate:90
+leaf-big
+bounds:989,359,40,98
+rotate:90
+leaf-small
+bounds:989,319,32,57
+offsets:1,1,34,59
+rotate:90
+petal-1
+bounds:477,292,50,34
+offsets:1,1,52,36
+petal-2
+bounds:166,296,54,32
+offsets:1,1,56,34
+petal-3
+bounds:477,334,56,40
+offsets:1,1,58,42
+pot-base
+bounds:8,250,150,116
+offsets:1,1,152,118
+pot-eyes-closed
+bounds:1011,408,90,15
+offsets:1,1,92,17
+pot-eyes-open
+bounds:989,291,78,20
+offsets:1,1,80,22
+pot-mouth-open
+bounds:4047,394,25,29
+offsets:1,1,27,31
+pot-mouth-pouty
+bounds:228,287,33,17
+offsets:1,1,35,19
+pot-mouth-smile
+bounds:3971,281,25,18
+offsets:1,1,27,20
+pot-mouth-smile-big
+bounds:228,312,37,16
+offsets:1,1,39,18
+rain-blue
+bounds:4047,310,21,34
+offsets:1,1,23,36
+rain-color
+bounds:4047,270,16,32
+offsets:1,1,18,34
+rain-green
+bounds:4047,352,21,34
+offsets:1,1,23,36
+rain-white
+bounds:1054,330,21,42
+offsets:1,1,23,44
+rotate:90
+rain-white-reflex
+bounds:4080,406,8,17
+offsets:1,1,10,19
+stem
+bounds:793,407,16,210
+rotate:90
+stem-end
+bounds:1075,298,23,24
+offsets:1,1,25,26

+ 779 - 0
spine-haxe/example/assets/cloud-pot.json

@@ -0,0 +1,779 @@
+{
+"skeleton": { "hash": "WlXIcG5lrwQ", "spine": "4.2.67-beta", "x": -345, "y": -17, "width": 756, "height": 1098 },
+"bones": [
+	{ "name": "root" },
+	{ "name": "pot-control", "parent": "root", "x": 5, "y": 42 },
+	{ "name": "cloud", "parent": "pot-control", "x": 26.5, "y": 772 },
+	{ "name": "cloud-base-1", "parent": "cloud", "x": -4, "y": 57 },
+	{ "name": "cloud-base-2", "parent": "cloud-base-1", "x": 148.5, "y": -18.5 },
+	{ "name": "cloud-base-3", "parent": "cloud-base-1", "x": -182, "y": -87.5 },
+	{ "name": "cloud-base-4", "parent": "cloud", "x": -31.5, "y": -77 },
+	{ "name": "cloud-base-5", "parent": "cloud-base-4", "x": 177.5, "y": 8 },
+	{ "name": "cloud-base-6", "parent": "cloud-base-1", "x": -150.5, "y": 40 },
+	{ "name": "cloud-base-7", "parent": "cloud-base-1", "x": 8.5, "y": 36.5 },
+	{ "name": "cloud-base-8", "parent": "cloud-base-2", "x": 3.5, "y": 68.5 },
+	{ "name": "cloud-base-9", "parent": "cloud-base-3", "x": -83.5, "y": 30.5 },
+	{ "name": "cloud-base-10", "parent": "cloud-base-5", "x": 137, "y": 54.5 },
+	{ "name": "rain-blue", "parent": "cloud", "x": 102.49, "y": -26 },
+	{ "name": "rain-color", "parent": "cloud", "x": -39.42, "y": -26 },
+	{ "name": "rain-green", "parent": "cloud", "x": 35.08, "y": -26 },
+	{ "name": "rain-white", "parent": "cloud", "x": -103.92, "y": -26 },
+	{ "name": "pot", "parent": "pot-control", "x": -5, "y": -42 },
+	{ "name": "pot-face", "parent": "pot", "x": -1.06, "y": 28.16 },
+	{ "name": "leaf-big", "parent": "pot", "length": 46.73, "rotation": 119.24, "x": 4.04, "y": 95.05 },
+	{ "name": "leaf-big-tip", "parent": "leaf-big", "length": 46.73, "x": 46.73 },
+	{ "name": "leaf-small", "parent": "pot", "length": 51.32, "rotation": 50.93, "x": 10.16, "y": 96.81 },
+	{ "name": "stem", "parent": "pot", "length": 104.76, "rotation": 90, "x": 7.24, "y": 92.61 },
+	{ "name": "stem2", "parent": "stem", "length": 69.84, "x": 104.76 },
+	{ "name": "stem3", "parent": "stem2", "length": 34.92, "x": 69.84 },
+	{ "name": "petal-3", "parent": "stem3", "length": 37.74, "rotation": 1.03, "x": 30.73, "y": 0.64 },
+	{ "name": "petal-1", "parent": "stem3", "length": 40.11, "rotation": 70.18, "x": 34.13, "y": 3.02 },
+	{ "name": "petal-2", "parent": "stem3", "length": 48.62, "rotation": -80.34, "x": 32.09, "y": -4.46 },
+	{ "name": "cloud-face", "parent": "cloud", "y": 14.93 }
+],
+"slots": [
+	{ "name": "rain-green", "bone": "rain-green", "attachment": "rain-green" },
+	{ "name": "rain-blue", "bone": "rain-blue", "attachment": "rain-blue" },
+	{ "name": "rain-color", "bone": "rain-color", "attachment": "rain-color" },
+	{ "name": "rain-white", "bone": "rain-white", "attachment": "rain-white" },
+	{ "name": "rain-white-reflex", "bone": "rain-white", "attachment": "rain-white-reflex" },
+	{ "name": "petal-1", "bone": "petal-1", "attachment": "petal-1" },
+	{ "name": "petal-2", "bone": "petal-2", "attachment": "petal-2" },
+	{ "name": "petal-3", "bone": "petal-3", "attachment": "petal-3" },
+	{ "name": "stem", "bone": "stem", "attachment": "stem" },
+	{ "name": "leaf-big", "bone": "leaf-big", "attachment": "leaf-big" },
+	{ "name": "leaf-small", "bone": "leaf-small", "attachment": "leaf-small" },
+	{ "name": "stem-end", "bone": "stem3", "attachment": "stem-end" },
+	{ "name": "pot-base", "bone": "pot", "attachment": "pot-base" },
+	{ "name": "pot-mouth", "bone": "pot-face", "attachment": "pot-mouth-smile-big" },
+	{ "name": "pot-eyes", "bone": "pot-face", "attachment": "pot-eyes-open" },
+	{ "name": "cloud-base-1", "bone": "cloud-base-1", "attachment": "cloud-base-1" },
+	{ "name": "cloud-base-2", "bone": "cloud-base-2", "attachment": "cloud-base-2" },
+	{ "name": "cloud-base-3", "bone": "cloud-base-3", "attachment": "cloud-base-3" },
+	{ "name": "cloud-base-4", "bone": "cloud-base-4", "attachment": "cloud-base-4" },
+	{ "name": "cloud-base-5", "bone": "cloud-base-5", "attachment": "cloud-base-5" },
+	{ "name": "cloud-base-6", "bone": "cloud-base-6", "attachment": "cloud-base-6" },
+	{ "name": "cloud-base-7", "bone": "cloud-base-7", "attachment": "cloud-base-7" },
+	{ "name": "cloud-base-8", "bone": "cloud-base-8", "attachment": "cloud-base-8" },
+	{ "name": "cloud-base-9", "bone": "cloud-base-9", "attachment": "cloud-base-9" },
+	{ "name": "cloud-base-10", "bone": "cloud-base-10", "attachment": "cloud-base-10" },
+	{ "name": "cloud-cheeks", "bone": "cloud-face", "attachment": "cloud-cheeks" },
+	{ "name": "cloud-eyes", "bone": "cloud-face", "attachment": "cloud-eyes-open" },
+	{ "name": "cloud-eyes-reflex", "bone": "cloud-face", "attachment": "cloud-eyes-reflex" },
+	{ "name": "cloud-mouth", "bone": "cloud-face", "attachment": "cloud-mouth-closed" }
+],
+"physics": [
+	{
+		"name": "cloud",
+		"order": 25,
+		"bone": "cloud",
+		"x": 1,
+		"y": 1,
+		"inertia": 0.5,
+		"strength": 172.8,
+		"damping": 0.8571,
+		"mass": 3
+	},
+	{
+		"name": "cloud-face",
+		"order": 24,
+		"bone": "cloud-face",
+		"x": 0.1923,
+		"y": 0.141,
+		"limit": 500,
+		"inertia": 0.5,
+		"damping": 0.15
+	},
+	{
+		"name": "pot-face",
+		"order": 23,
+		"bone": "pot-face",
+		"x": 0.1667,
+		"y": 0.1026,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 137.3,
+		"damping": 0.6078
+	},
+	{
+		"name": "cloud-base/cloud-base-1",
+		"order": 4,
+		"bone": "cloud-base-1",
+		"x": 1,
+		"y": 1,
+		"limit": 500,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-2",
+		"order": 5,
+		"bone": "cloud-base-2",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-3",
+		"order": 6,
+		"bone": "cloud-base-3",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-4",
+		"order": 7,
+		"bone": "cloud-base-4",
+		"x": 1,
+		"y": 1,
+		"limit": 500,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-5",
+		"order": 8,
+		"bone": "cloud-base-5",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-6",
+		"order": 9,
+		"bone": "cloud-base-6",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-7",
+		"order": 10,
+		"bone": "cloud-base-7",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-8",
+		"order": 11,
+		"bone": "cloud-base-8",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-9",
+		"order": 12,
+		"bone": "cloud-base-9",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "cloud-base/cloud-base-10",
+		"order": 13,
+		"bone": "cloud-base-10",
+		"x": 1,
+		"y": 1,
+		"limit": 300,
+		"inertia": 0.3741,
+		"strength": 134.7,
+		"damping": 0.8163,
+		"mass": 2.8
+	},
+	{
+		"name": "plant/leaf-big",
+		"order": 14,
+		"bone": "leaf-big",
+		"rotate": 0.7532,
+		"shearX": 0.2468,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 160.5,
+		"damping": 0.8367,
+		"mass": 4
+	},
+	{
+		"name": "plant/leaf-big-tip",
+		"order": 22,
+		"bone": "leaf-big-tip",
+		"rotate": 1,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 160.5,
+		"damping": 0.8367,
+		"mass": 4
+	},
+	{
+		"name": "plant/leaf-small",
+		"order": 15,
+		"bone": "leaf-small",
+		"rotate": 0.6026,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 160.5,
+		"damping": 0.8367,
+		"mass": 4
+	},
+	{
+		"name": "plant/petal-1",
+		"order": 19,
+		"bone": "petal-1",
+		"rotate": 1,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 164.6,
+		"damping": 0.6531,
+		"mass": 2.6
+	},
+	{
+		"name": "plant/petal-2",
+		"order": 21,
+		"bone": "petal-2",
+		"rotate": 1,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 164.6,
+		"damping": 0.6531,
+		"mass": 2.6
+	},
+	{
+		"name": "plant/petal-3",
+		"order": 20,
+		"bone": "petal-3",
+		"rotate": 1,
+		"limit": 500,
+		"inertia": 0.5,
+		"strength": 164.6,
+		"damping": 0.7823,
+		"mass": 3.83
+	},
+	{
+		"name": "plant/stem",
+		"order": 16,
+		"bone": "stem",
+		"rotate": 0.8205,
+		"limit": 700,
+		"inertia": 0.5,
+		"strength": 152.4,
+		"damping": 0.9388,
+		"mass": 2.6
+	},
+	{
+		"name": "plant/stem2",
+		"order": 17,
+		"bone": "stem2",
+		"rotate": 0.8205,
+		"limit": 700,
+		"inertia": 0.5,
+		"strength": 152.4,
+		"damping": 0.9388,
+		"mass": 2.6
+	},
+	{
+		"name": "plant/stem3",
+		"order": 18,
+		"bone": "stem3",
+		"rotate": 0.8205,
+		"limit": 700,
+		"inertia": 0.5,
+		"strength": 152.4,
+		"damping": 0.9388,
+		"mass": 2.6
+	},
+	{
+		"name": "rain/rain-blue",
+		"order": 3,
+		"bone": "rain-blue",
+		"x": 1,
+		"y": 1,
+		"strength": 0,
+		"gravity": 70
+	},
+	{
+		"name": "rain/rain-color",
+		"order": 2,
+		"bone": "rain-color",
+		"x": 1,
+		"y": 1,
+		"strength": 0,
+		"gravity": 70
+	},
+	{
+		"name": "rain/rain-green",
+		"order": 1,
+		"bone": "rain-green",
+		"x": 1,
+		"y": 1,
+		"strength": 0,
+		"gravity": 70
+	},
+	{ "name": "rain/rain-white", "bone": "rain-white", "x": 1, "y": 1, "strength": 0, "gravity": 70 }
+],
+"skins": [
+	{
+		"name": "default",
+		"attachments": {
+			"cloud-base-1": {
+				"cloud-base-1": { "width": 465, "height": 420 }
+			},
+			"cloud-base-2": {
+				"cloud-base-2": { "width": 420, "height": 415 }
+			},
+			"cloud-base-3": {
+				"cloud-base-3": { "width": 349, "height": 327 }
+			},
+			"cloud-base-4": {
+				"cloud-base-4": { "width": 352, "height": 326 }
+			},
+			"cloud-base-5": {
+				"cloud-base-5": { "width": 289, "height": 250 }
+			},
+			"cloud-base-6": {
+				"cloud-base-6": { "width": 322, "height": 272 }
+			},
+			"cloud-base-7": {
+				"cloud-base-7": { "width": 300, "height": 297 }
+			},
+			"cloud-base-8": {
+				"cloud-base-8": { "width": 307, "height": 256 }
+			},
+			"cloud-base-9": {
+				"cloud-base-9": { "width": 214, "height": 216 }
+			},
+			"cloud-base-10": {
+				"cloud-base-10": { "width": 193, "height": 201 }
+			},
+			"cloud-cheeks": {
+				"cloud-cheeks": { "x": -19, "y": -53.93, "width": 435, "height": 158 }
+			},
+			"cloud-eyes": {
+				"cloud-eyes-closed": { "x": -10, "y": -5.43, "width": 263, "height": 43 },
+				"cloud-eyes-open": { "x": -8, "y": -4.43, "width": 265, "height": 51 }
+			},
+			"cloud-eyes-reflex": {
+				"cloud-eyes-reflex": { "x": -10, "y": 2.07, "width": 239, "height": 34 }
+			},
+			"cloud-mouth": {
+				"cloud-mouth-closed": { "y": -14.93, "width": 97, "height": 32 },
+				"cloud-mouth-open": { "x": -0.5, "y": -27.93, "width": 118, "height": 70 }
+			},
+			"leaf-big": {
+				"leaf-big": {
+					"type": "mesh",
+					"uvs": [ 1, 1, 0, 1, 0, 0.75, 0, 0.5, 0, 0.25, 0, 0, 1, 0, 1, 0.25, 1, 0.5, 1, 0.75 ],
+					"triangles": [ 8, 3, 7, 3, 4, 7, 7, 4, 6, 4, 5, 6, 0, 1, 9, 1, 2, 9, 9, 2, 8, 2, 3, 8 ],
+					"vertices": [ 1, 19, -5.05, -21.72, 1, 1, 19, -5.05, 18.28, 1, 2, 19, 19.45, 18.28, 0.75483, 20, -27.28, 18.28, 0.24517, 2, 19, 43.95, 18.28, 0.50538, 20, -2.78, 18.28, 0.49462, 2, 19, 68.45, 18.28, 0.25278, 20, 21.72, 18.28, 0.74722, 1, 20, 46.22, 18.28, 1, 1, 20, 46.22, -21.72, 1, 2, 19, 68.45, -21.72, 0.24458, 20, 21.72, -21.72, 0.75542, 2, 19, 43.95, -21.72, 0.4937, 20, -2.78, -21.72, 0.5063, 2, 19, 19.45, -21.72, 0.74651, 20, -27.28, -21.72, 0.25349 ],
+					"hull": 10
+				}
+			},
+			"leaf-small": {
+				"leaf-small": { "x": 25.02, "y": 0.4, "rotation": -91.36, "width": 34, "height": 59 }
+			},
+			"petal-1": {
+				"petal-1": { "x": 18.88, "y": -4.54, "rotation": -160.18, "width": 52, "height": 36 }
+			},
+			"petal-2": {
+				"petal-2": { "x": 21.96, "y": 2.06, "rotation": -9.66, "width": 56, "height": 34 }
+			},
+			"petal-3": {
+				"petal-3": { "x": 16.97, "y": -5.71, "rotation": -91.03, "width": 58, "height": 42 }
+			},
+			"stem": {
+				"stem": {
+					"type": "mesh",
+					"uvs": [ 1, 1, 0, 1, 0, 0.90909, 0, 0.81818, 0, 0.72727, 0, 0.63636, 0, 0.54545, 0, 0.45455, 0, 0.36364, 0, 0.27273, 0, 0.18182, 0, 0.09091, 0, 0, 1, 0, 1, 0.09091, 1, 0.18182, 1, 0.27273, 1, 0.36364, 1, 0.45455, 1, 0.54545, 1, 0.63636, 1, 0.72727, 1, 0.81818, 1, 0.90909 ],
+					"triangles": [ 15, 10, 14, 10, 11, 14, 14, 11, 13, 11, 12, 13, 18, 7, 17, 7, 8, 17, 17, 8, 16, 8, 9, 16, 16, 9, 15, 9, 10, 15, 0, 1, 23, 1, 2, 23, 23, 2, 22, 2, 3, 22, 22, 3, 21, 3, 4, 21, 21, 4, 20, 4, 5, 20, 20, 5, 19, 5, 6, 19, 19, 6, 18, 6, 7, 18 ],
+					"vertices": [ 1, 22, -3.61, -6.76, 1, 1, 22, -3.61, 9.24, 1, 3, 22, 15.49, 9.24, 0.97258, 23, -89.27, 9.24, 0.02734, 24, -159.11, 9.24, 8.0E-5, 3, 22, 34.58, 9.24, 0.92758, 23, -70.18, 9.24, 0.07175, 24, -140.02, 9.24, 6.7E-4, 3, 22, 53.67, 9.24, 0.851, 23, -51.09, 9.24, 0.14565, 24, -120.93, 9.24, 0.00335, 3, 22, 72.76, 9.24, 0.73702, 23, -32, 9.24, 0.25075, 24, -101.84, 9.24, 0.01223, 3, 22, 91.85, 9.24, 0.59184, 23, -12.91, 9.24, 0.37282, 24, -82.74, 9.24, 0.03534, 3, 22, 110.94, 9.24, 0.43333, 23, 6.18, 9.24, 0.482, 24, -63.65, 9.24, 0.08467, 3, 22, 130.03, 9.24, 0.28467, 23, 25.27, 9.24, 0.54153, 24, -44.56, 9.24, 0.1738, 3, 22, 149.12, 9.24, 0.16502, 23, 44.37, 9.24, 0.52188, 24, -25.47, 9.24, 0.3131, 3, 22, 168.21, 9.24, 0.08234, 23, 63.46, 9.24, 0.4129, 24, -6.38, 9.24, 0.50477, 3, 22, 187.3, 9.24, 0.03198, 23, 82.55, 9.24, 0.228, 24, 12.71, 9.24, 0.74001, 1, 24, 31.8, 9.24, 1, 1, 24, 31.8, -6.76, 1, 3, 22, 187.3, -6.76, 0.02989, 23, 82.55, -6.76, 0.23389, 24, 12.71, -6.76, 0.73622, 3, 22, 168.21, -6.76, 0.07799, 23, 63.46, -6.76, 0.42357, 24, -6.38, -6.76, 0.49844, 3, 22, 149.12, -6.76, 0.1584, 23, 44.37, -6.76, 0.53549, 24, -25.47, -6.76, 0.30611, 3, 22, 130.03, -6.76, 0.27629, 23, 25.27, -6.76, 0.55594, 24, -44.56, -6.76, 0.16777, 3, 22, 110.94, -6.76, 0.42428, 23, 6.18, -6.76, 0.49529, 24, -63.65, -6.76, 0.08044, 3, 22, 91.85, -6.76, 0.58346, 23, -12.91, -6.76, 0.38366, 24, -82.74, -6.76, 0.03289, 3, 22, 72.76, -6.76, 0.73038, 23, -32, -6.76, 0.25856, 24, -101.84, -6.76, 0.01107, 3, 22, 53.67, -6.76, 0.84652, 23, -51.09, -6.76, 0.15057, 24, -120.93, -6.76, 0.00291, 3, 22, 34.58, -6.76, 0.92506, 23, -70.18, -6.76, 0.0744, 24, -140.02, -6.76, 5.4E-4, 3, 22, 15.49, -6.76, 0.97151, 23, -89.27, -6.76, 0.02843, 24, -159.11, -6.76, 6.0E-5 ],
+					"hull": 24
+				}
+			},
+			"stem-end": {
+				"stem-end": { "x": 25.8, "y": -0.26, "rotation": -90, "width": 25, "height": 26 }
+			},
+			"pot-base": {
+				"pot-base": { "x": 5, "y": 42, "width": 152, "height": 118 }
+			},
+			"pot-eyes": {
+				"pot-eyes-closed": { "x": -0.94, "y": 2.34, "width": 92, "height": 17 },
+				"pot-eyes-open": { "x": 0.06, "y": 3.84, "width": 80, "height": 22 }
+			},
+			"pot-mouth": {
+				"pot-mouth-open": { "x": -1.44, "y": -13.66, "width": 27, "height": 31 },
+				"pot-mouth-pouty": { "x": 0.56, "y": -12.66, "width": 35, "height": 19 },
+				"pot-mouth-smile": { "x": 0.56, "y": -12.16, "width": 27, "height": 20 },
+				"pot-mouth-smile-big": { "x": 1.56, "y": -9.16, "width": 39, "height": 18 }
+			},
+			"rain-blue": {
+				"rain-blue": { "width": 23, "height": 36 }
+			},
+			"rain-color": {
+				"rain-color": { "width": 18, "height": 34 }
+			},
+			"rain-green": {
+				"rain-green": { "width": 23, "height": 36 }
+			},
+			"rain-white": {
+				"rain-white": { "width": 23, "height": 44 }
+			},
+			"rain-white-reflex": {
+				"rain-white-reflex": { "x": -0.5, "y": 3.5, "width": 10, "height": 19 }
+			}
+		}
+	}
+],
+"animations": {
+	"playing-in-the-rain": {
+		"slots": {
+			"cloud-eyes": {
+				"attachment": [
+					{ "time": 0.2, "name": "cloud-eyes-closed" },
+					{ "time": 0.9, "name": "cloud-eyes-open" },
+					{ "time": 1.7667, "name": "cloud-eyes-closed" },
+					{ "time": 1.9333, "name": "cloud-eyes-open" },
+					{ "time": 2.4333, "name": "cloud-eyes-closed" },
+					{ "time": 2.6, "name": "cloud-eyes-open" },
+					{ "time": 3.9333, "name": "cloud-eyes-closed" },
+					{ "time": 4.1, "name": "cloud-eyes-open" }
+				]
+			},
+			"cloud-mouth": {
+				"attachment": [
+					{ "time": 0.2, "name": "cloud-mouth-open" },
+					{ "time": 0.9, "name": "cloud-mouth-closed" }
+				]
+			},
+			"pot-eyes": {
+				"attachment": [
+					{ "time": 0.1333, "name": "pot-eyes-closed" },
+					{ "time": 0.3, "name": "pot-eyes-open" },
+					{ "time": 1.0667, "name": "pot-eyes-closed" },
+					{ "time": 1.5, "name": "pot-eyes-open" },
+					{ "time": 3.0333, "name": "pot-eyes-closed" },
+					{ "time": 3.2333, "name": "pot-eyes-open" },
+					{ "time": 3.4667, "name": "pot-eyes-closed" },
+					{ "time": 3.6667, "name": "pot-eyes-open" }
+				]
+			},
+			"pot-mouth": {
+				"attachment": [
+					{ "time": 0.1333, "name": "pot-mouth-open" },
+					{ "time": 0.3, "name": "pot-mouth-smile-big" },
+					{ "time": 1.0667, "name": "pot-mouth-pouty" },
+					{ "time": 2.4, "name": "pot-mouth-smile" },
+					{ "time": 3.0333, "name": "pot-mouth-smile-big" }
+				]
+			}
+		},
+		"bones": {
+			"pot": {
+				"rotate": [
+					{ "time": 1.1 },
+					{ "time": 1.2, "value": -12.76 },
+					{ "time": 1.5333, "curve": "stepped" },
+					{ "time": 3.7667 },
+					{ "time": 3.9, "value": 8.28 },
+					{ "time": 4.2333, "value": -4.34 },
+					{ "time": 4.4333 }
+				],
+				"scale": [
+					{},
+					{ "time": 0.2, "y": 0.752 },
+					{ "time": 0.4, "x": 0.845, "y": 1.068 },
+					{ "time": 0.6333 }
+				]
+			},
+			"pot-control": {
+				"translatex": [
+					{
+						"time": 1.0667,
+						"curve": [ 1.222, -203.48, 1.378, -610.44 ]
+					},
+					{ "time": 1.5333, "value": -610.44, "curve": "stepped" },
+					{
+						"time": 2.2333,
+						"value": -610.44,
+						"curve": [ 2.389, -610.44, 2.544, -478.45 ]
+					},
+					{ "time": 2.7, "value": -478.45, "curve": "stepped" },
+					{
+						"time": 3.8333,
+						"value": -478.45,
+						"curve": [ 3.971, -478.45, 4.095, -135.56 ]
+					},
+					{ "time": 4.2333 }
+				],
+				"translatey": [
+					{
+						"time": 1.0333,
+						"curve": [ 1.089, 10.56, 1.144, 44.34 ]
+					},
+					{
+						"time": 1.2,
+						"value": 44.34,
+						"curve": [ 1.256, 44.34, 1.311, 0 ]
+					},
+					{ "time": 1.3667, "curve": "stepped" },
+					{
+						"time": 2.2333,
+						"curve": [ 2.408, 0, 2.392, 44.34 ]
+					},
+					{
+						"time": 2.4333,
+						"value": 44.34,
+						"curve": [ 2.455, 44.34, 2.51, 0 ]
+					},
+					{ "time": 2.6, "curve": "stepped" },
+					{
+						"time": 3.8,
+						"curve": [ 3.841, 14.78, 3.893, 44.34 ]
+					},
+					{
+						"time": 3.9333,
+						"value": 44.34,
+						"curve": [ 4.023, 44.34, 4.111, 14.78 ]
+					},
+					{ "time": 4.2 }
+				]
+			},
+			"cloud-base-1": {
+				"rotate": [
+					{
+						"curve": [ 0.144, -9.36, 0.289, -17.29 ]
+					},
+					{
+						"time": 0.4333,
+						"value": -17.29,
+						"curve": [ 0.5, -17.29, 0.567, -4.32 ]
+					},
+					{ "time": 0.6333 }
+				],
+				"scale": [
+					{
+						"curve": [ 0.089, 1, 0.178, 1.064, 0.089, 1, 0.178, 1.064 ]
+					},
+					{
+						"time": 0.2667,
+						"x": 1.064,
+						"y": 1.064,
+						"curve": [ 0.411, 1.064, 0.556, 1.021, 0.411, 1.064, 0.556, 1.021 ]
+					},
+					{ "time": 0.7 }
+				]
+			},
+			"cloud-base-4": {
+				"rotate": [
+					{
+						"curve": [ 0.1, 5.55, 0.2, 14.81 ]
+					},
+					{
+						"time": 0.3,
+						"value": 14.81,
+						"curve": [ 0.467, 14.81, 0.633, 9.25 ]
+					},
+					{ "time": 0.8 }
+				],
+				"scale": [
+					{
+						"curve": [ 0.089, 1, 0.178, 1.064, 0.089, 1, 0.178, 1.064 ]
+					},
+					{
+						"time": 0.2667,
+						"x": 1.064,
+						"y": 1.064,
+						"curve": [ 0.411, 1.064, 0.556, 1.021, 0.411, 1.064, 0.556, 1.021 ]
+					},
+					{ "time": 0.7 }
+				]
+			},
+			"cloud": {
+				"translate": [
+					{ "time": 0.2333 },
+					{ "time": 0.3333, "y": 30.43 },
+					{ "time": 0.4667 },
+					{ "time": 0.5667, "y": 30.43 },
+					{ "time": 0.6667 },
+					{ "time": 0.7667, "y": 30.43 },
+					{ "time": 0.9333 }
+				]
+			}
+		},
+		"physics": {
+			"rain/rain-blue": {
+				"reset": [
+					{ "time": 0.4667 },
+					{ "time": 0.9333 },
+					{ "time": 1.4 },
+					{ "time": 1.8667 },
+					{ "time": 2.3333 },
+					{ "time": 2.8 },
+					{ "time": 3.2667 },
+					{ "time": 3.7333 },
+					{ "time": 4.2 },
+					{ "time": 4.6667 }
+				]
+			},
+			"rain/rain-color": {
+				"reset": [
+					{ "time": 0.3 },
+					{ "time": 0.7667 },
+					{ "time": 1.2333 },
+					{ "time": 1.7 },
+					{ "time": 2.1667 },
+					{ "time": 2.6333 },
+					{ "time": 3.1 },
+					{ "time": 3.5667 },
+					{ "time": 4.0333 },
+					{ "time": 4.5 }
+				]
+			},
+			"rain/rain-green": {
+				"reset": [
+					{ "time": 0.1333 },
+					{ "time": 0.6 },
+					{ "time": 1.0667 },
+					{ "time": 1.5333 },
+					{ "time": 2 },
+					{ "time": 2.4667 },
+					{ "time": 2.9333 },
+					{ "time": 3.4 },
+					{ "time": 3.8667 },
+					{ "time": 4.3333 }
+				]
+			},
+			"rain/rain-white": {
+				"reset": [
+					{},
+					{ "time": 0.4667 },
+					{ "time": 0.9333 },
+					{ "time": 1.4 },
+					{ "time": 1.8667 },
+					{ "time": 2.3333 },
+					{ "time": 2.8 },
+					{ "time": 3.2667 },
+					{ "time": 3.7333 },
+					{ "time": 4.2 }
+				]
+			}
+		}
+	},
+	"pot-moving-followed-by-rain": {
+		"bones": {
+			"pot-control": {
+				"translate": [
+					{},
+					{ "time": 0.5667, "x": -389.34, "curve": "stepped" },
+					{ "time": 1.1667, "x": -389.34 },
+					{ "time": 2.2, "x": 463.88, "curve": "stepped" },
+					{ "time": 2.4667, "x": 463.88 },
+					{ "time": 3 }
+				]
+			}
+		},
+		"physics": {
+			"rain/rain-blue": {
+				"reset": [
+					{ "time": 0.4667 },
+					{ "time": 0.9333 },
+					{ "time": 1.4 },
+					{ "time": 1.8667 },
+					{ "time": 2.3333 },
+					{ "time": 2.8 },
+					{ "time": 3.2667 }
+				]
+			},
+			"rain/rain-color": {
+				"reset": [
+					{ "time": 0.3 },
+					{ "time": 0.7667 },
+					{ "time": 1.2333 },
+					{ "time": 1.7 },
+					{ "time": 2.1667 },
+					{ "time": 2.6333 },
+					{ "time": 3.1 }
+				]
+			},
+			"rain/rain-green": {
+				"reset": [
+					{ "time": 0.1333 },
+					{ "time": 0.6 },
+					{ "time": 1.0667 },
+					{ "time": 1.5333 },
+					{ "time": 2 },
+					{ "time": 2.4667 },
+					{ "time": 2.9333 }
+				]
+			},
+			"rain/rain-white": {
+				"reset": [
+					{},
+					{ "time": 0.4667 },
+					{ "time": 0.9333 },
+					{ "time": 1.4 },
+					{ "time": 1.8667 },
+					{ "time": 2.3333 },
+					{ "time": 2.8 }
+				]
+			}
+		}
+	},
+	"rain": {
+		"physics": {
+			"rain/rain-blue": {
+				"reset": [
+					{ "time": 0.4667 }
+				]
+			},
+			"rain/rain-color": {
+				"reset": [
+					{ "time": 0.3 }
+				]
+			},
+			"rain/rain-green": {
+				"reset": [
+					{ "time": 0.1333 }
+				]
+			},
+			"rain/rain-white": {
+				"reset": [
+					{}
+				]
+			}
+		}
+	}
+}
+}

BIN
spine-haxe/example/assets/cloud-pot.png


+ 11 - 0
spine-haxe/example/assets/sack-pma.atlas

@@ -0,0 +1,11 @@
+sack-pma.png
+	size: 512, 512
+	filter: Linear, Linear
+	pma: true
+	scale: 0.5
+cape-back
+	bounds: 237, 149, 260, 260
+cape-front
+	bounds: 237, 43, 200, 104
+sack
+	bounds: 2, 2, 233, 407

BIN
spine-haxe/example/assets/sack-pma.png


Файловите разлики са ограничени, защото са твърде много
+ 203 - 0
spine-haxe/example/assets/sack-pro.json


BIN
spine-haxe/example/assets/sack-pro.skel


+ 1 - 0
spine-haxe/example/src/Main.hx

@@ -49,6 +49,7 @@ class Main extends Sprite {
 		starlingSingleton.start();
 		Starling.current.stage.color = 0x000000;
 
+		// SceneManager.getInstance().switchScene(new TankExample());
 		SceneManager.getInstance().switchScene(new VineExample());
 	}
 }

+ 22 - 6
spine-haxe/example/src/VineExample.hx

@@ -27,9 +27,11 @@
  * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/
 
+import spine.BlendMode;
 import Scene.SceneManager;
 import openfl.utils.Assets;
 import spine.SkeletonData;
+import spine.Physics;
 import spine.animation.AnimationStateData;
 import spine.atlas.TextureAtlas;
 import spine.starling.SkeletonSprite;
@@ -43,17 +45,31 @@ class VineExample extends Scene {
 
 	public function load():Void {
 		background.color = 0xffffffff;
-		var atlas = new TextureAtlas(Assets.getText("assets/vine.atlas"), new StarlingTextureLoader("assets/vine.atlas"));
-		var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/vine-pro.skel") : Assets.getText("assets/vine-pro.json"), atlas);
+
+		// var atlas = new TextureAtlas(Assets.getText("assets/cloud-pot.atlas"), new StarlingTextureLoader("assets/cloud-pot.atlas"));
+		// var skeletondata = SkeletonData.from(Assets.getText("assets/cloud-pot.json"), atlas);
+
+		var atlas = new TextureAtlas(Assets.getText("assets/sack-pma.atlas"), new StarlingTextureLoader("assets/sack-pma.atlas"));
+		var skeletondata = SkeletonData.from(Assets.getText("assets/sack-pro.json"), atlas);
+
 		var animationStateData = new AnimationStateData(skeletondata);
 		animationStateData.defaultMix = 0.25;
 
 		var skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
-		skeletonSprite.skeleton.updateWorldTransform();
+		skeletonSprite.skeleton.updateWorldTransform(Physics.update);
 		var bounds = skeletonSprite.skeleton.getBounds();
-		skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width;
+
+		
+		skeletonSprite.scale = 0.2;
 		skeletonSprite.x = Starling.current.stage.stageWidth / 2;
-		skeletonSprite.y = Starling.current.stage.stageHeight * 0.5;
+		skeletonSprite.y = Starling.current.stage.stageHeight/ 2;
+		
+		trace(skeletonSprite);
+
+		// skeletonSprite.state.setAnimationByName(0, "playing-in-the-rain", true);
+		
+		
+		skeletonSprite.state.setAnimationByName(0, "cape-follow-example", true);
 
 		addChild(skeletonSprite);
 		juggler.add(skeletonSprite);
@@ -64,7 +80,7 @@ class VineExample extends Scene {
 	public function onTouch(e:TouchEvent) {
 		var touch = e.getTouch(this);
 		if (touch != null && touch.phase == TouchPhase.ENDED) {
-			SceneManager.getInstance().switchScene(new BasicExample());
+			// SceneManager.getInstance().switchScene(new BasicExample());
 		}
 	}
 }

+ 165 - 109
spine-haxe/spine-haxe/spine/Bone.hx

@@ -57,9 +57,34 @@ class Bone implements Updatable {
 	public var d:Float = 0;
 	public var worldX:Float = 0;
 	public var worldY:Float = 0;
+	public var inherit:Inherit = Inherit.normal;
 	public var sorted:Bool = false;
 	public var active:Bool = false;
 
+	public var data(get, never):BoneData;
+
+	private function get_data():BoneData {
+		return _data;
+	}
+
+	public var skeleton(get, never):Skeleton;
+
+	private function get_skeleton():Skeleton {
+		return _skeleton;
+	}
+
+	public var parent(get, never):Bone;
+
+	private function get_parent():Bone {
+		return _parent;
+	}
+
+	public var children(get, never):Array<Bone>;
+
+	private function get_children():Array<Bone> {
+		return _children;
+	}
+
 	/** @param parent May be null. */
 	public function new(data:BoneData, skeleton:Skeleton, parent:Bone) {
 		if (data == null)
@@ -77,7 +102,7 @@ class Bone implements Updatable {
 	}
 
 	/** Same as updateWorldTransform(). This method exists for Bone to implement Updatable. */
-	public function update():Void {
+	public function update(physics:Physics):Void {
 		updateWorldTransformWith(ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY);
 	}
 
@@ -96,7 +121,6 @@ class Bone implements Updatable {
 		ashearX = shearX;
 		ashearY = shearY;
 
-		var rotationY:Float = 0;
 		var la:Float = 0;
 		var lb:Float = 0;
 		var lc:Float = 0;
@@ -110,11 +134,12 @@ class Bone implements Updatable {
 		var parent:Bone = _parent;
 		if (parent == null) {
 			// Root bone.
-			rotationY = rotation + 90 + shearY;
-			a = MathUtils.cosDeg(rotation + shearX) * scaleX * sx;
-			b = MathUtils.cosDeg(rotationY) * scaleY * sx;
-			c = MathUtils.sinDeg(rotation + shearX) * scaleX * sy;
-			d = MathUtils.sinDeg(rotationY) * scaleY * sy;
+			var rx:Float = (rotation + shearX) * MathUtils.degRad;
+			var ry:Float = (rotation + 90 + shearY) * MathUtils.degRad;
+			a = Math.cos(rx) * scaleX * sx;
+			b = Math.cos(ry) * scaleY * sx;
+			c = Math.sin(rx) * scaleX * sy;
+			d = Math.sin(ry) * scaleY * sy;
 			worldX = x * sx + skeleton.x;
 			worldY = y * sy + skeleton.y;
 			return;
@@ -127,25 +152,27 @@ class Bone implements Updatable {
 		worldX = pa * x + pb * y + parent.worldX;
 		worldY = pc * x + pd * y + parent.worldY;
 
-		switch (data.transformMode) {
-			case TransformMode.normal:
-				rotationY = rotation + 90 + shearY;
-				la = MathUtils.cosDeg(rotation + shearX) * scaleX;
-				lb = MathUtils.cosDeg(rotationY) * scaleY;
-				lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
-				ld = MathUtils.sinDeg(rotationY) * scaleY;
+		switch (data.inherit) {
+			case Inherit.normal:
+				var rx:Float = (rotation + shearX) * MathUtils.degRad;
+				var ry:Float = (rotation + 90 + shearY) * MathUtils.degRad;
+				la = Math.cos(rx) * scaleX;
+				lb = Math.cos(ry) * scaleY;
+				lc = Math.sin(rx) * scaleX;
+				ld = Math.sin(ry) * scaleY;
 				a = pa * la + pb * lc;
 				b = pa * lb + pb * ld;
 				c = pc * la + pd * lc;
 				d = pc * lb + pd * ld;
 				return;
-			case TransformMode.onlyTranslation:
-				rotationY = rotation + 90 + shearY;
-				a = MathUtils.cosDeg(rotation + shearX) * scaleX;
-				b = MathUtils.cosDeg(rotationY) * scaleY;
-				c = MathUtils.sinDeg(rotation + shearX) * scaleX;
-				d = MathUtils.sinDeg(rotationY) * scaleY;
-			case TransformMode.noRotationOrReflection:
+			case Inherit.onlyTranslation:
+				var rx:Float = (rotation + shearX) * MathUtils.degRad;
+				var ry:Float = (rotation + 90 + shearY) * MathUtils.degRad;
+				a = Math.cos(rx) * scaleX;
+				b = Math.cos(ry) * scaleY;
+				c = Math.sin(rx) * scaleX;
+				d = Math.sin(ry) * scaleY;
+			case Inherit.noRotationOrReflection:
 				s = pa * pa + pc * pc;
 				var prx:Float = 0;
 				if (s > 0.0001) {
@@ -158,19 +185,20 @@ class Bone implements Updatable {
 					pc = 0;
 					prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg;
 				}
-				var rx:Float = rotation + shearX - prx;
-				var ry:Float = rotation + shearY - prx + 90;
-				la = MathUtils.cosDeg(rx) * scaleX;
-				lb = MathUtils.cosDeg(ry) * scaleY;
-				lc = MathUtils.sinDeg(rx) * scaleX;
-				ld = MathUtils.sinDeg(ry) * scaleY;
+				var rx:Float = (rotation + shearX - prx) * MathUtils.degRad;
+				var ry:Float = (rotation + shearY - prx + 90) * MathUtils.degRad;
+				la = Math.cos(rx) * scaleX;
+				lb = Math.cos(ry) * scaleY;
+				lc = Math.sin(rx) * scaleX;
+				ld = Math.sin(ry) * scaleY;
 				a = pa * la - pb * lc;
 				b = pa * lb - pb * ld;
 				c = pc * la + pd * lc;
 				d = pc * lb + pd * ld;
-			case TransformMode.noScale, TransformMode.noScaleOrReflection:
-				cos = MathUtils.cosDeg(rotation);
-				sin = MathUtils.sinDeg(rotation);
+			case Inherit.noScale, Inherit.noScaleOrReflection:
+				rotation *= MathUtils.degRad;
+				cos = Math.cos(rotation);
+				sin = Math.sin(rotation);
 				var za:Float = (pa * cos + pb * sin) / sx;
 				var zc:Float = (pc * cos + pd * sin) / sy;
 				s = Math.sqrt(za * za + zc * zc);
@@ -179,16 +207,18 @@ class Bone implements Updatable {
 				za *= s;
 				zc *= s;
 				s = Math.sqrt(za * za + zc * zc);
-				if (data.transformMode == TransformMode.noScale && ((pa * pd - pb * pc < 0) != ((sx < 0) != (sy < 0)))) {
+				if (data.inherit == Inherit.noScale && ((pa * pd - pb * pc < 0) != ((sx < 0) != (sy < 0)))) {
 					s = -s;
 				}
-				var r:Float = Math.PI / 2 + Math.atan2(zc, za);
-				var zb:Float = Math.cos(r) * s;
-				var zd:Float = Math.sin(r) * s;
-				la = MathUtils.cosDeg(shearX) * scaleX;
-				lb = MathUtils.cosDeg(90 + shearY) * scaleY;
-				lc = MathUtils.sinDeg(shearX) * scaleX;
-				ld = MathUtils.sinDeg(90 + shearY) * scaleY;
+				rotation = Math.PI / 2 + Math.atan2(zc, za);
+				var zb:Float = Math.cos(rotation) * s;
+				var zd:Float = Math.sin(rotation) * s;
+				shearX *= MathUtils.degRad;
+				shearY = (90 + shearY) * MathUtils.degRad;
+				la = Math.cos(shearX) * scaleX;
+				lb = Math.cos(shearY) * scaleY;
+				lc = Math.sin(shearX) * scaleX;
+				ld = Math.sin(shearY) * scaleY;
 				a = za * la + zb * lc;
 				b = za * lb + zb * ld;
 				c = zc * la + zd * lc;
@@ -208,54 +238,7 @@ class Bone implements Updatable {
 		scaleY = data.scaleY;
 		shearX = data.shearX;
 		shearY = data.shearY;
-	}
-
-	public var data(get, never):BoneData;
-
-	private function get_data():BoneData {
-		return _data;
-	}
-
-	public var skeleton(get, never):Skeleton;
-
-	private function get_skeleton():Skeleton {
-		return _skeleton;
-	}
-
-	public var parent(get, never):Bone;
-
-	private function get_parent():Bone {
-		return _parent;
-	}
-
-	public var children(get, never):Array<Bone>;
-
-	private function get_children():Array<Bone> {
-		return _children;
-	}
-
-	public var worldRotationX(get, never):Float;
-
-	private function get_worldRotationX():Float {
-		return Math.atan2(c, a) * MathUtils.radDeg;
-	}
-
-	public var worldRotationY(get, never):Float;
-
-	private function get_worldRotationY():Float {
-		return Math.atan2(d, b) * MathUtils.radDeg;
-	}
-
-	public var worldScaleX(get, never):Float;
-
-	private function get_worldScaleX():Float {
-		return Math.sqrt(a * a + c * c);
-	}
-
-	public var worldScaleY(get, never):Float;
-
-	private function get_worldScaleY():Float {
-		return Math.sqrt(b * b + d * d);
+		inherit = data.inherit;
 	}
 
 	/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
@@ -279,24 +262,62 @@ class Bone implements Updatable {
 			pc:Float = parent.c,
 			pd:Float = parent.d;
 		var pid:Float = 1 / (pa * pd - pb * pc);
+		var ia:Float = pd * pid,
+			ib:Float = pb * pid,
+			ic:Float = pc * pid,
+			id:Float = pa * pid;
 		var dx:Float = worldX - parent.worldX,
 			dy:Float = worldY - parent.worldY;
-		ax = (dx * pd * pid - dy * pb * pid);
-		ay = (dy * pa * pid - dx * pc * pid);
-		var ia:Float = pid * pd;
-		var id:Float = pid * pa;
-		var ib:Float = pid * pb;
-		var ic:Float = pid * pc;
-		var ra:Float = ia * a - ib * c;
-		var rb:Float = ia * b - ib * d;
-		var rc:Float = id * c - ic * a;
-		var rd:Float = id * d - ic * b;
+		ax = (dx * ia - dy * ib);
+		ay = (dy * id - dx * ic);
+		var ra:Float, rb:Float, rc:Float, rd:Float;
+		if (inherit == Inherit.onlyTranslation) {
+			ra = a;
+			rb = b;
+			rc = c;
+			rd = d;
+		} else {
+			switch (inherit) {
+				case Inherit.noRotationOrReflection:
+					var s:Float = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
+					var sa:Float = pa / skeleton.scaleX;
+					var sc:Float = pc / skeleton.scaleY;
+					pb = -sc * s * skeleton.scaleX;
+					pd = sa * s * skeleton.scaleY;
+					pid = 1 / (pa * pd - pb * pc);
+					ia = pd * pid;
+					ib = pb * pid;
+				case Inherit.noScale | Inherit.noScaleOrReflection:
+					var cos:Float = MathUtils.cosDeg(rotation), sin:Float = MathUtils.sinDeg(rotation);
+					pa = (pa * cos + pb * sin) / skeleton.scaleX;
+					pc = (pc * cos + pd * sin) / skeleton.scaleY;
+					var s:Float = Math.sqrt(pa * pa + pc * pc);
+					if (s > 0.00001) s = 1 / s;
+					pa *= s;
+					pc *= s;
+					s = Math.sqrt(pa * pa + pc * pc);
+					if (inherit == Inherit.noScale && pid < 0 != ((skeleton.scaleX < 0) != (skeleton.scaleY < 0))) s = -s;
+					var r:Float = MathUtils.PI / 2 + Math.atan2(pc, pa);
+					pb = Math.cos(r) * s;
+					pd = Math.sin(r) * s;
+					pid = 1 / (pa * pd - pb * pc);
+					ia = pd * pid;
+					ib = pb * pid;
+					ic = pc * pid;
+					id = pa * pid;
+			}
+			ra = ia * a - ib * c;
+			rb = ia * b - ib * d;
+			rc = id * c - ic * a;
+			rd = id * d - ic * b;
+		}
+
 		ashearX = 0;
 		ascaleX = Math.sqrt(ra * ra + rc * rc);
 		if (scaleX > 0.0001) {
 			var det:Float = ra * rd - rb * rc;
 			ascaleY = det / ascaleX;
-			ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
+			ashearY = -Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
 			arotation = Math.atan2(rc, ra) * MathUtils.radDeg;
 		} else {
 			ascaleX = 0;
@@ -306,18 +327,56 @@ class Bone implements Updatable {
 		}
 	}
 
-	public function worldToLocal(world:Array<Float>):Void {
+	public var worldRotationX(get, never):Float;
+
+	private function get_worldRotationX():Float {
+		return Math.atan2(c, a) * MathUtils.radDeg;
+	}
+
+	public var worldRotationY(get, never):Float;
+
+	private function get_worldRotationY():Float {
+		return Math.atan2(d, b) * MathUtils.radDeg;
+	}
+
+	public var worldScaleX(get, never):Float;
+
+	private function get_worldScaleX():Float {
+		return Math.sqrt(a * a + c * c);
+	}
+
+	public var worldScaleY(get, never):Float;
+
+	private function get_worldScaleY():Float {
+		return Math.sqrt(b * b + d * d);
+	}
+
+	private function worldToParent(world: Array<Float>):Array<Float> {
+		if (world == null)
+			throw new SpineException("world cannot be null.");
+		return parent == null ? world : parent.worldToLocal(world);
+	}
+
+	private function parentToWorld(world: Array<Float>):Array<Float> {
+		if (world == null)
+			throw new SpineException("world cannot be null.");
+		return parent == null ? world : parent.localToWorld(world);
+	}
+
+	public function worldToLocal(world:Array<Float>):Array<Float> {
 		var a:Float = a, b:Float = b, c:Float = c, d:Float = d;
 		var invDet:Float = 1 / (a * d - b * c);
 		var x:Float = world[0] - worldX, y:Float = world[1] - worldY;
 		world[0] = (x * d * invDet - y * b * invDet);
 		world[1] = (y * a * invDet - x * c * invDet);
+		return world;
 	}
 
-	public function localToWorld(local:Array<Float>):Void {
+	public function localToWorld(local:Array<Float>):Array<Float> {
 		var localX:Float = local[0], localY:Float = local[1];
 		local[0] = localX * a + localY * b + worldX;
 		local[1] = localX * c + localY * d + worldY;
+		return local;
 	}
 
 	public function worldToLocalRotation(worldRotation:Float):Float {
@@ -334,16 +393,13 @@ class Bone implements Updatable {
 	}
 
 	public function rotateWorld(degrees:Float):Void {
-		var a:Float = this.a,
-			b:Float = this.b,
-			c:Float = this.c,
-			d:Float = this.d;
-		var cos:Float = MathUtils.cosDeg(degrees),
-			sin:Float = MathUtils.sinDeg(degrees);
-		this.a = cos * a - sin * c;
-		this.b = cos * b - sin * d;
-		this.c = sin * a + cos * c;
-		this.d = sin * b + cos * d;
+		degrees *= MathUtils.degRad;
+		var sin:Float = Math.sin(degrees), cos:Float = Math.cos(degrees);
+		var ra:Float = a, rb:Float = b;
+		a = cos * ra - sin * c;
+		b = cos * rb - sin * d;
+		c = sin * ra + cos * c;
+		d = sin * rb + cos * d;
 	}
 
 	public function toString():String {

+ 4 - 2
spine-haxe/spine-haxe/spine/BoneData.hx

@@ -42,9 +42,11 @@ class BoneData {
 	public var scaleY:Float = 1;
 	public var shearX:Float = 0;
 	public var shearY:Float = 0;
-	public var transformMode:TransformMode = TransformMode.normal;
+	public var inherit:Inherit = Inherit.normal;
 	public var skinRequired:Bool = false;
 	public var color:Color = new Color(0, 0, 0, 0);
+	public var icon:String;
+	public var visible:Bool = false;
 
 	/** @param parent May be null. */
 	public function new(index:Int, name:String, parent:BoneData) {
@@ -65,7 +67,7 @@ class BoneData {
 
 	public var name(get, never):String;
 
-	private function get_name():String {
+	function get_name():String {
 		return _name;
 	}
 

+ 25 - 13
spine-haxe/spine-haxe/spine/IkConstraint.hx

@@ -64,7 +64,16 @@ class IkConstraint implements Updatable {
 		return active;
 	}
 
-	public function update():Void {
+	public function setToSetupPose () {
+		var data:IkConstraintData = _data;
+		mix = data.mix;
+		softness = data.softness;
+		bendDirection = data.bendDirection;
+		compress = data.compress;
+		stretch = data.stretch;
+	}
+
+	public function update(physics:Physics):Void {
 		if (mix == 0)
 			return;
 		switch (bones.length) {
@@ -93,11 +102,11 @@ class IkConstraint implements Updatable {
 		var rotationIK:Float = -bone.ashearX - bone.arotation,
 			tx:Float = 0,
 			ty:Float = 0;
-		switch (bone.data.transformMode) {
-			case TransformMode.onlyTranslation:
+		switch (bone.inherit) {
+			case Inherit.onlyTranslation:
 				tx = (targetX - bone.worldX) * MathUtils.signum(bone.skeleton.scaleX);
 				ty = (targetY - bone.worldY) * MathUtils.signum(bone.skeleton.scaleY);
-			case TransformMode.noRotationOrReflection:
+			case Inherit.noRotationOrReflection:
 				var s = Math.abs(pa * pd - pb * pc) / Math.max(0.0001, pa * pa + pc * pc);
 				var sa:Float = pa / bone.skeleton.scaleX;
 				var sc:Float = pc / bone.skeleton.scaleY;
@@ -108,6 +117,7 @@ class IkConstraint implements Updatable {
 				var d:Float = pa * pd - pb * pc;
 				tx = (x * pd - y * pb) / d - bone.ax;
 				ty = (y * pa - x * pc) / d - bone.ay;
+				// TODO: this should fall-through!
 			default:
 				var x:Float = targetX - p.worldX, y:Float = targetY - p.worldY;
 				var d:Float = pa * pd - pb * pc;
@@ -130,18 +140,19 @@ class IkConstraint implements Updatable {
 		var sx:Float = bone.ascaleX;
 		var sy:Float = bone.ascaleY;
 		if (compress || stretch) {
-			switch (bone.data.transformMode) {
-				case TransformMode.noScale, TransformMode.noScaleOrReflection:
+			switch (bone.inherit) {
+				case Inherit.noScale, Inherit.noScaleOrReflection:
 					tx = targetX - bone.worldX;
 					ty = targetY - bone.worldY;
 			}
-			var b:Float = bone.data.length * sx,
-				dd:Float = Math.sqrt(tx * tx + ty * ty);
-			if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) {
-				var ss:Float = (dd / b - 1) * alpha + 1;
-				sx *= ss;
-				if (uniform)
-					sy *= ss;
+			var b:Float = bone.data.length * sx;
+			if (b > 0.0001) {
+				var	dd:Float = tx * tx + ty * ty;
+				if ((compress && dd < b * b) || (stretch && dd > b * b)) {
+					var s:Float = (Math.sqrt(dd) / b - 1) * alpha + 1;
+					sx *= s;
+					if (uniform) sy *= s;
+				}
 			}
 		}
 		bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
@@ -152,6 +163,7 @@ class IkConstraint implements Updatable {
 	 * @param child Any descendant bone of the parent. */
 	static public function apply2(parent:Bone, child:Bone, targetX:Float, targetY:Float, bendDir:Int, stretch:Bool, uniform:Bool, softness:Float,
 			alpha:Float):Void {
+		if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal) return;
 		var px:Float = parent.ax;
 		var py:Float = parent.ay;
 		var psx:Float = parent.ascaleX;

+ 2 - 2
spine-haxe/spine-haxe/spine/IkConstraintData.hx

@@ -32,8 +32,8 @@ package spine;
 class IkConstraintData extends ConstraintData {
 	public var bones:Array<BoneData> = new Array<BoneData>();
 	public var target:BoneData;
-	public var mix:Float = 1;
-	public var bendDirection:Int = 1;
+	public var mix:Float = 0;
+	public var bendDirection:Int = 0;
 	public var compress:Bool = false;
 	public var stretch:Bool = false;
 	public var uniform:Bool = false;

+ 56 - 0
spine-haxe/spine-haxe/spine/Inherit.hx

@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine;
+
+class Inherit {
+	public static var normal(default, never):Inherit = new Inherit(0, "normal");
+	public static var onlyTranslation(default, never):Inherit = new Inherit(1, "onlyTranslation");
+	public static var noRotationOrReflection(default, never):Inherit = new Inherit(2, "noRotationOrReflection");
+	public static var noScale(default, never):Inherit = new Inherit(3, "noScale");
+	public static var noScaleOrReflection(default, never):Inherit = new Inherit(4, "noScaleOrReflection");
+
+	public static var values:Array<Inherit> = [normal, onlyTranslation, noRotationOrReflection, noScale, noScaleOrReflection];
+
+	public var ordinal(default, null):Int;
+	public var name(default, null):String;
+
+	public function new(ordinal:Int, name:String) {
+		this.ordinal = ordinal;
+		this.name = name;
+	}
+
+	public static function fromName(name:String):Inherit {
+		for (value in values) {
+			if (value.name == name)
+				return value;
+		}
+		return null;
+	}
+}

+ 5 - 0
spine-haxe/spine-haxe/spine/MathUtils.hx

@@ -32,6 +32,7 @@ package spine;
 class MathUtils {
 	static public var PI:Float = Math.PI;
 	static public var PI2:Float = Math.PI * 2;
+	static public var invPI2 = 1 / MathUtils.PI2;
 	static public var radDeg:Float = 180 / Math.PI;
 	static public var degRad:Float = Math.PI / 180;
 
@@ -43,6 +44,10 @@ class MathUtils {
 		return Math.sin(degrees * degRad);
 	}
 
+	static public function atan2Deg (y:Float, x:Float):Float {
+		return Math.atan2(y, x) * MathUtils.degRad;
+	}
+
 	static public function clamp(value:Float, min:Float, max:Float):Float {
 		if (value < min)
 			return min;

+ 13 - 8
spine-haxe/spine-haxe/spine/PathConstraint.hx

@@ -78,7 +78,16 @@ class PathConstraint implements Updatable {
 		return active;
 	}
 
-	public function update():Void {
+	public function setToSetupPose () {
+		var data:PathConstraintData = _data;
+		position = data.position;
+		spacing = data.spacing;
+		mixRotate = data.mixRotate;
+		mixX = data.mixX;
+		mixY = data.mixY;
+	}
+
+	public function update(physics:Physics):Void {
 		var attachment:PathAttachment = cast(target.attachment, PathAttachment);
 		if (attachment == null)
 			return;
@@ -111,13 +120,9 @@ class PathConstraint implements Updatable {
 					for (i in 0...n) {
 						bone = bones[i];
 						setupLength = bone.data.length;
-						if (setupLength < PathConstraint.epsilon) {
-							_lengths[i] = 0;
-						} else {
-							x = setupLength * bone.a;
-							y = setupLength * bone.c;
-							_lengths[i] = Math.sqrt(x * x + y * y);
-						}
+						x = setupLength * bone.a;
+						y = setupLength * bone.c;
+						_lengths[i] = Math.sqrt(x * x + y * y);
 					}
 				}
 				for (i in 1...spacesCount) {

+ 7 - 8
spine-haxe/spine-haxe/spine/TransformMode.hx → spine-haxe/spine-haxe/spine/Physics.hx

@@ -29,14 +29,13 @@
 
 package spine;
 
-class TransformMode {
-	public static var normal(default, never):TransformMode = new TransformMode("normal");
-	public static var onlyTranslation(default, never):TransformMode = new TransformMode("onlyTranslation");
-	public static var noRotationOrReflection(default, never):TransformMode = new TransformMode("noRotationOrReflection");
-	public static var noScale(default, never):TransformMode = new TransformMode("noScale");
-	public static var noScaleOrReflection(default, never):TransformMode = new TransformMode("noScaleOrReflection");
+class Physics {
+	public static var none(default, never):Physics = new Physics("none");
+	public static var reset(default, never):Physics = new Physics("reset");
+	public static var update(default, never):Physics = new Physics("update");
+	public static var pose(default, never):Physics = new Physics("pose");
 
-	public static var values:Array<TransformMode> = [normal, onlyTranslation, noRotationOrReflection, noScale, noScaleOrReflection];
+	public static var values:Array<Physics> = [none, reset, update, pose];
 
 	public var name(default, null):String;
 
@@ -44,7 +43,7 @@ class TransformMode {
 		this.name = name;
 	}
 
-	public static function fromName(name:String):TransformMode {
+	public static function fromName(name:String):Physics {
 		for (value in values) {
 			if (value.name == name)
 				return value;

+ 322 - 0
spine-haxe/spine-haxe/spine/PhysicsConstraint.hx

@@ -0,0 +1,322 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine;
+
+class PhysicsConstraint implements Updatable {
+	private var _data:PhysicsConstraintData;
+	private var _bone:Bone = null;
+	
+	public var inertia:Float = 0;
+	public var strength:Float = 0;
+	public var damping:Float = 0;
+	public var massInverse:Float = 0;
+	public var wind:Float = 0;
+	public var gravity:Float = 0;
+	public var mix:Float = 0;
+
+	private var _reset:Bool = true;
+
+	public var ux:Float = 0;
+	public var uy:Float = 0;
+	public var cx:Float = 0;
+	public var cy:Float = 0;
+	public var tx:Float = 0;
+	public var ty:Float = 0;
+	public var xOffset:Float = 0;
+	public var xVelocity:Float = 0;
+	public var yOffset:Float = 0;
+	public var yVelocity:Float = 0;
+	public var rotateOffset:Float = 0;
+	public var rotateVelocity:Float = 0;
+	public var scaleOffset:Float = 0;
+	public var scaleVelocity:Float = 0;
+
+	public var active:Bool = false;
+
+	private var _skeleton:Skeleton;
+	public var remaining:Float = 0;
+	public var lastTime:Float = 0;
+	
+	public function new(data: PhysicsConstraintData, skeleton: Skeleton) {
+		_data = data;
+		_skeleton = skeleton;
+		_bone = skeleton.bones[data.bone.index];
+		inertia = data.inertia;
+		strength = data.strength;
+		damping = data.damping;
+		massInverse = data.massInverse;
+		wind = data.wind;
+		gravity = data.gravity;
+		mix = data.mix;
+	}
+
+	public function reset () {
+		remaining = 0;
+		lastTime = skeleton.time;
+		_reset = true;
+		xOffset = 0;
+		xVelocity = 0;
+		yOffset = 0;
+		yVelocity = 0;
+		rotateOffset = 0;
+		rotateVelocity = 0;
+		scaleOffset = 0;
+		scaleVelocity = 0;
+	}
+
+	public function setToSetupPose () {
+		var data:PhysicsConstraintData = _data;
+		inertia = data.inertia;
+		strength = data.strength;
+		damping = data.damping;
+		massInverse = data.massInverse;
+		wind = data.wind;
+		gravity = data.gravity;
+		mix = data.mix;
+	}
+
+	public function isActive():Bool {
+		return active;
+	}
+
+	public function update(physics:Physics):Void {
+		var mix:Float = this.mix;
+		if (mix == 0) return;
+
+		var x:Bool = _data.x > 0, y:Bool = _data.y > 0,
+			rotateOrShearX:Bool = _data.rotate > 0 || _data.shearX > 0,
+			scaleX:Bool = _data.scaleX > 0;
+		var bone:Bone = _bone;
+		var l:Float = bone.data.length;
+
+		switch (physics) {
+			case Physics.none:
+				return;
+			case Physics.reset, Physics.update:
+				if (physics == Physics.reset) reset();
+				
+				var delta:Float = Math.max(skeleton.time - lastTime, 0);
+				remaining += delta;
+				lastTime = _skeleton.time;
+
+				var bx:Float = bone.worldX, by:Float = bone.worldY;
+				if (_reset) {
+					_reset = false;
+					ux = bx;
+					uy = by;
+				} else {
+					var a:Float = remaining,
+						i:Float = inertia,
+						q:Float = _data.limit * delta,
+						t:Float = _data.step,
+						f:Float = skeleton.data.referenceScale,
+						d:Float = -1;
+					if (x || y) {
+						if (x) {
+							var u:Float = (ux - bx) * i;
+							xOffset += u > q ? q : u < -q ? -q : u;
+							ux = bx;
+						}
+						if (y) {
+							var u:Float = (uy - by) * i;
+							yOffset += u > q ? q : u < -q ? -q : u;
+							uy = by;
+						}
+						if (a >= t) {
+							d = Math.pow(damping, 60 * t);
+							var m:Float = massInverse * t,
+								e:Float = strength,
+								w:Float = wind * f,
+								g:Float = (Bone.yDown ? -gravity : gravity) * f;
+							do {
+								if (x) {
+									xVelocity += (w - xOffset * e) * m;
+									xOffset += xVelocity * t;
+									xVelocity *= d;
+								}
+								if (y) {
+									yVelocity -= (g + yOffset * e) * m;
+									yOffset += yVelocity * t;
+									yVelocity *= d;
+								}
+								a -= t;
+							}  while (a >= t);
+						}
+						if (x) bone.worldX += xOffset * mix * data.x;
+						if (y) bone.worldY += yOffset * mix * data.y;
+					}
+					if (rotateOrShearX || scaleX) {
+						var ca:Float = Math.atan2(bone.c, bone.a),
+							c:Float = 0,
+							s:Float = 0,
+							mr:Float = 0;
+						var dx:Float = cx - bone.worldX,
+							dy:Float = cy - bone.worldY;
+						if (dx > q)
+							dx = q;
+						else if (dx < -q) //
+							dx = -q;
+						if (dy > q)
+							dy = q;
+						else if (dy < -q) //
+							dy = -q;
+						if (rotateOrShearX) {
+							mr = (_data.rotate + _data.shearX) * mix;
+							var r:Float = Math.atan2(dy + ty, dx + tx) - ca - rotateOffset * mr;
+							rotateOffset += (r - Math.ceil(r * MathUtils.invPI2 - 0.5) * MathUtils.PI2) * i;
+							r = rotateOffset * mr + ca;
+							c = Math.cos(r);
+							s = Math.sin(r);
+							if (scaleX) {
+								r = l * bone.worldScaleX;
+								if (r > 0) scaleOffset += (dx * c + dy * s) * i / r;
+							}
+						} else {
+							c = Math.cos(ca);
+							s = Math.sin(ca);
+							var r:Float = l * bone.worldScaleX;
+							if (r > 0) scaleOffset += (dx * c + dy * s) * i / r;
+						}
+						a = remaining;
+						if (a >= t) {
+							if (d == -1) d = Math.pow(damping, 60 * t);
+							var m:Float = massInverse * t,
+							e:Float = strength,
+							w:Float = wind,
+							g:Float = (Bone.yDown ? -gravity : gravity),
+							h:Float = l / f;
+							while (true) {
+								a -= t;
+								if (scaleX) {
+									scaleVelocity += (w * c - g * s - scaleOffset * e) * m;
+									scaleOffset += scaleVelocity * t;
+									scaleVelocity *= d;
+								}
+								if (rotateOrShearX) {
+									rotateVelocity -= ((w * s + g * c) * h + rotateOffset * e) * m;
+									rotateOffset += rotateVelocity * t;
+									rotateVelocity *= d;
+									if (a < t) break;
+									var r:Float = rotateOffset * mr + ca;
+									c = Math.cos(r);
+									s = Math.sin(r);
+								} else if (a < t) //
+									break;
+							}
+						}
+					}
+					remaining = a;
+				}
+				cx = bone.worldX;
+				cy = bone.worldY;
+			case Physics.pose:
+				if (x) bone.worldX += xOffset * mix * data.x;
+				if (y) bone.worldY += yOffset * mix * data.y;
+		}
+
+		if (rotateOrShearX) {
+			var o:Float = rotateOffset * mix,
+				s:Float = 0,
+				c:Float = 0,
+				a:Float = 0;
+			if (_data.shearX > 0) {
+				var r:Float = 0;
+				if (_data.rotate > 0) {
+					r = o * _data.rotate;
+					s = Math.sin(r);
+					c = Math.cos(r);
+					a = bone.b;
+					bone.b = c * a - s * bone.d;
+					bone.d = s * a + c * bone.d;
+				}
+				r += o * _data.shearX;
+				s = Math.sin(r);
+				c = Math.cos(r);
+				a = bone.a;
+				bone.a = c * a - s * bone.c;
+				bone.c = s * a + c * bone.c;
+			} else {
+				o *= _data.rotate;
+				s = Math.sin(o);
+				c = Math.cos(o);
+				a = bone.a;
+				bone.a = c * a - s * bone.c;
+				bone.c = s * a + c * bone.c;
+				a = bone.b;
+				bone.b = c * a - s * bone.d;
+				bone.d = s * a + c * bone.d;
+			}
+		}
+		if (scaleX) {
+			var s:Float = 1 + scaleOffset * mix * data.scaleX;
+			bone.a *= s;
+			bone.c *= s;
+		}
+		if (physics != Physics.pose) {
+			tx = l * bone.a;
+			ty = l * bone.c;
+		}
+		bone.updateAppliedTransform();
+	}
+
+	public function translate (x:Float, y:Float):Void {
+		ux -= x;
+		uy -= y;
+		cx -= x;
+		cy -= y;
+	}
+
+	public function rotate (x:Float, y:Float, degrees:Float):Void {
+		var r:Float = degrees * MathUtils.degRad, cos:Float = Math.cos(r), sin:Float = Math.sin(r);
+		var dx:Float = cx - x, dy:Float = cy - y;
+		translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
+	}
+
+	public var bone(get, never):Bone;
+
+	private function get_bone():Bone {
+		if (_bone == null)
+			throw new SpineException("Bone not set.")
+		else return _bone;
+	}
+
+	public var data(get, never):PhysicsConstraintData;
+
+	private function get_data():PhysicsConstraintData {
+		return _data;
+	}
+
+	public var skeleton(get, never):Skeleton;
+
+	private function get_skeleton():Skeleton {
+		return _skeleton;
+	}
+
+}

+ 60 - 0
spine-haxe/spine-haxe/spine/PhysicsConstraintData.hx

@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine;
+
+class PhysicsConstraintData extends ConstraintData {
+	public var bone:BoneData;
+	public var x:Float = 0;
+	public var y:Float = 0;
+	public var rotate:Float = 0;
+	public var scaleX:Float = 0;
+	public var shearX:Float = 0;
+	public var limit:Float = 0;
+	public var step:Float = 0;
+	public var inertia:Float = 0;
+	public var strength:Float = 0;
+	public var damping:Float = 0;
+	public var massInverse:Float = 0;
+	public var wind:Float = 0;
+	public var gravity:Float = 0;
+	public var mix:Float = 0;
+	public var inertiaGlobal:Bool = false;
+	public var strengthGlobal:Bool = false;
+	public var dampingGlobal:Bool = false;
+	public var massGlobal:Bool = false;
+	public var windGlobal:Bool = false;
+	public var gravityGlobal:Bool = false;
+	public var mixGlobal:Bool = false;
+	
+	public function new(name:String) {
+		super(name, 0, false);
+	}
+
+}

+ 72 - 39
spine-haxe/spine-haxe/spine/Skeleton.hx

@@ -40,11 +40,12 @@ class Skeleton {
 	private var _data:SkeletonData;
 
 	public var bones:Array<Bone>;
-	public var slots:Array<Slot>;
+	public var slots:Array<Slot>; // Setup pose draw order.
 	public var drawOrder:Array<Slot>;
 	public var ikConstraints:Array<IkConstraint>;
 	public var transformConstraints:Array<TransformConstraint>;
 	public var pathConstraints:Array<PathConstraint>;
+	public var physicsConstraints:Array<PhysicsConstraint>;
 
 	private var _updateCache:Array<Updatable> = new Array<Updatable>();
 	private var _skin:Skin;
@@ -54,6 +55,7 @@ class Skeleton {
 	public var scaleY:Float = 1;
 	public var x:Float = 0;
 	public var y:Float = 0;
+	public var time:Float = 0;
 
 	public function new(data:SkeletonData) {
 		if (data == null) {
@@ -98,6 +100,11 @@ class Skeleton {
 			pathConstraints.push(new PathConstraint(pathConstraintData, this));
 		}
 
+		physicsConstraints = new Array<PhysicsConstraint>();
+		for (physicConstraintData in data.physicsConstraints) {
+			physicsConstraints.push(new PhysicsConstraint(physicConstraintData, this));
+		}
+
 		updateCache();
 	}
 
@@ -127,7 +134,8 @@ class Skeleton {
 		var ikCount:Int = ikConstraints.length;
 		var transformCount:Int = transformConstraints.length;
 		var pathCount:Int = pathConstraints.length;
-		var constraintCount:Int = ikCount + transformCount + pathCount;
+		var physicCount:Int = physicsConstraints.length;
+		var constraintCount:Int = ikCount + transformCount + pathCount + physicCount;
 
 		var continueOuter:Bool;
 		for (i in 0...constraintCount) {
@@ -156,6 +164,14 @@ class Skeleton {
 					break;
 				}
 			}
+			if (continueOuter)
+				continue;
+			for (physicConstraint in physicsConstraints) {
+				if (physicConstraint.data.order == i) {
+					sortPhysicsConstraint(physicConstraint);
+					break;
+				}
+			}
 		}
 
 		for (bone in bones) {
@@ -294,6 +310,19 @@ class Skeleton {
 		}
 	}
 
+	private function sortPhysicsConstraint (constraint: PhysicsConstraint) {
+		var bone:Bone = constraint.bone;
+		constraint.active = bone.active && (!constraint.data.skinRequired || (skin != null && contains(skin.constraints, constraint.data)));
+		if (!constraint.active) return;
+
+		sortBone(bone);
+
+		_updateCache.push(constraint);
+
+		sortReset(bone.children);
+		bone.sorted = true;
+	}
+
 	private function sortBone(bone:Bone):Void {
 		if (bone.sorted)
 			return;
@@ -315,7 +344,8 @@ class Skeleton {
 	}
 
 	/** Updates the world transform for each bone and applies constraints. */
-	public function updateWorldTransform():Void {
+	public function updateWorldTransform(physics:Physics):Void {
+		if (physics == null) throw new SpineException("physics is undefined");
 		for (bone in bones) {
 			bone.ax = bone.x;
 			bone.ay = bone.y;
@@ -327,11 +357,11 @@ class Skeleton {
 		}
 
 		for (updatable in _updateCache) {
-			updatable.update();
+			updatable.update(physics);
 		}
 	}
 
-	public function updateWorldTransformWith(parent:Bone):Void {
+	public function updateWorldTransformWith(physics:Physics, parent:Bone):Void {
 		// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
 		var rootBone:Bone = rootBone;
 		var pa:Float = parent.a,
@@ -341,11 +371,12 @@ class Skeleton {
 		rootBone.worldX = pa * x + pb * y + parent.worldX;
 		rootBone.worldY = pc * x + pd * y + parent.worldY;
 
-		var rotationY:Float = rootBone.rotation + 90 + rootBone.shearY;
-		var la:Float = MathUtils.cosDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX;
-		var lb:Float = MathUtils.cosDeg(rotationY) * rootBone.scaleY;
-		var lc:Float = MathUtils.sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX;
-		var ld:Float = MathUtils.sinDeg(rotationY) * rootBone.scaleY;
+		var rx:Float = (rootBone.rotation + rootBone.shearX) * MathUtils.degRad;
+		var ry:Float = (rootBone.rotation + 90 + rootBone.shearY) * MathUtils.degRad;
+		var la:Float = Math.cos(rx) * rootBone.scaleX;
+		var lb:Float = Math.cos(ry) * rootBone.scaleY;
+		var lc:Float = Math.sin(rx) * rootBone.scaleX;
+		var ld:Float = Math.sin(ry) * rootBone.scaleY;
 		rootBone.a = (pa * la + pb * lc) * scaleX;
 		rootBone.b = (pa * lb + pb * ld) * scaleX;
 		rootBone.c = (pc * la + pd * lc) * scaleY;
@@ -354,7 +385,7 @@ class Skeleton {
 		// Update everything except root bone.
 		for (updatable in _updateCache) {
 			if (updatable != rootBone)
-				updatable.update();
+				updatable.update(physics);
 		}
 	}
 
@@ -366,34 +397,11 @@ class Skeleton {
 
 	/** Sets the bones and constraints to their setup pose values. */
 	public function setBonesToSetupPose():Void {
-		for (bone in bones) {
-			bone.setToSetupPose();
-		}
-
-		for (ikConstraint in ikConstraints) {
-			ikConstraint.mix = ikConstraint.data.mix;
-			ikConstraint.softness = ikConstraint.data.softness;
-			ikConstraint.bendDirection = ikConstraint.data.bendDirection;
-			ikConstraint.compress = ikConstraint.data.compress;
-			ikConstraint.stretch = ikConstraint.data.stretch;
-		}
-
-		for (transformConstraint in transformConstraints) {
-			transformConstraint.mixRotate = transformConstraint.data.mixRotate;
-			transformConstraint.mixX = transformConstraint.data.mixX;
-			transformConstraint.mixY = transformConstraint.data.mixY;
-			transformConstraint.mixScaleX = transformConstraint.data.mixScaleX;
-			transformConstraint.mixScaleY = transformConstraint.data.mixScaleY;
-			transformConstraint.mixShearY = transformConstraint.data.mixShearY;
-		}
-
-		for (pathConstraint in pathConstraints) {
-			pathConstraint.position = pathConstraint.data.position;
-			pathConstraint.spacing = pathConstraint.data.spacing;
-			pathConstraint.mixRotate = pathConstraint.data.mixRotate;
-			pathConstraint.mixX = pathConstraint.data.mixX;
-			pathConstraint.mixY = pathConstraint.data.mixY;
-		}
+		for (bone in this.bones) bone.setToSetupPose();
+		for (constraint in this.ikConstraints) constraint.setToSetupPose();
+		for (constraint in this.transformConstraints) constraint.setToSetupPose();
+		for (constraint in this.pathConstraints) constraint.setToSetupPose();
+		for (constraint in this.physicsConstraints) constraint.setToSetupPose();
 	}
 
 	public function setSlotsToSetupPose():Void {
@@ -585,6 +593,17 @@ class Skeleton {
 		return null;
 	}
 
+	/** @return May be null. */
+	public function findPhysicsConstraint(constraintName:String):PhysicsConstraint {
+		if (constraintName == null)
+			throw new SpineException("constraintName cannot be null.");
+		for (physicsConstraint in physicsConstraints) {
+			if (physicsConstraint.data.name == constraintName)
+				return physicsConstraint;
+		}
+		return null;
+	}
+
 	public function toString():String {
 		return _data.name != null ? _data.name : "Skeleton?";
 	}
@@ -632,4 +651,18 @@ class Skeleton {
 		_bounds.height = maxY - minY;
 		return _bounds;
 	}
+
+	public function update (delta:Float):Void {
+		time += delta;
+	}
+
+	public function physicsTranslate (x:Float, y:Float):Void {
+		for (physicsConstraint in physicsConstraints)
+			physicsConstraint.translate(x, y);
+	}
+
+	public function physicsRotate (x:Float, y:Float, degrees:Float):Void {
+		for (physicsConstraint in physicsConstraints)
+			physicsConstraint.rotate(x, y, degrees);
+	}
 }

+ 2 - 1
spine-haxe/spine-haxe/spine/SkeletonBinary.hx

@@ -127,6 +127,7 @@ class SkeletonBinary {
 		skeletonData.y = input.readFloat();
 		skeletonData.width = input.readFloat();
 		skeletonData.height = input.readFloat();
+		skeletonData.referenceScale = input.readFloat() * scale;
 
 		var nonessential:Bool = input.readBoolean();
 		if (nonessential) {
@@ -158,7 +159,7 @@ class SkeletonBinary {
 			boneData.shearX = input.readFloat();
 			boneData.shearY = input.readFloat();
 			boneData.length = input.readFloat() * scale;
-			boneData.transformMode = TransformMode.values[input.readInt(true)];
+			boneData.inherit = Inherit.values[input.readInt(true)];
 			boneData.skinRequired = input.readBoolean();
 			if (nonessential)
 				boneData.color.setFromRgba8888(input.readInt32());

+ 27 - 0
spine-haxe/spine-haxe/spine/SkeletonData.hx

@@ -48,10 +48,12 @@ class SkeletonData {
 	public var ikConstraints:Array<IkConstraintData> = new Array<IkConstraintData>();
 	public var transformConstraints:Array<TransformConstraintData> = new Array<TransformConstraintData>();
 	public var pathConstraints:Array<PathConstraintData> = new Array<PathConstraintData>();
+	public var physicsConstraints:Array<PhysicsConstraintData> = new Array<PhysicsConstraintData>();
 	public var x:Float = 0;
 	public var y:Float = 0;
 	public var width:Float = 0;
 	public var height:Float = 0;
+	public var referenceScale:Float = 100;
 	public var version:String;
 	public var hash:String;
 	public var fps:Float = 0;
@@ -214,6 +216,31 @@ class SkeletonData {
 		return -1;
 	}
 
+	// --- Physics constraints.
+
+	/** @return May be null. */
+	public function findPhysicsConstraint(constraintName:String):PhysicsConstraintData {
+		if (constraintName == null)
+			throw new SpineException("physicsConstraintName cannot be null.");
+		for (i in 0...physicsConstraints.length) {
+			var constraint:PhysicsConstraintData = physicsConstraints[i];
+			if (constraint.name == constraintName)
+				return constraint;
+		}
+		return null;
+	}
+	
+	/** @return -1 if the path constraint was not found. */
+	public function findPhysicsConstraintIndex(constraintName:String):Int {
+		if (constraintName == null)
+			throw new SpineException("constraintName cannot be null.");
+		for (i in 0...physicsConstraints.length) {
+			if (physicsConstraints[i].name == constraintName)
+				return i;
+		}
+		return -1;
+	}
+
 	public function toString():String {
 		return name;
 	}

+ 123 - 2
spine-haxe/spine-haxe/spine/SkeletonJson.hx

@@ -41,9 +41,19 @@ import spine.animation.DeformTimeline;
 import spine.animation.DrawOrderTimeline;
 import spine.animation.EventTimeline;
 import spine.animation.IkConstraintTimeline;
+import spine.animation.InheritTimeline;
 import spine.animation.PathConstraintMixTimeline;
 import spine.animation.PathConstraintPositionTimeline;
 import spine.animation.PathConstraintSpacingTimeline;
+import spine.animation.PhysicsConstraintResetTimeline;
+import spine.animation.PhysicsConstraintInertiaTimeline;
+import spine.animation.PhysicsConstraintStrengthTimeline;
+import spine.animation.PhysicsConstraintDampingTimeline;
+import spine.animation.PhysicsConstraintMassTimeline;
+import spine.animation.PhysicsConstraintWindTimeline;
+import spine.animation.PhysicsConstraintGravityTimeline;
+import spine.animation.PhysicsConstraintMixTimeline;
+import spine.animation.PhysicsConstraintTimeline;
 import spine.animation.RGB2Timeline;
 import spine.animation.RGBA2Timeline;
 import spine.animation.RGBATimeline;
@@ -99,8 +109,10 @@ class SkeletonJson {
 			skeletonData.y = getFloat(skeletonMap, "y");
 			skeletonData.width = getFloat(skeletonMap, "width");
 			skeletonData.height = getFloat(skeletonMap, "height");
+			skeletonData.referenceScale = getFloat(skeletonMap, "referenceScale", 100);
 			skeletonData.fps = getFloat(skeletonMap, "fps");
 			skeletonData.imagesPath = getString(skeletonMap, "images", "");
+			skeletonData.audioPath = getString(skeletonMap, "audio", "");
 		}
 
 		// Bones.
@@ -122,8 +134,8 @@ class SkeletonJson {
 			boneData.scaleY = getFloat(boneMap, "scaleY", 1);
 			boneData.shearX = getFloat(boneMap, "shearX");
 			boneData.shearY = getFloat(boneMap, "shearY");
-			boneData.transformMode = Reflect.hasField(boneMap,
-				"transform") ? TransformMode.fromName(Reflect.getProperty(boneMap, "transform")) : TransformMode.normal;
+			boneData.inherit = Reflect.hasField(boneMap,
+				"inherit") ? Inherit.fromName(Reflect.getProperty(boneMap, "inherit")) : Inherit.normal;
 			boneData.skinRequired = Reflect.hasField(boneMap, "skin") ? cast(Reflect.getProperty(boneMap, "skin"), Bool) : false;
 
 			var color:String = Reflect.getProperty(boneMap, "color");
@@ -136,7 +148,14 @@ class SkeletonJson {
 
 		// Slots.
 		for (slotMap in cast(Reflect.getProperty(root, "slots"), Array<Dynamic>)) {
+			var path:String = null;
 			var slotName:String = Reflect.getProperty(slotMap, "name");
+			var slash:Int = slotName.lastIndexOf('/');
+			if (slash != -1) {
+				path = slotName.substring(0, slash);
+				slotName = slotName.substring(slash + 1);
+			}
+
 			var boneName:String = Reflect.getProperty(slotMap, "bone");
 			boneData = skeletonData.findBone(boneName);
 			if (boneData == null)
@@ -156,6 +175,8 @@ class SkeletonJson {
 
 			slotData.attachmentName = Reflect.getProperty(slotMap, "attachment");
 			slotData.blendMode = Reflect.hasField(slotMap, "blend") ? BlendMode.fromName(Reflect.getProperty(slotMap, "blend")) : BlendMode.normal;
+			slotData.visible = getValue(slotMap, "visible", true);
+			slotData.path = path;
 			skeletonData.slots.push(slotData);
 		}
 
@@ -270,6 +291,45 @@ class SkeletonJson {
 			}
 		}
 
+		// Physics constraints.
+		if (Reflect.hasField(root, "physics")) {
+			for (constraintMap in cast(Reflect.getProperty(root, "physics"), Array<Dynamic>)) {
+				var physicsData:PhysicsConstraintData = new PhysicsConstraintData(Reflect.getProperty(constraintMap, "name"));
+				physicsData.order = getInt(constraintMap, "order");
+				physicsData.skinRequired = Reflect.hasField(constraintMap, "skin") ? cast(Reflect.getProperty(constraintMap, "skin"), Bool) : false;
+
+				var boneName:String = Reflect.getProperty(constraintMap, "bone");
+				var bone = skeletonData.findBone(boneName);
+				if (bone == null)
+					throw new SpineException("Physics constraint bone not found: " + boneName);
+				physicsData.bone = bone;
+
+				physicsData.x = getFloat(constraintMap, "x");
+				physicsData.y = getFloat(constraintMap, "y");
+				physicsData.rotate = getFloat(constraintMap, "rotate");
+				physicsData.scaleX = getFloat(constraintMap, "scaleX");
+				physicsData.shearX = getFloat(constraintMap, "shearX");
+				physicsData.limit = getFloat(constraintMap, "limit", 5000) * scale;
+				physicsData.step = 1 / getFloat(constraintMap, "fps", 60);
+				physicsData.inertia = getFloat(constraintMap, "inertia", 1);
+				physicsData.strength = getFloat(constraintMap, "strength", 100);
+				physicsData.damping = getFloat(constraintMap, "damping", 1);
+				physicsData.massInverse = 1 / getFloat(constraintMap, "mass", 1);
+				physicsData.wind = getFloat(constraintMap, "wind");
+				physicsData.gravity = getFloat(constraintMap, "gravity");
+				physicsData.mix = getValue(constraintMap, "mix", 1);
+				physicsData.inertiaGlobal = Reflect.hasField(constraintMap, "inertiaGlobal") ? cast(Reflect.getProperty(constraintMap, "inertiaGlobal"), Bool) : false;
+				physicsData.strengthGlobal = Reflect.hasField(constraintMap, "strengthGlobal") ? cast(Reflect.getProperty(constraintMap, "strengthGlobal"), Bool) : false;
+				physicsData.dampingGlobal = Reflect.hasField(constraintMap, "dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false;
+				physicsData.dampingGlobal = Reflect.hasField(constraintMap, "dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false;
+				physicsData.windGlobal = Reflect.hasField(constraintMap, "windGlobal") ? cast(Reflect.getProperty(constraintMap, "windGlobal"), Bool) : false;
+				physicsData.gravityGlobal = Reflect.hasField(constraintMap, "gravityGlobal") ? cast(Reflect.getProperty(constraintMap, "gravityGlobal"), Bool) : false;
+				physicsData.mixGlobal = Reflect.hasField(constraintMap, "mixGlobal") ? cast(Reflect.getProperty(constraintMap, "mixGlobal"), Bool) : false;
+
+				skeletonData.physicsConstraints.push(physicsData);
+			}
+		}
+
 		// Skins.
 		if (Reflect.hasField(root, "skins")) {
 			for (skinMap in cast(Reflect.getProperty(root, "skins"), Array<Dynamic>)) {
@@ -315,6 +375,16 @@ class SkeletonJson {
 					}
 				}
 
+				if (Reflect.hasField(skinMap, "physics")) {
+					var physics:Array<Dynamic> = cast(Reflect.getProperty(skinMap, "physics"), Array<Dynamic>);
+					for (ii in 0...physics.length) {
+						var constraint:ConstraintData = skeletonData.findPhysicsConstraint(physics[ii]);
+						if (constraint == null)
+							throw new SpineException("Skin physics constraint not found: " + physics[ii]);
+						skin.constraints.push(constraint);
+					}
+				}
+
 				if (Reflect.hasField(skinMap, "attachments")) {
 					var attachments:Dynamic = Reflect.getProperty(skinMap, "attachments");
 					for (slotName in Reflect.fields(attachments)) {
@@ -759,6 +829,13 @@ class SkeletonJson {
 				} else if (timelineName == "sheary") {
 					var shearYTimeline:ShearYTimeline = new ShearYTimeline(timelineMap.length, timelineMap.length, boneIndex);
 					timelines.push(readTimeline(timelineMap, shearYTimeline, 0, 1));
+				} else if (timelineName == "inherit") {
+					var inheritTimeline:InheritTimeline = new InheritTimeline(timelineMap.length, boneIndex);
+					for (frame in 0...timelineMap.length) {
+						var aFrame:Dynamic = timelineMap[frame];
+						inheritTimeline.setFrame(frame, getFloat(aFrame, "time"), Inherit.fromName(getValue(aFrame, "inherit", "Normal")));
+					}
+					timelines.push(inheritTimeline);
 				} else {
 					throw new SpineException("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
 				}
@@ -938,6 +1015,50 @@ class SkeletonJson {
 			}
 		}
 
+		// Physics constraint timelines.
+		var physics:Dynamic = Reflect.getProperty(map, "physics");
+		for (physicsName in Reflect.fields(physics)) {
+			var constraintIndex:Int = skeletonData.findPhysicsConstraintIndex(physicsName);
+			if (constraintIndex == -1)
+				throw new SpineException("Physics constraint not found: " + physicsName);
+
+			var physicsMap:Dynamic = Reflect.field(physics, physicsName);
+			for (timelineName in Reflect.fields(physicsMap)) {
+				timelineMap = Reflect.field(physicsMap, timelineName);
+				keyMap = timelineMap[0];
+				if (keyMap == null)
+					continue;
+
+				var frames:Int = timelineMap.length;
+				if (timelineName == "reset") {
+					var timeline:PhysicsConstraintResetTimeline = new PhysicsConstraintResetTimeline(frames, constraintIndex);
+					for (frame => keyMap in timelineMap)
+						timeline.setFrame(frame, getFloat(keyMap, "time"));
+					timelines.push(timeline);
+					continue;
+				}
+
+				var timeline:PhysicsConstraintTimeline;
+					if (timelineName == "inertia")
+						timeline = new PhysicsConstraintInertiaTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "strength")
+						timeline = new PhysicsConstraintStrengthTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "damping")
+						timeline = new PhysicsConstraintDampingTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "mass")
+						timeline = new PhysicsConstraintMassTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "wind")
+						timeline = new PhysicsConstraintWindTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "gravity")
+						timeline = new PhysicsConstraintGravityTimeline(frames, frames, constraintIndex);
+					else if (timelineName == "mix") //
+						timeline = new PhysicsConstraintMixTimeline(frames, frames, constraintIndex);
+					else
+						continue;
+				timelines.push(readTimeline(timelineMap, timeline, 0, 1));
+			}
+		}
+
 		// Attachment timelines.
 		var attachments:Dynamic = Reflect.getProperty(map, "attachments");
 		for (attachmentsName in Reflect.fields(attachments)) {

+ 7 - 0
spine-haxe/spine-haxe/spine/Skin.hx

@@ -39,6 +39,7 @@ class Skin {
 	private var _attachments:Array<StringMap<Attachment>> = new Array<StringMap<Attachment>>();
 	private var _bones:Array<BoneData> = new Array<BoneData>();
 	private var _constraints:Array<ConstraintData> = new Array<ConstraintData>();
+	private var _color:Color = new Color(0.99607843, 0.61960787, 0.30980393, 1); // fe9e4fff
 
 	public function new(name:String) {
 		if (name == null)
@@ -208,6 +209,12 @@ class Skin {
 		return _name;
 	}
 
+	public var color(get, never):Color;
+
+	private function get_color():Color {
+		return _color;
+	}
+
 	/*
 		public function toString():String
 		{

+ 2 - 0
spine-haxe/spine-haxe/spine/SlotData.hx

@@ -38,6 +38,8 @@ class SlotData {
 	public var darkColor:Color = null;
 	public var attachmentName:String;
 	public var blendMode:BlendMode = BlendMode.normal;
+	public var visible:Bool = true;
+	public var path:String = null;
 
 	public function new(index:Int, name:String, boneData:BoneData) {
 		if (index < 0)

+ 13 - 11
spine-haxe/spine-haxe/spine/TransformConstraint.hx

@@ -68,7 +68,17 @@ class TransformConstraint implements Updatable {
 		return active;
 	}
 
-	public function update():Void {
+	public function setToSetupPose () {
+		var data:TransformConstraintData = _data;
+		mixRotate = data.mixRotate;
+		mixX = data.mixX;
+		mixY = data.mixY;
+		mixScaleX = data.mixScaleX;
+		mixScaleY = data.mixScaleY;
+		mixShearY = data.mixShearY;
+	}
+
+	public function update(physics:Physics):Void {
 		if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0)
 			return;
 
@@ -226,11 +236,7 @@ class TransformConstraint implements Updatable {
 	public function applyAbsoluteLocal():Void {
 		for (bone in bones) {
 			var rotation:Float = bone.arotation;
-			if (mixRotate != 0) {
-				var r:Float = target.arotation - rotation + _data.offsetRotation;
-				r -= (16384 - (Std.int(16384.499999999996 - r / 360) | 0)) * 360;
-				rotation += r * mixRotate;
-			}
+			if (mixRotate != 0) rotation += (target.arotation - rotation + _data.offsetRotation) * mixRotate;
 
 			var x:Float = bone.ax, y:Float = bone.ay;
 			x += (target.ax - x + _data.offsetX) * mixX;
@@ -245,11 +251,7 @@ class TransformConstraint implements Updatable {
 			}
 
 			var shearY:Float = bone.ashearY;
-			if (mixShearY != 0) {
-				var r:Float = target.ashearY - shearY + _data.offsetShearY;
-				r -= (16384 - (Std.int(16384.499999999996 - r / 360) | 0)) * 360;
-				bone.shearY += r * mixShearY;
-			}
+			if (mixShearY != 0) shearY += (target.ashearY - shearY + _data.offsetShearY) * mixShearY;
 
 			bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
 		}

+ 1 - 1
spine-haxe/spine-haxe/spine/Updatable.hx

@@ -30,7 +30,7 @@
 package spine;
 
 interface Updatable {
-	function update():Void;
+	function update(physics:Physics):Void;
 
 	function isActive():Bool;
 }

+ 1 - 2
spine-haxe/spine-haxe/spine/animation/AlphaTimeline.hx

@@ -61,8 +61,7 @@ class AlphaTimeline extends CurveTimeline1 implements SlotTimeline {
 			return;
 
 		var color:Color = slot.color;
-		if (time < frames[0]) // Time is before first frame.
-		{
+		if (time < frames[0]) {
 			var setup:Color = slot.data.color;
 			switch (blend) {
 				case MixBlend.setup:

+ 43 - 31
spine-haxe/spine-haxe/spine/animation/AnimationState.hx

@@ -181,12 +181,13 @@ class AnimationState {
 			var blend:MixBlend = i == 0 ? MixBlend.first : current.mixBlend;
 
 			// Apply mixing from entries first.
-			var mix:Float = current.alpha;
+			var alpha:Float = current.alpha;
 			if (current.mixingFrom != null) {
-				mix *= applyMixingFrom(current, skeleton, blend);
+				alpha *= applyMixingFrom(current, skeleton, blend);
 			} else if (current.trackTime >= current.trackEnd && current.next == null) {
-				mix = 0;
+				alpha = 0;
 			}
+			var attachments:Bool = alpha >= current.alphaAttachmentThreshold;
 
 			// Apply current entry.
 			var animationLast:Float = current.animationLast,
@@ -200,9 +201,14 @@ class AnimationState {
 			var timelines:Array<Timeline> = current.animation.timelines;
 			var timelineCount:Int = timelines.length;
 			var timeline:Timeline;
-			if ((i == 0 && mix == 1) || blend == MixBlend.add) {
+			if ((i == 0 && alpha == 1) || blend == MixBlend.add) {
+				if (i == 0) attachments = true;
 				for (timeline in timelines) {
-					timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, blend, MixDirection.mixIn);
+					if (Std.isOfType(timeline, AttachmentTimeline)) {
+						applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
+					} else {
+						timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection.mixIn);
+					}
 				}
 			} else {
 				var timelineMode:Array<Int> = current.timelineMode;
@@ -216,12 +222,12 @@ class AnimationState {
 					var timeline:Timeline = timelines[ii];
 					var timelineBlend:MixBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup;
 					if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
-						this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, mix, timelineBlend, current.timelinesRotation, ii << 1,
+						this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation, ii << 1,
 							firstFrame);
 					} else if (Std.isOfType(timeline, AttachmentTimeline)) {
-						this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, true);
+						this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
 					} else {
-						timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, MixDirection.mixIn);
+						timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, MixDirection.mixIn);
 					}
 				}
 			}
@@ -266,8 +272,8 @@ class AnimationState {
 				blend = from.mixBlend;
 		}
 
-		var attachments:Bool = mix < from.attachmentThreshold,
-			drawOrder:Bool = mix < from.drawOrderThreshold;
+		var attachments:Bool = mix < from.mixAttachmentThreshold,
+			drawOrder:Bool = mix < from.mixDrawOrderThreshold;
 		var timelineCount:Int = from.animation.timelines.length;
 		var timelines:Array<Timeline> = from.animation.timelines;
 		var alphaHold:Float = from.alpha * to.interruptAlpha,
@@ -322,13 +328,12 @@ class AnimationState {
 						var holdMix:TrackEntry = timelineHoldMix[i];
 						alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
 				}
-
 				from.totalAlpha += alpha;
 
 				if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
 					applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame);
 				} else if (Std.isOfType(timeline, AttachmentTimeline)) {
-					applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, timelineBlend, attachments);
+					applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, timelineBlend, attachments && alpha >= from.alphaAttachmentThreshold);
 				} else {
 					if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
 						direction = MixDirection.mixIn;
@@ -394,7 +399,7 @@ class AnimationState {
 
 		// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
 		var total:Float = 0, diff:Float = r2 - r1;
-		diff -= (16384.0 - Std.int((16384.499999999996 - diff / 360.0))) * 360.0;
+		diff -= Math.ceil(diff / 360 - 0.5) * 360;
 		if (diff == 0) {
 			total = timelinesRotation[i];
 		} else {
@@ -403,18 +408,21 @@ class AnimationState {
 				lastTotal = 0;
 				lastDiff = diff;
 			} else {
-				lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
-				lastDiff = timelinesRotation[i + 1]; // Difference between bones.
+				lastTotal = timelinesRotation[i];
+				lastDiff = timelinesRotation[i + 1];
 			}
-			var current = diff > 0, dir = lastTotal >= 0;
-			// Detect cross at 0 (not 180).
-			if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) {
-				// A cross after a 360 rotation is a loop.
-				if (Math.abs(lastTotal) > 180)
-					lastTotal += 360 * MathUtils.signum(lastTotal);
-				dir = current;
+			var loops:Float = lastTotal - lastTotal % 360;
+			total = diff + loops;
+			var current = diff >= 0, dir = lastTotal >= 0;
+			if (Math.abs(lastDiff) <= 90 && MathUtils.signum(lastDiff) != MathUtils.signum(diff)) {
+				if (Math.abs(lastTotal - loops) > 180) {
+					total += 360 * MathUtils.signum(lastTotal);
+					dir = current;
+				} else if (loops != 0)
+					total -= 360 * MathUtils.signum(lastTotal);
+				else
+					dir = current;
 			}
-			total = diff + lastTotal - lastTotal % 360; // Store loops as part of lastTotal.
 			if (dir != current)
 				total += 360 * MathUtils.signum(lastTotal);
 			timelinesRotation[i] = total;
@@ -451,14 +459,17 @@ class AnimationState {
 		}
 
 		// Queue complete if completed a loop iteration or the animation.
-		var complete:Bool;
+		var complete = false;
 		if (entry.loop) {
-			complete = duration == 0 || trackLastWrapped > entry.trackTime % duration;
-		} else {
+			if (duration == 0)
+				complete = true;
+			else {
+				var cycles:Float = Math.floor(entry.trackTime / duration);
+				complete = cycles > 0 && cycles > Math.floor(entry.trackTime / duration);
+			}
+		} else
 			complete = animationTime >= animationEnd && entry.animationLast < animationEnd;
-		}
-		if (complete)
-			queue.complete(entry);
+		if (complete) queue.complete(entry);
 
 		// Queue events after complete.
 		while (i < n) {
@@ -641,8 +652,9 @@ class AnimationState {
 		entry.shortestRotation = false;
 
 		entry.eventThreshold = 0;
-		entry.attachmentThreshold = 0;
-		entry.drawOrderThreshold = 0;
+		entry.alphaAttachmentThreshold = 0;
+		entry.mixAttachmentThreshold = 0;
+		entry.mixDrawOrderThreshold = 0;
 
 		entry.animationStart = 0;
 		entry.animationEnd = animation.duration;

+ 87 - 0
spine-haxe/spine-haxe/spine/animation/CurveTimeline1.hx

@@ -75,4 +75,91 @@ class CurveTimeline1 extends CurveTimeline {
 		}
 		return getBezierValue(time, i, VALUE, curveType - CurveTimeline.BEZIER);
 	}
+
+	public function getRelativeValue (time:Float, alpha:Float, blend: MixBlend, current:Float, setup:Float):Float {
+		if (time < frames[0]) {
+			switch (blend) {
+				case MixBlend.setup:
+					return setup;
+				case MixBlend.first:
+					return current + (setup - current) * alpha;
+			}
+			return current;
+		}
+		var value:Float = getCurveValue(time);
+		switch (blend) {
+			case MixBlend.setup:
+				return setup + value * alpha;
+			case MixBlend.first, MixBlend.replace:
+				value += setup - current;
+		}
+		return current + value * alpha;
+	}
+
+	public function getAbsoluteValue (time:Float, alpha:Float, blend: MixBlend, current:Float, setup:Float):Float {
+		if (time < frames[0]) {
+			switch (blend) {
+				case MixBlend.setup:
+					return setup;
+				case MixBlend.first:
+					return current + (setup - current) * alpha;
+			}
+			return current;
+		}
+		var value:Float = getCurveValue(time);
+		if (blend == MixBlend.setup) return setup + (value - setup) * alpha;
+		return current + (value - current) * alpha;
+	}
+
+	public function getAbsoluteValue2 (time:Float, alpha:Float, blend: MixBlend, current:Float, setup:Float, value:Float):Float {
+		if (time < frames[0]) {
+			switch (blend) {
+				case MixBlend.setup:
+					return setup;
+				case MixBlend.first:
+					return current + (setup - current) * alpha;
+			}
+			return current;
+		}
+		if (blend == MixBlend.setup) return setup + (value - setup) * alpha;
+		return current + (value - current) * alpha;
+	}
+
+	public function getScaleValue (time:Float, alpha:Float, blend: MixBlend, direction: MixDirection, current:Float, setup:Float):Float {
+		var frames:Array<Float> = frames;
+		if (time < frames[0]) {
+			switch (blend) {
+				case MixBlend.setup:
+					return setup;
+				case MixBlend.first:
+					return current + (setup - current) * alpha;
+			}
+			return current;
+		}
+		var value:Float = getCurveValue(time) * setup;
+		if (alpha == 1) {
+			if (blend == MixBlend.add) return current + value - setup;
+			return value;
+		}
+		// Mixing out uses sign of setup or current pose, else use sign of key.
+		if (direction == MixDirection.mixOut) {
+			switch (blend) {
+				case MixBlend.setup:
+					return setup + (Math.abs(value) * MathUtils.signum(setup) - setup) * alpha;
+				case MixBlend.first, MixBlend.replace:
+					return current + (Math.abs(value) * MathUtils.signum(current) - current) * alpha;
+			}
+		} else {
+			var s:Float = 0;
+			switch (blend) {
+				case MixBlend.setup:
+					s = Math.abs(setup) * MathUtils.signum(value);
+					return s + (value - s) * alpha;
+				case MixBlend.first, MixBlend.replace:
+					s = Math.abs(current) * MathUtils.signum(value);
+					return s + (value - s) * alpha;
+			}
+		}
+		return current + (value - setup) * alpha;
+	}
 }

+ 1 - 2
spine-haxe/spine-haxe/spine/animation/DeformTimeline.hx

@@ -177,8 +177,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
 
 		ArrayUtils.resize(deform, vertexCount, 0);
 		var setup:Float;
-		if (time >= frames[frames.length - 1]) // Time is after last frame.
-		{
+		if (time >= frames[frames.length - 1]) {
 			var lastVertices:Array<Float> = vertices[frames.length - 1];
 			if (alpha == 1) {
 				if (blend == MixBlend.add) {

+ 2 - 5
spine-haxe/spine-haxe/spine/animation/EventTimeline.hx

@@ -60,7 +60,7 @@ class EventTimeline extends Timeline {
 
 		var frameCount:Int = frames.length;
 
-		if (lastTime > time) // Fire events after last time for looped animations.
+		if (lastTime > time) // Apply events after lastTime for looped animations.
 		{
 			apply(skeleton, lastTime, 2147483647, events, alpha, blend, direction);
 			lastTime = -1;
@@ -69,10 +69,7 @@ class EventTimeline extends Timeline {
 			return;
 		}
 
-		if (time < frames[0]) // Time is before first frame.
-		{
-			return;
-		}
+		if (time < frames[0]) return;
 
 		var frame:Int;
 		var i:Int = 0;

+ 4 - 4
spine-haxe/spine-haxe/spine/animation/IkConstraintTimeline.hx

@@ -41,12 +41,12 @@ class IkConstraintTimeline extends CurveTimeline {
 	private static inline var COMPRESS:Int = 4;
 	private static inline var STRETCH:Int = 5;
 
-	/** The index of the IK constraint slot in {@link Skeleton#ikConstraints} that will be changed. */
-	public var ikConstraintIndex:Int = 0;
+	/** The index of the IK constraint in {@link Skeleton#ikConstraints} when this timeline is applied. */
+	public var constraintIndex:Int = 0;
 
 	public function new(frameCount:Int, bezierCount:Int, ikConstraintIndex:Int) {
 		super(frameCount, bezierCount, [Property.ikConstraint + "|" + ikConstraintIndex]);
-		this.ikConstraintIndex = ikConstraintIndex;
+		this.constraintIndex = ikConstraintIndex;
 	}
 
 	public override function getFrameEntries():Int {
@@ -66,7 +66,7 @@ class IkConstraintTimeline extends CurveTimeline {
 
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
-		var constraint:IkConstraint = skeleton.ikConstraints[ikConstraintIndex];
+		var constraint:IkConstraint = skeleton.ikConstraints[constraintIndex];
 		if (!constraint.active)
 			return;
 

+ 73 - 0
spine-haxe/spine-haxe/spine/animation/InheritTimeline.hx

@@ -0,0 +1,73 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+import spine.Bone;
+import spine.Event;
+import spine.Skeleton;
+
+class InheritTimeline extends Timeline implements BoneTimeline {
+	public static inline var ENTRIES:Int = 2;
+	private static inline var INHERIT:Int = 1;
+
+	private var boneIndex:Int = 0;
+
+	public function new(frameCount:Int, boneIndex:Int) {
+		super(frameCount, [Property.inherit + "|" + boneIndex]);
+		this.boneIndex = boneIndex;
+	}
+
+	public override function getFrameEntries():Int {
+		return ENTRIES;
+	}
+
+	public function getBoneIndex():Int {
+		return boneIndex;
+	}
+
+	public function setFrame(frame:Int, time:Float, inherit: Inherit):Void {
+		frame *= ENTRIES;
+		frames[frame] = time;
+		frames[frame + INHERIT] = inherit.ordinal;
+	}
+
+	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
+			direction:MixDirection):Void {
+		var bone:Bone = skeleton.bones[boneIndex];
+		if (!bone.active) return;
+
+		var frames:Array<Float> = frames;
+		if (time < frames[0]) {
+			if (blend == MixBlend.setup || blend == MixBlend.first) bone.inherit = bone.data.inherit;
+			return;
+		}
+		bone.inherit = Inherit.values[Std.int(frames[Timeline.search(frames, time, ENTRIES) + INHERIT])];
+	}
+}

+ 4 - 4
spine-haxe/spine-haxe/spine/animation/PathConstraintMixTimeline.hx

@@ -39,12 +39,12 @@ class PathConstraintMixTimeline extends CurveTimeline {
 	private static inline var X:Int = 2;
 	private static inline var Y:Int = 3;
 
-	/** The index of the path constraint slot in {@link Skeleton#getPathConstraints()} that will be changed. */
-	public var pathConstraintIndex:Int = 0;
+	/** The index of the path constraint in {@link Skeleton#getPathConstraints()} when this timeline is applied. */
+	public var constraintIndex:Int = 0;
 
 	public function new(frameCount:Int, bezierCount:Int, pathConstraintIndex:Int) {
 		super(frameCount, bezierCount, [Property.pathConstraintMix + "|" + pathConstraintIndex]);
-		this.pathConstraintIndex = pathConstraintIndex;
+		this.constraintIndex = pathConstraintIndex;
 	}
 
 	public override function getFrameEntries():Int {
@@ -61,7 +61,7 @@ class PathConstraintMixTimeline extends CurveTimeline {
 
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
-		var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
+		var constraint:PathConstraint = skeleton.pathConstraints[constraintIndex];
 		if (!constraint.active)
 			return;
 

+ 6 - 23
spine-haxe/spine-haxe/spine/animation/PathConstraintPositionTimeline.hx

@@ -34,35 +34,18 @@ import spine.PathConstraint;
 import spine.Skeleton;
 
 class PathConstraintPositionTimeline extends CurveTimeline1 {
-	/** The index of the path constraint slot in {@link Skeleton#pathConstraints} that will be changed. */
-	public var pathConstraintIndex:Int = 0;
+	/** The index of the path constraint in {@link Skeleton#pathConstraints}  when this timeline is applied. */
+	public var constraintIndex:Int = 0;
 
 	public function new(frameCount:Int, bezierCount:Int, pathConstraintIndex:Int) {
 		super(frameCount, bezierCount, [Property.pathConstraintPosition + "|" + pathConstraintIndex]);
-		this.pathConstraintIndex = pathConstraintIndex;
+		this.constraintIndex = pathConstraintIndex;
 	}
 
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
-		var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
-		if (!constraint.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					constraint.position = constraint.data.position;
-				case MixBlend.first:
-					constraint.position += (constraint.data.position - constraint.position) * alpha;
-			}
-			return;
-		}
-
-		var position:Float = getCurveValue(time);
-		if (blend == MixBlend.setup) {
-			constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
-		} else {
-			constraint.position += (position - constraint.position) * alpha;
-		}
+		var constraint:PathConstraint = skeleton.pathConstraints[constraintIndex];
+		if (constraint.active)
+			constraint.position = getAbsoluteValue(time, alpha, blend, constraint.position, constraint.data.position);
 	}
 }

+ 5 - 23
spine-haxe/spine-haxe/spine/animation/PathConstraintSpacingTimeline.hx

@@ -34,35 +34,17 @@ import spine.PathConstraint;
 import spine.Skeleton;
 
 class PathConstraintSpacingTimeline extends CurveTimeline1 {
-	/** The index of the path constraint slot in {@link Skeleton#pathConstraints} that will be changed. */
-	public var pathConstraintIndex:Int = 0;
+	/** The index of the path constraint in {@link Skeleton#pathConstraints} when this timeline is applied. */
+	public var constraintIndex:Int = 0;
 
 	public function new(frameCount:Int, bezierCount:Int, pathConstraintIndex:Int) {
 		super(frameCount, bezierCount, [Property.pathConstraintSpacing + "|" + pathConstraintIndex]);
-		this.pathConstraintIndex = pathConstraintIndex;
+		this.constraintIndex = pathConstraintIndex;
 	}
 
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
-		var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
-		if (!constraint.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					constraint.spacing = constraint.data.spacing;
-				case MixBlend.first:
-					constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha;
-			}
-			return;
-		}
-
-		var spacing:Float = getCurveValue(time);
-		if (blend == MixBlend.setup) {
-			constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
-		} else {
-			constraint.spacing += (spacing - constraint.spacing) * alpha;
-		}
+		var constraint:PathConstraint = skeleton.pathConstraints[constraintIndex];
+		if (constraint.active) constraint.spacing = getAbsoluteValue(time, alpha, blend, constraint.spacing, constraint.data.spacing);
 	}
 }

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintDampingTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getDamping()}. */
+class PhysicsConstraintDampingTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintDamping);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.damping;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.damping;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.damping = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.dampingGlobal;
+	}
+
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintGravityTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getWind()}. */
+class PhysicsConstraintGravityTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintGravity);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.gravity;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.gravity;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.gravity = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.gravityGlobal;
+	}
+
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintInertiaTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getInertia()}. */
+class PhysicsConstraintInertiaTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintInertia);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.inertia;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.inertia;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.inertia = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.inertiaGlobal;
+	}
+
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintMassTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getMassInverse()}. The timeline values are not inverted. */
+class PhysicsConstraintMassTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMass);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.massInverse;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.massInverse;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.massInverse = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.massGlobal;
+	}
+
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintMixTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getWind()}. */
+class PhysicsConstraintMixTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMix);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.mix;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.mix;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.mix = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.mixGlobal;
+	}
+
+}

+ 86 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintResetTimeline.hx

@@ -0,0 +1,86 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+import spine.animation.Timeline;
+import spine.Event;
+import spine.Skeleton;
+
+class PhysicsConstraintResetTimeline extends Timeline {
+	/** The index of the physics constraint in {@link Skeleton#physicsConstraints} that will be reset when this timeline is
+	* applied, or -1 if all physics constraints in the skeleton will be reset. */
+	public var constraintIndex:Int = 0;
+
+	public function new(frameCount:Int, physicsConstraintIndex:Int) {
+		propertyIds = [Std.string(Property.physicsConstraintReset)];
+		super(frameCount, propertyIds);
+		constraintIndex = physicsConstraintIndex;
+	}
+
+	public override function getFrameCount():Int {
+		return frames.length;
+	}
+
+	/** Sets the time in seconds and the event for the specified key frame. */
+	public function setFrame(frame:Int, time:Float):Void {
+		frames[frame] = time;
+	}
+
+	/** Resets the physics constraint when frames > lastTime and <= time. */
+	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, firedEvents:Array<Event>, alpha:Float, blend:MixBlend,
+			direction:MixDirection):Void {
+		var constraint:PhysicsConstraint = null;
+		if (this.constraintIndex != -1) {
+			constraint = skeleton.physicsConstraints[constraintIndex];
+			if (!constraint.active) return;
+		}
+
+		var frames:Array<Float> = this.frames;
+		if (lastTime > time) // Apply events after lastTime for looped animations.
+		{
+			apply(skeleton, lastTime, 2147483647, [], alpha, blend, direction);
+			lastTime = -1;
+		} else if (lastTime >= frames[frames.length - 1]) // Last time is after last frame.
+		{
+			return;
+		}
+		if (time < frames[0]) return;
+
+		if (lastTime < frames[0] || time >= frames[Timeline.search1(frames, lastTime) + 1]) {
+			if (constraint != null)
+				constraint.reset();
+			else {
+				for (constraint in skeleton.physicsConstraints) {
+					if (constraint.active) constraint.reset();
+				}
+			}
+		}
+	}
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintStrengthTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getStrength()}. */
+class PhysicsConstraintStrengthTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintStrength);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.strength;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.strength;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.strength = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.strengthGlobal;
+	}
+
+}

+ 70 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintTimeline.hx

@@ -0,0 +1,70 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+import spine.Event;
+import spine.PathConstraint;
+import spine.Skeleton;
+
+/** The base class for most {@link PhysicsConstraint} timelines. */
+abstract class PhysicsConstraintTimeline extends CurveTimeline1 {
+	/** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be changed when this timeline
+	 * is applied, or -1 if all physics constraints in the skeleton will be changed. */
+	public var constraintIndex:Int = 0;
+
+	/** @param physicsConstraintIndex -1 for all physics constraints in the skeleton. */
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int, property:Int) {
+		super(frameCount, bezierCount, [property + "|" + physicsConstraintIndex]);
+		constraintIndex = physicsConstraintIndex;
+	}
+
+	public override function apply (skeleton:Skeleton, lastTime:Float, time:Float, firedEvents:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection):Void {
+		var constraint:PhysicsConstraint;
+		if (constraintIndex == -1) {
+			var value:Float = time >= frames[0] ? getCurveValue(time) : 0;
+
+			for (constraint in skeleton.physicsConstraints) {
+				if (constraint.active && global(constraint.data))
+					set(constraint, getAbsoluteValue2(time, alpha, blend, get(constraint), setup(constraint), value));
+			}
+		} else {
+			constraint = skeleton.physicsConstraints[constraintIndex];
+			if (constraint.active) set(constraint, getAbsoluteValue(time, alpha, blend, get(constraint), setup(constraint)));
+		}
+	}
+
+	abstract public function setup (constraint: PhysicsConstraint):Float;
+
+	abstract public function get (constraint: PhysicsConstraint):Float;
+
+	abstract public function set (constraint: PhysicsConstraint, value:Float):Void;
+
+	abstract public function global (constraint: PhysicsConstraintData):Bool;
+}

+ 54 - 0
spine-haxe/spine-haxe/spine/animation/PhysicsConstraintWindTimeline.hx

@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+package spine.animation;
+
+/** Changes a physics constraint's {@link PhysicsConstraint#getWind()}. */
+class PhysicsConstraintWindTimeline extends PhysicsConstraintTimeline {
+	public function new(frameCount:Int, bezierCount:Int, physicsConstraintIndex:Int) {
+		super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintWind);
+	}
+
+	public function setup (constraint: PhysicsConstraint):Float {
+		return constraint.data.wind;
+	}
+
+	public function get (constraint: PhysicsConstraint):Float {
+		return constraint.wind;
+	}
+
+	public function set (constraint: PhysicsConstraint, value:Float):Void {
+		constraint.wind = value;
+	}
+
+	public function global (constraint: PhysicsConstraintData):Bool {
+		return constraint.windGlobal;
+	}
+
+}

+ 23 - 13
spine-haxe/spine-haxe/spine/animation/Property.hx

@@ -37,25 +37,35 @@ class Property {
 	public static inline var scaleY:Int = 4;
 	public static inline var shearX:Int = 5;
 	public static inline var shearY:Int = 6;
+	public static inline var inherit:Int = 7;
 
-	public static inline var rgb:Int = 7;
-	public static inline var alpha:Int = 8;
-	public static inline var rgb2:Int = 9;
+	public static inline var rgb:Int = 8;
+	public static inline var alpha:Int = 9;
+	public static inline var rgb2:Int = 10;
 
-	public static inline var attachment:Int = 10;
-	public static inline var deform:Int = 11;
+	public static inline var attachment:Int = 11;
+	public static inline var deform:Int = 12;
 
-	public static inline var event:Int = 12;
-	public static inline var drawOrder:Int = 13;
+	public static inline var event:Int = 13;
+	public static inline var drawOrder:Int = 14;
 
-	public static inline var ikConstraint:Int = 14;
-	public static inline var transformConstraint:Int = 15;
+	public static inline var ikConstraint:Int = 15;
+	public static inline var transformConstraint:Int = 16;
 
-	public static inline var pathConstraintPosition:Int = 16;
-	public static inline var pathConstraintSpacing:Int = 17;
-	public static inline var pathConstraintMix:Int = 18;
+	public static inline var pathConstraintPosition:Int = 17;
+	public static inline var pathConstraintSpacing:Int = 18;
+	public static inline var pathConstraintMix:Int = 19;
 
-	public static inline var sequence:Int = 19;
+	public static inline var physicsConstraintInertia:Int = 20;
+	public static inline var physicsConstraintStrength:Int = 21;
+	public static inline var physicsConstraintDamping:Int = 22;
+	public static inline var physicsConstraintMass:Int = 23;
+	public static inline var physicsConstraintWind:Int = 24;
+	public static inline var physicsConstraintGravity:Int = 25;
+	public static inline var physicsConstraintMix:Int = 26;
+	public static inline var physicsConstraintReset:Int = 27;
+
+	public static inline var sequence:Int = 28;
 
 	public function new() {}
 }

+ 2 - 24
spine-haxe/spine-haxe/spine/animation/RotateTimeline.hx

@@ -48,29 +48,7 @@ class RotateTimeline extends CurveTimeline1 implements BoneTimeline {
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.rotation = bone.data.rotation;
-				case MixBlend.first:
-					bone.rotation += (bone.data.rotation - bone.rotation) * alpha;
-			}
-			return;
-		}
-
-		var r:Float = getCurveValue(time);
-		if (Math.abs(r) == 360)
-			r = 0;
-		switch (blend) {
-			case MixBlend.setup:
-				bone.rotation = bone.data.rotation + r * alpha;
-			case MixBlend.first, MixBlend.replace:
-				r += bone.data.rotation - bone.rotation;
-				bone.rotation += r * alpha;
-			case MixBlend.add:
-				bone.rotation += r * alpha;
-		}
+		if (bone.active)
+			bone.rotation = getRelativeValue(time, alpha, blend, bone.rotation, bone.data.rotation);
 	}
 }

+ 1 - 46
spine-haxe/spine-haxe/spine/animation/ScaleXTimeline.hx

@@ -49,51 +49,6 @@ class ScaleXTimeline extends CurveTimeline1 implements BoneTimeline {
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.scaleX = bone.data.scaleX;
-				case MixBlend.first:
-					bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha;
-			}
-			return;
-		}
-
-		var x:Float = getCurveValue(time) * bone.data.scaleX;
-		if (alpha == 1) {
-			if (blend == MixBlend.add)
-				bone.scaleX += x - bone.data.scaleX;
-			else
-				bone.scaleX = x;
-		} else {
-			// Mixing out uses sign of setup or current pose, else use sign of key.
-			var bx:Float = 0;
-			if (direction == MixDirection.mixOut) {
-				switch (blend) {
-					case MixBlend.setup:
-						bx = bone.data.scaleX;
-						bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha;
-					case MixBlend.first, MixBlend.replace:
-						bx = bone.scaleX;
-						bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha;
-					case MixBlend.add:
-						bone.scaleX = (x - bone.data.scaleX) * alpha;
-				}
-			} else {
-				switch (blend) {
-					case MixBlend.setup:
-						bx = Math.abs(bone.data.scaleX) * MathUtils.signum(x);
-						bone.scaleX = bx + (x - bx) * alpha;
-					case MixBlend.first, MixBlend.replace:
-						bx = Math.abs(bone.scaleX) * MathUtils.signum(x);
-						bone.scaleX = bx + (x - bx) * alpha;
-					case MixBlend.add:
-						bone.scaleX += (x - bone.data.scaleX) * alpha;
-				}
-			}
-		}
+		if (bone.active) bone.scaleX = getScaleValue(time, alpha, blend, direction, bone.scaleX, bone.data.scaleX);
 	}
 }

+ 1 - 45
spine-haxe/spine-haxe/spine/animation/ScaleYTimeline.hx

@@ -49,51 +49,7 @@ class ScaleYTimeline extends CurveTimeline1 implements BoneTimeline {
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
+		if (bone.active) bone.scaleY = getScaleValue(time, alpha, blend, direction, bone.scaleY, bone.data.scaleY);
 
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.scaleY = bone.data.scaleY;
-				case MixBlend.first:
-					bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha;
-			}
-			return;
-		}
-
-		var y:Float = getCurveValue(time) * bone.data.scaleY;
-		if (alpha == 1) {
-			if (blend == MixBlend.add)
-				bone.scaleY += y - bone.data.scaleY;
-			else
-				bone.scaleY = y;
-		} else {
-			// Mixing out uses sign of setup or current pose, else use sign of key.
-			var by:Float = 0;
-			if (direction == MixDirection.mixOut) {
-				switch (blend) {
-					case MixBlend.setup:
-						by = bone.data.scaleY;
-						bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha;
-					case MixBlend.first, MixBlend.replace:
-						by = bone.scaleY;
-						bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha;
-					case MixBlend.add:
-						bone.scaleY = (y - bone.data.scaleY) * alpha;
-				}
-			} else {
-				switch (blend) {
-					case MixBlend.setup:
-						by = Math.abs(bone.data.scaleY) * MathUtils.signum(y);
-						bone.scaleY = by + (y - by) * alpha;
-					case MixBlend.first, MixBlend.replace:
-						by = Math.abs(bone.scaleY) * MathUtils.signum(y);
-						bone.scaleY = by + (y - by) * alpha;
-					case MixBlend.add:
-						bone.scaleY += (y - bone.data.scaleY) * alpha;
-				}
-			}
-		}
 	}
 }

+ 1 - 1
spine-haxe/spine-haxe/spine/animation/SequenceTimeline.hx

@@ -82,7 +82,7 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
 				return;
 		}
 
-		if (time < frames[0]) { // Time is before first frame.
+		if (time < frames[0]) {
 			if (blend == MixBlend.setup || blend == MixBlend.first)
 				slot.sequenceIndex = -1;
 			return;

+ 1 - 22
spine-haxe/spine-haxe/spine/animation/ShearXTimeline.hx

@@ -48,27 +48,6 @@ class ShearXTimeline extends CurveTimeline1 implements BoneTimeline {
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.shearX = bone.data.shearX;
-				case MixBlend.first:
-					bone.shearX += (bone.data.shearX - bone.shearX) * alpha;
-			}
-			return;
-		}
-
-		var x:Float = getCurveValue(time);
-		switch (blend) {
-			case MixBlend.setup:
-				bone.shearX = bone.data.shearX + x * alpha;
-			case MixBlend.first, MixBlend.replace:
-				bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
-			case MixBlend.add:
-				bone.shearX += x * alpha;
-		}
+		if (bone.active) bone.shearX = getRelativeValue(time, alpha, blend, bone.shearX, bone.data.shearX);
 	}
 }

+ 1 - 22
spine-haxe/spine-haxe/spine/animation/ShearYTimeline.hx

@@ -48,27 +48,6 @@ class ShearYTimeline extends CurveTimeline1 implements BoneTimeline {
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.shearY = bone.data.shearY;
-				case MixBlend.first:
-					bone.shearY += (bone.data.shearY - bone.shearY) * alpha;
-			}
-			return;
-		}
-
-		var y:Float = getCurveValue(time);
-		switch (blend) {
-			case MixBlend.setup:
-				bone.shearY = bone.data.shearY + y * alpha;
-			case MixBlend.first, MixBlend.replace:
-				bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
-			case MixBlend.add:
-				bone.shearY += y * alpha;
-		}
+		if (bone.active) bone.shearY = getRelativeValue(time, alpha, blend, bone.shearY, bone.data.shearY);
 	}
 }

+ 21 - 3
spine-haxe/spine-haxe/spine/animation/TrackEntry.hx

@@ -49,8 +49,9 @@ class TrackEntry implements Poolable {
 	public var reverse:Bool = false;
 	public var holdPrevious:Bool = false;
 	public var eventThreshold:Float = 0;
-	public var attachmentThreshold:Float = 0;
-	public var drawOrderThreshold:Float = 0;
+	public var mixAttachmentThreshold:Float = 0;
+	public var alphaAttachmentThreshold:Float = 0;
+	public var mixDrawOrderThreshold:Float = 0;
 	public var animationStart:Float = 0;
 	public var animationEnd:Float = 0;
 	public var animationLast:Float = 0;
@@ -63,7 +64,7 @@ class TrackEntry implements Poolable {
 	public var timeScale:Float = 0;
 	public var alpha:Float = 0;
 	public var mixTime:Float = 0;
-	public var mixDuration:Float = 0;
+	@:isVar public var mixDuration(get, set):Float = 0;
 	public var interruptAlpha:Float = 0;
 	public var totalAlpha:Float = 0;
 	public var mixBlend:MixBlend = MixBlend.replace;
@@ -72,6 +73,16 @@ class TrackEntry implements Poolable {
 	public var timelinesRotation:Array<Float> = new Array<Float>();
 	public var shortestRotation = false;
 
+	function get_mixDuration():Float {
+		return mixDuration;
+	}
+
+	function set_mixDuration(mixDuration:Float):Float {
+		this.mixDuration = mixDuration;
+		if (previous != null && delay <= 0) delay += previous.getTrackComplete() - mixDuration;
+		return mixDuration;
+	}
+
 	public function new() {}
 
 	public function getAnimationTime():Float {
@@ -98,6 +109,13 @@ class TrackEntry implements Poolable {
 		return trackTime; // Next update.
 	}
 
+	/** Returns true if this track entry has been applied at least once.
+	 * <p>
+	 * See {@link AnimationState#apply(Skeleton)}. */
+	 public function wasApplied () {
+		return nextTrackLast != -1;
+	}
+
 	public function reset():Void {
 		next = null;
 		previous = null;

+ 3 - 3
spine-haxe/spine-haxe/spine/animation/TransformConstraintTimeline.hx

@@ -44,11 +44,11 @@ class TransformConstraintTimeline extends CurveTimeline {
 	private static inline var SHEARY:Int = 6;
 
 	/** The index of the transform constraint slot in {@link Skeleton#transformConstraints} that will be changed. */
-	public var transformConstraintIndex:Int = 0;
+	public var constraintIndex:Int = 0;
 
 	public function new(frameCount:Int, bezierCount:Int, transformConstraintIndex:Int) {
 		super(frameCount, bezierCount, [Property.transformConstraint + "|" + transformConstraintIndex]);
-		this.transformConstraintIndex = transformConstraintIndex;
+		this.constraintIndex = transformConstraintIndex;
 	}
 
 	public override function getFrameEntries():Int {
@@ -69,7 +69,7 @@ class TransformConstraintTimeline extends CurveTimeline {
 
 	override public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
-		var constraint:TransformConstraint = skeleton.transformConstraints[transformConstraintIndex];
+		var constraint:TransformConstraint = skeleton.transformConstraints[constraintIndex];
 		if (!constraint.active)
 			return;
 

+ 1 - 22
spine-haxe/spine-haxe/spine/animation/TranslateXTimeline.hx

@@ -48,27 +48,6 @@ class TranslateXTimeline extends CurveTimeline1 implements BoneTimeline {
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.x = bone.data.x;
-				case MixBlend.first:
-					bone.x += (bone.data.x - bone.x) * alpha;
-			}
-			return;
-		}
-
-		var x:Float = getCurveValue(time);
-		switch (blend) {
-			case MixBlend.setup:
-				bone.x = bone.data.x + x * alpha;
-			case MixBlend.first, MixBlend.replace:
-				bone.x += (bone.data.x + x - bone.x) * alpha;
-			case MixBlend.add:
-				bone.x += x * alpha;
-		}
+		if (bone.active) bone.x = getRelativeValue(time, alpha, blend, bone.x, bone.data.x);
 	}
 }

+ 1 - 22
spine-haxe/spine-haxe/spine/animation/TranslateYTimeline.hx

@@ -48,27 +48,6 @@ class TranslateYTimeline extends CurveTimeline1 implements BoneTimeline {
 	public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend,
 			direction:MixDirection):Void {
 		var bone:Bone = skeleton.bones[boneIndex];
-		if (!bone.active)
-			return;
-
-		if (time < frames[0]) {
-			switch (blend) {
-				case MixBlend.setup:
-					bone.y = bone.data.y;
-				case MixBlend.first:
-					bone.y += (bone.data.y - bone.y) * alpha;
-			}
-			return;
-		}
-
-		var y:Float = getCurveValue(time);
-		switch (blend) {
-			case MixBlend.setup:
-				bone.y = bone.data.y + y * alpha;
-			case MixBlend.first, MixBlend.replace:
-				bone.y += (bone.data.y + y - bone.y) * alpha;
-			case MixBlend.add:
-				bone.y += y * alpha;
-		}
+		if (bone.active) bone.y = getRelativeValue(time, alpha, blend, bone.y, bone.data.y);
 	}
 }

+ 3 - 3
spine-haxe/spine-haxe/spine/attachments/MeshAttachment.hx

@@ -31,6 +31,7 @@ package spine.attachments;
 
 import spine.Color;
 import spine.atlas.TextureAtlasRegion;
+import spine.atlas.TextureAtlasPage;
 
 class MeshAttachment extends VertexAttachment implements HasTextureRegion {
 	public var region:TextureRegion;
@@ -66,9 +67,8 @@ class MeshAttachment extends VertexAttachment implements HasTextureRegion {
 		var n = uvs.length;
 		var u = region.u, v = region.v, width:Float = 0, height:Float = 0;
 		if (Std.isOfType(region, TextureAtlasRegion)) {
-			var atlasRegion:TextureAtlasRegion = cast(region, TextureAtlasRegion);
-			var textureWidth = atlasRegion.page.width,
-				textureHeight = atlasRegion.page.height;
+			var atlasRegion:TextureAtlasRegion = cast(region, TextureAtlasRegion), page:TextureAtlasPage = atlasRegion.page;
+			var textureWidth = page.width, textureHeight = page.height;
 			switch (atlasRegion.degrees) {
 				case 90:
 					u -= (region.originalHeight - region.offsetY - region.height) / textureWidth;

+ 2 - 3
spine-haxe/spine-haxe/spine/attachments/PointAttachment.hx

@@ -50,11 +50,10 @@ class PointAttachment extends VertexAttachment {
 	}
 
 	public function computeWorldRotation(bone:Bone):Float {
-		var cos:Float = MathUtils.cosDeg(this.rotation),
-			sin:Float = MathUtils.sinDeg(this.rotation);
+		var r:Float = this.rotation * MathUtils.degRad, cos:Float = Math.cos(r), sin:Float = Math.sin(r);
 		var x:Float = cos * bone.a + sin * bone.b;
 		var y:Float = cos * bone.c + sin * bone.d;
-		return Math.atan2(y, x) * MathUtils.radDeg;
+		return MathUtils.atan2Deg(y, x);
 	}
 
 	override public function copy():Attachment {

+ 1 - 1
spine-haxe/spine-haxe/spine/attachments/RegionAttachment.hx

@@ -83,7 +83,7 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
 		var localY = -height / 2 * scaleY + region.offsetY * regionScaleY;
 		var localX2 = localX + region.width * regionScaleX;
 		var localY2 = localY + region.height * regionScaleY;
-		var radians = rotation * Math.PI / 180;
+		var radians = rotation * MathUtils.degRad;
 		var cos = Math.cos(radians);
 		var sin = Math.sin(radians);
 		var x = this.x, y = this.y;

+ 4 - 2
spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx

@@ -76,7 +76,7 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
 		super();
 		Bone.yDown = true;
 		_skeleton = new Skeleton(skeletonData);
-		_skeleton.updateWorldTransform();
+		_skeleton.updateWorldTransform(Physics.update);
 		_state = new AnimationState(animationStateData != null ? animationStateData : new AnimationStateData(skeletonData));
 	}
 
@@ -340,7 +340,9 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
 	public function advanceTime(time:Float):Void {
 		_state.update(time);
 		_state.apply(skeleton);
-		skeleton.updateWorldTransform();
+		skeleton.update(time);
+		skeleton.updateWorldTransform(Physics.update);
+
 		this.setRequiresRedraw();
 	}
 }

Някои файлове не бяха показани, защото твърде много файлове са промени