babylon.animation.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. var BABYLON;
  2. (function (BABYLON) {
  3. var AnimationRange = (function () {
  4. function AnimationRange(name, from, to) {
  5. this.name = name;
  6. this.from = from;
  7. this.to = to;
  8. }
  9. AnimationRange.prototype.clone = function () {
  10. return new AnimationRange(this.name, this.from, this.to);
  11. };
  12. return AnimationRange;
  13. }());
  14. BABYLON.AnimationRange = AnimationRange;
  15. /**
  16. * Composed of a frame, and an action function
  17. */
  18. var AnimationEvent = (function () {
  19. function AnimationEvent(frame, action, onlyOnce) {
  20. this.frame = frame;
  21. this.action = action;
  22. this.onlyOnce = onlyOnce;
  23. this.isDone = false;
  24. }
  25. return AnimationEvent;
  26. }());
  27. BABYLON.AnimationEvent = AnimationEvent;
  28. var PathCursor = (function () {
  29. function PathCursor(path) {
  30. this.path = path;
  31. this._onchange = new Array();
  32. this.value = 0;
  33. this.animations = new Array();
  34. }
  35. PathCursor.prototype.getPoint = function () {
  36. var point = this.path.getPointAtLengthPosition(this.value);
  37. return new BABYLON.Vector3(point.x, 0, point.y);
  38. };
  39. PathCursor.prototype.moveAhead = function (step) {
  40. if (step === void 0) { step = 0.002; }
  41. this.move(step);
  42. return this;
  43. };
  44. PathCursor.prototype.moveBack = function (step) {
  45. if (step === void 0) { step = 0.002; }
  46. this.move(-step);
  47. return this;
  48. };
  49. PathCursor.prototype.move = function (step) {
  50. if (Math.abs(step) > 1) {
  51. throw "step size should be less than 1.";
  52. }
  53. this.value += step;
  54. this.ensureLimits();
  55. this.raiseOnChange();
  56. return this;
  57. };
  58. PathCursor.prototype.ensureLimits = function () {
  59. while (this.value > 1) {
  60. this.value -= 1;
  61. }
  62. while (this.value < 0) {
  63. this.value += 1;
  64. }
  65. return this;
  66. };
  67. // used by animation engine
  68. PathCursor.prototype.markAsDirty = function (propertyName) {
  69. this.ensureLimits();
  70. this.raiseOnChange();
  71. return this;
  72. };
  73. PathCursor.prototype.raiseOnChange = function () {
  74. var _this = this;
  75. this._onchange.forEach(function (f) { return f(_this); });
  76. return this;
  77. };
  78. PathCursor.prototype.onchange = function (f) {
  79. this._onchange.push(f);
  80. return this;
  81. };
  82. return PathCursor;
  83. }());
  84. BABYLON.PathCursor = PathCursor;
  85. var Animation = (function () {
  86. function Animation(name, targetProperty, framePerSecond, dataType, loopMode, enableBlending) {
  87. this.name = name;
  88. this.targetProperty = targetProperty;
  89. this.framePerSecond = framePerSecond;
  90. this.dataType = dataType;
  91. this.loopMode = loopMode;
  92. this.enableBlending = enableBlending;
  93. this._offsetsCache = {};
  94. this._highLimitsCache = {};
  95. this._stopped = false;
  96. this._blendingFactor = 0;
  97. // The set of event that will be linked to this animation
  98. this._events = new Array();
  99. this.allowMatricesInterpolation = false;
  100. this.blendingSpeed = 0.01;
  101. this._ranges = {};
  102. this.targetPropertyPath = targetProperty.split(".");
  103. this.dataType = dataType;
  104. this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
  105. }
  106. Animation._PrepareAnimation = function (name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction) {
  107. var dataType = undefined;
  108. if (!isNaN(parseFloat(from)) && isFinite(from)) {
  109. dataType = Animation.ANIMATIONTYPE_FLOAT;
  110. }
  111. else if (from instanceof BABYLON.Quaternion) {
  112. dataType = Animation.ANIMATIONTYPE_QUATERNION;
  113. }
  114. else if (from instanceof BABYLON.Vector3) {
  115. dataType = Animation.ANIMATIONTYPE_VECTOR3;
  116. }
  117. else if (from instanceof BABYLON.Vector2) {
  118. dataType = Animation.ANIMATIONTYPE_VECTOR2;
  119. }
  120. else if (from instanceof BABYLON.Color3) {
  121. dataType = Animation.ANIMATIONTYPE_COLOR3;
  122. }
  123. else if (from instanceof BABYLON.Size) {
  124. dataType = Animation.ANIMATIONTYPE_SIZE;
  125. }
  126. if (dataType == undefined) {
  127. return null;
  128. }
  129. var animation = new Animation(name, targetProperty, framePerSecond, dataType, loopMode);
  130. var keys = [{ frame: 0, value: from }, { frame: totalFrame, value: to }];
  131. animation.setKeys(keys);
  132. if (easingFunction !== undefined) {
  133. animation.setEasingFunction(easingFunction);
  134. }
  135. return animation;
  136. };
  137. Animation.CreateAndStartAnimation = function (name, node, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction, onAnimationEnd) {
  138. var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
  139. return node.getScene().beginDirectAnimation(node, [animation], 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
  140. };
  141. Animation.CreateMergeAndStartAnimation = function (name, node, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction, onAnimationEnd) {
  142. var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
  143. node.animations.push(animation);
  144. return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
  145. };
  146. // Methods
  147. /**
  148. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  149. */
  150. Animation.prototype.toString = function (fullDetails) {
  151. var ret = "Name: " + this.name + ", property: " + this.targetProperty;
  152. ret += ", datatype: " + (["Float", "Vector3", "Quaternion", "Matrix", "Color3", "Vector2"])[this.dataType];
  153. ret += ", nKeys: " + (this._keys ? this._keys.length : "none");
  154. ret += ", nRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
  155. if (fullDetails) {
  156. ret += ", Ranges: {";
  157. var first = true;
  158. for (var name in this._ranges) {
  159. if (first) {
  160. ret += ", ";
  161. first = false;
  162. }
  163. ret += name;
  164. }
  165. ret += "}";
  166. }
  167. return ret;
  168. };
  169. /**
  170. * Add an event to this animation.
  171. */
  172. Animation.prototype.addEvent = function (event) {
  173. this._events.push(event);
  174. };
  175. /**
  176. * Remove all events found at the given frame
  177. * @param frame
  178. */
  179. Animation.prototype.removeEvents = function (frame) {
  180. for (var index = 0; index < this._events.length; index++) {
  181. if (this._events[index].frame === frame) {
  182. this._events.splice(index, 1);
  183. index--;
  184. }
  185. }
  186. };
  187. Animation.prototype.createRange = function (name, from, to) {
  188. // check name not already in use; could happen for bones after serialized
  189. if (!this._ranges[name]) {
  190. this._ranges[name] = new AnimationRange(name, from, to);
  191. }
  192. };
  193. Animation.prototype.deleteRange = function (name, deleteFrames) {
  194. if (deleteFrames === void 0) { deleteFrames = true; }
  195. if (this._ranges[name]) {
  196. if (deleteFrames) {
  197. var from = this._ranges[name].from;
  198. var to = this._ranges[name].to;
  199. // this loop MUST go high to low for multiple splices to work
  200. for (var key = this._keys.length - 1; key >= 0; key--) {
  201. if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
  202. this._keys.splice(key, 1);
  203. }
  204. }
  205. }
  206. this._ranges[name] = undefined; // said much faster than 'delete this._range[name]'
  207. }
  208. };
  209. Animation.prototype.getRange = function (name) {
  210. return this._ranges[name];
  211. };
  212. Animation.prototype.reset = function () {
  213. this._offsetsCache = {};
  214. this._highLimitsCache = {};
  215. this.currentFrame = 0;
  216. this._blendingFactor = 0;
  217. this._originalBlendValue = null;
  218. };
  219. Animation.prototype.isStopped = function () {
  220. return this._stopped;
  221. };
  222. Animation.prototype.getKeys = function () {
  223. return this._keys;
  224. };
  225. Animation.prototype.getHighestFrame = function () {
  226. var ret = 0;
  227. for (var key = 0, nKeys = this._keys.length; key < nKeys; key++) {
  228. if (ret < this._keys[key].frame) {
  229. ret = this._keys[key].frame;
  230. }
  231. }
  232. return ret;
  233. };
  234. Animation.prototype.getEasingFunction = function () {
  235. return this._easingFunction;
  236. };
  237. Animation.prototype.setEasingFunction = function (easingFunction) {
  238. this._easingFunction = easingFunction;
  239. };
  240. Animation.prototype.floatInterpolateFunction = function (startValue, endValue, gradient) {
  241. return startValue + (endValue - startValue) * gradient;
  242. };
  243. Animation.prototype.quaternionInterpolateFunction = function (startValue, endValue, gradient) {
  244. return BABYLON.Quaternion.Slerp(startValue, endValue, gradient);
  245. };
  246. Animation.prototype.vector3InterpolateFunction = function (startValue, endValue, gradient) {
  247. return BABYLON.Vector3.Lerp(startValue, endValue, gradient);
  248. };
  249. Animation.prototype.vector2InterpolateFunction = function (startValue, endValue, gradient) {
  250. return BABYLON.Vector2.Lerp(startValue, endValue, gradient);
  251. };
  252. Animation.prototype.sizeInterpolateFunction = function (startValue, endValue, gradient) {
  253. return BABYLON.Size.Lerp(startValue, endValue, gradient);
  254. };
  255. Animation.prototype.color3InterpolateFunction = function (startValue, endValue, gradient) {
  256. return BABYLON.Color3.Lerp(startValue, endValue, gradient);
  257. };
  258. Animation.prototype.matrixInterpolateFunction = function (startValue, endValue, gradient) {
  259. return BABYLON.Matrix.Lerp(startValue, endValue, gradient);
  260. };
  261. Animation.prototype.clone = function () {
  262. var clone = new Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
  263. if (this._keys) {
  264. clone.setKeys(this._keys);
  265. }
  266. if (this._ranges) {
  267. clone._ranges = {};
  268. for (var name in this._ranges) {
  269. clone._ranges[name] = this._ranges[name].clone();
  270. }
  271. }
  272. return clone;
  273. };
  274. Animation.prototype.setKeys = function (values) {
  275. this._keys = values.slice(0);
  276. this._offsetsCache = {};
  277. this._highLimitsCache = {};
  278. };
  279. Animation.prototype._getKeyValue = function (value) {
  280. if (typeof value === "function") {
  281. return value();
  282. }
  283. return value;
  284. };
  285. Animation.prototype._interpolate = function (currentFrame, repeatCount, loopMode, offsetValue, highLimitValue) {
  286. if (loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
  287. return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
  288. }
  289. this.currentFrame = currentFrame;
  290. // Try to get a hash to find the right key
  291. var startKey = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
  292. if (this._keys[startKey].frame >= currentFrame) {
  293. while (startKey - 1 >= 0 && this._keys[startKey].frame >= currentFrame) {
  294. startKey--;
  295. }
  296. }
  297. for (var key = startKey; key < this._keys.length; key++) {
  298. if (this._keys[key + 1].frame >= currentFrame) {
  299. var startValue = this._getKeyValue(this._keys[key].value);
  300. var endValue = this._getKeyValue(this._keys[key + 1].value);
  301. // gradient : percent of currentFrame between the frame inf and the frame sup
  302. var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
  303. // check for easingFunction and correction of gradient
  304. if (this._easingFunction != null) {
  305. gradient = this._easingFunction.ease(gradient);
  306. }
  307. switch (this.dataType) {
  308. // Float
  309. case Animation.ANIMATIONTYPE_FLOAT:
  310. switch (loopMode) {
  311. case Animation.ANIMATIONLOOPMODE_CYCLE:
  312. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  313. return this.floatInterpolateFunction(startValue, endValue, gradient);
  314. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  315. return offsetValue * repeatCount + this.floatInterpolateFunction(startValue, endValue, gradient);
  316. }
  317. break;
  318. // Quaternion
  319. case Animation.ANIMATIONTYPE_QUATERNION:
  320. var quaternion = null;
  321. switch (loopMode) {
  322. case Animation.ANIMATIONLOOPMODE_CYCLE:
  323. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  324. quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient);
  325. break;
  326. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  327. quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  328. break;
  329. }
  330. return quaternion;
  331. // Vector3
  332. case Animation.ANIMATIONTYPE_VECTOR3:
  333. switch (loopMode) {
  334. case Animation.ANIMATIONLOOPMODE_CYCLE:
  335. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  336. return this.vector3InterpolateFunction(startValue, endValue, gradient);
  337. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  338. return this.vector3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  339. }
  340. // Vector2
  341. case Animation.ANIMATIONTYPE_VECTOR2:
  342. switch (loopMode) {
  343. case Animation.ANIMATIONLOOPMODE_CYCLE:
  344. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  345. return this.vector2InterpolateFunction(startValue, endValue, gradient);
  346. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  347. return this.vector2InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  348. }
  349. // Size
  350. case Animation.ANIMATIONTYPE_SIZE:
  351. switch (loopMode) {
  352. case Animation.ANIMATIONLOOPMODE_CYCLE:
  353. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  354. return this.sizeInterpolateFunction(startValue, endValue, gradient);
  355. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  356. return this.sizeInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  357. }
  358. // Color3
  359. case Animation.ANIMATIONTYPE_COLOR3:
  360. switch (loopMode) {
  361. case Animation.ANIMATIONLOOPMODE_CYCLE:
  362. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  363. return this.color3InterpolateFunction(startValue, endValue, gradient);
  364. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  365. return this.color3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  366. }
  367. // Matrix
  368. case Animation.ANIMATIONTYPE_MATRIX:
  369. switch (loopMode) {
  370. case Animation.ANIMATIONLOOPMODE_CYCLE:
  371. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  372. if (this.allowMatricesInterpolation) {
  373. return this.matrixInterpolateFunction(startValue, endValue, gradient);
  374. }
  375. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  376. return startValue;
  377. }
  378. default:
  379. break;
  380. }
  381. break;
  382. }
  383. }
  384. return this._getKeyValue(this._keys[this._keys.length - 1].value);
  385. };
  386. Animation.prototype.setValue = function (currentValue, blend) {
  387. if (blend === void 0) { blend = false; }
  388. // Set value
  389. var path;
  390. var destination;
  391. if (this.targetPropertyPath.length > 1) {
  392. var property = this._target[this.targetPropertyPath[0]];
  393. for (var index = 1; index < this.targetPropertyPath.length - 1; index++) {
  394. property = property[this.targetPropertyPath[index]];
  395. }
  396. path = this.targetPropertyPath[this.targetPropertyPath.length - 1];
  397. destination = property;
  398. }
  399. else {
  400. path = this.targetPropertyPath[0];
  401. destination = this._target;
  402. }
  403. // Blending
  404. if (this.enableBlending && this._blendingFactor <= 1.0) {
  405. if (!this._originalBlendValue) {
  406. if (destination[path].clone) {
  407. this._originalBlendValue = destination[path].clone();
  408. }
  409. else {
  410. this._originalBlendValue = destination[path];
  411. }
  412. }
  413. if (this._originalBlendValue.prototype) {
  414. if (this._originalBlendValue.prototype.Lerp) {
  415. destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
  416. }
  417. else {
  418. destination[path] = currentValue;
  419. }
  420. }
  421. else if (this._originalBlendValue.m) {
  422. destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
  423. }
  424. else {
  425. destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
  426. }
  427. this._blendingFactor += this.blendingSpeed;
  428. }
  429. else {
  430. destination[path] = currentValue;
  431. }
  432. if (this._target.markAsDirty) {
  433. this._target.markAsDirty(this.targetProperty);
  434. }
  435. };
  436. Animation.prototype.goToFrame = function (frame) {
  437. if (frame < this._keys[0].frame) {
  438. frame = this._keys[0].frame;
  439. }
  440. else if (frame > this._keys[this._keys.length - 1].frame) {
  441. frame = this._keys[this._keys.length - 1].frame;
  442. }
  443. var currentValue = this._interpolate(frame, 0, this.loopMode);
  444. this.setValue(currentValue);
  445. };
  446. Animation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
  447. if (blend === void 0) { blend = false; }
  448. if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
  449. this._stopped = true;
  450. return false;
  451. }
  452. var returnValue = true;
  453. // Adding a start key at frame 0 if missing
  454. if (this._keys[0].frame !== 0) {
  455. var newKey = { frame: 0, value: this._keys[0].value };
  456. this._keys.splice(0, 0, newKey);
  457. }
  458. // Check limits
  459. if (from < this._keys[0].frame || from > this._keys[this._keys.length - 1].frame) {
  460. from = this._keys[0].frame;
  461. }
  462. if (to < this._keys[0].frame || to > this._keys[this._keys.length - 1].frame) {
  463. to = this._keys[this._keys.length - 1].frame;
  464. }
  465. // Compute ratio
  466. var range = to - from;
  467. var offsetValue;
  468. // ratio represents the frame delta between from and to
  469. var ratio = delay * (this.framePerSecond * speedRatio) / 1000.0;
  470. var highLimitValue = 0;
  471. if (ratio > range && !loop) {
  472. returnValue = false;
  473. highLimitValue = this._getKeyValue(this._keys[this._keys.length - 1].value);
  474. }
  475. else {
  476. // Get max value if required
  477. if (this.loopMode !== Animation.ANIMATIONLOOPMODE_CYCLE) {
  478. var keyOffset = to.toString() + from.toString();
  479. if (!this._offsetsCache[keyOffset]) {
  480. var fromValue = this._interpolate(from, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
  481. var toValue = this._interpolate(to, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
  482. switch (this.dataType) {
  483. // Float
  484. case Animation.ANIMATIONTYPE_FLOAT:
  485. this._offsetsCache[keyOffset] = toValue - fromValue;
  486. break;
  487. // Quaternion
  488. case Animation.ANIMATIONTYPE_QUATERNION:
  489. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  490. break;
  491. // Vector3
  492. case Animation.ANIMATIONTYPE_VECTOR3:
  493. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  494. // Vector2
  495. case Animation.ANIMATIONTYPE_VECTOR2:
  496. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  497. // Size
  498. case Animation.ANIMATIONTYPE_SIZE:
  499. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  500. // Color3
  501. case Animation.ANIMATIONTYPE_COLOR3:
  502. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  503. default:
  504. break;
  505. }
  506. this._highLimitsCache[keyOffset] = toValue;
  507. }
  508. highLimitValue = this._highLimitsCache[keyOffset];
  509. offsetValue = this._offsetsCache[keyOffset];
  510. }
  511. }
  512. if (offsetValue === undefined) {
  513. switch (this.dataType) {
  514. // Float
  515. case Animation.ANIMATIONTYPE_FLOAT:
  516. offsetValue = 0;
  517. break;
  518. // Quaternion
  519. case Animation.ANIMATIONTYPE_QUATERNION:
  520. offsetValue = new BABYLON.Quaternion(0, 0, 0, 0);
  521. break;
  522. // Vector3
  523. case Animation.ANIMATIONTYPE_VECTOR3:
  524. offsetValue = BABYLON.Vector3.Zero();
  525. break;
  526. // Vector2
  527. case Animation.ANIMATIONTYPE_VECTOR2:
  528. offsetValue = BABYLON.Vector2.Zero();
  529. break;
  530. // Size
  531. case Animation.ANIMATIONTYPE_SIZE:
  532. offsetValue = BABYLON.Size.Zero();
  533. break;
  534. // Color3
  535. case Animation.ANIMATIONTYPE_COLOR3:
  536. offsetValue = BABYLON.Color3.Black();
  537. }
  538. }
  539. // Compute value
  540. var repeatCount = (ratio / range) >> 0;
  541. var currentFrame = returnValue ? from + ratio % range : to;
  542. var currentValue = this._interpolate(currentFrame, repeatCount, this.loopMode, offsetValue, highLimitValue);
  543. // Set value
  544. this.setValue(currentValue);
  545. // Check events
  546. for (var index = 0; index < this._events.length; index++) {
  547. if (currentFrame >= this._events[index].frame) {
  548. var event = this._events[index];
  549. if (!event.isDone) {
  550. // If event should be done only once, remove it.
  551. if (event.onlyOnce) {
  552. this._events.splice(index, 1);
  553. index--;
  554. }
  555. event.isDone = true;
  556. event.action();
  557. } // Don't do anything if the event has already be done.
  558. }
  559. else if (this._events[index].isDone && !this._events[index].onlyOnce) {
  560. // reset event, the animation is looping
  561. this._events[index].isDone = false;
  562. }
  563. }
  564. if (!returnValue) {
  565. this._stopped = true;
  566. }
  567. return returnValue;
  568. };
  569. Animation.prototype.serialize = function () {
  570. var serializationObject = {};
  571. serializationObject.name = this.name;
  572. serializationObject.property = this.targetProperty;
  573. serializationObject.framePerSecond = this.framePerSecond;
  574. serializationObject.dataType = this.dataType;
  575. serializationObject.loopBehavior = this.loopMode;
  576. var dataType = this.dataType;
  577. serializationObject.keys = [];
  578. var keys = this.getKeys();
  579. for (var index = 0; index < keys.length; index++) {
  580. var animationKey = keys[index];
  581. var key = {};
  582. key.frame = animationKey.frame;
  583. switch (dataType) {
  584. case Animation.ANIMATIONTYPE_FLOAT:
  585. key.values = [animationKey.value];
  586. break;
  587. case Animation.ANIMATIONTYPE_QUATERNION:
  588. case Animation.ANIMATIONTYPE_MATRIX:
  589. case Animation.ANIMATIONTYPE_VECTOR3:
  590. case Animation.ANIMATIONTYPE_COLOR3:
  591. key.values = animationKey.value.asArray();
  592. break;
  593. }
  594. serializationObject.keys.push(key);
  595. }
  596. serializationObject.ranges = [];
  597. for (var name in this._ranges) {
  598. var range = {};
  599. range.name = name;
  600. range.from = this._ranges[name].from;
  601. range.to = this._ranges[name].to;
  602. serializationObject.ranges.push(range);
  603. }
  604. return serializationObject;
  605. };
  606. Object.defineProperty(Animation, "ANIMATIONTYPE_FLOAT", {
  607. get: function () {
  608. return Animation._ANIMATIONTYPE_FLOAT;
  609. },
  610. enumerable: true,
  611. configurable: true
  612. });
  613. Object.defineProperty(Animation, "ANIMATIONTYPE_VECTOR3", {
  614. get: function () {
  615. return Animation._ANIMATIONTYPE_VECTOR3;
  616. },
  617. enumerable: true,
  618. configurable: true
  619. });
  620. Object.defineProperty(Animation, "ANIMATIONTYPE_VECTOR2", {
  621. get: function () {
  622. return Animation._ANIMATIONTYPE_VECTOR2;
  623. },
  624. enumerable: true,
  625. configurable: true
  626. });
  627. Object.defineProperty(Animation, "ANIMATIONTYPE_SIZE", {
  628. get: function () {
  629. return Animation._ANIMATIONTYPE_SIZE;
  630. },
  631. enumerable: true,
  632. configurable: true
  633. });
  634. Object.defineProperty(Animation, "ANIMATIONTYPE_QUATERNION", {
  635. get: function () {
  636. return Animation._ANIMATIONTYPE_QUATERNION;
  637. },
  638. enumerable: true,
  639. configurable: true
  640. });
  641. Object.defineProperty(Animation, "ANIMATIONTYPE_MATRIX", {
  642. get: function () {
  643. return Animation._ANIMATIONTYPE_MATRIX;
  644. },
  645. enumerable: true,
  646. configurable: true
  647. });
  648. Object.defineProperty(Animation, "ANIMATIONTYPE_COLOR3", {
  649. get: function () {
  650. return Animation._ANIMATIONTYPE_COLOR3;
  651. },
  652. enumerable: true,
  653. configurable: true
  654. });
  655. Object.defineProperty(Animation, "ANIMATIONLOOPMODE_RELATIVE", {
  656. get: function () {
  657. return Animation._ANIMATIONLOOPMODE_RELATIVE;
  658. },
  659. enumerable: true,
  660. configurable: true
  661. });
  662. Object.defineProperty(Animation, "ANIMATIONLOOPMODE_CYCLE", {
  663. get: function () {
  664. return Animation._ANIMATIONLOOPMODE_CYCLE;
  665. },
  666. enumerable: true,
  667. configurable: true
  668. });
  669. Object.defineProperty(Animation, "ANIMATIONLOOPMODE_CONSTANT", {
  670. get: function () {
  671. return Animation._ANIMATIONLOOPMODE_CONSTANT;
  672. },
  673. enumerable: true,
  674. configurable: true
  675. });
  676. Animation.Parse = function (parsedAnimation) {
  677. var animation = new Animation(parsedAnimation.name, parsedAnimation.property, parsedAnimation.framePerSecond, parsedAnimation.dataType, parsedAnimation.loopBehavior);
  678. var dataType = parsedAnimation.dataType;
  679. var keys = [];
  680. var data;
  681. var index;
  682. for (index = 0; index < parsedAnimation.keys.length; index++) {
  683. var key = parsedAnimation.keys[index];
  684. switch (dataType) {
  685. case Animation.ANIMATIONTYPE_FLOAT:
  686. data = key.values[0];
  687. break;
  688. case Animation.ANIMATIONTYPE_QUATERNION:
  689. data = BABYLON.Quaternion.FromArray(key.values);
  690. break;
  691. case Animation.ANIMATIONTYPE_MATRIX:
  692. data = BABYLON.Matrix.FromArray(key.values);
  693. break;
  694. case Animation.ANIMATIONTYPE_COLOR3:
  695. data = BABYLON.Color3.FromArray(key.values);
  696. break;
  697. case Animation.ANIMATIONTYPE_VECTOR3:
  698. default:
  699. data = BABYLON.Vector3.FromArray(key.values);
  700. break;
  701. }
  702. keys.push({
  703. frame: key.frame,
  704. value: data
  705. });
  706. }
  707. animation.setKeys(keys);
  708. if (parsedAnimation.ranges) {
  709. for (index = 0; index < parsedAnimation.ranges.length; index++) {
  710. data = parsedAnimation.ranges[index];
  711. animation.createRange(data.name, data.from, data.to);
  712. }
  713. }
  714. return animation;
  715. };
  716. Animation.AppendSerializedAnimations = function (source, destination) {
  717. if (source.animations) {
  718. destination.animations = [];
  719. for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
  720. var animation = source.animations[animationIndex];
  721. destination.animations.push(animation.serialize());
  722. }
  723. }
  724. };
  725. // Statics
  726. Animation._ANIMATIONTYPE_FLOAT = 0;
  727. Animation._ANIMATIONTYPE_VECTOR3 = 1;
  728. Animation._ANIMATIONTYPE_QUATERNION = 2;
  729. Animation._ANIMATIONTYPE_MATRIX = 3;
  730. Animation._ANIMATIONTYPE_COLOR3 = 4;
  731. Animation._ANIMATIONTYPE_VECTOR2 = 5;
  732. Animation._ANIMATIONTYPE_SIZE = 6;
  733. Animation._ANIMATIONLOOPMODE_RELATIVE = 0;
  734. Animation._ANIMATIONLOOPMODE_CYCLE = 1;
  735. Animation._ANIMATIONLOOPMODE_CONSTANT = 2;
  736. return Animation;
  737. }());
  738. BABYLON.Animation = Animation;
  739. })(BABYLON || (BABYLON = {}));