minidraco 0.5.0 → 0.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 +15 -21
- package/dist/index.d.ts +23 -56
- package/dist/index.js +2280 -3973
- package/dist/pool.js +154 -0
- package/dist/three.d.ts +57 -77
- package/dist/three.js +2342 -4156
- package/dist/worker.js +2259 -3949
- package/package.json +1 -1
package/dist/pool.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/three/pool.ts
|
|
2
|
+
var decodeError = (message) => {
|
|
3
|
+
const error = new Error(message);
|
|
4
|
+
error.isDecodeError = true;
|
|
5
|
+
return error;
|
|
6
|
+
};
|
|
7
|
+
var WorkerPool = class {
|
|
8
|
+
// Pool size; the loader keeps it in sync with setWorkerLimit().
|
|
9
|
+
limit;
|
|
10
|
+
Ha;
|
|
11
|
+
D = [];
|
|
12
|
+
Gc = 0;
|
|
13
|
+
_ = /* @__PURE__ */ new Map();
|
|
14
|
+
// Tasks queued during the current microtask; flushed as one batched message
|
|
15
|
+
// per worker (a 488-primitive scene costs 4 postMessages, not 488).
|
|
16
|
+
Ia = [];
|
|
17
|
+
Za = false;
|
|
18
|
+
// Set when spawning a worker fails (bundler without module-worker support,
|
|
19
|
+
// file:// pages, …) or a worker errors: the loader then decodes on the main
|
|
20
|
+
// thread.
|
|
21
|
+
broken = false;
|
|
22
|
+
// Same-origin blob bootstrap used when the worker asset lives on a CDN
|
|
23
|
+
// origin (created lazily, revoked on dispose).
|
|
24
|
+
pa = null;
|
|
25
|
+
constructor(limit, workerUrl) {
|
|
26
|
+
this.limit = limit;
|
|
27
|
+
this.Ha = workerUrl;
|
|
28
|
+
}
|
|
29
|
+
// Spawns the whole pool up front: each fresh worker runs a short JIT warmup
|
|
30
|
+
// at startup (see worker.ts), so spawning early lets that overlap the model
|
|
31
|
+
// download instead of the first decode burst.
|
|
32
|
+
spawnAll() {
|
|
33
|
+
while (this.D.length < this.limit && this.cc() !== null) {
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
dispose() {
|
|
37
|
+
for (const entry of this.D) entry.worker.terminate();
|
|
38
|
+
this.D = [];
|
|
39
|
+
const error = decodeError("MinidracoLoader: disposed while decoding");
|
|
40
|
+
for (const task of this.Ia) task.reject(error);
|
|
41
|
+
this.Ia = [];
|
|
42
|
+
this.Za = false;
|
|
43
|
+
for (const [, task] of this._) task.reject(error);
|
|
44
|
+
this._.clear();
|
|
45
|
+
if (this.pa !== null) {
|
|
46
|
+
URL.revokeObjectURL(this.pa);
|
|
47
|
+
this.pa = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
decode(buffer, taskConfig) {
|
|
51
|
+
const id = this.Gc++;
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
this.Ia.push({ id, buffer, taskConfig, resolve, reject });
|
|
54
|
+
if (!this.Za) {
|
|
55
|
+
this.Za = true;
|
|
56
|
+
queueMicrotask(() => this.Hc());
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
cc() {
|
|
61
|
+
if (this.broken) return null;
|
|
62
|
+
if (this.D.length < this.limit) {
|
|
63
|
+
const workerUrl = this.Ha ?? new URL("./worker.js", import.meta.url);
|
|
64
|
+
let worker;
|
|
65
|
+
try {
|
|
66
|
+
worker = new Worker(workerUrl, { type: "module" });
|
|
67
|
+
} catch {
|
|
68
|
+
try {
|
|
69
|
+
if (this.pa === null) {
|
|
70
|
+
const bootstrap = `import ${JSON.stringify(String(workerUrl))};`;
|
|
71
|
+
this.pa = URL.createObjectURL(new Blob([bootstrap], { type: "text/javascript" }));
|
|
72
|
+
}
|
|
73
|
+
worker = new Worker(this.pa, { type: "module" });
|
|
74
|
+
} catch {
|
|
75
|
+
this.broken = true;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const entry = { worker, pending: 0 };
|
|
80
|
+
worker.onmessage = (event) => {
|
|
81
|
+
for (const { id, ok, indices, attributes, error } of event.data.results) {
|
|
82
|
+
const task = this._.get(id);
|
|
83
|
+
if (!task) continue;
|
|
84
|
+
this._.delete(id);
|
|
85
|
+
task.entry.pending--;
|
|
86
|
+
if (ok) {
|
|
87
|
+
task.resolve({ indices, attributes });
|
|
88
|
+
} else {
|
|
89
|
+
task.reject(decodeError(error));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
worker.onerror = (event) => {
|
|
94
|
+
this.broken = true;
|
|
95
|
+
for (const [id, task] of this._) {
|
|
96
|
+
if (task.entry.worker === worker) {
|
|
97
|
+
this._.delete(id);
|
|
98
|
+
task.reject(new Error(`MinidracoLoader worker failed: ${event.message ?? "unknown error"}`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
this.D.push(entry);
|
|
103
|
+
return entry;
|
|
104
|
+
}
|
|
105
|
+
let best = this.D[0];
|
|
106
|
+
for (const entry of this.D) if (entry.pending < best.pending) best = entry;
|
|
107
|
+
return best;
|
|
108
|
+
}
|
|
109
|
+
Hc() {
|
|
110
|
+
this.Za = false;
|
|
111
|
+
const batch = this.Ia;
|
|
112
|
+
if (batch.length === 0) return;
|
|
113
|
+
this.Ia = [];
|
|
114
|
+
while (this.D.length < Math.min(this.limit, batch.length) && this.cc() !== null) {
|
|
115
|
+
}
|
|
116
|
+
if (this.broken || this.D.length === 0) {
|
|
117
|
+
const error = new Error("MinidracoLoader: worker unavailable");
|
|
118
|
+
for (const task of batch) task.reject(error);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
batch.sort((a, b) => b.buffer.byteLength - a.buffer.byteLength);
|
|
122
|
+
let totalBytes = 0;
|
|
123
|
+
for (const task of batch) totalBytes += task.buffer.byteLength;
|
|
124
|
+
const averageBytes = totalBytes / batch.length;
|
|
125
|
+
const buckets = this.D.map((entry) => ({
|
|
126
|
+
entry,
|
|
127
|
+
tasks: [],
|
|
128
|
+
bytes: entry.pending * averageBytes
|
|
129
|
+
}));
|
|
130
|
+
for (const task of batch) {
|
|
131
|
+
let best = buckets[0];
|
|
132
|
+
for (const bucket of buckets) if (bucket.bytes < best.bytes) best = bucket;
|
|
133
|
+
best.tasks.push(task);
|
|
134
|
+
best.bytes += task.buffer.byteLength;
|
|
135
|
+
}
|
|
136
|
+
for (const { entry, tasks } of buckets) {
|
|
137
|
+
if (tasks.length === 0) continue;
|
|
138
|
+
entry.pending += tasks.length;
|
|
139
|
+
for (const task of tasks) this._.set(task.id, { resolve: task.resolve, reject: task.reject, entry });
|
|
140
|
+
entry.worker.postMessage({
|
|
141
|
+
tasks: tasks.map((task) => ({
|
|
142
|
+
id: task.id,
|
|
143
|
+
buffer: task.buffer,
|
|
144
|
+
attributeIDs: task.taskConfig.attributeIDs,
|
|
145
|
+
attributeTypes: task.taskConfig.attributeTypes,
|
|
146
|
+
useUniqueIDs: task.taskConfig.useUniqueIDs
|
|
147
|
+
}))
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
export {
|
|
153
|
+
WorkerPool
|
|
154
|
+
};
|
package/dist/three.d.ts
CHANGED
|
@@ -2,13 +2,9 @@ import { Loader, BufferGeometry, LoadingManager, BufferAttribute } from 'three';
|
|
|
2
2
|
|
|
3
3
|
declare class DataBuffer {
|
|
4
4
|
_data: Uint8Array;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
resize(newSize: number): void;
|
|
8
|
-
adoptScratch(size: number): void;
|
|
9
|
-
write(bytePos: number, inArray: Uint8Array | ArrayBufferView | ArrayBuffer, dataSize: number): void;
|
|
5
|
+
update(data: Uint8Array | null, size: number): void;
|
|
6
|
+
write(bytePos: number, inArray: Uint8Array, dataSize: number): void;
|
|
10
7
|
get data(): Uint8Array;
|
|
11
|
-
get dataSize(): number;
|
|
12
8
|
_resize(newSize: number): void;
|
|
13
9
|
}
|
|
14
10
|
|
|
@@ -21,10 +17,7 @@ declare class GeometryAttribute {
|
|
|
21
17
|
_byteOffset: number;
|
|
22
18
|
_attributeType: number;
|
|
23
19
|
_uniqueId: number;
|
|
24
|
-
constructor();
|
|
25
20
|
init(attributeType: number, buffer: DataBuffer | null, numComponents: number, dataType: number, normalized: boolean, byteStride: number, byteOffset: number): void;
|
|
26
|
-
getAddress(attIndex: number): Uint8Array;
|
|
27
|
-
copyFrom(srcAtt: GeometryAttribute): boolean;
|
|
28
21
|
resetBuffer(buffer: DataBuffer, byteStride: number, byteOffset: number): void;
|
|
29
22
|
get attributeType(): number;
|
|
30
23
|
get dataType(): number;
|
|
@@ -36,72 +29,52 @@ declare class GeometryAttribute {
|
|
|
36
29
|
set uniqueId(id: number);
|
|
37
30
|
}
|
|
38
31
|
|
|
39
|
-
declare class AttributeTransformData {
|
|
40
|
-
_transformType: number;
|
|
41
|
-
_bytes: Uint8Array;
|
|
42
|
-
_view: DataView;
|
|
43
|
-
_size: number;
|
|
44
|
-
constructor();
|
|
45
|
-
get transformType(): number;
|
|
46
|
-
set transformType(type: number);
|
|
47
|
-
get dataSize(): number;
|
|
48
|
-
get data(): Uint8Array;
|
|
49
|
-
_reserve(sizeNeeded: number): void;
|
|
50
|
-
setParameterValue(byteOffset: number, value: number, type: string): void;
|
|
51
|
-
appendParameterValue(value: number, type: string): void;
|
|
52
|
-
_typeSize(type: string): number;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
32
|
type ExtractTypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
|
|
33
|
+
type ViewCtor = (new (buffer: ArrayBufferLike) => ExtractTypedArray) & {
|
|
34
|
+
BYTES_PER_ELEMENT: number;
|
|
35
|
+
};
|
|
56
36
|
declare class PointAttribute extends GeometryAttribute {
|
|
57
37
|
_identityMapping: boolean;
|
|
58
38
|
_numUniqueEntries: number;
|
|
59
39
|
_indicesMap: number[] | Uint32Array;
|
|
60
40
|
_attributeBuffer: DataBuffer | null;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
_cachedUint16View?: Uint16Array;
|
|
69
|
-
_cachedUint16Buffer?: ArrayBufferLike;
|
|
70
|
-
_cachedInt16View?: Int16Array;
|
|
71
|
-
_cachedInt16Buffer?: ArrayBufferLike;
|
|
72
|
-
_cachedUint8View?: Uint8Array;
|
|
73
|
-
_cachedUint8Buffer?: ArrayBufferLike;
|
|
74
|
-
_cachedInt8View?: Int8Array;
|
|
75
|
-
_cachedInt8Buffer?: ArrayBufferLike;
|
|
76
|
-
_cachedFloat64View?: Float64Array;
|
|
77
|
-
_cachedFloat64Buffer?: ArrayBufferLike;
|
|
78
|
-
_cachedDataView?: DataView;
|
|
79
|
-
_cachedDVBuffer?: ArrayBufferLike;
|
|
41
|
+
_cachedViewCtor: ViewCtor | null;
|
|
42
|
+
_cachedViewBuffer: ArrayBufferLike | null;
|
|
43
|
+
_cachedView: ExtractTypedArray | null;
|
|
44
|
+
_lazyKind: number;
|
|
45
|
+
_lazyValues: Int32Array | null;
|
|
46
|
+
_lazyMin: number[];
|
|
47
|
+
_lazyScale: number;
|
|
80
48
|
constructor(geometryAttribute?: GeometryAttribute);
|
|
81
49
|
init(attributeType: number, numComponents: number, dataType: number, normalized: boolean, numAttributeValues: number): void;
|
|
82
50
|
reset(numAttributeValues: number): boolean;
|
|
83
|
-
|
|
51
|
+
resetLazy(numAttributeValues: number): void;
|
|
52
|
+
setLazyInteger(values: Int32Array | null): void;
|
|
53
|
+
setLazyQuantized(values: Int32Array | null, minValues: number[], delta: number): void;
|
|
54
|
+
setLazyOctahedron(values: Int32Array | null, scale: number): void;
|
|
84
55
|
get size(): number;
|
|
85
56
|
mappedIndex(pointIndex: number): number;
|
|
86
57
|
get isMappingIdentity(): boolean;
|
|
87
58
|
get indicesMapSize(): number;
|
|
88
59
|
get indicesMap(): number[] | Uint32Array;
|
|
89
60
|
setIdentityMapping(): void;
|
|
90
|
-
setExplicitMapping(numPoints: number): void;
|
|
91
61
|
setExplicitMappingUnfilled(numPoints: number): void;
|
|
92
62
|
setExplicitMappingShared(map: Uint32Array): void;
|
|
93
63
|
setExplicitMappingScratch(numPoints: number): void;
|
|
94
|
-
|
|
64
|
+
_view(Ctor: ViewCtor, bufData: Uint8Array): ExtractTypedArray;
|
|
95
65
|
convertValue(attIndex: number, outVal: number[] | Int32Array | Uint32Array | Float32Array | Float64Array): void;
|
|
96
66
|
extractTo<C extends new (length: number) => ExtractTypedArray>(OutputTypedArray: C, numPoints: number): InstanceType<C>;
|
|
97
|
-
|
|
67
|
+
_lazyMap(numPoints: number): Uint32Array;
|
|
68
|
+
_lazyFloatValues(): Int32Array;
|
|
69
|
+
_extractQuantized(out: ExtractTypedArray, numPoints: number): void;
|
|
70
|
+
_extractOctahedron(out: ExtractTypedArray, numPoints: number): void;
|
|
71
|
+
_extractInteger(out: ExtractTypedArray, numPoints: number): void;
|
|
98
72
|
}
|
|
99
73
|
|
|
100
74
|
declare class PointCloud {
|
|
101
75
|
num_points_: number;
|
|
102
76
|
attributes_: (PointAttribute | null)[];
|
|
103
77
|
named_attribute_index_: number[][];
|
|
104
|
-
constructor();
|
|
105
78
|
numNamedAttributes(type: number): number;
|
|
106
79
|
getNamedAttributeId(type: number, i?: number): number;
|
|
107
80
|
getNamedAttribute(type: number, i?: number): PointAttribute | null;
|
|
@@ -116,26 +89,12 @@ declare class PointCloud {
|
|
|
116
89
|
}
|
|
117
90
|
|
|
118
91
|
declare class Mesh extends PointCloud {
|
|
119
|
-
faces_: Int32Array
|
|
92
|
+
faces_: Int32Array<ArrayBuffer>;
|
|
120
93
|
numFaces_: number;
|
|
121
|
-
attribute_data_: {
|
|
122
|
-
elementType: number;
|
|
123
|
-
}[];
|
|
124
|
-
constructor();
|
|
125
94
|
setNumFaces(numFaces: number): void;
|
|
126
95
|
numFaces(): number;
|
|
127
|
-
face(faceId: number): number[];
|
|
128
|
-
setAttribute(attId: number, pa: PointAttribute): void;
|
|
129
96
|
}
|
|
130
97
|
|
|
131
|
-
type AttributeIDs = Record<string, number | string>;
|
|
132
|
-
type AttributeTypes = Record<string, string>;
|
|
133
|
-
interface MinidracoLoaderOptions {
|
|
134
|
-
manager?: LoadingManager;
|
|
135
|
-
workers?: boolean;
|
|
136
|
-
workerLimit?: number;
|
|
137
|
-
mainThreadByteThreshold?: number;
|
|
138
|
-
}
|
|
139
98
|
interface TaskConfig {
|
|
140
99
|
attributeIDs: AttributeIDs;
|
|
141
100
|
attributeTypes: AttributeTypes;
|
|
@@ -162,23 +121,46 @@ interface QueuedTask {
|
|
|
162
121
|
resolve: (raw: RawGeometry) => void;
|
|
163
122
|
reject: (error: unknown) => void;
|
|
164
123
|
}
|
|
124
|
+
interface PendingTask {
|
|
125
|
+
resolve: (raw: RawGeometry) => void;
|
|
126
|
+
reject: (error: unknown) => void;
|
|
127
|
+
entry: WorkerEntry;
|
|
128
|
+
}
|
|
129
|
+
declare class WorkerPool {
|
|
130
|
+
limit: number;
|
|
131
|
+
_workerUrl: string | URL | null;
|
|
132
|
+
_workers: WorkerEntry[];
|
|
133
|
+
_taskId: number;
|
|
134
|
+
_tasks: Map<number, PendingTask>;
|
|
135
|
+
_batch: QueuedTask[];
|
|
136
|
+
_batchScheduled: boolean;
|
|
137
|
+
broken: boolean;
|
|
138
|
+
_blobUrl: string | null;
|
|
139
|
+
constructor(limit: number, workerUrl: string | URL | null);
|
|
140
|
+
spawnAll(): void;
|
|
141
|
+
dispose(): void;
|
|
142
|
+
decode(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<RawGeometry>;
|
|
143
|
+
_getWorker(): WorkerEntry | null;
|
|
144
|
+
_flushBatch(): void;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
type AttributeIDs = Record<string, number | string>;
|
|
148
|
+
type AttributeTypes = Record<string, string>;
|
|
149
|
+
interface MinidracoLoaderOptions {
|
|
150
|
+
manager?: LoadingManager;
|
|
151
|
+
workers?: boolean;
|
|
152
|
+
workerLimit?: number;
|
|
153
|
+
mainThreadByteThreshold?: number;
|
|
154
|
+
}
|
|
165
155
|
declare class MinidracoLoader extends Loader<BufferGeometry> {
|
|
166
156
|
defaultAttributeIDs: AttributeIDs;
|
|
167
157
|
defaultAttributeTypes: AttributeTypes;
|
|
168
158
|
workerLimit: number;
|
|
169
159
|
mainThreadByteThreshold: number;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
_tasks: Map<number, {
|
|
173
|
-
resolve: (raw: RawGeometry) => void;
|
|
174
|
-
reject: (error: unknown) => void;
|
|
175
|
-
entry: WorkerEntry;
|
|
176
|
-
}>;
|
|
177
|
-
_batch: QueuedTask[];
|
|
178
|
-
_batchScheduled: boolean;
|
|
160
|
+
_pool: WorkerPool | null;
|
|
161
|
+
_poolPromise: Promise<WorkerPool | null> | null;
|
|
179
162
|
_workersBroken: boolean;
|
|
180
163
|
_workerUrl: string | URL | null;
|
|
181
|
-
_workerBlobUrl: string | null;
|
|
182
164
|
constructor(managerOrOptions?: LoadingManager | MinidracoLoaderOptions);
|
|
183
165
|
setWorkerUrl(url: string | URL | null): this;
|
|
184
166
|
setDecoderPath(_path?: unknown): this;
|
|
@@ -193,9 +175,7 @@ declare class MinidracoLoader extends Loader<BufferGeometry> {
|
|
|
193
175
|
decodeGeometry(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<BufferGeometry>;
|
|
194
176
|
_runTask(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<BufferGeometry>;
|
|
195
177
|
_workersAvailable(): boolean;
|
|
196
|
-
|
|
197
|
-
_decodeInWorker(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<RawGeometry>;
|
|
198
|
-
_flushBatch(): void;
|
|
178
|
+
_getPool(): Promise<WorkerPool | null>;
|
|
199
179
|
_buildGeometryFromRaw(raw: RawGeometry, taskConfig: TaskConfig): BufferGeometry;
|
|
200
180
|
_decodeBuffer(buffer: ArrayBuffer, taskConfig: TaskConfig): BufferGeometry;
|
|
201
181
|
_buildGeometry(dracoGeometry: Mesh, taskConfig: TaskConfig): BufferGeometry;
|