three-cad-viewer 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92269,6 +92269,20 @@ void main() {
92269
92269
  this.tracks = [];
92270
92270
  this.root = null;
92271
92271
  }
92272
+ /**
92273
+ * Apply the current animation time to the objects without advancing it, so a
92274
+ * single on-demand render shows the pose (e.g. after {@link setRelativeTime}).
92275
+ */
92276
+ apply() {
92277
+ this.mixer?.update(0);
92278
+ }
92279
+ /**
92280
+ * Restart the frame-time measurement, so resuming playback after a pause does
92281
+ * not advance the animation by the whole pause.
92282
+ */
92283
+ resetClock() {
92284
+ this.clock.reset();
92285
+ }
92272
92286
  /**
92273
92287
  * Update the animation mixer (call each frame when animating).
92274
92288
  */
@@ -97840,7 +97854,7 @@ void main() {
97840
97854
  }
97841
97855
  }
97842
97856
 
97843
- const version = "5.1.0";
97857
+ const version = "5.1.2";
97844
97858
 
97845
97859
  /**
97846
97860
  * `PickedComponent` over a GPU id-pick result. Drives the shader
@@ -109435,6 +109449,8 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
109435
109449
  * @param updateMarker - enforce to redraw orientation marker after every ui activity
109436
109450
  */
109437
109451
  constructor(display, options, notifyCallback, pinAsPngCallback = null, updateMarker = true) {
109452
+ /** Reasons for continuous rendering; the render loop runs while any is set. */
109453
+ this._loopReasons = new Set();
109438
109454
  // Hide-undo stack: each meta-double-click hide pushes the leaf id + its pre-hide
109439
109455
  // state; meta-double-click on empty space pops and restores the last one. Lets a
109440
109456
  // hidden object be brought back without the tree (e.g. in Studio, where it's hidden).
@@ -109461,7 +109477,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
109461
109477
  this._capOutlineCamera = [];
109462
109478
  /** Pending redraw that adds the outline once the camera has settled. */
109463
109479
  this._capOutlineSettle = null;
109464
- /** Whether the attached animation has moved parts (Play pressed or time slider moved). */
109480
+ /** Whether the attached animation has moved parts (Play or time slider, not stopped since). */
109465
109481
  this._animationStarted = false;
109466
109482
  // ---------------------------------------------------------------------------
109467
109483
  // Render Loop & Scene Updates
@@ -109870,12 +109886,19 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
109870
109886
  this.clipAction.paused = false;
109871
109887
  }
109872
109888
  this.clipAction.play();
109889
+ this._setAnimationPlaying(true);
109873
109890
  break;
109874
109891
  case "pause":
109875
109892
  this.clipAction.paused = !this.clipAction.paused;
109893
+ this._setAnimationPlaying(!this.clipAction.paused && this.clipAction.isRunning());
109876
109894
  break;
109877
109895
  case "stop":
109878
109896
  this.clipAction.stop();
109897
+ // stop() restores the parts' original transforms (three.js
109898
+ // AnimationMixer._deactivateAction -> restoreOriginalState), so they are
109899
+ // at their model positions again and points can be copied.
109900
+ this._animationStarted = false;
109901
+ this._setAnimationPlaying(false);
109879
109902
  break;
109880
109903
  }
109881
109904
  };
@@ -110765,10 +110788,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
110765
110788
  return Promise.resolve({ task: taskId, dataUrl: null });
110766
110789
  }
110767
110790
  // canvas.toBlob can be very slow when animation loop is off!
110768
- const animationLoop = this.hasAnimationLoop;
110769
- if (!animationLoop) {
110770
- this.toggleAnimationLoop(true);
110771
- }
110791
+ this.setLoopReason("capture", true);
110772
110792
  this.rendered.orientationMarker.setVisible(false);
110773
110793
  this.update(true);
110774
110794
  return this.display.captureCanvas({
@@ -110786,10 +110806,8 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
110786
110806
  }
110787
110807
  },
110788
110808
  onComplete: () => {
110789
- // Restore animation loop to original state
110790
- if (!animationLoop) {
110791
- this.toggleAnimationLoop(false);
110792
- }
110809
+ // Restore the loop to what the other reasons need
110810
+ this.setLoopReason("capture", false);
110793
110811
  this.rendered.orientationMarker.setVisible(true);
110794
110812
  this.update(true);
110795
110813
  },
@@ -111187,14 +111205,13 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111187
111205
  return;
111188
111206
  }
111189
111207
  logger.debug("Animation initialized");
111190
- if (!this.hasAnimationLoop) {
111191
- this.toggleAnimationLoop(true);
111192
- }
111193
111208
  this.state.set("animationMode", label === "E" ? "explode" : "animation");
111194
111209
  this._animationStarted = false;
111195
111210
  this.clipAction = this.animation.animate(this.rendered.nestedGroup.rootGroup, duration, speed, repeat);
111196
111211
  // Reset animation slider to start
111197
111212
  this.state.set("animationSliderValue", 0);
111213
+ // Not playing yet: render on demand only (the loop starts with Play).
111214
+ this._setAnimationPlaying(false);
111198
111215
  }
111199
111216
  /**
111200
111217
  * Check whether animation object exists
@@ -111211,7 +111228,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111211
111228
  }
111212
111229
  this.state.set("animationMode", "none");
111213
111230
  this._animationStarted = false;
111214
- this.toggleAnimationLoop(false);
111231
+ this.setLoopReason("animation", false);
111215
111232
  }
111216
111233
  /**
111217
111234
  * Set the animation to a specific relative time (0-1).
@@ -111223,6 +111240,8 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111223
111240
  this._animationStarted = true;
111224
111241
  this.animation.setRelativeTime(fraction);
111225
111242
  this.state.set("animationSliderValue", fraction * 1000);
111243
+ // Setting a time pauses the animation: stop the loop and show the new pose.
111244
+ this._setAnimationPlaying(false);
111226
111245
  }
111227
111246
  /**
111228
111247
  * Get the current relative animation time (0-1).
@@ -111231,6 +111250,44 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111231
111250
  getRelativeTime() {
111232
111251
  return this.animation.getRelativeTime();
111233
111252
  }
111253
+ /**
111254
+ * Add or remove a reason for continuous rendering. The render loop runs while at
111255
+ * least one reason is set; otherwise the viewer renders on demand (camera changes
111256
+ * and explicit updates), so an idle viewer costs no CPU/GPU time.
111257
+ * @param reason - why continuous rendering is needed.
111258
+ * @param flag - whether the reason applies.
111259
+ */
111260
+ setLoopReason(reason, flag) {
111261
+ if (flag) {
111262
+ this._loopReasons.add(reason);
111263
+ }
111264
+ else {
111265
+ this._loopReasons.delete(reason);
111266
+ }
111267
+ const run = this._loopReasons.size > 0;
111268
+ if (run !== this.hasAnimationLoop)
111269
+ this.toggleAnimationLoop(run);
111270
+ }
111271
+ /**
111272
+ * Run the render loop only while the animation plays. When it stops (pause,
111273
+ * stop, slider), render once so the final pose is shown.
111274
+ */
111275
+ _setAnimationPlaying(playing) {
111276
+ if (playing) {
111277
+ // Resume without jumping ahead by the time spent paused.
111278
+ this.animation.resetClock();
111279
+ }
111280
+ this.setLoopReason("animation", playing);
111281
+ if (!playing && this._rendered !== null) {
111282
+ this.animation.apply();
111283
+ this.update(true, false);
111284
+ }
111285
+ }
111286
+ /**
111287
+ * Start or stop the render loop directly. Prefer {@link setLoopReason}, which keeps
111288
+ * the loop running while any other reason still needs it.
111289
+ * @param flag - whether the render loop should run.
111290
+ */
111234
111291
  toggleAnimationLoop(flag) {
111235
111292
  if (flag) {
111236
111293
  this.continueAnimation = true;
@@ -111381,6 +111438,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111381
111438
  // Hide the topo filter (+ detach its shortcuts) for a clean cleared canvas.
111382
111439
  this.display.shapeFilterDropDownMenu.show(false);
111383
111440
  // stop animation
111441
+ this._loopReasons.clear();
111384
111442
  this.hasAnimationLoop = false;
111385
111443
  this.continueAnimation = false;
111386
111444
  // remove change listener if exists
@@ -111963,8 +112021,9 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111963
112021
  * Copy the world-space point under the cursor as `"x, y, z"` to the clipboard and
111964
112022
  * send it to the host as a `copiedPoint` notification (for hosts that block the
111965
112023
  * browser clipboard). Does nothing while parts may be displaced from their model
111966
- * positions — explode mode, an animation once started (Play or time slider), a
111967
- * z-scale other than 1 — or when no visible component is under the cursor.
112024
+ * positions — explode mode, an animation that was played or scrubbed and not
112025
+ * stopped since (Stop puts the parts back), a z-scale other than 1 — or when no
112026
+ * visible component is under the cursor.
111968
112027
  * @returns true when a point was copied (the caller then consumes the key event).
111969
112028
  */
111970
112029
  copyPointUnderCursor() {
@@ -114075,7 +114134,7 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
114075
114134
  if (flag && this.viewer.isStudioActive) {
114076
114135
  return;
114077
114136
  }
114078
- this.viewer.toggleAnimationLoop(flag);
114137
+ this.viewer.setLoopReason("tool", flag);
114079
114138
  if (flag) {
114080
114139
  // Delegate state mutations to Viewer
114081
114140
  this.viewer.activateTool(name, true);