@driftengine/assets 4.5.0 → 4.6.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 +1 -1
- package/dist/drftLoader.d.ts +68 -4
- package/dist/drftLoader.js +194 -56
- package/dist/index.d.ts +1 -0
- package/dist/regionStore.d.ts +94 -0
- package/dist/regionStore.js +272 -0
- package/dist/repeats.js +1 -0
- package/dist/weld.js +6 -0
- package/package.json +4 -4
- package/src/drftLoader.ts +223 -57
- package/src/index.ts +1 -0
- package/src/regionStore.ts +333 -0
- package/src/repeats.ts +1 -0
- package/src/weld.ts +6 -0
package/src/drftLoader.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { MeshData } from '@driftengine/drft';
|
|
4
4
|
import type { MeshHandle, RendererApi } from '@driftengine/core';
|
|
5
5
|
import type { GlassOptions, SurfaceTextureHandle } from '@driftengine/core';
|
|
6
|
-
import { MeshBuilder, concatMeshes,
|
|
6
|
+
import { MeshBuilder, concatMeshes, placeMesh } from '@driftengine/core';
|
|
7
7
|
import type { DrftMaterial } from '@driftengine/drft';
|
|
8
8
|
import type { DrftSdfvEntry } from '@driftengine/drft';
|
|
9
9
|
import { placeFields } from './fieldPlacement.ts';
|
|
@@ -19,9 +19,13 @@ import {
|
|
|
19
19
|
CODEC_RAW,
|
|
20
20
|
CODEC_WEBP,
|
|
21
21
|
DrftError,
|
|
22
|
+
expandAssembly,
|
|
22
23
|
} from '@driftengine/drft';
|
|
23
24
|
import type { AnimationClip, DrftLight, DrftMorph, DrftNode, DrftSkin } from '@driftengine/drft';
|
|
25
|
+
import type { DrftLightVolume, EntsScene, NavPolyMesh } from '@driftengine/drft';
|
|
24
26
|
import type { DrftLoadProgress, DrftPart } from './loadProgress.ts';
|
|
27
|
+
import { RegionStore, fitCopies } from './regionStore.ts';
|
|
28
|
+
import type { LoadedRegion } from './regionStore.ts';
|
|
25
29
|
import {
|
|
26
30
|
DEFAULT_REVEAL_SEC,
|
|
27
31
|
DEFAULT_UPLOAD_MS_PER_FRAME,
|
|
@@ -178,6 +182,23 @@ export interface DrftLoaderOptions {
|
|
|
178
182
|
* of the file — which is why it is an option a caller weighs rather than a default.
|
|
179
183
|
*/
|
|
180
184
|
readonly texturePreview?: number;
|
|
185
|
+
/**
|
|
186
|
+
* Take each image as it decodes, by the name its `TEXS` chunk gives it, and upload none: for a
|
|
187
|
+
* consumer that builds its own textures — a world packing every picture into a layer of an
|
|
188
|
+
* array — where a surface texture of each as well would spend the memory twice. On the same
|
|
189
|
+
* frame clock as an upload, one a frame; `null` for an image that did not decode. Materials in
|
|
190
|
+
* the file that name an image then draw untextured, which is the consumer's to answer.
|
|
191
|
+
*/
|
|
192
|
+
readonly onImage?: (name: string, image: ImageBitmap | null) => void;
|
|
193
|
+
/**
|
|
194
|
+
* Offered each mesh no region holds as it arrives, by its ordinal in the file; return true to
|
|
195
|
+
* take it, and it is neither uploaded as a part nor merged. For a consumer that draws some of a
|
|
196
|
+
* file's meshes its own way — a crowd of kinds it instances and moves every frame — which a part
|
|
197
|
+
* cannot be, since the merge bakes a part into a static group by the image it wears. Counted as
|
|
198
|
+
* arrived, so a loading bar still finishes. What it gives up: the loader's upload budget and
|
|
199
|
+
* fade, which a taken mesh leaves to the consumer.
|
|
200
|
+
*/
|
|
201
|
+
readonly onMesh?: (mesh: MeshData, ordinal: number) => boolean;
|
|
181
202
|
}
|
|
182
203
|
|
|
183
204
|
/**
|
|
@@ -213,10 +234,20 @@ export class DrftLoader {
|
|
|
213
234
|
/** Arrived, not yet uploaded. Drained by `update` at the budget. */
|
|
214
235
|
private readonly queue: {
|
|
215
236
|
mesh: MeshData;
|
|
237
|
+
ordinal: number;
|
|
216
238
|
material: DrftMaterial | undefined;
|
|
217
239
|
/** Sixteen floats a copy when the file draws this mesh many times, else null. */
|
|
218
240
|
instances: Float32Array | null;
|
|
219
241
|
}[] = [];
|
|
242
|
+
/**
|
|
243
|
+
* Paged region meshes asked for and not yet up, drained after `queue` on the same clock: each is
|
|
244
|
+
* an expansion from the copies the file carried, then an upload.
|
|
245
|
+
*/
|
|
246
|
+
private pageQueue: {
|
|
247
|
+
ordinal: number;
|
|
248
|
+
material: DrftMaterial | undefined;
|
|
249
|
+
expand: () => MeshData;
|
|
250
|
+
}[] = [];
|
|
220
251
|
/** `INST`'s placements by mesh ordinal, in hand before the meshes they place arrive. */
|
|
221
252
|
private readonly loadedInstances = new Map<number, Float32Array>();
|
|
222
253
|
/**
|
|
@@ -305,6 +336,10 @@ export class DrftLoader {
|
|
|
305
336
|
*/
|
|
306
337
|
private loadedNodes: readonly DrftNode[] = [];
|
|
307
338
|
private loadedLights: readonly DrftLight[] = [];
|
|
339
|
+
private loadedColliders: readonly Float32Array[] = [];
|
|
340
|
+
private loadedNavigation: NavPolyMesh | null = null;
|
|
341
|
+
private loadedEntities: EntsScene | null = null;
|
|
342
|
+
private loadedLightVolume: DrftLightVolume | null = null;
|
|
308
343
|
private loadedFields: readonly DrftSdfvEntry[] = [];
|
|
309
344
|
/** The fields placed, built once the fit and the fields are both known. See `fields`. */
|
|
310
345
|
private placedFields: readonly DrftFieldPlacement[] | null = null;
|
|
@@ -337,10 +372,13 @@ export class DrftLoader {
|
|
|
337
372
|
private merged = false;
|
|
338
373
|
private disposed = false;
|
|
339
374
|
private arrived = 0;
|
|
375
|
+
/** A streamed world's regions, kept apart from the parts and never merged. See `regionStore.ts`. */
|
|
376
|
+
private readonly regionStore: RegionStore;
|
|
340
377
|
|
|
341
378
|
constructor(renderer: RendererApi, options: DrftLoaderOptions = {}) {
|
|
342
379
|
this.renderer = renderer;
|
|
343
380
|
this.options = options;
|
|
381
|
+
this.regionStore = new RegionStore(renderer, () => this.fit);
|
|
344
382
|
}
|
|
345
383
|
|
|
346
384
|
get progress(): DrftLoadProgress {
|
|
@@ -384,6 +422,97 @@ export class DrftLoader {
|
|
|
384
422
|
return this.loadedLights;
|
|
385
423
|
}
|
|
386
424
|
|
|
425
|
+
/**
|
|
426
|
+
* The convex hulls the asset collides as, in the file's own space and unfitted, or empty. Handed
|
|
427
|
+
* on for the caller to build shapes from, as `hullShape` takes them.
|
|
428
|
+
*/
|
|
429
|
+
get colliders(): readonly Float32Array[] {
|
|
430
|
+
return this.loadedColliders;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** The asset's navigation mesh, unfitted, or null for a file carrying no `NAVM`. */
|
|
434
|
+
get navigation(): NavPolyMesh | null {
|
|
435
|
+
return this.loadedNavigation;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* The asset's serialised entities, or null for a file carrying no `ENTS` — handed on as
|
|
440
|
+
* `deserializeWorld` takes them, because what an entity is belongs to the caller's schemas.
|
|
441
|
+
*/
|
|
442
|
+
get entities(): EntsScene | null {
|
|
443
|
+
return this.loadedEntities;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* A streamed world's regions by id, each filling as its meshes and props upload — `pending` is 0
|
|
448
|
+
* once one is whole. Their meshes are never among `parts`: a region's levels are alternatives,
|
|
449
|
+
* drawn one at a time through `HlodSet`, and its batches cull instance by instance.
|
|
450
|
+
*/
|
|
451
|
+
get regions(): ReadonlyMap<number, LoadedRegion> {
|
|
452
|
+
return this.regionStore.regions;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** One mesh to draw, from the stream or expanded from an assembly, queued for upload. */
|
|
456
|
+
private take(mesh: MeshData, ordinal: number): void {
|
|
457
|
+
if (this.disposed) return;
|
|
458
|
+
/* A region's own meshes are known by now: a region is written ahead of what it introduces. */
|
|
459
|
+
if (!this.regionStore.owns(ordinal) && this.options.onMesh?.(mesh, ordinal) === true) {
|
|
460
|
+
this.arrived++;
|
|
461
|
+
this.set({ phase: 'geometry', partsDone: this.arrived });
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const material = this.materials[ordinal];
|
|
465
|
+
/*
|
|
466
|
+
* Deltas onto the mesh they name, before it is queued for upload. The container writes a
|
|
467
|
+
* `MORP` immediately ahead of its `MESH` so this is in hand; a file that puts them the
|
|
468
|
+
* other way round still opens, and that mesh simply does not morph — a defined
|
|
469
|
+
* degradation rather than a wrong picture.
|
|
470
|
+
*/
|
|
471
|
+
const morph = this.loadedMorphs.find((entry) => entry.mesh === ordinal);
|
|
472
|
+
const withMorph =
|
|
473
|
+
morph === undefined
|
|
474
|
+
? mesh
|
|
475
|
+
: { ...mesh, morphTargets: morph.deltas, morphTargetCount: morph.targetCount };
|
|
476
|
+
this.queue.push({
|
|
477
|
+
mesh: withMorph,
|
|
478
|
+
ordinal,
|
|
479
|
+
material,
|
|
480
|
+
instances: this.loadedInstances.get(ordinal) ?? null,
|
|
481
|
+
});
|
|
482
|
+
this.arrived++;
|
|
483
|
+
this.set({ phase: 'geometry', partsDone: this.arrived });
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Bring a region's paged level up, or free it. A level that arrived as assemblies (`paged`) is
|
|
488
|
+
* held as the copies the file carried; asked for, each mesh is expanded and uploaded on the
|
|
489
|
+
* loader's clocked queue in later `update`s, and `resident` turns true when the last is up. Freed,
|
|
490
|
+
* its meshes go and the copies stay. A level that is not paged ignores this.
|
|
491
|
+
*
|
|
492
|
+
* The caller decides from what it will draw: page in the levels `HlodSet` is choosing or about
|
|
493
|
+
* to, draw a coarser one until the fine one is resident, and page out what the eye has left.
|
|
494
|
+
*/
|
|
495
|
+
pageRegion(id: number, level: number, resident: boolean): void {
|
|
496
|
+
const changes = this.regionStore.page(id, level, resident);
|
|
497
|
+
if (resident) {
|
|
498
|
+
for (const { ordinal, expand } of changes) {
|
|
499
|
+
this.pageQueue.push({ ordinal, material: this.materials[ordinal], expand });
|
|
500
|
+
}
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (changes.length === 0) return;
|
|
504
|
+
const released = new Set(changes.map((c) => c.ordinal));
|
|
505
|
+
this.pageQueue = this.pageQueue.filter((item) => !released.has(item.ordinal));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* A world's summed lights, unfitted, or null until `LVOL` lands and for a file carrying none.
|
|
510
|
+
* Handed straight to `createWorldLightField`, whose volume it is shaped as.
|
|
511
|
+
*/
|
|
512
|
+
get lightVolume(): DrftLightVolume | null {
|
|
513
|
+
return this.loadedLightVolume;
|
|
514
|
+
}
|
|
515
|
+
|
|
387
516
|
/**
|
|
388
517
|
* The distance fields the file carries, each where it stands: at the loader's fit, and once a
|
|
389
518
|
* copy for a mesh drawn many times. Empty until the fields and the fit have both arrived, and for
|
|
@@ -563,6 +692,15 @@ export class DrftLoader {
|
|
|
563
692
|
onLights: (lights) => {
|
|
564
693
|
this.loadedLights = lights;
|
|
565
694
|
},
|
|
695
|
+
onColliders: (hulls) => {
|
|
696
|
+
this.loadedColliders = hulls;
|
|
697
|
+
},
|
|
698
|
+
onNavigation: (navigation) => {
|
|
699
|
+
this.loadedNavigation = navigation;
|
|
700
|
+
},
|
|
701
|
+
onEntities: (entities) => {
|
|
702
|
+
this.loadedEntities = entities;
|
|
703
|
+
},
|
|
566
704
|
onFields: (fields) => {
|
|
567
705
|
this.loadedFields = fields;
|
|
568
706
|
this.placedFields = null;
|
|
@@ -570,6 +708,13 @@ export class DrftLoader {
|
|
|
570
708
|
onInstances: (groups) => {
|
|
571
709
|
for (const group of groups) this.loadedInstances.set(group.mesh, group.transforms);
|
|
572
710
|
},
|
|
711
|
+
onLightVolume: (volume) => {
|
|
712
|
+
this.loadedLightVolume = volume;
|
|
713
|
+
},
|
|
714
|
+
onRegion: (region) => {
|
|
715
|
+
if (this.disposed) return;
|
|
716
|
+
this.regionStore.admit(region);
|
|
717
|
+
},
|
|
573
718
|
onSkin: (skin) => {
|
|
574
719
|
this.loadedSkins.push(skin);
|
|
575
720
|
},
|
|
@@ -638,27 +783,22 @@ export class DrftLoader {
|
|
|
638
783
|
this.set({ phase: 'materials' });
|
|
639
784
|
},
|
|
640
785
|
|
|
641
|
-
|
|
786
|
+
onKit: (pieces) => {
|
|
787
|
+
/* A piece is drawn only as copies: it is not a part, and the count said it was. */
|
|
788
|
+
this.set({ partsTotal: Math.max(0, this.state.partsTotal - pieces.length) });
|
|
789
|
+
},
|
|
790
|
+
onAssembly: (assembly, ordinal, piece) => {
|
|
642
791
|
if (this.disposed) return;
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
? mesh
|
|
654
|
-
: { ...mesh, morphTargets: morph.deltas, morphTargetCount: morph.targetCount };
|
|
655
|
-
this.queue.push({
|
|
656
|
-
mesh: withMorph,
|
|
657
|
-
material,
|
|
658
|
-
instances: this.loadedInstances.get(ordinal) ?? null,
|
|
659
|
-
});
|
|
660
|
-
this.arrived++;
|
|
661
|
-
this.set({ phase: 'geometry', partsDone: this.arrived });
|
|
792
|
+
if (this.regionStore.isLevelMesh(ordinal)) {
|
|
793
|
+
this.regionStore.hold(ordinal, assembly, piece);
|
|
794
|
+
this.arrived++;
|
|
795
|
+
this.set({ phase: 'geometry', partsDone: this.arrived });
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
this.take(expandAssembly(assembly, piece), ordinal);
|
|
799
|
+
},
|
|
800
|
+
onMesh: (mesh, ordinal) => {
|
|
801
|
+
this.take(mesh, ordinal);
|
|
662
802
|
},
|
|
663
803
|
|
|
664
804
|
onTexture: (texture, ordinal) => {
|
|
@@ -794,7 +934,27 @@ export class DrftLoader {
|
|
|
794
934
|
) {
|
|
795
935
|
const next = this.queue.shift();
|
|
796
936
|
if (next === undefined) break;
|
|
797
|
-
if (this.uploadOne(next.mesh, next.material, next.instances)) changed = true;
|
|
937
|
+
if (this.uploadOne(next.mesh, next.material, next.instances, next.ordinal)) changed = true;
|
|
938
|
+
begun++;
|
|
939
|
+
}
|
|
940
|
+
/* Paged region meshes, after the stream's own: an expansion from the copies, then an upload. */
|
|
941
|
+
while (
|
|
942
|
+
this.pageQueue.length > 0 &&
|
|
943
|
+
mayBeginMore(begun, performance.now() - startedMs, msBudget)
|
|
944
|
+
) {
|
|
945
|
+
const next = this.pageQueue.shift();
|
|
946
|
+
if (next === undefined) break;
|
|
947
|
+
if (this.uploadOne(next.expand(), next.material, null, next.ordinal)) changed = true;
|
|
948
|
+
begun++;
|
|
949
|
+
}
|
|
950
|
+
/* A region's prop batches, on the same clock: each is an allocation and an upload. Drained
|
|
951
|
+
before the merge below can begin, which is what lets `ready` not wait on them separately. */
|
|
952
|
+
while (
|
|
953
|
+
this.regionStore.busy &&
|
|
954
|
+
mayBeginMore(begun, performance.now() - startedMs, msBudget) &&
|
|
955
|
+
this.regionStore.buildNext()
|
|
956
|
+
) {
|
|
957
|
+
changed = true;
|
|
798
958
|
begun++;
|
|
799
959
|
}
|
|
800
960
|
|
|
@@ -807,7 +967,9 @@ export class DrftLoader {
|
|
|
807
967
|
) {
|
|
808
968
|
const ordinal = this.imageQueue.shift();
|
|
809
969
|
if (ordinal !== undefined) {
|
|
810
|
-
this.
|
|
970
|
+
const take = this.options.onImage;
|
|
971
|
+
if (take === undefined) this.rebuildTextures(ordinal);
|
|
972
|
+
else take(this.chunks[ordinal]?.name ?? '', this.images[ordinal] ?? null);
|
|
811
973
|
/*
|
|
812
974
|
* Counted here, once, and only for the image itself.
|
|
813
975
|
*
|
|
@@ -884,6 +1046,7 @@ export class DrftLoader {
|
|
|
884
1046
|
dispose(): void {
|
|
885
1047
|
if (this.disposed) return;
|
|
886
1048
|
this.disposed = true;
|
|
1049
|
+
this.regionStore.dispose();
|
|
887
1050
|
/*
|
|
888
1051
|
* Everything this class ever made, each disposed once.
|
|
889
1052
|
*
|
|
@@ -986,6 +1149,7 @@ export class DrftLoader {
|
|
|
986
1149
|
mesh: MeshData,
|
|
987
1150
|
material: DrftMaterial | undefined,
|
|
988
1151
|
instances: Float32Array | null,
|
|
1152
|
+
ordinal: number,
|
|
989
1153
|
): boolean {
|
|
990
1154
|
const fit = this.fit;
|
|
991
1155
|
if (fit === null) return false;
|
|
@@ -1018,6 +1182,37 @@ export class DrftLoader {
|
|
|
1018
1182
|
doubleSided,
|
|
1019
1183
|
} = g;
|
|
1020
1184
|
|
|
1185
|
+
/*
|
|
1186
|
+
* A region's mesh — a level or a prop's prototype — is one part of its own, never grouped: the
|
|
1187
|
+
* merge would weld a region's levels together and one region to the next. See `regionStore.ts`.
|
|
1188
|
+
*/
|
|
1189
|
+
if (this.regionStore.owns(ordinal)) {
|
|
1190
|
+
try {
|
|
1191
|
+
this.regionStore.arrived(ordinal, {
|
|
1192
|
+
mesh: this.renderer.createMesh(placed),
|
|
1193
|
+
albedo,
|
|
1194
|
+
orm,
|
|
1195
|
+
normal,
|
|
1196
|
+
emissive,
|
|
1197
|
+
opacity,
|
|
1198
|
+
reflectivity,
|
|
1199
|
+
roughnessScale,
|
|
1200
|
+
metallicScale,
|
|
1201
|
+
occlusionStrength,
|
|
1202
|
+
cutout,
|
|
1203
|
+
blend,
|
|
1204
|
+
doubleSided,
|
|
1205
|
+
glass: glassOf(g),
|
|
1206
|
+
reveal: 1,
|
|
1207
|
+
instances: null,
|
|
1208
|
+
});
|
|
1209
|
+
return true;
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
console.warn(`DrftLoader: region mesh ${ordinal} would not upload and was skipped`, error);
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1021
1216
|
/*
|
|
1022
1217
|
* Added to its merged group here, while there is a budget governing how much of this happens
|
|
1023
1218
|
* in one frame.
|
|
@@ -1123,10 +1318,9 @@ export class DrftLoader {
|
|
|
1123
1318
|
/**
|
|
1124
1319
|
* A mesh the file draws many times: uploaded once, placed by a batch, and kept out of the merge.
|
|
1125
1320
|
*
|
|
1126
|
-
* **The fit is conjugated into each placement
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
* model's copies then land where its geometry does, and are not scaled twice.
|
|
1321
|
+
* **The fit is conjugated into each placement** by `fitCopies`, which a region's props share: the
|
|
1322
|
+
* prototype is uploaded with the fit already applied, so the copies land where its geometry does
|
|
1323
|
+
* and are not scaled twice.
|
|
1130
1324
|
*/
|
|
1131
1325
|
private uploadInstanced(
|
|
1132
1326
|
prototype: MeshData,
|
|
@@ -1136,36 +1330,8 @@ export class DrftLoader {
|
|
|
1136
1330
|
): boolean {
|
|
1137
1331
|
try {
|
|
1138
1332
|
const uploaded = this.renderer.createMesh(prototype);
|
|
1139
|
-
const
|
|
1140
|
-
const batch = this.renderer.createInstanced(uploaded, count);
|
|
1141
|
-
const data = createMeshInstances(count);
|
|
1142
|
-
const s = fit.scale;
|
|
1143
|
-
for (let k = 0; k < count; k++) {
|
|
1144
|
-
const at = k * 16;
|
|
1145
|
-
for (let i = 0; i < 12; i++) data.models[at + i] = instances[at + i] as number;
|
|
1146
|
-
const ux = instances[at + 12] as number;
|
|
1147
|
-
const uy = instances[at + 13] as number;
|
|
1148
|
-
const uz = instances[at + 14] as number;
|
|
1149
|
-
/* R·t, with R the copy's own 3×3 read column-major. */
|
|
1150
|
-
const rtx =
|
|
1151
|
-
(instances[at] as number) * fit.x +
|
|
1152
|
-
(instances[at + 4] as number) * fit.y +
|
|
1153
|
-
(instances[at + 8] as number) * fit.z;
|
|
1154
|
-
const rty =
|
|
1155
|
-
(instances[at + 1] as number) * fit.x +
|
|
1156
|
-
(instances[at + 5] as number) * fit.y +
|
|
1157
|
-
(instances[at + 9] as number) * fit.z;
|
|
1158
|
-
const rtz =
|
|
1159
|
-
(instances[at + 2] as number) * fit.x +
|
|
1160
|
-
(instances[at + 6] as number) * fit.y +
|
|
1161
|
-
(instances[at + 10] as number) * fit.z;
|
|
1162
|
-
data.models[at + 12] = fit.x - rtx + s * ux;
|
|
1163
|
-
data.models[at + 13] = fit.y - rty + s * uy;
|
|
1164
|
-
data.models[at + 14] = fit.z - rtz + s * uz;
|
|
1165
|
-
data.models[at + 15] = 1;
|
|
1166
|
-
}
|
|
1167
|
-
data.tints.fill(1);
|
|
1168
|
-
data.count = count;
|
|
1333
|
+
const data = fitCopies(instances, fit);
|
|
1334
|
+
const batch = this.renderer.createInstanced(uploaded, data.count);
|
|
1169
1335
|
this.renderer.uploadInstanced(batch, data);
|
|
1170
1336
|
const part: DrftPart = { mesh: uploaded, ...surface, reveal: 0, instances: { batch, data } };
|
|
1171
1337
|
this.revealed.push(part);
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type { DrftFit, DrftLoaderOptions } from './drftLoader.ts';
|
|
|
33
33
|
export { drawKeyOf, resolveDrawGrouping } from './drawKey.ts';
|
|
34
34
|
export type { DrawGrouping, DrawSurfaceOverride } from './drawKey.ts';
|
|
35
35
|
export type { DrftLoadPhase, DrftLoadProgress, DrftPart } from './loadProgress.ts';
|
|
36
|
+
export type { LoadedRegion, LoadedRegionLevel } from './regionStore.ts';
|
|
36
37
|
export type { DrftFieldPlacement } from './fieldPlacement.ts';
|
|
37
38
|
/* Addressing a texture by name, so a consumer never holds an ordinal. */
|
|
38
39
|
export { TextureSet, textureColorSpaces } from './drftTextures.ts';
|