源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
11 KiB

  1. /******************************************************************************
  2. * Spine Runtimes Software License v2.5
  3. *
  4. * Copyright (c) 2013-2016, Esoteric Software
  5. * All rights reserved.
  6. *
  7. * You are granted a perpetual, non-exclusive, non-sublicensable, and
  8. * non-transferable license to use, install, execute, and perform the Spine
  9. * Runtimes software and derivative works solely for personal or internal
  10. * use. Without the written permission of Esoteric Software (see Section 2 of
  11. * the Spine Software License Agreement), you may not (a) modify, translate,
  12. * adapt, or develop new applications using the Spine Runtimes or otherwise
  13. * create derivative works or improvements of the Spine Runtimes or (b) remove,
  14. * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
  15. * or other intellectual property or proprietary rights notices on or in the
  16. * Software, including any copy thereof. Redistributions in binary or source
  17. * form must include this license and terms.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  22. * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
  25. * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *****************************************************************************/
  30. using System;
  31. namespace Spine {
  32. public class TransformConstraint : IConstraint {
  33. internal TransformConstraintData data;
  34. internal ExposedList<Bone> bones;
  35. internal Bone target;
  36. internal float rotateMix, translateMix, scaleMix, shearMix;
  37. public TransformConstraintData Data { get { return data; } }
  38. public int Order { get { return data.order; } }
  39. public ExposedList<Bone> Bones { get { return bones; } }
  40. public Bone Target { get { return target; } set { target = value; } }
  41. public float RotateMix { get { return rotateMix; } set { rotateMix = value; } }
  42. public float TranslateMix { get { return translateMix; } set { translateMix = value; } }
  43. public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } }
  44. public float ShearMix { get { return shearMix; } set { shearMix = value; } }
  45. public TransformConstraint (TransformConstraintData data, Skeleton skeleton) {
  46. if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
  47. if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null.");
  48. this.data = data;
  49. rotateMix = data.rotateMix;
  50. translateMix = data.translateMix;
  51. scaleMix = data.scaleMix;
  52. shearMix = data.shearMix;
  53. bones = new ExposedList<Bone>();
  54. foreach (BoneData boneData in data.bones)
  55. bones.Add (skeleton.FindBone (boneData.name));
  56. target = skeleton.FindBone(data.target.name);
  57. }
  58. public void Apply () {
  59. Update();
  60. }
  61. public void Update () {
  62. if (data.local) {
  63. if (data.relative)
  64. ApplyRelativeLocal();
  65. else
  66. ApplyAbsoluteLocal();
  67. } else {
  68. if (data.relative)
  69. ApplyRelativeWorld();
  70. else
  71. ApplyAbsoluteWorld();
  72. }
  73. }
  74. void ApplyAbsoluteWorld () {
  75. float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
  76. Bone target = this.target;
  77. float ta = target.a, tb = target.b, tc = target.c, td = target.d;
  78. float degRadReflect = ta * td - tb * tc > 0 ? MathUtils.DegRad : -MathUtils.DegRad;
  79. float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
  80. var bones = this.bones;
  81. for (int i = 0, n = bones.Count; i < n; i++) {
  82. Bone bone = bones.Items[i];
  83. bool modified = false;
  84. if (rotateMix != 0) {
  85. float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
  86. float r = MathUtils.Atan2(tc, ta) - MathUtils.Atan2(c, a) + offsetRotation;
  87. if (r > MathUtils.PI)
  88. r -= MathUtils.PI2;
  89. else if (r < -MathUtils.PI) r += MathUtils.PI2;
  90. r *= rotateMix;
  91. float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r);
  92. bone.a = cos * a - sin * c;
  93. bone.b = cos * b - sin * d;
  94. bone.c = sin * a + cos * c;
  95. bone.d = sin * b + cos * d;
  96. modified = true;
  97. }
  98. if (translateMix != 0) {
  99. float tx, ty; //Vector2 temp = this.temp;
  100. target.LocalToWorld(data.offsetX, data.offsetY, out tx, out ty); //target.localToWorld(temp.set(data.offsetX, data.offsetY));
  101. bone.worldX += (tx - bone.worldX) * translateMix;
  102. bone.worldY += (ty - bone.worldY) * translateMix;
  103. modified = true;
  104. }
  105. if (scaleMix > 0) {
  106. float s = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c);
  107. //float ts = (float)Math.sqrt(ta * ta + tc * tc);
  108. if (s > 0.00001f) s = (s + ((float)Math.Sqrt(ta * ta + tc * tc) - s + data.offsetScaleX) * scaleMix) / s;
  109. bone.a *= s;
  110. bone.c *= s;
  111. s = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d);
  112. //ts = (float)Math.Sqrt(tb * tb + td * td);
  113. if (s > 0.00001f) s = (s + ((float)Math.Sqrt(tb * tb + td * td) - s + data.offsetScaleY) * scaleMix) / s;
  114. bone.b *= s;
  115. bone.d *= s;
  116. modified = true;
  117. }
  118. if (shearMix > 0) {
  119. float b = bone.b, d = bone.d;
  120. float by = MathUtils.Atan2(d, b);
  121. float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta) - (by - MathUtils.Atan2(bone.c, bone.a));
  122. if (r > MathUtils.PI)
  123. r -= MathUtils.PI2;
  124. else if (r < -MathUtils.PI) r += MathUtils.PI2;
  125. r = by + (r + offsetShearY) * shearMix;
  126. float s = (float)Math.Sqrt(b * b + d * d);
  127. bone.b = MathUtils.Cos(r) * s;
  128. bone.d = MathUtils.Sin(r) * s;
  129. modified = true;
  130. }
  131. if (modified) bone.appliedValid = false;
  132. }
  133. }
  134. void ApplyRelativeWorld () {
  135. float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
  136. Bone target = this.target;
  137. float ta = target.a, tb = target.b, tc = target.c, td = target.d;
  138. float degRadReflect = ta * td - tb * tc > 0 ? MathUtils.DegRad : -MathUtils.DegRad;
  139. float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
  140. var bones = this.bones;
  141. for (int i = 0, n = bones.Count; i < n; i++) {
  142. Bone bone = bones.Items[i];
  143. bool modified = false;
  144. if (rotateMix != 0) {
  145. float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
  146. float r = MathUtils.Atan2(tc, ta) + offsetRotation;
  147. if (r > MathUtils.PI)
  148. r -= MathUtils.PI2;
  149. else if (r < -MathUtils.PI) r += MathUtils.PI2;
  150. r *= rotateMix;
  151. float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r);
  152. bone.a = cos * a - sin * c;
  153. bone.b = cos * b - sin * d;
  154. bone.c = sin * a + cos * c;
  155. bone.d = sin * b + cos * d;
  156. modified = true;
  157. }
  158. if (translateMix != 0) {
  159. float tx, ty; //Vector2 temp = this.temp;
  160. target.LocalToWorld(data.offsetX, data.offsetY, out tx, out ty); //target.localToWorld(temp.set(data.offsetX, data.offsetY));
  161. bone.worldX += tx * translateMix;
  162. bone.worldY += ty * translateMix;
  163. modified = true;
  164. }
  165. if (scaleMix > 0) {
  166. float s = ((float)Math.Sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * scaleMix + 1;
  167. bone.a *= s;
  168. bone.c *= s;
  169. s = ((float)Math.Sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * scaleMix + 1;
  170. bone.b *= s;
  171. bone.d *= s;
  172. modified = true;
  173. }
  174. if (shearMix > 0) {
  175. float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta);
  176. if (r > MathUtils.PI)
  177. r -= MathUtils.PI2;
  178. else if (r < -MathUtils.PI) r += MathUtils.PI2;
  179. float b = bone.b, d = bone.d;
  180. r = MathUtils.Atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * shearMix;
  181. float s = (float)Math.Sqrt(b * b + d * d);
  182. bone.b = MathUtils.Cos(r) * s;
  183. bone.d = MathUtils.Sin(r) * s;
  184. modified = true;
  185. }
  186. if (modified) bone.appliedValid = false;
  187. }
  188. }
  189. void ApplyAbsoluteLocal () {
  190. float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
  191. Bone target = this.target;
  192. if (!target.appliedValid) target.UpdateAppliedTransform();
  193. var bonesItems = this.bones.Items;
  194. for (int i = 0, n = this.bones.Count; i < n; i++) {
  195. Bone bone = bonesItems[i];
  196. if (!bone.appliedValid) bone.UpdateAppliedTransform();
  197. float rotation = bone.arotation;
  198. if (rotateMix != 0) {
  199. float r = target.arotation - rotation + data.offsetRotation;
  200. r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
  201. rotation += r * rotateMix;
  202. }
  203. float x = bone.ax, y = bone.ay;
  204. if (translateMix != 0) {
  205. x += (target.ax - x + data.offsetX) * translateMix;
  206. y += (target.ay - y + data.offsetY) * translateMix;
  207. }
  208. float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
  209. if (scaleMix > 0) {
  210. if (scaleX > 0.00001f) scaleX = (scaleX + (target.ascaleX - scaleX + data.offsetScaleX) * scaleMix) / scaleX;
  211. if (scaleY > 0.00001f) scaleY = (scaleY + (target.ascaleY - scaleY + data.offsetScaleY) * scaleMix) / scaleY;
  212. }
  213. float shearY = bone.ashearY;
  214. if (shearMix > 0) {
  215. float r = target.ashearY - shearY + data.offsetShearY;
  216. r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
  217. bone.shearY += r * shearMix;
  218. }
  219. bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
  220. }
  221. }
  222. void ApplyRelativeLocal () {
  223. float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
  224. Bone target = this.target;
  225. if (!target.appliedValid) target.UpdateAppliedTransform();
  226. var bonesItems = this.bones.Items;
  227. for (int i = 0, n = this.bones.Count; i < n; i++) {
  228. Bone bone = bonesItems[i];
  229. if (!bone.appliedValid) bone.UpdateAppliedTransform();
  230. float rotation = bone.arotation;
  231. if (rotateMix != 0) rotation += (target.arotation + data.offsetRotation) * rotateMix;
  232. float x = bone.ax, y = bone.ay;
  233. if (translateMix != 0) {
  234. x += (target.ax + data.offsetX) * translateMix;
  235. y += (target.ay + data.offsetY) * translateMix;
  236. }
  237. float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
  238. if (scaleMix > 0) {
  239. if (scaleX > 0.00001f) scaleX *= ((target.ascaleX - 1 + data.offsetScaleX) * scaleMix) + 1;
  240. if (scaleY > 0.00001f) scaleY *= ((target.ascaleY - 1 + data.offsetScaleY) * scaleMix) + 1;
  241. }
  242. float shearY = bone.ashearY;
  243. if (shearMix > 0) shearY += (target.ashearY + data.offsetShearY) * shearMix;
  244. bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
  245. }
  246. }
  247. override public string ToString () {
  248. return data.name;
  249. }
  250. }
  251. }