babylon.referenceDeformation.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. module BABYLON{
  2. /**
  3. * Class to store Deformation info & evaluate how complete it should be.
  4. */
  5. export class ReferenceDeformation {
  6. private _syncPartner : ReferenceDeformation; // not part of constructor, since cannot be in both partners constructors, use setSyncPartner()
  7. // time and state management members
  8. private _startTime = -1;
  9. private _currentDurationRatio = ReferenceDeformation._COMPLETE;
  10. // wallclock prorating members, used for acceleration / deceleration across AutomaonEventSeries runs
  11. private _proratedMilliDuration : number;
  12. private _proratedMillisBefore : number;
  13. /**
  14. * @param {string} shapeKeyGroupName - Used by Automaton to place in the correct ShapeKeyGroup queue(s).
  15. * @param {string} referenceStateName - Name of state key to be used as a reference, so that a endStateRatio can be used
  16. * @param {string} endStateName - Name of state key to deform to
  17. * @param {number} milliDuration - The number of milli seconds the deformation is to be completed in
  18. * @param {number} millisBefore - Fixed wait period, once a syncPartner (if any) is also ready (default 0)
  19. * @param {number} endStateRatio - ratio of the end state to be obtained from reference state: -1 (mirror) to 1 (default 1)
  20. * @param {Vector3} movePOV - Mesh movement relative to its current position/rotation to be performed at the same time (default null)
  21. * right-up-forward
  22. * @param {Vector3} rotatePOV - Incremental Mesh rotation to be performed at the same time (default null)
  23. * flipBack-twirlClockwise-tiltRight
  24. * @param {Pace} pace - Any Object with the function: getCompletionMilestone(currentDurationRatio) (default Pace.LINEAR)
  25. */
  26. constructor(
  27. public shapeKeyGroupName : string,
  28. private _referenceStateName : string,
  29. private _endStateName : string,
  30. private _milliDuration : number,
  31. private _millisBefore : number = 0,
  32. private _endStateRatio : number = 1,
  33. public movePOV : Vector3 = null,
  34. public rotatePOV : Vector3 = null,
  35. private _pace : Pace = Pace.LINEAR)
  36. {
  37. // argument validations
  38. if (this._referenceStateName === this._endStateName) throw "Deformation: reference state cannot be the same as the end state";
  39. if (this._milliDuration <= 0) throw "Deformation: milliDuration must > 0";
  40. if (this._millisBefore < 0) throw "Deformation: millisBefore cannot be negative";
  41. if (this._endStateRatio < -1 || this._endStateRatio > 1) throw "Deformation: endStateRatio range > -1 and < 1";
  42. // mixed case group & state names not supported
  43. this.shapeKeyGroupName = this.shapeKeyGroupName .toUpperCase();
  44. this._referenceStateName = this._referenceStateName.toUpperCase();
  45. this._endStateName = this._endStateName .toUpperCase();
  46. this.setProratedWallClocks(1); // ensure values actually used for timings are initialized
  47. }
  48. // =================================== run time processing ===================================
  49. /**
  50. * Indicate readiness by caller to start processing event.
  51. * @param {number} lateStartMilli - indication of how far behind already
  52. */
  53. public activate(lateStartMilli = 0) : void {
  54. this._startTime = Automaton.now();
  55. if (lateStartMilli > 0){
  56. // apply 20% of the late start or 10% of duration which ever is less
  57. lateStartMilli /= 5;
  58. this._startTime -= (lateStartMilli < this._milliDuration / 10) ? lateStartMilli : this._milliDuration / 10;
  59. }
  60. this._currentDurationRatio = (this._syncPartner) ? ReferenceDeformation._BLOCKED :
  61. ((this._proratedMillisBefore > 0) ? ReferenceDeformation._WAITING : ReferenceDeformation._READY);
  62. }
  63. /** called by ShapeKeyGroup.incrementallyDeform() to determine how much of the deformation should be performed right now */
  64. public getCompletionMilestone() : number {
  65. if (this._currentDurationRatio === ReferenceDeformation._COMPLETE){
  66. return ReferenceDeformation._COMPLETE;
  67. }
  68. // BLOCK only occurs when there is a sync partner
  69. if (this._currentDurationRatio === ReferenceDeformation._BLOCKED){
  70. // change both to WAITING & start clock, once both are BLOCKED
  71. if (this._syncPartner.isBlocked() ){
  72. this._startTime = Automaton.now(); // reset the start clock
  73. this._currentDurationRatio = ReferenceDeformation._WAITING;
  74. this._syncPartner.syncReady(this._startTime);
  75. }
  76. else return ReferenceDeformation._BLOCKED;
  77. }
  78. var millisSoFar = Automaton.now() - this._startTime;
  79. if (this._currentDurationRatio === ReferenceDeformation._WAITING){
  80. millisSoFar -= this._proratedMillisBefore;
  81. if (millisSoFar >= 0){
  82. this._startTime = Automaton.now() - millisSoFar; // prorate start for time served
  83. }
  84. else return ReferenceDeformation._WAITING;
  85. }
  86. this._currentDurationRatio = millisSoFar / this._proratedMilliDuration;
  87. if (this._currentDurationRatio > ReferenceDeformation._COMPLETE)
  88. this._currentDurationRatio = ReferenceDeformation._COMPLETE;
  89. return this._pace.getCompletionMilestone(this._currentDurationRatio);
  90. }
  91. /** support game pausing / resuming. There is no need to actively pause a Deformation. */
  92. public resumePlay() : void {
  93. if (this._currentDurationRatio === ReferenceDeformation._COMPLETE ||
  94. this._currentDurationRatio === ReferenceDeformation._BLOCKED ||
  95. this._currentDurationRatio === ReferenceDeformation._COMPLETE) return;
  96. // back into a start time which reflects the currentDurationRatio
  97. this._startTime = Automaton.now() - (this._proratedMilliDuration * this._currentDurationRatio);
  98. }
  99. // =================================== sync partner methods ===================================
  100. /**
  101. * @param {Deformation} syncPartner - Deformation which should start at the same time as this one. MUST be in a different shape key group!
  102. */
  103. public setSyncPartner(syncPartner : ReferenceDeformation) : void{
  104. this._syncPartner = syncPartner;
  105. }
  106. /**
  107. * Called by the first of the syncPartners to detect that both are waiting for each other.
  108. * Only intended to be called from getCompletionMilestone() of the partner.
  109. * @param {number} startTime - passed from partner, so both are in sync as close as possible.
  110. */
  111. public syncReady(startTime : number) : void{
  112. this._startTime = startTime;
  113. this._currentDurationRatio = ReferenceDeformation._WAITING;
  114. }
  115. // ==================================== Getters & setters ====================================
  116. public isBlocked () : boolean { return this._currentDurationRatio === ReferenceDeformation._BLOCKED ; }
  117. public isComplete() : boolean { return this._currentDurationRatio === ReferenceDeformation._COMPLETE; }
  118. public getReferenceStateName() : string { return this._referenceStateName; }
  119. public getEndStateName() : string { return this._endStateName; }
  120. public getMilliDuration() : number { return this._milliDuration; }
  121. public getMillisBefore() : number { return this._millisBefore; }
  122. public getEndStateRatio() :number {return this._endStateRatio; }
  123. public getPace() : Pace {return this._pace; }
  124. public getSyncPartner() : ReferenceDeformation{return this._syncPartner; }
  125. /**
  126. * Called by the Automaton Event Series, before Deformation is passed to the ShapeKeyGroup. This
  127. * is to support acceleration / deceleration across event series repeats.
  128. * @param {number} factor - amount to multiply the constructor supplied duration & time before by.
  129. */
  130. public setProratedWallClocks(factor : number) : void {
  131. this._proratedMilliDuration = this._milliDuration * factor;
  132. this._proratedMillisBefore = this._millisBefore * factor;
  133. }
  134. // ========================================== Enums =========================================
  135. private static _BLOCKED = -20;
  136. private static _WAITING = -10;
  137. private static _READY = 0;
  138. private static _COMPLETE = 1;
  139. public static get BLOCKED (): number { return ReferenceDeformation._BLOCKED ; }
  140. public static get WAITING (): number { return ReferenceDeformation._WAITING ; }
  141. public static get READY (): number { return ReferenceDeformation._READY ; }
  142. public static get COMPLETE(): number { return ReferenceDeformation._COMPLETE; }
  143. }
  144. }