rig-play 1.5.0 → 1.7.0
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.
- package/README.md +34 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -19
- package/dist/index.js.map +1 -1
- package/dist/player.d.ts +54 -8
- package/dist/player.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,30 @@ box, an inverse clip removes nothing, and bounding boxes, paths and points do
|
|
|
263
263
|
not draw and do not count. Both cost nothing until called and read the same
|
|
264
264
|
numbers in `dom` and `canvas` mode.
|
|
265
265
|
|
|
266
|
+
### Drawing some slots only
|
|
267
|
+
|
|
268
|
+
`slots` is a draw filter — an allow list of slot names or a predicate — settable up
|
|
269
|
+
front and on a live player. The pose is the whole rig's whatever the filter:
|
|
270
|
+
bones, constraints, physics, `bone()`, `adjust`, events and tracks see no filter;
|
|
271
|
+
only the draw does, in both modes, and `bounds()` reads the drawn slots. A
|
|
272
|
+
clipping slot the filter leaves out does not clip. An allow list naming a slot
|
|
273
|
+
the document does not have is refused by name.
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
const hand = new RigPlayer(frontRoot, assets, { slots: ['hand_f', 'arm_f_lo'] });
|
|
277
|
+
player.slots = (slot) => !slot.startsWith('weapon');
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Two players over one `ModelAssets` share the load but each poses the rig. To
|
|
281
|
+
pose it once and draw it twice — a hand drawn again in front of another
|
|
282
|
+
character — give a second renderer this player's pose under another filter:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
const front = new DomRenderer(frontRoot, assets.regionImages, assets.pageImages);
|
|
286
|
+
// each frame, after player.frame(dt):
|
|
287
|
+
front.render(player.posedFrame(['hand_f', 'arm_f_lo']));
|
|
288
|
+
```
|
|
289
|
+
|
|
266
290
|
### Several tracks
|
|
267
291
|
|
|
268
292
|
A base on track 0, a layer over it, a one-shot played once and mixed back out —
|
|
@@ -282,9 +306,15 @@ player.entry(2); // { animation, loop
|
|
|
282
306
|
`play(name)` keeps meaning what it meant: a plain play on track 0 runs on rig-c's
|
|
283
307
|
single live track, which poses everything the core poses. The first call that
|
|
284
308
|
composes — a `mix`, a `track` above 0, a `queue`, a `clear` — moves the player onto
|
|
285
|
-
the tracks, carrying the single track over by replay (its animation set, pose 0
|
|
286
|
-
taken, stepped to its time
|
|
287
|
-
|
|
309
|
+
the tracks, carrying the single track over by **replay** (its animation set, pose 0
|
|
310
|
+
taken, stepped to its time in `seekStep` increments — one pose per step played, so
|
|
311
|
+
on a stage that idled a while that is one long frame; the core offers no hand-over
|
|
312
|
+
of a live track's state). To never pay it, stand the player on the tracks from the
|
|
313
|
+
start: `new RigPlayer(root, assets, { tracks: true })`. Pick the single track for a
|
|
314
|
+
rig whose animations key what the tracks do not mix (below); pick the tracks for
|
|
315
|
+
layering. Either way, after the first `mix`, `track` above 0, `queue` or `clear`,
|
|
316
|
+
`seek` and `skin` are refused by name, since the player cannot replay a composition
|
|
317
|
+
to a time — step it forward instead.
|
|
288
318
|
Every entry mixes from the setup pose each step, so `adjust` writes still last one
|
|
289
319
|
pose. **What the tracks do not mix**, in rig-c's words at `play`/`queue`: an
|
|
290
320
|
animation keying a constraint (ik, transform, path, physics, slider), a sequence,
|
|
@@ -628,6 +658,7 @@ name, and unloading is still elements first, bitmaps second.
|
|
|
628
658
|
| `DomTexture` | none | Not exported; there is no atlas page to attach a texture to. |
|
|
629
659
|
| `new Skeleton(assets.data)` and `new AnimationState(new AnimationStateData(assets.data))` | `new RigPlayer(root, assets, options?)` | The player holds the pose and the track. |
|
|
630
660
|
| `state.setAnimation(0, 'walk', true)` | `player.play('walk', { loop: true })` | `loop` defaults to true. `play` opens the animation at its first pose with the physics reset there. `player.current` names what is playing. |
|
|
661
|
+
| `skeleton.findSlot('x').attachment = null` to hide a slot, or a second skeleton with slots emptied | `RigPlayerOptions.slots`, `player.slots`, `player.posedFrame(slots)` | A draw filter since 1.6.0 — the pose is the whole rig's; a clipping slot left out does not clip. See *Drawing some slots only*. |
|
|
631
662
|
| `state.setAnimation(1, 'smile', false)` with a mix, `addAnimation`, `setEmptyAnimation`, `addEmptyAnimation`, `getCurrent(track)` | `player.play(name, { track, loop, mix })`, `player.queue(name, { track, loop, mix, delay })`, `player.clear(track, { mix })`, `player.queueClear(track, { mix, delay })`, `player.entry(track)` | Since 1.5.0, rig-c's live tracks: the runtime's mixing at tolerance 0. Constraint, sequence, draw-order and path-deform timelines are not mixed and are refused on the tracks. See *Several tracks*. |
|
|
632
663
|
| `state.update(delta)`, `state.apply(skeleton)`, `skeleton.update(delta)`, `skeleton.updateWorldTransform(Physics.update)`, `renderer.render(skeleton)` | `player.frame(dt)` | Or `player.advance(dt)` then `player.draw()`, to time the two apart. |
|
|
633
664
|
| time scale (the caller's own, on the spine-core side) | `player.timeScale` | Multiplies every step. 0 holds the pose without re-posing it; a negative value is not stepped. |
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { type CanvasBackend, CanvasRenderer, type CanvasViewport } from './Canva
|
|
|
2
2
|
export { DomRenderer, type MeshBackend } from './DomRenderer.js';
|
|
3
3
|
export { type PageLayout, type PageRegion, type RegionEncoding, type RegionImage, revokeRegions, type UnpackRegionsOptions, unpackRegions } from './DomTexture.js';
|
|
4
4
|
export { type LoadModelOptions, loadModel, type ModelAssets, type ModelDocument, type RegionLoading } from './loadModel.js';
|
|
5
|
-
export { type AdjustableBones, type BoneAdjust, type BoneLocals, type BoneWorld, type PlayOptions, type PoseBounds, type QueueOptions, type RenderMode, type RigComplete, type RigEvent, RigPlayer, type RigPlayerOptions, type TrackEntry } from './player.js';
|
|
5
|
+
export { type AdjustableBones, type BoneAdjust, type BoneLocals, type BoneWorld, type PlayOptions, type PoseBounds, type QueueOptions, type RenderMode, type RigComplete, type RigEvent, RigPlayer, type RigPlayerOptions, type SlotFilter, type TrackEntry } from './player.js';
|
|
6
6
|
export type { BlendMode, PosedClip, PosedFrame, PosedMesh, PosedRegion, PosedSlot, } from './posedFrame.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnK,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5H,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnK,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5H,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACjR,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8216,7 +8216,7 @@ function trianglesOf(source, drawn) {
|
|
|
8216
8216
|
}
|
|
8217
8217
|
return kept;
|
|
8218
8218
|
}
|
|
8219
|
-
function clipCover(pose, active) {
|
|
8219
|
+
function clipCover(pose, active, draws = () => true) {
|
|
8220
8220
|
const polygons = new Map(pose.clips.map((c) => [c[0], { end: c[2], polygon: c[3] }]));
|
|
8221
8221
|
const shownOf = new Map(pose.shown.map((s) => [s.slot, s]));
|
|
8222
8222
|
const cover = /* @__PURE__ */ new Map();
|
|
@@ -8227,7 +8227,7 @@ function clipCover(pose, active) {
|
|
|
8227
8227
|
const clip = g?.kind === "clipping" ? polygons.get(slot) : void 0;
|
|
8228
8228
|
if (shown !== void 0 && g?.kind === "clipping" && clip !== void 0) {
|
|
8229
8229
|
if (current !== null && current.end === slot) current = null;
|
|
8230
|
-
if (active.has(shown.bone) && current === null) {
|
|
8230
|
+
if (active.has(shown.bone) && current === null && draws(slot)) {
|
|
8231
8231
|
current = { end: clip.end, clip: { polygon: clip.polygon, inverse: g.inverse, convex: g.convex } };
|
|
8232
8232
|
}
|
|
8233
8233
|
continue;
|
|
@@ -8237,16 +8237,17 @@ function clipCover(pose, active) {
|
|
|
8237
8237
|
}
|
|
8238
8238
|
return cover;
|
|
8239
8239
|
}
|
|
8240
|
-
function frameOf(source, pose, color = [1, 1, 1, 1]) {
|
|
8240
|
+
function frameOf(source, pose, color = [1, 1, 1, 1], draws = () => true) {
|
|
8241
8241
|
const { drawn: regions, why } = drawnRegions(source.doc, pose.shown, pose.drawOrder, source.uv);
|
|
8242
8242
|
if (regions === null) throw new CoreInputError(`the page UVs are not posed: ${why}`);
|
|
8243
8243
|
const regionOf = new Map(regions.map((r) => [r.slot, r]));
|
|
8244
8244
|
const rows = new Map(pose.slots.map((row) => [row[0], row]));
|
|
8245
8245
|
const z = new Map(pose.drawOrder.map((slot, index) => [slot, index]));
|
|
8246
|
-
const cover = clipCover(pose, source.active);
|
|
8246
|
+
const cover = clipCover(pose, source.active, draws);
|
|
8247
8247
|
const [sr, sg, sb, sa] = color;
|
|
8248
8248
|
const order = [];
|
|
8249
8249
|
for (const d of pose.drawn) {
|
|
8250
|
+
if (!draws(d.slot)) continue;
|
|
8250
8251
|
const bone2 = source.boneOf.get(d.slot);
|
|
8251
8252
|
if (bone2 === void 0 || !source.active.has(bone2)) continue;
|
|
8252
8253
|
const found = regionOf.get(d.slot);
|
|
@@ -8294,6 +8295,10 @@ function frameOf(source, pose, color = [1, 1, 1, 1]) {
|
|
|
8294
8295
|
}
|
|
8295
8296
|
return { order };
|
|
8296
8297
|
}
|
|
8298
|
+
function predicateOf(names) {
|
|
8299
|
+
const allowed = new Set(names);
|
|
8300
|
+
return (slot) => allowed.has(slot);
|
|
8301
|
+
}
|
|
8297
8302
|
class RigPlayer {
|
|
8298
8303
|
/**
|
|
8299
8304
|
* The renderer this player draws through — its knobs and counters are the
|
|
@@ -8337,10 +8342,17 @@ class RigPlayer {
|
|
|
8337
8342
|
loop = true;
|
|
8338
8343
|
/** One past the highest track touched — how many `current(track)` reads a step takes. */
|
|
8339
8344
|
trackCount = 0;
|
|
8345
|
+
/** `RigPlayerOptions.tracks`: every play opens the live tracks, never the single track. */
|
|
8346
|
+
trackMode;
|
|
8347
|
+
/** Set once anything beyond a plain play on track 0 happened: a mix, another track, a queue, a clear. `seek` and `skin` then cannot replay and refuse. */
|
|
8348
|
+
beyondBase = false;
|
|
8340
8349
|
paused = false;
|
|
8341
8350
|
pose = null;
|
|
8342
8351
|
setup = null;
|
|
8343
8352
|
adjustFn = null;
|
|
8353
|
+
slotFilter = null;
|
|
8354
|
+
/** `slotFilter` as a predicate; every slot when null. */
|
|
8355
|
+
draws = () => true;
|
|
8344
8356
|
/** Handed to every track the player opens; reads the current `adjust` so setting it later needs no reopen. */
|
|
8345
8357
|
adjustHook = (locals) => {
|
|
8346
8358
|
if (this.adjustFn !== null) this.adjustFn(locals);
|
|
@@ -8356,11 +8368,13 @@ class RigPlayer {
|
|
|
8356
8368
|
this.view = options.skin === void 0 ? underNoSkin(read.doc) : underSkin(read.doc, options.skin);
|
|
8357
8369
|
this.source = frameSource(this.view, read.parsed);
|
|
8358
8370
|
this.seekStep = options.seekStep ?? 1 / 60;
|
|
8371
|
+
this.trackMode = options.tracks === true;
|
|
8359
8372
|
if (!(this.seekStep > 0)) throw new Error(`seekStep must be a positive number of seconds, got ${String(options.seekStep)}`);
|
|
8360
8373
|
this.root = root;
|
|
8361
8374
|
this.assets = assets;
|
|
8362
8375
|
this.meshBackend = options.meshBackend;
|
|
8363
8376
|
this.adjustFn = options.adjust ?? null;
|
|
8377
|
+
if (options.slots !== void 0 && options.slots !== null) this.slots = options.slots;
|
|
8364
8378
|
this.active = this.create(options.mode ?? "dom");
|
|
8365
8379
|
}
|
|
8366
8380
|
/**
|
|
@@ -8425,7 +8439,8 @@ class RigPlayer {
|
|
|
8425
8439
|
const loop = options.loop ?? true;
|
|
8426
8440
|
const mix = options.mix ?? 0;
|
|
8427
8441
|
this.paused = false;
|
|
8428
|
-
if (
|
|
8442
|
+
if (track !== 0 || mix !== 0) this.beyondBase = true;
|
|
8443
|
+
if (this.tracks === null && track === 0 && mix === 0 && !this.trackMode) {
|
|
8429
8444
|
this.animation = name;
|
|
8430
8445
|
this.loop = loop;
|
|
8431
8446
|
this.track = openTrack(this.view, name, { loop, reset: "animation", adjust: this.adjustHook });
|
|
@@ -8449,6 +8464,7 @@ class RigPlayer {
|
|
|
8449
8464
|
*/
|
|
8450
8465
|
queue(name, options = {}) {
|
|
8451
8466
|
const track = options.track ?? 0;
|
|
8467
|
+
this.beyondBase = true;
|
|
8452
8468
|
const tracks = this.compose();
|
|
8453
8469
|
tracks.addAnimation(track, name, { loop: options.loop ?? true, mixDuration: options.mix ?? 0, delay: options.delay ?? 0 });
|
|
8454
8470
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8460,6 +8476,7 @@ class RigPlayer {
|
|
|
8460
8476
|
* setup pose. The pose the player holds is re-posed at once.
|
|
8461
8477
|
*/
|
|
8462
8478
|
clear(track = 0, options = {}) {
|
|
8479
|
+
this.beyondBase = true;
|
|
8463
8480
|
const tracks = this.compose();
|
|
8464
8481
|
tracks.setEmptyAnimation(track, options.mix ?? 0);
|
|
8465
8482
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8472,6 +8489,7 @@ class RigPlayer {
|
|
|
8472
8489
|
* its last `mix` seconds.
|
|
8473
8490
|
*/
|
|
8474
8491
|
queueClear(track = 0, options = {}) {
|
|
8492
|
+
this.beyondBase = true;
|
|
8475
8493
|
const tracks = this.compose();
|
|
8476
8494
|
tracks.addEmptyAnimation(track, options.mix ?? 0, options.delay ?? 0);
|
|
8477
8495
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8492,11 +8510,14 @@ class RigPlayer {
|
|
|
8492
8510
|
return this.tracks !== null;
|
|
8493
8511
|
}
|
|
8494
8512
|
/**
|
|
8495
|
-
* The live tracks, opened by the first composing call
|
|
8496
|
-
* play
|
|
8497
|
-
*
|
|
8498
|
-
*
|
|
8499
|
-
*
|
|
8513
|
+
* The live tracks, opened by the first composing call (or by the first
|
|
8514
|
+
* `play` under `tracks: true`). A single track in play is carried over by
|
|
8515
|
+
* replay: track 0 set to its animation, pose 0 taken by `start()` (the
|
|
8516
|
+
* player's — nothing steps before it) and the tracks stepped to the single
|
|
8517
|
+
* track's time in `seekStep` increments, so a physics rig's history
|
|
8518
|
+
* restarts there and nothing is fired on the way. The core offers no
|
|
8519
|
+
* hand-over of a live track's state, so that replay costs one pose per
|
|
8520
|
+
* `seekStep` of time played — which `tracks: true` avoids entirely.
|
|
8500
8521
|
*/
|
|
8501
8522
|
compose() {
|
|
8502
8523
|
if (this.tracks !== null) return this.tracks;
|
|
@@ -8533,12 +8554,20 @@ class RigPlayer {
|
|
|
8533
8554
|
seek(time) {
|
|
8534
8555
|
if (this.animation === null) throw new Error("seek before play: no animation is open");
|
|
8535
8556
|
if (!(time >= 0) || !Number.isFinite(time)) throw new Error(`seek time must be a finite time at or above 0, got ${String(time)}`);
|
|
8536
|
-
if (this.
|
|
8557
|
+
if (this.beyondBase) throw new Error("seek is defined for a single animation on track 0; after a mix, another track, a queue or a clear the player cannot replay to a time — step it forward with frame/advance instead");
|
|
8537
8558
|
this.reopen();
|
|
8538
8559
|
this.stepTo(time);
|
|
8539
8560
|
}
|
|
8540
|
-
/**
|
|
8561
|
+
/** Whatever is open, opened again with track 0's animation as `play` last set it, at pose 0: the single track, or the tracks under `tracks: true`. */
|
|
8541
8562
|
reopen() {
|
|
8563
|
+
if (this.tracks !== null) {
|
|
8564
|
+
const tracks = openTracks(this.view, { reset: "animation", adjust: this.adjustHook });
|
|
8565
|
+
tracks.setAnimation(0, this.animation, { loop: this.loop, mixDuration: 0 });
|
|
8566
|
+
this.trackCount = 1;
|
|
8567
|
+
this.tracks = tracks;
|
|
8568
|
+
this.pose = tracks.start();
|
|
8569
|
+
return;
|
|
8570
|
+
}
|
|
8542
8571
|
this.track = openTrack(this.view, this.animation, { loop: this.loop, reset: "animation", adjust: this.adjustHook });
|
|
8543
8572
|
this.pose = this.track.first;
|
|
8544
8573
|
}
|
|
@@ -8607,18 +8636,49 @@ class RigPlayer {
|
|
|
8607
8636
|
}
|
|
8608
8637
|
set skin(name) {
|
|
8609
8638
|
if (name === this.skinName) return;
|
|
8610
|
-
if (this.
|
|
8639
|
+
if (this.beyondBase) throw new Error("skin cannot change after a mix, another track, a queue or a clear: the player cannot replay those to the current time — set it before composing, or play again");
|
|
8611
8640
|
const view = name === void 0 ? underNoSkin(this.read.doc) : underSkin(this.read.doc, name);
|
|
8612
8641
|
this.view = view;
|
|
8613
8642
|
this.source = frameSource(view, this.read.parsed);
|
|
8614
8643
|
this.skinName = name;
|
|
8615
8644
|
this.setup = null;
|
|
8616
|
-
if (this.animation !== null && this.track !== null) {
|
|
8617
|
-
const time = this.
|
|
8645
|
+
if (this.animation !== null && (this.track !== null || this.tracks !== null)) {
|
|
8646
|
+
const time = this.time;
|
|
8618
8647
|
this.reopen();
|
|
8619
8648
|
this.stepTo(time);
|
|
8620
8649
|
}
|
|
8621
8650
|
}
|
|
8651
|
+
/**
|
|
8652
|
+
* Which slots this player draws (`SlotFilter`), or null for every slot.
|
|
8653
|
+
* Settable on a live player: the next `draw` shows it, and `bounds()` reads
|
|
8654
|
+
* the drawn slots. An allow list naming a slot the document does not have
|
|
8655
|
+
* is refused by name. The pose is the whole rig's: `bone()`, `adjust`, the
|
|
8656
|
+
* events and the tracks see no filter.
|
|
8657
|
+
*/
|
|
8658
|
+
get slots() {
|
|
8659
|
+
return this.slotFilter;
|
|
8660
|
+
}
|
|
8661
|
+
set slots(filter) {
|
|
8662
|
+
if (filter === null) {
|
|
8663
|
+
this.slotFilter = null;
|
|
8664
|
+
this.draws = () => true;
|
|
8665
|
+
return;
|
|
8666
|
+
}
|
|
8667
|
+
if (typeof filter === "function") {
|
|
8668
|
+
this.slotFilter = filter;
|
|
8669
|
+
this.draws = filter;
|
|
8670
|
+
return;
|
|
8671
|
+
}
|
|
8672
|
+
if (!Array.isArray(filter)) throw new Error(`slots must be an array of slot names, a function, or null, got ${typeof filter}`);
|
|
8673
|
+
const known = new Set(this.read.doc.slots.map((slot) => slot.name));
|
|
8674
|
+
const unknown = filter.filter((name) => !known.has(name));
|
|
8675
|
+
if (unknown.length > 0) {
|
|
8676
|
+
throw new Error(`no slot named ${unknown.map((n) => JSON.stringify(n)).join(", ")} in this document (slots: ${[...known].join(", ")})`);
|
|
8677
|
+
}
|
|
8678
|
+
const allowed = new Set(filter);
|
|
8679
|
+
this.slotFilter = [...filter];
|
|
8680
|
+
this.draws = (slot) => allowed.has(slot);
|
|
8681
|
+
}
|
|
8622
8682
|
/**
|
|
8623
8683
|
* The per-pose adjustment of bone locals (`BoneAdjust`), or null for none.
|
|
8624
8684
|
* It is applied by every track the player opens — `play`, the reopen inside
|
|
@@ -8684,7 +8744,7 @@ class RigPlayer {
|
|
|
8684
8744
|
* mode; nothing is computed until called.
|
|
8685
8745
|
*/
|
|
8686
8746
|
bounds() {
|
|
8687
|
-
const frame2 = this.pose === null ? frameOf(this.source, this.posed(), this.color) : this.posedFrame();
|
|
8747
|
+
const frame2 = this.pose === null ? frameOf(this.source, this.posed(), this.color, this.draws) : this.posedFrame();
|
|
8688
8748
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
8689
8749
|
for (const slot of frame2.order) {
|
|
8690
8750
|
const points = slot.kind === "region" ? slot.corners : slot.vertices;
|
|
@@ -8720,10 +8780,17 @@ class RigPlayer {
|
|
|
8720
8780
|
if (this.setup === null) this.setup = poseRawSetup(this.view);
|
|
8721
8781
|
return this.setup;
|
|
8722
8782
|
}
|
|
8723
|
-
/**
|
|
8724
|
-
|
|
8783
|
+
/**
|
|
8784
|
+
* The pose the player holds, as the frame record the renderer draws — under
|
|
8785
|
+
* this player's `slots` filter, or under `slots` given here instead (a
|
|
8786
|
+
* second renderer over the same assets drawing this player's pose on
|
|
8787
|
+
* another root: `other.render(player.posedFrame(['hand_f']))`, the one rig
|
|
8788
|
+
* posed once).
|
|
8789
|
+
*/
|
|
8790
|
+
posedFrame(slots) {
|
|
8725
8791
|
if (this.pose === null) return { order: [] };
|
|
8726
|
-
|
|
8792
|
+
const draws = slots === void 0 ? this.draws : slots === null ? () => true : typeof slots === "function" ? slots : predicateOf(slots);
|
|
8793
|
+
return frameOf(this.source, this.pose, this.color, draws);
|
|
8727
8794
|
}
|
|
8728
8795
|
/** Removes the renderer's elements and hands its GPU pages back. The assets stay the caller's. */
|
|
8729
8796
|
dispose() {
|