babylon.animation.js 34 KB

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