@loaders.gl/splats 5.0.0-alpha.6 → 5.0.0-alpha.8

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/dist/index.cjs CHANGED
@@ -81,1894 +81,2196 @@ var init_splats_format = __esm({
81
81
  }
82
82
  });
83
83
 
84
- // dist/lib/splat-utils.js
85
- function convertColorByteToSphericalHarmonicDc(colorByte) {
86
- return (colorByte / 255 - 0.5) / SH_C0;
87
- }
88
- function convertAlphaByteToLinearOpacity(alphaByte) {
89
- return Math.min(Math.max(alphaByte / 255, 0), 1);
90
- }
91
- function normalizeQuaternion(w, x, y, z2) {
92
- const length = Math.hypot(w, x, y, z2);
93
- if (!Number.isFinite(length) || length <= Number.EPSILON) {
94
- return [1, 0, 0, 0];
95
- }
96
- return [w / length, x / length, y / length, z2 / length];
97
- }
98
- function decodeQuaternionByte(byte) {
99
- return (byte - 128) / 128;
100
- }
101
- function decodeFloat16(value) {
102
- const sign = value & 32768 ? -1 : 1;
103
- const exponent = value >> 10 & 31;
104
- const fraction = value & 1023;
105
- if (exponent === 0) {
106
- return sign * Math.pow(2, -14) * (fraction / 1024);
107
- }
108
- if (exponent === 31) {
109
- return fraction ? Number.NaN : sign * Number.POSITIVE_INFINITY;
110
- }
111
- return sign * Math.pow(2, exponent - 15) * (1 + fraction / 1024);
84
+ // ../loader-utils/src/lib/log-utils/log.ts
85
+ function createLog() {
86
+ const log2 = new import_log.Log({ id: "loaders.gl" });
87
+ globalThis.loaders ||= {};
88
+ globalThis.loaders.log = log2;
89
+ globalThis.loaders.version = version;
90
+ globalThis.probe ||= {};
91
+ globalThis.probe.loaders = log2;
92
+ return log2;
112
93
  }
113
- var SH_C0;
114
- var init_splat_utils = __esm({
115
- "dist/lib/splat-utils.js"() {
94
+ var import_log, VERSION, version, log;
95
+ var init_log = __esm({
96
+ "../loader-utils/src/lib/log-utils/log.ts"() {
116
97
  "use strict";
117
- SH_C0 = 0.28209479177387814;
98
+ import_log = require("@probe.gl/log");
99
+ VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
100
+ version = VERSION[0] >= "0" && VERSION[0] <= "9" ? `v${VERSION}` : "";
101
+ log = createLog();
118
102
  }
119
103
  });
120
104
 
121
- // dist/lib/splats-arrow-table.js
122
- function makeGaussianSplatsArrowTable(splats) {
123
- const columns = {};
124
- const fields = [];
125
- const schemaFields = [];
126
- addColumn(columns, fields, schemaFields, "POSITION", makeFixedSizeListVector(splats.positions, 3), {
127
- type: "fixed-size-list",
128
- listSize: 3,
129
- children: [{ name: "value", type: "float32" }]
130
- });
131
- const colorCoefficients = getColorCoefficients(splats);
132
- addScalarColumn(columns, fields, schemaFields, "f_dc_0", colorCoefficients[0], {
133
- "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
134
- "loaders_gl.gaussian_splats.component": "0",
135
- "loaders_gl.gaussian_splats.encoding": "coefficient"
136
- });
137
- addScalarColumn(columns, fields, schemaFields, "f_dc_1", colorCoefficients[1], {
138
- "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
139
- "loaders_gl.gaussian_splats.component": "1",
140
- "loaders_gl.gaussian_splats.encoding": "coefficient"
141
- });
142
- addScalarColumn(columns, fields, schemaFields, "f_dc_2", colorCoefficients[2], {
143
- "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
144
- "loaders_gl.gaussian_splats.component": "2",
145
- "loaders_gl.gaussian_splats.encoding": "coefficient"
146
- });
147
- addScalarColumn(columns, fields, schemaFields, "opacity", splats.opacities, {
148
- "loaders_gl.gaussian_splats.semantic": "opacity",
149
- "loaders_gl.gaussian_splats.encoding": "linear"
150
- });
151
- addVectorComponents(columns, fields, schemaFields, "scale", splats.scales, 3, {
152
- "loaders_gl.gaussian_splats.semantic": "scale",
153
- "loaders_gl.gaussian_splats.encoding": "linear"
154
- });
155
- addVectorComponents(columns, fields, schemaFields, "rot", splats.rotations, 4, {
156
- "loaders_gl.gaussian_splats.semantic": "rotation",
157
- "loaders_gl.gaussian_splats.encoding": "quaternion"
158
- });
159
- if (splats.sphericalHarmonics && splats.sphericalHarmonicsComponentCount) {
160
- addSphericalHarmonicRestColumns(columns, fields, schemaFields, splats.sphericalHarmonics, splats.sphericalHarmonicsComponentCount);
105
+ // ../loader-utils/src/lib/javascript-utils/is-type.ts
106
+ var isObject, isPureObject, isSharedArrayBuffer;
107
+ var init_is_type = __esm({
108
+ "../loader-utils/src/lib/javascript-utils/is-type.ts"() {
109
+ "use strict";
110
+ isObject = (value) => value !== null && typeof value === "object";
111
+ isPureObject = (value) => isObject(value) && value.constructor === {}.constructor;
112
+ isSharedArrayBuffer = (value) => typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
161
113
  }
162
- const metadata = /* @__PURE__ */ new Map([
163
- ["loaders_gl.semantic_type", "gaussian-splats"],
164
- ["loaders_gl.gaussian_splats.version", "1"],
165
- ["loaders_gl.gaussian_splats.source_format", splats.format],
166
- ["topology", "point-list"],
167
- ["mode", "0"]
168
- ]);
169
- const arrowSchema = new arrow.Schema(fields, metadata);
170
- const schema = {
171
- fields: schemaFields,
172
- metadata: Object.fromEntries(metadata)
173
- };
174
- return {
175
- shape: "arrow-table",
176
- schema,
177
- data: new arrow.Table(arrowSchema, columns),
178
- topology: "point-list",
179
- loaderData: splats.loaderData
180
- };
114
+ });
115
+
116
+ // ../loader-utils/src/lib/option-utils/merge-options.ts
117
+ function mergeOptions(baseOptions, newOptions) {
118
+ return mergeOptionsRecursively(baseOptions || {}, newOptions);
181
119
  }
182
- function addVectorComponents(columns, fields, schemaFields, prefix, values, size, metadata) {
183
- for (let component = 0; component < size; component++) {
184
- const componentValues = new Float32Array(values.length / size);
185
- for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
186
- componentValues[rowIndex] = values[rowIndex * size + component];
120
+ function mergeOptionsRecursively(baseOptions, newOptions, level = 0) {
121
+ if (level > 3) {
122
+ return newOptions;
123
+ }
124
+ const options = { ...baseOptions };
125
+ for (const [key, newValue] of Object.entries(newOptions)) {
126
+ if (isPureObject(newValue)) {
127
+ options[key] = mergeOptionsRecursively(
128
+ options[key] || {},
129
+ newOptions[key],
130
+ level + 1
131
+ );
132
+ } else {
133
+ options[key] = newOptions[key];
187
134
  }
188
- addScalarColumn(columns, fields, schemaFields, `${prefix}_${component}`, componentValues, {
189
- ...metadata,
190
- "loaders_gl.gaussian_splats.component": String(component)
191
- });
192
135
  }
136
+ return options;
193
137
  }
194
- function addSphericalHarmonicRestColumns(columns, fields, schemaFields, sphericalHarmonics, componentCount) {
195
- for (let component = 0; component < componentCount; component++) {
196
- const componentValues = new Float32Array(sphericalHarmonics.length / componentCount);
197
- for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
198
- componentValues[rowIndex] = sphericalHarmonics[rowIndex * componentCount + component];
199
- }
200
- addScalarColumn(columns, fields, schemaFields, `f_rest_${component}`, componentValues, {
201
- "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_rest",
202
- "loaders_gl.gaussian_splats.component": String(component),
203
- "loaders_gl.gaussian_splats.encoding": "coefficient"
204
- });
138
+ var init_merge_options = __esm({
139
+ "../loader-utils/src/lib/option-utils/merge-options.ts"() {
140
+ "use strict";
141
+ init_is_type();
205
142
  }
143
+ });
144
+
145
+ // ../loader-utils/src/lib/module-utils/js-module-utils.ts
146
+ function registerJSModules(modules) {
147
+ globalThis.loaders ||= {};
148
+ globalThis.loaders.modules ||= {};
149
+ Object.assign(globalThis.loaders.modules, modules);
206
150
  }
207
- function addScalarColumn(columns, fields, schemaFields, name, values, metadata) {
208
- addColumn(columns, fields, schemaFields, name, arrow.makeVector(values), "float32", metadata);
151
+ function getJSModule(name, caller) {
152
+ var _a, _b;
153
+ const module2 = (_b = (_a = globalThis.loaders) == null ? void 0 : _a.modules) == null ? void 0 : _b[name];
154
+ if (!module2) {
155
+ throw new Error(`${caller}: ${name} library not installed`);
156
+ }
157
+ return module2;
209
158
  }
210
- function addColumn(columns, fields, schemaFields, name, column, schemaType, metadata = {}) {
211
- columns[name] = column;
212
- fields.push(new arrow.Field(name, column.type, false, new Map(Object.entries(metadata))));
213
- schemaFields.push({ name, type: schemaType, nullable: false, metadata });
159
+ function getJSModuleOrNull(name) {
160
+ var _a, _b;
161
+ const module2 = (_b = (_a = globalThis.loaders) == null ? void 0 : _a.modules) == null ? void 0 : _b[name];
162
+ return module2 || null;
214
163
  }
215
- function makeFixedSizeListVector(value, size) {
216
- const values = arrow.makeVector(value);
217
- const child = values.data[0];
218
- const type = new arrow.FixedSizeList(size, new arrow.Field("value", child.type, false));
219
- const data = new arrow.Data(type, 0, value.length / size, 0, {}, [child]);
220
- return new arrow.Vector([data]);
164
+ var init_js_module_utils = __esm({
165
+ "../loader-utils/src/lib/module-utils/js-module-utils.ts"() {
166
+ "use strict";
167
+ }
168
+ });
169
+
170
+ // ../loader-utils/src/lib/binary-utils/array-buffer-utils.ts
171
+ function concatenateArrayBuffers(...sources) {
172
+ return concatenateArrayBuffersFromArray(sources);
221
173
  }
222
- function getColorCoefficients(splats) {
223
- const rowCount = splats.splatCount;
224
- const fdc0 = new Float32Array(rowCount);
225
- const fdc1 = new Float32Array(rowCount);
226
- const fdc2 = new Float32Array(rowCount);
227
- for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
228
- if (splats.sphericalHarmonicDcs) {
229
- fdc0[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 0];
230
- fdc1[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 1];
231
- fdc2[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 2];
232
- } else {
233
- fdc0[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 0]);
234
- fdc1[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 1]);
235
- fdc2[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 2]);
236
- }
174
+ function concatenateArrayBuffersFromArray(sources) {
175
+ const sourceArrays = sources.map(
176
+ (source2) => source2 instanceof ArrayBuffer ? new Uint8Array(source2) : source2
177
+ );
178
+ const byteLength = sourceArrays.reduce((length, typedArray) => length + typedArray.byteLength, 0);
179
+ const result = new Uint8Array(byteLength);
180
+ let offset = 0;
181
+ for (const sourceArray of sourceArrays) {
182
+ result.set(sourceArray, offset);
183
+ offset += sourceArray.byteLength;
237
184
  }
238
- return [fdc0, fdc1, fdc2];
185
+ return result.buffer;
239
186
  }
240
- var arrow;
241
- var init_splats_arrow_table = __esm({
242
- "dist/lib/splats-arrow-table.js"() {
187
+ var init_array_buffer_utils = __esm({
188
+ "../loader-utils/src/lib/binary-utils/array-buffer-utils.ts"() {
243
189
  "use strict";
244
- arrow = __toESM(require("apache-arrow"), 1);
245
- init_splat_utils();
246
190
  }
247
191
  });
248
192
 
249
- // dist/lib/parse-splat.js
250
- function parseSPLAT(data) {
251
- return makeGaussianSplatsArrowTable(parseSPLATToGaussianSplats(data));
193
+ // ../loader-utils/src/lib/iterators/async-iteration.ts
194
+ async function concatenateArrayBuffersAsync(asyncIterator) {
195
+ const arrayBuffers = [];
196
+ for await (const chunk of asyncIterator) {
197
+ arrayBuffers.push(copyToArrayBuffer(chunk));
198
+ }
199
+ return concatenateArrayBuffers(...arrayBuffers);
252
200
  }
253
- function parseSPLATToGaussianSplats(data) {
254
- if (data.byteLength % SPLAT_ROW_BYTE_LENGTH !== 0) {
255
- throw new Error(`SPLATLoader: byte length must be a multiple of ${SPLAT_ROW_BYTE_LENGTH}.`);
201
+ function copyToArrayBuffer(chunk) {
202
+ if (chunk instanceof ArrayBuffer) {
203
+ return chunk;
256
204
  }
257
- const splatCount = data.byteLength / SPLAT_ROW_BYTE_LENGTH;
258
- const dataView = new DataView(data);
259
- const positions = new Float32Array(splatCount * 3);
260
- const scales = new Float32Array(splatCount * 3);
261
- const rotations = new Float32Array(splatCount * 4);
262
- const colors = new Uint8Array(splatCount * 3);
263
- const opacities = new Float32Array(splatCount);
264
- for (let splatIndex = 0; splatIndex < splatCount; splatIndex++) {
265
- const byteOffset = splatIndex * SPLAT_ROW_BYTE_LENGTH;
266
- const positionOffset = splatIndex * 3;
267
- const rotationOffset = splatIndex * 4;
268
- positions[positionOffset + 0] = dataView.getFloat32(byteOffset + 0, true);
269
- positions[positionOffset + 1] = dataView.getFloat32(byteOffset + 4, true);
270
- positions[positionOffset + 2] = dataView.getFloat32(byteOffset + 8, true);
271
- scales[positionOffset + 0] = dataView.getFloat32(byteOffset + 12, true);
272
- scales[positionOffset + 1] = dataView.getFloat32(byteOffset + 16, true);
273
- scales[positionOffset + 2] = dataView.getFloat32(byteOffset + 20, true);
274
- colors[positionOffset + 0] = dataView.getUint8(byteOffset + 24);
275
- colors[positionOffset + 1] = dataView.getUint8(byteOffset + 25);
276
- colors[positionOffset + 2] = dataView.getUint8(byteOffset + 26);
277
- opacities[splatIndex] = convertAlphaByteToLinearOpacity(dataView.getUint8(byteOffset + 27));
278
- const [w, x, y, z2] = normalizeQuaternion(decodeQuaternionByte(dataView.getUint8(byteOffset + 28)), decodeQuaternionByte(dataView.getUint8(byteOffset + 29)), decodeQuaternionByte(dataView.getUint8(byteOffset + 30)), decodeQuaternionByte(dataView.getUint8(byteOffset + 31)));
279
- rotations[rotationOffset + 0] = w;
280
- rotations[rotationOffset + 1] = x;
281
- rotations[rotationOffset + 2] = y;
282
- rotations[rotationOffset + 3] = z2;
205
+ if (ArrayBuffer.isView(chunk)) {
206
+ const { buffer, byteOffset, byteLength } = chunk;
207
+ return copyFromBuffer(buffer, byteOffset, byteLength);
283
208
  }
284
- return {
285
- format: "splat",
286
- splatCount,
287
- positions,
288
- scales,
289
- rotations,
290
- colors,
291
- opacities,
292
- loaderData: {
293
- format: "splat",
294
- splatCount,
295
- rowByteLength: SPLAT_ROW_BYTE_LENGTH
296
- }
297
- };
209
+ return copyFromBuffer(chunk);
298
210
  }
299
- var SPLAT_ROW_BYTE_LENGTH;
300
- var init_parse_splat = __esm({
301
- "dist/lib/parse-splat.js"() {
211
+ function copyFromBuffer(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
212
+ const view = new Uint8Array(buffer, byteOffset, byteLength);
213
+ const copy = new Uint8Array(view.length);
214
+ copy.set(view);
215
+ return copy.buffer;
216
+ }
217
+ var init_async_iteration = __esm({
218
+ "../loader-utils/src/lib/iterators/async-iteration.ts"() {
302
219
  "use strict";
303
- init_splats_arrow_table();
304
- init_splat_utils();
305
- SPLAT_ROW_BYTE_LENGTH = 32;
220
+ init_array_buffer_utils();
306
221
  }
307
222
  });
308
223
 
309
- // dist/splat-loader.js
310
- var splat_loader_exports = {};
311
- __export(splat_loader_exports, {
312
- SPLATLoaderWithParser: () => SPLATLoaderWithParser
313
- });
314
- var _SPLATLoaderPreload, SPLATLoaderMetadataWithoutPreload, SPLATLoaderWithParser;
315
- var init_splat_loader = __esm({
316
- "dist/splat-loader.js"() {
224
+ // ../loader-utils/src/lib/request-utils/authentication.ts
225
+ function resolveCredentials(credentials, authentications = []) {
226
+ if (credentials.every(isAuthentication)) return credentials;
227
+ return credentials.map((credential, index) => {
228
+ if (isAuthentication(credential)) return credential;
229
+ const AuthenticationClass = authentications.find(
230
+ (authentication2) => authentication2.type === (credential == null ? void 0 : credential.type)
231
+ );
232
+ if (!AuthenticationClass) {
233
+ throw new Error(`No authentication class registered for credential at index ${index}.`);
234
+ }
235
+ let authentication;
236
+ try {
237
+ authentication = new AuthenticationClass(credential);
238
+ } catch {
239
+ throw new Error(`Invalid authentication configuration at index ${index}.`);
240
+ }
241
+ if (!isAuthentication(authentication)) {
242
+ throw new Error(`Authentication class returned an invalid credential at index ${index}.`);
243
+ }
244
+ return authentication;
245
+ });
246
+ }
247
+ function resolveAuthenticationOptions(options) {
248
+ var _a, _b;
249
+ if (!((_b = (_a = options.core) == null ? void 0 : _a.credentials) == null ? void 0 : _b.length)) return options;
250
+ const credentials = resolveCredentials(options.core.credentials, options.core.authentications);
251
+ if (credentials === options.core.credentials) return options;
252
+ return { ...options, core: { ...options.core, credentials } };
253
+ }
254
+ function isAuthentication(credential) {
255
+ if (!credential || typeof credential !== "object") return false;
256
+ if (typeof credential.id !== "string" || !Array.isArray(credential.origins)) return false;
257
+ if (credential.type === "request") return typeof credential.authenticate === "function";
258
+ return (credential.type === "header" || credential.type === "query-parameter") && typeof credential.name === "string" && (typeof credential.token === "string" || typeof credential.token === "function") && Array.isArray(credential.refreshStatusCodes);
259
+ }
260
+ var init_authentication = __esm({
261
+ "../loader-utils/src/lib/request-utils/authentication.ts"() {
317
262
  "use strict";
318
- init_parse_splat();
319
- init_splat_loader_types();
320
- ({ preload: _SPLATLoaderPreload, ...SPLATLoaderMetadataWithoutPreload } = SPLATLoader);
321
- SPLATLoaderWithParser = {
322
- ...SPLATLoaderMetadataWithoutPreload,
323
- parse: async (arrayBuffer) => parseSPLAT(arrayBuffer),
324
- parseSync: (arrayBuffer) => parseSPLAT(arrayBuffer)
325
- };
326
263
  }
327
264
  });
328
265
 
329
- // dist/splat-loader-types.js
330
- async function preload() {
331
- const { SPLATLoaderWithParser: SPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_splat_loader(), splat_loader_exports));
332
- return SPLATLoaderWithParser2;
266
+ // ../loader-utils/src/lib/request-utils/request-credentials.ts
267
+ function createAuthenticatedFetch(options) {
268
+ const suppliedFetch = options.fetch || ((url, requestOptions) => fetch(url, requestOptions));
269
+ const existingMetadata = suppliedFetch[AUTHENTICATED_FETCH];
270
+ const credentialResolutions = new Map(existingMetadata == null ? void 0 : existingMetadata.credentialResolutions);
271
+ const resolvedCredentials = resolveCredentials(
272
+ options.credentials.map((credential) => credentialResolutions.get(credential) || credential),
273
+ options.authentications
274
+ );
275
+ options.credentials.forEach((credential, index) => {
276
+ credentialResolutions.set(credential, resolvedCredentials[index]);
277
+ });
278
+ if (!options.fetchOptions && (!resolvedCredentials.length || (existingMetadata == null ? void 0 : existingMetadata.credentials.length) === resolvedCredentials.length && resolvedCredentials.every(
279
+ (credential, index) => credential === existingMetadata.credentials[index]
280
+ )))
281
+ return suppliedFetch;
282
+ const baseFetch = (existingMetadata == null ? void 0 : existingMetadata.fetch) || suppliedFetch;
283
+ const credentials = existingMetadata ? [.../* @__PURE__ */ new Set([...resolvedCredentials, ...existingMetadata.credentials])] : resolvedCredentials;
284
+ const fetchOptions = mergeFetchOptions(
285
+ (existingMetadata == null ? void 0 : existingMetadata.fetchOptions) || {},
286
+ options.fetchOptions
287
+ );
288
+ const tokenCredentials = credentials.filter(
289
+ (credential) => credential.type !== "request"
290
+ );
291
+ const requestCredentials = credentials.filter(
292
+ (credential) => credential.type === "request"
293
+ );
294
+ for (const credential of requestCredentials) normalizeRequestOrigins(credential.origins);
295
+ const authenticatedFetch = async (url, requestOptions = {}) => {
296
+ var _a, _b, _c, _d;
297
+ requestOptions = mergeFetchOptions(fetchOptions, requestOptions);
298
+ if ((_a = requestOptions.signal) == null ? void 0 : _a.aborted) throw createAbortError();
299
+ if (!credentials.length) return baseFetch(url, requestOptions);
300
+ const resolvedURL = parseHTTPURL(url);
301
+ const authorization = resolvedURL ? await authorizeRequest(resolvedURL, requestOptions, tokenCredentials) : { url, options: requestOptions, credentials: [] };
302
+ const signedRequest = await authenticateRequest(authorization, requestCredentials, "request");
303
+ const response = await baseFetch(signedRequest.url, signedRequest.options);
304
+ const refreshableCredentials = authorization.credentials.filter(
305
+ ({ credential }) => typeof credential.token === "function" && credential.refreshStatusCodes.includes(response.status)
306
+ );
307
+ const shouldRetrySignature = signedRequest.credentials.some(
308
+ (credential) => {
309
+ var _a2;
310
+ return (_a2 = credential.refreshStatusCodes) == null ? void 0 : _a2.includes(response.status);
311
+ }
312
+ );
313
+ if (!refreshableCredentials.length && !shouldRetrySignature || !isReplayableRequest(requestOptions) || !isReplayableRequest(signedRequest.options))
314
+ return response;
315
+ if ((_b = requestOptions.signal) == null ? void 0 : _b.aborted) throw createAbortError();
316
+ const refreshedTokens = /* @__PURE__ */ new Map();
317
+ await Promise.all(
318
+ refreshableCredentials.map(async ({ credential }) => {
319
+ const token = await refreshCredential(credential, url, response);
320
+ if (token) refreshedTokens.set(credential, token);
321
+ })
322
+ );
323
+ if (!refreshedTokens.size && !shouldRetrySignature) return response;
324
+ await ((_c = response.body) == null ? void 0 : _c.cancel().catch(() => {
325
+ }));
326
+ if ((_d = requestOptions.signal) == null ? void 0 : _d.aborted) throw createAbortError();
327
+ const replayAuthorization = resolvedURL ? await authorizeRequest(
328
+ resolvedURL,
329
+ requestOptions,
330
+ tokenCredentials,
331
+ refreshedTokens,
332
+ authorization.credentials
333
+ ) : { url, options: requestOptions };
334
+ const replayRequest = await authenticateRequest(
335
+ replayAuthorization,
336
+ requestCredentials,
337
+ "retry",
338
+ response
339
+ );
340
+ return baseFetch(replayRequest.url, replayRequest.options);
341
+ };
342
+ Object.defineProperty(authenticatedFetch, AUTHENTICATED_FETCH, {
343
+ value: {
344
+ fetch: baseFetch,
345
+ credentials,
346
+ credentialResolutions,
347
+ fetchOptions
348
+ }
349
+ });
350
+ return authenticatedFetch;
333
351
  }
334
- var VERSION, SPLATLoader;
335
- var init_splat_loader_types = __esm({
336
- "dist/splat-loader-types.js"() {
337
- "use strict";
338
- init_splats_format();
339
- VERSION = true ? "5.0.0-alpha.6" : "latest";
340
- SPLATLoader = {
341
- dataType: null,
342
- batchType: null,
343
- ...SPLATFormat,
344
- version: VERSION,
345
- options: {
346
- splats: {
347
- shape: "arrow-table"
348
- }
349
- },
350
- preload
351
- };
352
+ function getAuthenticatedFetch(options = {}) {
353
+ var _a, _b, _c;
354
+ const fetchOption = options.fetch ?? ((_a = options.core) == null ? void 0 : _a.fetch);
355
+ let fetchFunction;
356
+ if (typeof fetchOption === "function") {
357
+ fetchFunction = fetchOption;
358
+ } else {
359
+ fetchFunction = (url, requestOptions) => fetch(url, requestOptions);
352
360
  }
353
- });
354
-
355
- // dist/lib/parse-ksplat.js
356
- function parseKSPLAT(data) {
357
- return makeGaussianSplatsArrowTable(parseKSPLATToGaussianSplats(data));
361
+ return createAuthenticatedFetch({
362
+ fetch: fetchFunction,
363
+ fetchOptions: typeof fetchOption === "object" && fetchOption ? fetchOption : void 0,
364
+ credentials: ((_b = options.core) == null ? void 0 : _b.credentials) || [],
365
+ authentications: (_c = options.core) == null ? void 0 : _c.authentications
366
+ });
358
367
  }
359
- function parseKSPLATToGaussianSplats(data) {
360
- if (data.byteLength < HEADER_BYTE_LENGTH) {
361
- throw new Error(`KSPLATLoader: file must contain a ${HEADER_BYTE_LENGTH}-byte header.`);
368
+ function mergeFetchOptions(defaultOptions, requestOptions) {
369
+ const mergedOptions = { ...defaultOptions, ...requestOptions };
370
+ if (defaultOptions.headers || (requestOptions == null ? void 0 : requestOptions.headers)) {
371
+ const headers = new Headers(defaultOptions.headers);
372
+ new Headers(requestOptions == null ? void 0 : requestOptions.headers).forEach((value, key) => headers.set(key, value));
373
+ mergedOptions.headers = headers;
362
374
  }
363
- const header = parseKSPLATHeader(data);
364
- checkKSPLATVersion(header);
365
- const sections = parseKSPLATSections(data, header);
366
- const splatCount = getTotalSplatCount(header, sections);
367
- const sphericalHarmonicsComponentCount = Math.max(0, ...sections.slice(0, getActiveSectionCount(header)).map((section) => getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree)));
368
- const positions = new Float32Array(splatCount * 3);
369
- const scales = new Float32Array(splatCount * 3);
370
- const rotations = new Float32Array(splatCount * 4);
371
- const colors = new Uint8Array(splatCount * 3);
372
- const opacities = new Float32Array(splatCount);
373
- const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
374
- let outputSplatIndex = 0;
375
- for (const section of sections.slice(0, getActiveSectionCount(header))) {
376
- validateSectionBounds(data, section);
377
- for (let localSplatIndex = 0; localSplatIndex < section.splatCount && outputSplatIndex < splatCount; localSplatIndex++) {
378
- decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount);
379
- outputSplatIndex++;
375
+ return mergedOptions;
376
+ }
377
+ async function authenticateRequest(request, credentials, reason, response) {
378
+ const appliedCredentials = [];
379
+ const signal = request.options.signal;
380
+ for (const credential of credentials) {
381
+ const origin = getRequestOrigin(request.url);
382
+ if (!origin || !normalizeRequestOrigins(credential.origins).includes(origin)) continue;
383
+ if (signal == null ? void 0 : signal.aborted) throw createAbortError();
384
+ const authenticatedRequest = await credential.authenticate({
385
+ url: request.url,
386
+ options: { ...request.options, headers: new Headers(request.options.headers) },
387
+ reason,
388
+ response: response ? { status: response.status, headers: new Headers(response.headers) } : void 0
389
+ });
390
+ if (!authenticatedRequest || typeof authenticatedRequest.url !== "string" || !authenticatedRequest.options || typeof authenticatedRequest.options !== "object") {
391
+ throw new Error("Authentication callback returned an invalid request.");
380
392
  }
393
+ request = {
394
+ url: authenticatedRequest.url,
395
+ options: { ...authenticatedRequest.options, ...signal ? { signal } : {} }
396
+ };
397
+ appliedCredentials.push(credential);
381
398
  }
382
- return {
383
- format: "ksplat",
384
- splatCount,
385
- positions,
386
- scales,
387
- rotations,
388
- colors,
389
- opacities,
390
- sphericalHarmonics,
391
- sphericalHarmonicsComponentCount,
392
- loaderData: {
393
- format: "ksplat",
394
- ...header,
395
- sections: sections.slice(0, getActiveSectionCount(header)).map((section) => ({
396
- splatCount: section.splatCount,
397
- maxSplatCount: section.maxSplatCount,
398
- sphericalHarmonicsDegree: section.sphericalHarmonicsDegree
399
- }))
400
- }
401
- };
399
+ if (signal == null ? void 0 : signal.aborted) throw createAbortError();
400
+ return { ...request, credentials: appliedCredentials };
402
401
  }
403
- function decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount) {
404
- const layout = COMPRESSION_LAYOUTS[header.compressionLevel];
405
- const splatBase = section.dataBase + section.bytesPerSplat * localSplatIndex;
406
- const positionOffset = outputSplatIndex * 3;
407
- const rotationOffset = outputSplatIndex * 4;
408
- const bucketCenter = getBucketCenter(data, section, localSplatIndex);
409
- positions[positionOffset + 0] = decodeKSPLATCenterComponent(data, splatBase, 0, header, section, bucketCenter[0]);
410
- positions[positionOffset + 1] = decodeKSPLATCenterComponent(data, splatBase, 1, header, section, bucketCenter[1]);
411
- positions[positionOffset + 2] = decodeKSPLATCenterComponent(data, splatBase, 2, header, section, bucketCenter[2]);
412
- scales[positionOffset + 0] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 0, header.compressionLevel);
413
- scales[positionOffset + 1] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 1, header.compressionLevel);
414
- scales[positionOffset + 2] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 2, header.compressionLevel);
415
- const [w, x, y, z2] = normalizeQuaternion(readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 3, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 4, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 5, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 6, header.compressionLevel));
416
- rotations[rotationOffset + 0] = w;
417
- rotations[rotationOffset + 1] = x;
418
- rotations[rotationOffset + 2] = y;
419
- rotations[rotationOffset + 3] = z2;
420
- const colorBase = splatBase + layout.colorOffsetBytes;
421
- const colorView = new Uint8Array(data, colorBase, 4);
422
- colors[positionOffset + 0] = colorView[0];
423
- colors[positionOffset + 1] = colorView[1];
424
- colors[positionOffset + 2] = colorView[2];
425
- opacities[outputSplatIndex] = convertAlphaByteToLinearOpacity(colorView[3]);
426
- if (sphericalHarmonics && sphericalHarmonicsComponentCount) {
427
- decodeSphericalHarmonics(data, splatBase + layout.sphericalHarmonicsOffsetBytes, header, section, outputSplatIndex, sphericalHarmonics, sphericalHarmonicsComponentCount);
402
+ function getRequestOrigin(url) {
403
+ try {
404
+ const parsedURL = new URL(url);
405
+ if (!parsedURL.host || parsedURL.username || parsedURL.password) return null;
406
+ return parsedURL.origin !== "null" ? parsedURL.origin : `${parsedURL.protocol}//${parsedURL.host}`;
407
+ } catch {
408
+ return null;
428
409
  }
429
410
  }
430
- function parseKSPLATHeader(data) {
431
- const dataView = new DataView(data, 0, HEADER_BYTE_LENGTH);
432
- const compressionLevel = dataView.getUint16(20, true);
433
- if (compressionLevel !== 0 && compressionLevel !== 1 && compressionLevel !== 2) {
434
- throw new Error(`KSPLATLoader: unsupported compression level ${compressionLevel}.`);
411
+ function normalizeRequestOrigins(origins) {
412
+ if (!origins.length)
413
+ throw new Error("Request authentication requires at least one exact origin.");
414
+ return origins.map((origin) => {
415
+ const resolvedOrigin = getRequestOrigin(origin);
416
+ let url;
417
+ try {
418
+ url = new URL(origin);
419
+ } catch {
420
+ throw new Error("Invalid request authentication origin.");
421
+ }
422
+ if (!resolvedOrigin || url.pathname && url.pathname !== "/" || url.search || url.hash) {
423
+ throw new Error("Invalid request authentication origin.");
424
+ }
425
+ return resolvedOrigin;
426
+ });
427
+ }
428
+ async function authorizeRequest(sourceURL, requestOptions, credentials, tokenOverrides = /* @__PURE__ */ new Map(), previousCredentials = []) {
429
+ const url = new URL(sourceURL);
430
+ const headers = new Headers(requestOptions.headers);
431
+ const resolvedCredentials = [];
432
+ const previousTokens = new Map(
433
+ previousCredentials.map(({ credential, token }) => [credential, token])
434
+ );
435
+ for (const credential of credentials) {
436
+ if (!credential.origins.includes(url.origin)) continue;
437
+ const overrideToken = tokenOverrides.get(credential);
438
+ const previousToken = previousTokens.get(credential);
439
+ const ownsQueryParameter = credential.type === "query-parameter" && previousToken !== void 0;
440
+ const ownsHeader = credential.type === "header" && previousToken !== void 0;
441
+ if (credential.type === "query-parameter" && url.searchParams.has(credential.name) && !ownsQueryParameter || credential.type === "header" && headers.has(credential.name) && !ownsHeader) {
442
+ continue;
443
+ }
444
+ const token = overrideToken ?? previousToken ?? await resolveToken(credential.token, { url: sourceURL.toString(), reason: "request" });
445
+ if (!token) continue;
446
+ if (credential.type === "query-parameter") {
447
+ url.searchParams.set(credential.name, token);
448
+ } else {
449
+ headers.set(credential.name, `${credential.prefix || ""}${token}`);
450
+ }
451
+ resolvedCredentials.push({ credential, token });
435
452
  }
436
453
  return {
437
- versionMajor: dataView.getUint8(0),
438
- versionMinor: dataView.getUint8(1),
439
- maxSectionCount: dataView.getUint32(4, true),
440
- sectionCount: dataView.getUint32(8, true),
441
- maxSplatCount: dataView.getUint32(12, true),
442
- splatCount: dataView.getUint32(16, true),
443
- compressionLevel,
444
- minSphericalHarmonicsCoeff: dataView.getFloat32(36, true) || -DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE,
445
- maxSphericalHarmonicsCoeff: dataView.getFloat32(40, true) || DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE
446
- };
447
- }
448
- function checkKSPLATVersion(header) {
449
- if (header.versionMajor === CURRENT_MAJOR_VERSION ? header.versionMinor >= CURRENT_MINOR_VERSION : header.versionMajor > CURRENT_MAJOR_VERSION) {
450
- return;
451
- }
452
- throw new Error(`KSPLATLoader: version ${header.versionMajor}.${header.versionMinor} is not supported.`);
453
- }
454
- function parseKSPLATSections(data, header) {
455
- if (data.byteLength < HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH) {
456
- throw new Error("KSPLATLoader: file does not contain all section headers.");
457
- }
458
- const sections = [];
459
- let sectionBase = HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH;
460
- let splatCountOffset = 0;
461
- for (let sectionIndex = 0; sectionIndex < header.maxSectionCount; sectionIndex++) {
462
- const sectionHeaderBase = HEADER_BYTE_LENGTH + sectionIndex * SECTION_HEADER_BYTE_LENGTH;
463
- const dataView = new DataView(data, sectionHeaderBase, SECTION_HEADER_BYTE_LENGTH);
464
- const splatCount = dataView.getUint32(0, true);
465
- const maxSplatCount = dataView.getUint32(4, true);
466
- const bucketSize = dataView.getUint32(8, true);
467
- const bucketCount = dataView.getUint32(12, true);
468
- const bucketBlockSize = dataView.getFloat32(16, true);
469
- const bucketStorageSizeBytes = dataView.getUint16(20, true);
470
- const compressionScaleRange = dataView.getUint32(24, true) || COMPRESSION_LAYOUTS[header.compressionLevel].scaleRange;
471
- const fullBucketCount = dataView.getUint32(32, true);
472
- const partiallyFilledBucketCount = dataView.getUint32(36, true);
473
- const sphericalHarmonicsDegree = dataView.getUint16(40, true);
474
- const bytesPerSplat = getBytesPerSplat(header.compressionLevel, sphericalHarmonicsDegree);
475
- const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;
476
- const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;
477
- const storageSizeBytes = bytesPerSplat * maxSplatCount + bucketsStorageSizeBytes;
478
- sections.push({
479
- bytesPerSplat,
480
- splatCountOffset,
481
- splatCount: splatCount || maxSplatCount,
482
- maxSplatCount,
483
- bucketSize,
484
- bucketCount,
485
- bucketStorageSizeBytes,
486
- bucketsStorageSizeBytes,
487
- compressionScaleRange,
488
- compressionScaleFactor: bucketBlockSize / 2 / compressionScaleRange,
489
- base: sectionBase,
490
- bucketsBase: sectionBase + bucketsMetaDataSizeBytes,
491
- dataBase: sectionBase + bucketsStorageSizeBytes,
492
- fullBucketCount,
493
- partiallyFilledBucketCount,
494
- sphericalHarmonicsDegree
495
- });
496
- sectionBase += storageSizeBytes;
497
- splatCountOffset += maxSplatCount;
498
- }
499
- return sections;
454
+ url: url.toString(),
455
+ options: { ...requestOptions, headers },
456
+ credentials: resolvedCredentials
457
+ };
500
458
  }
501
- function decodeKSPLATCenterComponent(data, splatBase, component, header, section, bucketCenter) {
502
- const value = readCompressedCenterValue(data, splatBase, component, header.compressionLevel);
503
- return header.compressionLevel >= 1 ? (value - section.compressionScaleRange) * section.compressionScaleFactor + bucketCenter : value;
459
+ async function refreshCredential(credential, url, response) {
460
+ const existingPromise = refreshPromises.get(credential);
461
+ if (existingPromise) return existingPromise;
462
+ const tokenProvider = credential.token;
463
+ const promise = Promise.resolve(
464
+ tokenProvider({
465
+ url,
466
+ reason: "refresh",
467
+ response: { status: response.status, headers: response.headers }
468
+ })
469
+ ).finally(() => refreshPromises.delete(credential));
470
+ refreshPromises.set(credential, promise);
471
+ return promise;
504
472
  }
505
- function readCompressedCenterValue(data, byteOffset, component, compressionLevel) {
506
- const dataView = new DataView(data);
507
- return compressionLevel === 0 ? dataView.getFloat32(byteOffset + component * 4, true) : dataView.getUint16(byteOffset + component * 2, true);
473
+ async function resolveToken(token, context) {
474
+ return typeof token === "function" ? token(context) : token;
508
475
  }
509
- function getBucketCenter(data, section, localSplatIndex) {
510
- if (!section.bucketCount) {
511
- return [0, 0, 0];
476
+ function parseHTTPURL(url) {
477
+ try {
478
+ const parsedURL = new URL(url);
479
+ return ["http:", "https:"].includes(parsedURL.protocol) ? parsedURL : null;
480
+ } catch {
481
+ return null;
512
482
  }
513
- const bucketIndex = getBucketIndex(data, section, localSplatIndex);
514
- const bucketBase = section.bucketsBase + bucketIndex * section.bucketStorageSizeBytes;
515
- const dataView = new DataView(data, bucketBase, 12);
516
- return [dataView.getFloat32(0, true), dataView.getFloat32(4, true), dataView.getFloat32(8, true)];
517
483
  }
518
- function getBucketIndex(data, section, localSplatIndex) {
519
- const maxSplatIndexInFullBuckets = section.fullBucketCount * section.bucketSize;
520
- if (localSplatIndex < maxSplatIndexInFullBuckets) {
521
- return Math.floor(localSplatIndex / section.bucketSize);
484
+ function isReplayableRequest(options) {
485
+ const method = (options.method || "GET").toUpperCase();
486
+ if (!["GET", "HEAD", "OPTIONS", "PUT", "DELETE"].includes(method)) return false;
487
+ return !(options.body && typeof ReadableStream !== "undefined" && options.body instanceof ReadableStream);
488
+ }
489
+ function createAbortError() {
490
+ return new DOMException("The operation was aborted.", "AbortError");
491
+ }
492
+ var AUTHENTICATED_FETCH, refreshPromises;
493
+ var init_request_credentials = __esm({
494
+ "../loader-utils/src/lib/request-utils/request-credentials.ts"() {
495
+ "use strict";
496
+ init_authentication();
497
+ AUTHENTICATED_FETCH = /* @__PURE__ */ Symbol("loaders.gl.authenticated-fetch");
498
+ refreshPromises = /* @__PURE__ */ new WeakMap();
522
499
  }
523
- let bucketSplatIndex = maxSplatIndexInFullBuckets;
524
- let bucketIndex = section.fullBucketCount;
525
- for (let partiallyFilledBucketIndex = 0; partiallyFilledBucketIndex < section.partiallyFilledBucketCount; partiallyFilledBucketIndex++) {
526
- const bucketLength = new DataView(data, section.base + partiallyFilledBucketIndex * 4, 4).getUint32(0, true);
527
- if (localSplatIndex < bucketSplatIndex + bucketLength) {
528
- return bucketIndex;
500
+ });
501
+
502
+ // ../loader-utils/src/lib/path-utils/file-aliases.ts
503
+ function resolvePath(filename) {
504
+ for (const alias in fileAliases) {
505
+ if (filename.startsWith(alias)) {
506
+ const replacement = fileAliases[alias];
507
+ filename = filename.replace(alias, replacement);
529
508
  }
530
- bucketSplatIndex += bucketLength;
531
- bucketIndex++;
532
509
  }
533
- return Math.max(bucketIndex - 1, 0);
534
- }
535
- function decodeSphericalHarmonics(data, byteOffset, header, section, outputSplatIndex, output, outputComponentCount) {
536
- const componentCount = getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree);
537
- const componentBase = outputSplatIndex * outputComponentCount;
538
- for (let component = 0; component < componentCount; component++) {
539
- output[componentBase + component] = readCompressedFloat(data, byteOffset, component, header.compressionLevel, true, header.minSphericalHarmonicsCoeff, header.maxSphericalHarmonicsCoeff);
510
+ if (!filename.startsWith("http://") && !filename.startsWith("https://")) {
511
+ filename = `${pathPrefix}${filename}`;
540
512
  }
513
+ return filename;
541
514
  }
542
- function readCompressedFloat(data, byteOffset, component, compressionLevel, sphericalHarmonic = false, sphericalHarmonicRangeMin = 0, sphericalHarmonicRangeMax = 0) {
543
- const dataView = new DataView(data);
544
- if (compressionLevel === 0) {
545
- return dataView.getFloat32(byteOffset + component * 4, true);
515
+ var pathPrefix, fileAliases;
516
+ var init_file_aliases = __esm({
517
+ "../loader-utils/src/lib/path-utils/file-aliases.ts"() {
518
+ "use strict";
519
+ pathPrefix = "";
520
+ fileAliases = {};
546
521
  }
547
- if (compressionLevel === 1 || !sphericalHarmonic) {
548
- return decodeFloat16(dataView.getUint16(byteOffset + component * 2, true));
522
+ });
523
+
524
+ // ../loader-utils/src/lib/binary-utils/memory-conversion-utils.ts
525
+ function ensureArrayBuffer(bufferSource) {
526
+ if (bufferSource instanceof ArrayBuffer) {
527
+ return bufferSource;
549
528
  }
550
- const value = dataView.getUint8(byteOffset + component);
551
- return value / 255 * (sphericalHarmonicRangeMax - sphericalHarmonicRangeMin) + sphericalHarmonicRangeMin;
529
+ if (isSharedArrayBuffer(bufferSource)) {
530
+ return copyToArrayBuffer2(bufferSource);
531
+ }
532
+ const { buffer, byteOffset, byteLength } = bufferSource;
533
+ if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength) {
534
+ return buffer;
535
+ }
536
+ return copyToArrayBuffer2(buffer, byteOffset, byteLength);
552
537
  }
553
- function getBytesPerSplat(compressionLevel, sphericalHarmonicsDegree) {
554
- const layout = COMPRESSION_LAYOUTS[compressionLevel];
555
- return layout.bytesPerCenter + layout.bytesPerScale + layout.bytesPerRotation + layout.bytesPerColor + layout.bytesPerSphericalHarmonicsComponent * getSphericalHarmonicsComponentCount(sphericalHarmonicsDegree);
538
+ function copyToArrayBuffer2(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
539
+ const view = new Uint8Array(buffer, byteOffset, byteLength);
540
+ const copy = new Uint8Array(view.length);
541
+ copy.set(view);
542
+ return copy.buffer;
556
543
  }
557
- function getSphericalHarmonicsComponentCount(sphericalHarmonicsDegree) {
558
- switch (sphericalHarmonicsDegree) {
559
- case 0:
560
- return 0;
561
- case 1:
562
- return 9;
563
- case 2:
564
- return 24;
565
- case 3:
566
- return 45;
567
- default:
568
- throw new Error(`KSPLATLoader: unsupported spherical harmonics degree ${sphericalHarmonicsDegree}.`);
544
+ var init_memory_conversion_utils = __esm({
545
+ "../loader-utils/src/lib/binary-utils/memory-conversion-utils.ts"() {
546
+ "use strict";
547
+ init_is_type();
569
548
  }
549
+ });
550
+
551
+ // ../loader-utils/src/lib/sources/data-source.ts
552
+ function getFetchFunction(options) {
553
+ return getAuthenticatedFetch(options);
570
554
  }
571
- function getActiveSectionCount(header) {
572
- return header.sectionCount || header.maxSectionCount;
573
- }
574
- function getTotalSplatCount(header, sections) {
575
- const sectionSplatCount = sections.slice(0, getActiveSectionCount(header)).reduce((splatCount, section) => splatCount + section.splatCount, 0);
576
- return header.splatCount ? Math.min(header.splatCount, sectionSplatCount || header.splatCount) : sectionSplatCount;
555
+ function getSourceLoaderOptions(options) {
556
+ var _a;
557
+ if (options.loadOptions !== void 0 || ((_a = options.core) == null ? void 0 : _a.loadOptions) !== void 0) {
558
+ throw new Error(
559
+ "Source loadOptions and core.loadOptions were removed. Use core and root loader namespaces directly."
560
+ );
561
+ }
562
+ const loadOptions = { ...options };
563
+ if (options == null ? void 0 : options.core) {
564
+ loadOptions.core = { ...options.core };
565
+ const parserCore = loadOptions.core;
566
+ for (const key of ["type", "attributions", "loaders", "onError", "loadOptions"]) {
567
+ delete parserCore[key];
568
+ }
569
+ if (Object.keys(parserCore).length === 0) {
570
+ delete loadOptions.core;
571
+ }
572
+ }
573
+ const topLevelBaseUri = typeof loadOptions.baseUri === "string" ? loadOptions.baseUri : void 0;
574
+ const topLevelBaseUrl = typeof loadOptions.baseUrl === "string" ? loadOptions.baseUrl : void 0;
575
+ if (topLevelBaseUri !== void 0 || topLevelBaseUrl !== void 0) {
576
+ loadOptions.core ||= {};
577
+ if (loadOptions.core.baseUrl === void 0) {
578
+ loadOptions.core.baseUrl = topLevelBaseUrl ?? topLevelBaseUri;
579
+ }
580
+ delete loadOptions.baseUri;
581
+ delete loadOptions.baseUrl;
582
+ }
583
+ return loadOptions;
577
584
  }
578
- function validateSectionBounds(data, section) {
579
- const requiredByteLength = section.dataBase + section.bytesPerSplat * section.splatCount;
580
- if (requiredByteLength > data.byteLength) {
581
- throw new Error("KSPLATLoader: section data extends beyond the file length.");
585
+ function normalizeError(error, message) {
586
+ if (error instanceof Error) {
587
+ return error;
588
+ }
589
+ if (typeof error === "string") {
590
+ return new Error(error);
582
591
  }
592
+ return new Error(message);
583
593
  }
584
- var CURRENT_MAJOR_VERSION, CURRENT_MINOR_VERSION, HEADER_BYTE_LENGTH, SECTION_HEADER_BYTE_LENGTH, DEFAULT_SH_8BIT_COMPRESSION_RANGE, DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE, COMPRESSION_LAYOUTS;
585
- var init_parse_ksplat = __esm({
586
- "dist/lib/parse-ksplat.js"() {
594
+ function unavailableCoreApiMethod(methodName) {
595
+ return () => {
596
+ throw new Error(
597
+ `CoreAPI.${methodName} is unavailable. Use @loaders.gl/core.createDataSource().`
598
+ );
599
+ };
600
+ }
601
+ var UNAVAILABLE_CORE_API, DataSource;
602
+ var init_data_source = __esm({
603
+ "../loader-utils/src/lib/sources/data-source.ts"() {
587
604
  "use strict";
588
- init_splats_arrow_table();
589
- init_splat_utils();
590
- CURRENT_MAJOR_VERSION = 0;
591
- CURRENT_MINOR_VERSION = 1;
592
- HEADER_BYTE_LENGTH = 4096;
593
- SECTION_HEADER_BYTE_LENGTH = 1024;
594
- DEFAULT_SH_8BIT_COMPRESSION_RANGE = 3;
595
- DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE = DEFAULT_SH_8BIT_COMPRESSION_RANGE / 2;
596
- COMPRESSION_LAYOUTS = {
597
- 0: {
598
- bytesPerCenter: 12,
599
- bytesPerScale: 12,
600
- bytesPerRotation: 16,
601
- bytesPerColor: 4,
602
- scaleOffsetBytes: 12,
603
- colorOffsetBytes: 40,
604
- sphericalHarmonicsOffsetBytes: 44,
605
- scaleRange: 1,
606
- bytesPerSphericalHarmonicsComponent: 4
607
- },
608
- 1: {
609
- bytesPerCenter: 6,
610
- bytesPerScale: 6,
611
- bytesPerRotation: 8,
612
- bytesPerColor: 4,
613
- scaleOffsetBytes: 6,
614
- colorOffsetBytes: 20,
615
- sphericalHarmonicsOffsetBytes: 24,
616
- scaleRange: 32767,
617
- bytesPerSphericalHarmonicsComponent: 2
618
- },
619
- 2: {
620
- bytesPerCenter: 6,
621
- bytesPerScale: 6,
622
- bytesPerRotation: 8,
623
- bytesPerColor: 4,
624
- scaleOffsetBytes: 6,
625
- colorOffsetBytes: 20,
626
- sphericalHarmonicsOffsetBytes: 24,
627
- scaleRange: 32767,
628
- bytesPerSphericalHarmonicsComponent: 1
605
+ init_merge_options();
606
+ init_file_aliases();
607
+ init_log();
608
+ init_request_credentials();
609
+ init_authentication();
610
+ UNAVAILABLE_CORE_API = {
611
+ fetchFile: unavailableCoreApiMethod("fetchFile"),
612
+ parse: unavailableCoreApiMethod("parse"),
613
+ parseFile: unavailableCoreApiMethod("parseFile"),
614
+ parseSync: unavailableCoreApiMethod("parseSync"),
615
+ parseInBatches: unavailableCoreApiMethod("parseInBatches"),
616
+ load: unavailableCoreApiMethod("load"),
617
+ loadInBatches: unavailableCoreApiMethod("loadInBatches")
618
+ };
619
+ DataSource = class _DataSource {
620
+ static defaultOptions = {
621
+ core: {
622
+ type: "auto",
623
+ attributions: [],
624
+ loaders: [],
625
+ onError: void 0
626
+ }
627
+ };
628
+ optionsType;
629
+ options;
630
+ data;
631
+ url;
632
+ /** Shared parser options derived from the source options, excluding source-only core controls. */
633
+ loadOptions;
634
+ /** A resolved fetch function extracted from the shared core options. */
635
+ fetch;
636
+ /** Shared source-level runtime hooks, when supplied by the source factory. */
637
+ coreApi;
638
+ /** Whether a real CoreAPI instance was injected by the integration layer. */
639
+ hasCoreApi;
640
+ _needsRefresh = true;
641
+ constructor(data, options, defaultOptions, coreApi) {
642
+ this.options = mergeOptions(
643
+ mergeOptions(_DataSource.defaultOptions, defaultOptions || {}),
644
+ options
645
+ );
646
+ this.data = data;
647
+ this.url = typeof data === "string" ? resolvePath(data) : "";
648
+ const loadOptions = resolveAuthenticationOptions(getSourceLoaderOptions(this.options));
649
+ this.loadOptions = loadOptions;
650
+ const fetch2 = getFetchFunction(loadOptions);
651
+ this.coreApi = coreApi || UNAVAILABLE_CORE_API;
652
+ this.hasCoreApi = Boolean(coreApi);
653
+ this.fetch = fetch2;
654
+ }
655
+ setProps(options) {
656
+ const mergedOptions = mergeOptions(this.options, options);
657
+ const loadOptions = resolveAuthenticationOptions(getSourceLoaderOptions(mergedOptions));
658
+ this.options = mergedOptions;
659
+ this.loadOptions = loadOptions;
660
+ this.fetch = getFetchFunction(loadOptions);
661
+ this.setNeedsRefresh();
662
+ }
663
+ /** Mark this data source as needing a refresh (redraw) */
664
+ setNeedsRefresh() {
665
+ this._needsRefresh = true;
666
+ }
667
+ /**
668
+ * Does this data source need refreshing?
669
+ * @note The specifics of the refresh mechanism depends on type of data source
670
+ */
671
+ getNeedsRefresh(clear = true) {
672
+ const needsRefresh = this._needsRefresh;
673
+ if (clear) {
674
+ this._needsRefresh = false;
675
+ }
676
+ return needsRefresh;
677
+ }
678
+ /** Reports a source-level failure through the configured callback or the shared logger. */
679
+ reportError(error, message) {
680
+ var _a;
681
+ const normalizedError = normalizeError(error, message);
682
+ const callback = (_a = this.options.core) == null ? void 0 : _a.onError;
683
+ if (callback) {
684
+ callback(normalizedError, this);
685
+ } else {
686
+ log.warn(`${this.constructor.name}: ${normalizedError.message}`)();
687
+ }
688
+ return normalizedError;
629
689
  }
630
690
  };
631
691
  }
632
692
  });
633
693
 
634
- // dist/ksplat-loader.js
635
- var ksplat_loader_exports = {};
636
- __export(ksplat_loader_exports, {
637
- KSPLATLoaderWithParser: () => KSPLATLoaderWithParser
638
- });
639
- var _KSPLATLoaderPreload, KSPLATLoaderMetadataWithoutPreload, KSPLATLoaderWithParser;
640
- var init_ksplat_loader = __esm({
641
- "dist/ksplat-loader.js"() {
694
+ // ../loader-utils/src/index.ts
695
+ var init_src = __esm({
696
+ "../loader-utils/src/index.ts"() {
642
697
  "use strict";
643
- init_parse_ksplat();
644
- init_ksplat_loader_types();
645
- ({ preload: _KSPLATLoaderPreload, ...KSPLATLoaderMetadataWithoutPreload } = KSPLATLoader);
646
- KSPLATLoaderWithParser = {
647
- ...KSPLATLoaderMetadataWithoutPreload,
648
- parse: async (arrayBuffer) => parseKSPLAT(arrayBuffer),
649
- parseSync: (arrayBuffer) => parseKSPLAT(arrayBuffer)
650
- };
698
+ init_js_module_utils();
699
+ init_js_module_utils();
700
+ init_async_iteration();
701
+ init_memory_conversion_utils();
702
+ init_data_source();
651
703
  }
652
704
  });
653
705
 
654
- // dist/ksplat-loader-types.js
655
- async function preload2() {
656
- const { KSPLATLoaderWithParser: KSPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_ksplat_loader(), ksplat_loader_exports));
657
- return KSPLATLoaderWithParser2;
658
- }
659
- var VERSION2, KSPLATLoader;
660
- var init_ksplat_loader_types = __esm({
661
- "dist/ksplat-loader-types.js"() {
706
+ // ../compression/src/lib/compression.ts
707
+ var CompressionTransform, Compressor, Decompressor, Compression;
708
+ var init_compression = __esm({
709
+ "../compression/src/lib/compression.ts"() {
662
710
  "use strict";
663
- init_splats_format();
664
- VERSION2 = true ? "5.0.0-alpha.6" : "latest";
665
- KSPLATLoader = {
666
- dataType: null,
667
- batchType: null,
668
- ...KSPLATFormat,
669
- version: VERSION2,
670
- options: {
671
- splats: {
672
- shape: "arrow-table"
711
+ init_src();
712
+ CompressionTransform = class {
713
+ /** Preloads any dynamic libraries. May enable sync functions */
714
+ async preload(modules = {}) {
715
+ registerJSModules(modules);
716
+ return void 0;
717
+ }
718
+ // HELPERS
719
+ concatenate(asyncIterator) {
720
+ return concatenateArrayBuffersAsync(asyncIterator);
721
+ }
722
+ improveError(error) {
723
+ if (!error.message.includes(this.name)) {
724
+ error.message = `${this.name} ${error.message}`;
673
725
  }
674
- },
675
- preload: preload2
726
+ return error;
727
+ }
728
+ };
729
+ Compressor = class extends CompressionTransform {
730
+ constructor(options) {
731
+ super();
732
+ this.compressBatches = this.compressBatches.bind(this);
733
+ }
734
+ /** Asynchronously compresses data. */
735
+ async compress(input) {
736
+ await this.preload();
737
+ return this.compressSync(input);
738
+ }
739
+ /** Synchronously compresses data. */
740
+ compressSync(input) {
741
+ throw new Error(`${this.name}: sync compression not supported`);
742
+ }
743
+ /** Compresses batches. */
744
+ async *compressBatches(asyncIterator) {
745
+ const input = await this.concatenate(asyncIterator);
746
+ yield this.compress(input);
747
+ }
748
+ };
749
+ Decompressor = class extends CompressionTransform {
750
+ constructor(options) {
751
+ super();
752
+ this.decompressBatches = this.decompressBatches.bind(this);
753
+ }
754
+ /** Asynchronously decompresses data. */
755
+ async decompress(input, size) {
756
+ await this.preload();
757
+ return this.decompressSync(input, size);
758
+ }
759
+ /** Synchronously decompresses data. */
760
+ decompressSync(input, size) {
761
+ throw new Error(`${this.name}: sync decompression not supported`);
762
+ }
763
+ /** Decompresses batches. */
764
+ async *decompressBatches(asyncIterator) {
765
+ const input = await this.concatenate(asyncIterator);
766
+ yield this.decompress(input);
767
+ }
768
+ };
769
+ Compression = class extends Compressor {
770
+ constructor(options) {
771
+ super(options);
772
+ this.decompressBatches = this.decompressBatches.bind(this);
773
+ }
774
+ /** Asynchronously decompresses data. */
775
+ async decompress(input, size) {
776
+ await this.preload();
777
+ return this.decompressSync(input, size);
778
+ }
779
+ /** Synchronously decompresses data. */
780
+ decompressSync(input, size) {
781
+ throw new Error(`${this.name}: sync decompression not supported`);
782
+ }
783
+ /** Decompresses batches. */
784
+ async *decompressBatches(asyncIterator) {
785
+ const input = await this.concatenate(asyncIterator);
786
+ yield this.decompress(input);
787
+ }
676
788
  };
677
789
  }
678
790
  });
679
791
 
680
- // ../loader-utils/src/lib/log-utils/log.ts
681
- function createLog() {
682
- const log2 = new import_log.Log({ id: "loaders.gl" });
683
- globalThis.loaders ||= {};
684
- globalThis.loaders.log = log2;
685
- globalThis.loaders.version = version;
686
- globalThis.probe ||= {};
687
- globalThis.probe.loaders = log2;
688
- return log2;
792
+ // ../compression/src/lib/compression-stream.ts
793
+ async function compressWithNativeCompressionStream(input, format) {
794
+ const outputBatches = compressBatchesWithNativeCompressionStream([input], format);
795
+ return outputBatches ? await concatenateBatches(outputBatches) : null;
689
796
  }
690
- var import_log, VERSION3, version, log;
691
- var init_log = __esm({
692
- "../loader-utils/src/lib/log-utils/log.ts"() {
693
- "use strict";
694
- import_log = require("@probe.gl/log");
695
- VERSION3 = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
696
- version = VERSION3[0] >= "0" && VERSION3[0] <= "9" ? `v${VERSION3}` : "";
697
- log = createLog();
698
- }
699
- });
700
-
701
- // ../loader-utils/src/lib/javascript-utils/is-type.ts
702
- var isObject, isPureObject, isSharedArrayBuffer;
703
- var init_is_type = __esm({
704
- "../loader-utils/src/lib/javascript-utils/is-type.ts"() {
705
- "use strict";
706
- isObject = (value) => value !== null && typeof value === "object";
707
- isPureObject = (value) => isObject(value) && value.constructor === {}.constructor;
708
- isSharedArrayBuffer = (value) => typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
709
- }
710
- });
711
-
712
- // ../loader-utils/src/lib/option-utils/merge-options.ts
713
- function mergeOptions(baseOptions, newOptions) {
714
- return mergeOptionsRecursively(baseOptions || {}, newOptions);
797
+ function compressBatchesWithNativeCompressionStream(inputBatches, format) {
798
+ const compressionStream = createNativeCompressionStream(format);
799
+ return compressionStream ? transformBatches(inputBatches, compressionStream) : null;
715
800
  }
716
- function mergeOptionsRecursively(baseOptions, newOptions, level = 0) {
717
- if (level > 3) {
718
- return newOptions;
801
+ function createNativeCompressionStream(format) {
802
+ if (typeof globalThis.CompressionStream === "undefined") {
803
+ return null;
719
804
  }
720
- const options = { ...baseOptions };
721
- for (const [key, newValue] of Object.entries(newOptions)) {
722
- if (isPureObject(newValue)) {
723
- options[key] = mergeOptionsRecursively(
724
- options[key] || {},
725
- newOptions[key],
726
- level + 1
727
- );
728
- } else {
729
- options[key] = newOptions[key];
805
+ try {
806
+ const CompressionStreamConstructor = globalThis.CompressionStream;
807
+ return new CompressionStreamConstructor(format);
808
+ } catch (error) {
809
+ if (error instanceof TypeError || (error == null ? void 0 : error.name) === "TypeError") {
810
+ return null;
730
811
  }
812
+ throw error;
731
813
  }
732
- return options;
733
814
  }
734
- var init_merge_options = __esm({
735
- "../loader-utils/src/lib/option-utils/merge-options.ts"() {
736
- "use strict";
737
- init_is_type();
815
+ async function* transformBatches(inputBatches, compressionStream) {
816
+ const writer = compressionStream.writable.getWriter();
817
+ const reader = compressionStream.readable.getReader();
818
+ const writePromise = writeBatches(inputBatches, writer);
819
+ writePromise.catch(() => {
820
+ });
821
+ let outputCompleted = false;
822
+ try {
823
+ while (true) {
824
+ const { done, value } = await reader.read();
825
+ if (done) {
826
+ outputCompleted = true;
827
+ break;
828
+ }
829
+ yield new Uint8Array(value).buffer;
830
+ }
831
+ await writePromise;
832
+ } finally {
833
+ if (!outputCompleted) {
834
+ await reader.cancel().catch(() => {
835
+ });
836
+ await writer.abort().catch(() => {
837
+ });
838
+ await writePromise.catch(() => {
839
+ });
840
+ }
841
+ reader.releaseLock();
738
842
  }
739
- });
740
-
741
- // ../loader-utils/src/lib/module-utils/js-module-utils.ts
742
- function registerJSModules(modules) {
743
- globalThis.loaders ||= {};
744
- globalThis.loaders.modules ||= {};
745
- Object.assign(globalThis.loaders.modules, modules);
746
843
  }
747
- function getJSModule(name, caller) {
748
- var _a, _b;
749
- const module2 = (_b = (_a = globalThis.loaders) == null ? void 0 : _a.modules) == null ? void 0 : _b[name];
750
- if (!module2) {
751
- throw new Error(`${caller}: ${name} library not installed`);
844
+ async function writeBatches(inputBatches, writer) {
845
+ try {
846
+ for await (const inputBatch of inputBatches) {
847
+ await writer.write(new Uint8Array(inputBatch));
848
+ }
849
+ await writer.close();
850
+ } catch (error) {
851
+ await writer.abort(error).catch(() => {
852
+ });
853
+ throw error;
752
854
  }
753
- return module2;
754
- }
755
- function getJSModuleOrNull(name) {
756
- var _a, _b;
757
- const module2 = (_b = (_a = globalThis.loaders) == null ? void 0 : _a.modules) == null ? void 0 : _b[name];
758
- return module2 || null;
759
855
  }
760
- var init_js_module_utils = __esm({
761
- "../loader-utils/src/lib/module-utils/js-module-utils.ts"() {
762
- "use strict";
856
+ async function concatenateBatches(batches) {
857
+ const output = [];
858
+ let byteLength = 0;
859
+ for await (const batch of batches) {
860
+ const bytes = new Uint8Array(batch);
861
+ output.push(bytes);
862
+ byteLength += bytes.byteLength;
763
863
  }
764
- });
765
-
766
- // ../loader-utils/src/lib/binary-utils/array-buffer-utils.ts
767
- function concatenateArrayBuffers(...sources) {
768
- return concatenateArrayBuffersFromArray(sources);
769
- }
770
- function concatenateArrayBuffersFromArray(sources) {
771
- const sourceArrays = sources.map(
772
- (source2) => source2 instanceof ArrayBuffer ? new Uint8Array(source2) : source2
773
- );
774
- const byteLength = sourceArrays.reduce((length, typedArray) => length + typedArray.byteLength, 0);
775
864
  const result = new Uint8Array(byteLength);
776
865
  let offset = 0;
777
- for (const sourceArray of sourceArrays) {
778
- result.set(sourceArray, offset);
779
- offset += sourceArray.byteLength;
866
+ for (const batch of output) {
867
+ result.set(batch, offset);
868
+ offset += batch.byteLength;
780
869
  }
781
870
  return result.buffer;
782
871
  }
783
- var init_array_buffer_utils = __esm({
784
- "../loader-utils/src/lib/binary-utils/array-buffer-utils.ts"() {
872
+ var init_compression_stream = __esm({
873
+ "../compression/src/lib/compression-stream.ts"() {
785
874
  "use strict";
786
875
  }
787
876
  });
788
877
 
789
- // ../loader-utils/src/lib/iterators/async-iteration.ts
790
- async function concatenateArrayBuffersAsync(asyncIterator) {
791
- const arrayBuffers = [];
792
- for await (const chunk of asyncIterator) {
793
- arrayBuffers.push(copyToArrayBuffer(chunk));
878
+ // ../compression/src/lib/decompression-stream.ts
879
+ async function decompressWithNativeDecompressionStream(input, format) {
880
+ const outputBatches = decompressBatchesWithNativeDecompressionStream([input], format);
881
+ return outputBatches ? await concatenateNativeDecompressionBatches(outputBatches) : null;
882
+ }
883
+ function decompressBatchesWithNativeDecompressionStream(inputBatches, format) {
884
+ const decompressionStream = createNativeDecompressionStream(format);
885
+ return decompressionStream ? transformBatchesWithNativeDecompressionStream(inputBatches, decompressionStream) : null;
886
+ }
887
+ function isNativeDecompressionSupported(format) {
888
+ return Boolean(createNativeDecompressionStream(format));
889
+ }
890
+ function createNativeDecompressionStream(format) {
891
+ var _a, _b;
892
+ if (typeof globalThis.DecompressionStream === "undefined") {
893
+ return null;
894
+ }
895
+ if (((_b = (_a = globalThis.process) == null ? void 0 : _a.release) == null ? void 0 : _b.name) === "node" && typeof globalThis.Buffer === "undefined") {
896
+ return null;
897
+ }
898
+ try {
899
+ const DecompressionStreamConstructor = globalThis.DecompressionStream;
900
+ return new DecompressionStreamConstructor(format);
901
+ } catch (error) {
902
+ if (error instanceof TypeError || (error == null ? void 0 : error.name) === "TypeError") {
903
+ return null;
904
+ }
905
+ throw error;
794
906
  }
795
- return concatenateArrayBuffers(...arrayBuffers);
796
907
  }
797
- function copyToArrayBuffer(chunk) {
798
- if (chunk instanceof ArrayBuffer) {
799
- return chunk;
908
+ async function* transformBatchesWithNativeDecompressionStream(inputBatches, decompressionStream) {
909
+ const writer = decompressionStream.writable.getWriter();
910
+ const reader = decompressionStream.readable.getReader();
911
+ const writePromise = writeBatchesToNativeDecompressionStream(inputBatches, writer);
912
+ writePromise.catch(() => {
913
+ });
914
+ let outputCompleted = false;
915
+ try {
916
+ while (true) {
917
+ const { done, value } = await reader.read();
918
+ if (done) {
919
+ outputCompleted = true;
920
+ break;
921
+ }
922
+ yield copyExactArrayBuffer(value);
923
+ }
924
+ await writePromise;
925
+ } finally {
926
+ if (!outputCompleted) {
927
+ await reader.cancel().catch(() => {
928
+ });
929
+ await writer.abort().catch(() => {
930
+ });
931
+ await writePromise.catch(() => {
932
+ });
933
+ }
934
+ reader.releaseLock();
800
935
  }
801
- if (ArrayBuffer.isView(chunk)) {
802
- const { buffer, byteOffset, byteLength } = chunk;
803
- return copyFromBuffer(buffer, byteOffset, byteLength);
936
+ }
937
+ async function concatenateNativeDecompressionBatches(outputBatches) {
938
+ const batches = [];
939
+ let byteLength = 0;
940
+ for await (const outputBatch of outputBatches) {
941
+ const bytes = new Uint8Array(outputBatch);
942
+ batches.push(bytes);
943
+ byteLength += bytes.byteLength;
804
944
  }
805
- return copyFromBuffer(chunk);
945
+ const output = new Uint8Array(byteLength);
946
+ let byteOffset = 0;
947
+ for (const batch of batches) {
948
+ output.set(batch, byteOffset);
949
+ byteOffset += batch.byteLength;
950
+ }
951
+ return output.buffer;
806
952
  }
807
- function copyFromBuffer(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
808
- const view = new Uint8Array(buffer, byteOffset, byteLength);
809
- const copy = new Uint8Array(view.length);
810
- copy.set(view);
811
- return copy.buffer;
953
+ function copyExactArrayBuffer(value) {
954
+ return new Uint8Array(value).buffer;
812
955
  }
813
- var init_async_iteration = __esm({
814
- "../loader-utils/src/lib/iterators/async-iteration.ts"() {
956
+ async function writeBatchesToNativeDecompressionStream(inputBatches, writer) {
957
+ try {
958
+ for await (const inputBatch of inputBatches) {
959
+ await writer.write(new Uint8Array(inputBatch));
960
+ }
961
+ await writer.close();
962
+ } catch (error) {
963
+ await writer.abort(error).catch(() => {
964
+ });
965
+ throw error;
966
+ }
967
+ }
968
+ var init_decompression_stream = __esm({
969
+ "../compression/src/lib/decompression-stream.ts"() {
815
970
  "use strict";
816
- init_array_buffer_utils();
817
971
  }
818
972
  });
819
973
 
820
- // ../loader-utils/src/lib/request-utils/request-credentials.ts
821
- function createAuthenticatedFetch(options) {
822
- const baseFetch = options.fetch || ((url, requestOptions) => fetch(url, requestOptions));
823
- if (!options.credentials.length) return baseFetch;
824
- const existingMetadata = baseFetch[AUTHENTICATED_FETCH];
825
- if (existingMetadata === options.credentials) return baseFetch;
826
- const authenticatedFetch = async (url, requestOptions = {}) => {
827
- var _a, _b, _c;
828
- const resolvedURL = parseHTTPURL(url);
829
- if (!resolvedURL) return baseFetch(url, requestOptions);
830
- const authorization = await authorizeRequest(resolvedURL, requestOptions, options.credentials);
831
- const response = await baseFetch(authorization.url, authorization.options);
832
- const refreshableCredentials = authorization.credentials.filter(
833
- ({ credential }) => typeof credential.token === "function" && credential.refreshStatusCodes.includes(response.status)
834
- );
835
- if (!refreshableCredentials.length || !isReplayableRequest(requestOptions)) return response;
836
- if ((_a = requestOptions.signal) == null ? void 0 : _a.aborted) throw createAbortError();
837
- const refreshedTokens = /* @__PURE__ */ new Map();
838
- await Promise.all(
839
- refreshableCredentials.map(async ({ credential }) => {
840
- const token = await refreshCredential(credential, url, response);
841
- if (token) refreshedTokens.set(credential, token);
842
- })
843
- );
844
- if (!refreshedTokens.size) return response;
845
- await ((_b = response.body) == null ? void 0 : _b.cancel().catch(() => {
846
- }));
847
- if ((_c = requestOptions.signal) == null ? void 0 : _c.aborted) throw createAbortError();
848
- const replayAuthorization = await authorizeRequest(
849
- resolvedURL,
850
- requestOptions,
851
- options.credentials,
852
- refreshedTokens,
853
- authorization.credentials
854
- );
855
- return baseFetch(replayAuthorization.url, replayAuthorization.options);
856
- };
857
- Object.defineProperty(authenticatedFetch, AUTHENTICATED_FETCH, {
858
- value: options.credentials
859
- });
860
- return authenticatedFetch;
861
- }
862
- async function authorizeRequest(sourceURL, requestOptions, credentials, tokenOverrides = /* @__PURE__ */ new Map(), previousCredentials = []) {
863
- const url = new URL(sourceURL);
864
- const headers = new Headers(requestOptions.headers);
865
- const resolvedCredentials = [];
866
- const previousTokens = new Map(
867
- previousCredentials.map(({ credential, token }) => [credential, token])
868
- );
869
- for (const credential of credentials) {
870
- if (!credential.origins.includes(url.origin)) continue;
871
- const overrideToken = tokenOverrides.get(credential);
872
- const previousToken = previousTokens.get(credential);
873
- const ownsQueryParameter = credential.type === "query-parameter" && previousToken !== void 0;
874
- const ownsHeader = credential.type === "header" && previousToken !== void 0;
875
- if (credential.type === "query-parameter" && url.searchParams.has(credential.name) && !ownsQueryParameter || credential.type === "header" && headers.has(credential.name) && !ownsHeader) {
876
- continue;
877
- }
878
- const token = overrideToken ?? previousToken ?? await resolveToken(credential.token, { url: sourceURL.toString(), reason: "request" });
879
- if (!token) continue;
880
- if (credential.type === "query-parameter") {
881
- url.searchParams.set(credential.name, token);
882
- } else {
883
- headers.set(credential.name, `${credential.prefix || ""}${token}`);
884
- }
885
- resolvedCredentials.push({ credential, token });
886
- }
887
- return {
888
- url: url.toString(),
889
- options: { ...requestOptions, headers },
890
- credentials: resolvedCredentials
891
- };
892
- }
893
- async function refreshCredential(credential, url, response) {
894
- const existingPromise = refreshPromises.get(credential);
895
- if (existingPromise) return existingPromise;
896
- const tokenProvider = credential.token;
897
- const promise = Promise.resolve(
898
- tokenProvider({
899
- url,
900
- reason: "refresh",
901
- response: { status: response.status, headers: response.headers }
902
- })
903
- ).finally(() => refreshPromises.delete(credential));
904
- refreshPromises.set(credential, promise);
905
- return promise;
906
- }
907
- async function resolveToken(token, context) {
908
- return typeof token === "function" ? token(context) : token;
909
- }
910
- function parseHTTPURL(url) {
911
- try {
912
- const parsedURL = new URL(url);
913
- return ["http:", "https:"].includes(parsedURL.protocol) ? parsedURL : null;
914
- } catch {
915
- return null;
916
- }
917
- }
918
- function isReplayableRequest(options) {
919
- const method = (options.method || "GET").toUpperCase();
920
- if (!["GET", "HEAD", "OPTIONS", "PUT", "DELETE"].includes(method)) return false;
921
- return !(options.body && typeof ReadableStream !== "undefined" && options.body instanceof ReadableStream);
922
- }
923
- function createAbortError() {
924
- return new DOMException("The operation was aborted.", "AbortError");
925
- }
926
- var AUTHENTICATED_FETCH, refreshPromises;
927
- var init_request_credentials = __esm({
928
- "../loader-utils/src/lib/request-utils/request-credentials.ts"() {
974
+ // ../compression/src/lib/native-decompressor.ts
975
+ var native_decompressor_exports = {};
976
+ __export(native_decompressor_exports, {
977
+ NativeDecompressor: () => NativeDecompressor
978
+ });
979
+ var NativeDecompressor;
980
+ var init_native_decompressor = __esm({
981
+ "../compression/src/lib/native-decompressor.ts"() {
929
982
  "use strict";
930
- AUTHENTICATED_FETCH = /* @__PURE__ */ Symbol("loaders.gl.authenticated-fetch");
931
- refreshPromises = /* @__PURE__ */ new WeakMap();
983
+ init_compression();
984
+ init_decompression_stream();
985
+ NativeDecompressor = class extends Decompressor {
986
+ name;
987
+ extensions;
988
+ contentEncodings;
989
+ isSupported = true;
990
+ /** Runtime stream format used for every operation. */
991
+ format;
992
+ constructor(metadata, format, options = {}) {
993
+ super(options);
994
+ this.name = metadata.name;
995
+ this.extensions = [...metadata.extensions];
996
+ this.contentEncodings = [...metadata.contentEncodings];
997
+ this.format = format;
998
+ }
999
+ /** Decompresses one buffer with the runtime-provided stream. */
1000
+ async decompress(input) {
1001
+ const output = await decompressWithNativeDecompressionStream(input, this.format);
1002
+ if (!output) throw new Error(`${this.name}: built-in decompression is no longer available`);
1003
+ return output;
1004
+ }
1005
+ /** Decompresses batches incrementally with the runtime-provided stream. */
1006
+ async *decompressBatches(inputBatches) {
1007
+ const output = decompressBatchesWithNativeDecompressionStream(inputBatches, this.format);
1008
+ if (!output) throw new Error(`${this.name}: built-in decompression is no longer available`);
1009
+ yield* output;
1010
+ }
1011
+ };
932
1012
  }
933
1013
  });
934
1014
 
935
- // ../loader-utils/src/lib/path-utils/file-aliases.ts
936
- function resolvePath(filename) {
937
- for (const alias in fileAliases) {
938
- if (filename.startsWith(alias)) {
939
- const replacement = fileAliases[alias];
940
- filename = filename.replace(alias, replacement);
941
- }
942
- }
943
- if (!filename.startsWith("http://") && !filename.startsWith("https://")) {
944
- filename = `${pathPrefix}${filename}`;
945
- }
946
- return filename;
1015
+ // ../compression/src/lib/lazy-compression.ts
1016
+ function mergeModules(options, modules) {
1017
+ return { ...options, modules: { ...options.modules, ...modules } };
947
1018
  }
948
- var pathPrefix, fileAliases;
949
- var init_file_aliases = __esm({
950
- "../loader-utils/src/lib/path-utils/file-aliases.ts"() {
1019
+ var LazyDecompressor;
1020
+ var init_lazy_compression = __esm({
1021
+ "../compression/src/lib/lazy-compression.ts"() {
951
1022
  "use strict";
952
- pathPrefix = "";
953
- fileAliases = {};
1023
+ init_compression();
1024
+ init_decompression_stream();
1025
+ LazyDecompressor = class extends Decompressor {
1026
+ name;
1027
+ extensions;
1028
+ contentEncodings;
1029
+ isSupported = true;
1030
+ /** Constructor options retained until a concrete implementation is selected. */
1031
+ options;
1032
+ /** Built-in stream format to probe, or null when the format has no built-in path. */
1033
+ nativeFormat;
1034
+ /** Returns whether built-in selection remains eligible for the merged preload options. */
1035
+ shouldUseNative;
1036
+ /** Dynamically imports the balanced fallback constructor. */
1037
+ loadFallback;
1038
+ /** Selected concrete implementation after preload completes. */
1039
+ implementation = null;
1040
+ /** Shared in-flight selection used by concurrent asynchronous calls. */
1041
+ implementationPromise = null;
1042
+ constructor(metadata, loadFallback, options = {}, nativeFormat = null, shouldUseNative = () => true) {
1043
+ super(options);
1044
+ this.name = metadata.name;
1045
+ this.extensions = [...metadata.extensions];
1046
+ this.contentEncodings = [...metadata.contentEncodings];
1047
+ this.options = options;
1048
+ this.nativeFormat = nativeFormat;
1049
+ this.shouldUseNative = shouldUseNative;
1050
+ this.loadFallback = loadFallback;
1051
+ }
1052
+ /** Selects and returns the built-in or dynamically imported fallback decompressor. */
1053
+ async preload(modules = {}) {
1054
+ if (this.implementation) return this.implementation;
1055
+ const options = mergeModules(this.options, modules);
1056
+ this.implementationPromise ||= this.loadImplementation(options);
1057
+ try {
1058
+ this.implementation = await this.implementationPromise;
1059
+ return this.implementation;
1060
+ } catch (error) {
1061
+ this.implementationPromise = null;
1062
+ throw error;
1063
+ }
1064
+ }
1065
+ /** Loads the selected concrete decompressor. */
1066
+ async loadImplementation(options) {
1067
+ if (options.useNative !== false && this.nativeFormat && this.shouldUseNative(options) && isNativeDecompressionSupported(this.nativeFormat)) {
1068
+ const { NativeDecompressor: NativeDecompressor2 } = await Promise.resolve().then(() => (init_native_decompressor(), native_decompressor_exports));
1069
+ return new NativeDecompressor2(this, this.nativeFormat, options);
1070
+ }
1071
+ const Decompressor2 = await this.loadFallback();
1072
+ const implementation = new Decompressor2({ ...options, useNative: false });
1073
+ await implementation.preload(options.modules);
1074
+ return implementation;
1075
+ }
1076
+ /** Decompresses after lazily selecting the default implementation. */
1077
+ async decompress(input, size) {
1078
+ return (await this.preload()).decompress(input, size);
1079
+ }
1080
+ /** Decompresses synchronously after an implementation has been preloaded. */
1081
+ decompressSync(input, size) {
1082
+ if (!this.implementation) {
1083
+ throw new Error(`${this.name}: call preload() before decompressSync()`);
1084
+ }
1085
+ return this.implementation.decompressSync(input, size);
1086
+ }
1087
+ /** Decompresses batches after lazily selecting the default implementation. */
1088
+ async *decompressBatches(inputBatches) {
1089
+ yield* (await this.preload()).decompressBatches(inputBatches);
1090
+ }
1091
+ };
954
1092
  }
955
1093
  });
956
1094
 
957
- // ../loader-utils/src/lib/binary-utils/memory-conversion-utils.ts
958
- function ensureArrayBuffer(bufferSource) {
959
- if (bufferSource instanceof ArrayBuffer) {
960
- return bufferSource;
961
- }
962
- if (isSharedArrayBuffer(bufferSource)) {
963
- return copyToArrayBuffer2(bufferSource);
964
- }
965
- const { buffer, byteOffset, byteLength } = bufferSource;
966
- if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength) {
967
- return buffer;
1095
+ // ../compression/src/lib/fflate-stream.ts
1096
+ async function* transformFflateBatches(processor, inputBatches) {
1097
+ const chunks = [];
1098
+ processor.ondata = (data) => {
1099
+ chunks.push(data.slice().buffer);
1100
+ };
1101
+ for await (const batch of inputBatches) {
1102
+ processor.push(new Uint8Array(batch), false);
1103
+ yield* chunks.splice(0);
968
1104
  }
969
- return copyToArrayBuffer2(buffer, byteOffset, byteLength);
970
- }
971
- function copyToArrayBuffer2(buffer, byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
972
- const view = new Uint8Array(buffer, byteOffset, byteLength);
973
- const copy = new Uint8Array(view.length);
974
- copy.set(view);
975
- return copy.buffer;
1105
+ processor.push(new Uint8Array(0), true);
1106
+ yield* chunks;
976
1107
  }
977
- var init_memory_conversion_utils = __esm({
978
- "../loader-utils/src/lib/binary-utils/memory-conversion-utils.ts"() {
1108
+ var init_fflate_stream = __esm({
1109
+ "../compression/src/lib/fflate-stream.ts"() {
979
1110
  "use strict";
980
- init_is_type();
981
1111
  }
982
1112
  });
983
1113
 
984
- // ../loader-utils/src/lib/sources/data-source.ts
985
- function getFetchFunction(options) {
986
- var _a, _b;
987
- const fetchOption = (options == null ? void 0 : options.fetch) ?? ((_a = options == null ? void 0 : options.core) == null ? void 0 : _a.fetch);
988
- let fetchFunction;
989
- if (typeof fetchOption === "function") {
990
- fetchFunction = (url, fetchOptions) => fetchOption(url, fetchOptions);
991
- } else if (fetchOption) {
992
- fetchFunction = (url, requestOptions) => fetch(url, mergeFetchOptions(fetchOption, requestOptions));
993
- } else {
994
- fetchFunction = (url, requestOptions) => fetch(url, requestOptions);
995
- }
996
- return createAuthenticatedFetch({
997
- fetch: fetchFunction,
998
- credentials: ((_b = options == null ? void 0 : options.core) == null ? void 0 : _b.credentials) || []
999
- });
1000
- }
1001
- function mergeFetchOptions(fetchOptions, requestOptions) {
1002
- const mergedOptions = { ...fetchOptions, ...requestOptions };
1003
- if (fetchOptions.headers || (requestOptions == null ? void 0 : requestOptions.headers)) {
1004
- mergedOptions.headers = mergeHeaders(fetchOptions.headers, requestOptions == null ? void 0 : requestOptions.headers);
1005
- }
1006
- return mergedOptions;
1007
- }
1008
- function mergeHeaders(defaultHeaders, requestHeaders) {
1009
- const headers = new Headers(defaultHeaders);
1010
- if (requestHeaders) {
1011
- new Headers(requestHeaders).forEach((value, key) => headers.set(key, value));
1114
+ // ../compression/src/gzip-decompressor-fflate.ts
1115
+ var import_fflate, GZipFflateDecompressor;
1116
+ var init_gzip_decompressor_fflate = __esm({
1117
+ "../compression/src/gzip-decompressor-fflate.ts"() {
1118
+ "use strict";
1119
+ import_fflate = require("fflate");
1120
+ init_compression();
1121
+ init_fflate_stream();
1122
+ GZipFflateDecompressor = class extends Decompressor {
1123
+ name = "gzip";
1124
+ extensions = ["gz", "gzip"];
1125
+ contentEncodings = ["gzip", "x-gzip"];
1126
+ isSupported = true;
1127
+ constructor(options = {}) {
1128
+ super(options);
1129
+ }
1130
+ /** Decompresses one GZIP payload synchronously. */
1131
+ decompressSync(input) {
1132
+ return (0, import_fflate.gunzipSync)(new Uint8Array(input)).slice().buffer;
1133
+ }
1134
+ /** Decompresses GZIP batches incrementally. */
1135
+ async *decompressBatches(inputBatches) {
1136
+ yield* transformFflateBatches(new import_fflate.Gunzip(), inputBatches);
1137
+ }
1138
+ };
1012
1139
  }
1013
- return headers;
1014
- }
1015
- function normalizeDirectLoaderOptions(options) {
1016
- const loadOptions = { ...options };
1017
- if (options == null ? void 0 : options.core) {
1018
- loadOptions.core = { ...options.core };
1019
- }
1020
- const topLevelBaseUri = typeof loadOptions.baseUri === "string" ? loadOptions.baseUri : void 0;
1021
- const topLevelBaseUrl = typeof loadOptions.baseUrl === "string" ? loadOptions.baseUrl : void 0;
1022
- if (topLevelBaseUri !== void 0 || topLevelBaseUrl !== void 0) {
1023
- loadOptions.core ||= {};
1024
- if (loadOptions.core.baseUrl === void 0) {
1025
- loadOptions.core.baseUrl = topLevelBaseUrl ?? topLevelBaseUri;
1026
- }
1027
- delete loadOptions.baseUri;
1028
- delete loadOptions.baseUrl;
1029
- }
1030
- return loadOptions;
1031
- }
1032
- function normalizeError(error, message) {
1033
- if (error instanceof Error) {
1034
- return error;
1035
- }
1036
- if (typeof error === "string") {
1037
- return new Error(error);
1038
- }
1039
- return new Error(message);
1040
- }
1041
- function unavailableCoreApiMethod(methodName) {
1042
- return () => {
1043
- throw new Error(
1044
- `CoreAPI.${methodName} is unavailable. Use @loaders.gl/core.createDataSource().`
1045
- );
1046
- };
1047
- }
1048
- var UNAVAILABLE_CORE_API, DataSource;
1049
- var init_data_source = __esm({
1050
- "../loader-utils/src/lib/sources/data-source.ts"() {
1140
+ });
1141
+
1142
+ // ../compression/src/gzip-decompressor.ts
1143
+ var gzip_decompressor_exports = {};
1144
+ __export(gzip_decompressor_exports, {
1145
+ GZipDecompressor: () => GZipDecompressor
1146
+ });
1147
+ var GZipDecompressor;
1148
+ var init_gzip_decompressor = __esm({
1149
+ "../compression/src/gzip-decompressor.ts"() {
1051
1150
  "use strict";
1052
- init_merge_options();
1053
- init_file_aliases();
1054
- init_log();
1055
- init_request_credentials();
1056
- UNAVAILABLE_CORE_API = {
1057
- fetchFile: unavailableCoreApiMethod("fetchFile"),
1058
- parse: unavailableCoreApiMethod("parse"),
1059
- parseFile: unavailableCoreApiMethod("parseFile"),
1060
- parseSync: unavailableCoreApiMethod("parseSync"),
1061
- parseInBatches: unavailableCoreApiMethod("parseInBatches"),
1062
- load: unavailableCoreApiMethod("load"),
1063
- loadInBatches: unavailableCoreApiMethod("loadInBatches")
1064
- };
1065
- DataSource = class _DataSource {
1066
- static defaultOptions = {
1067
- core: {
1068
- type: "auto",
1069
- attributions: [],
1070
- loadOptions: {},
1071
- loaders: [],
1072
- onError: void 0
1073
- }
1074
- };
1075
- optionsType;
1151
+ init_gzip_decompressor_fflate();
1152
+ init_decompression_stream();
1153
+ GZipDecompressor = class extends GZipFflateDecompressor {
1076
1154
  options;
1077
- data;
1078
- url;
1079
- /** The actual load options, if calling a loaders.gl loader */
1080
- loadOptions;
1081
- /** A resolved fetch function extracted from loadOptions prop */
1082
- fetch;
1083
- /** Shared source-level runtime hooks, when supplied by the source factory. */
1084
- coreApi;
1085
- /** Whether a real CoreAPI instance was injected by the integration layer. */
1086
- hasCoreApi;
1087
- _needsRefresh = true;
1088
- constructor(data, options, defaultOptions, coreApi) {
1089
- var _a;
1090
- if (defaultOptions) {
1091
- this.options = mergeOptions({ ...defaultOptions, core: _DataSource.defaultOptions }, options);
1092
- } else {
1093
- this.options = { ...options };
1094
- }
1095
- this.data = data;
1096
- this.url = typeof data === "string" ? resolvePath(data) : "";
1097
- const loadOptions = normalizeDirectLoaderOptions((_a = this.options.core) == null ? void 0 : _a.loadOptions);
1098
- this.loadOptions = loadOptions;
1099
- const fetch2 = getFetchFunction(loadOptions);
1100
- this.coreApi = coreApi || UNAVAILABLE_CORE_API;
1101
- this.hasCoreApi = Boolean(coreApi);
1102
- this.fetch = fetch2;
1103
- }
1104
- setProps(options) {
1105
- this.options = Object.assign(this.options, options);
1106
- this.setNeedsRefresh();
1107
- }
1108
- /** Mark this data source as needing a refresh (redraw) */
1109
- setNeedsRefresh() {
1110
- this._needsRefresh = true;
1155
+ constructor(options = {}) {
1156
+ super(options);
1157
+ this.options = options;
1111
1158
  }
1112
- /**
1113
- * Does this data source need refreshing?
1114
- * @note The specifics of the refresh mechanism depends on type of data source
1115
- */
1116
- getNeedsRefresh(clear = true) {
1117
- const needsRefresh = this._needsRefresh;
1118
- if (clear) {
1119
- this._needsRefresh = false;
1159
+ /** Decompresses with the built-in stream when available, then falls back to fflate. */
1160
+ async decompress(input) {
1161
+ if (this.options.useNative !== false) {
1162
+ const output = await decompressWithNativeDecompressionStream(input, "gzip");
1163
+ if (output) return output;
1120
1164
  }
1121
- return needsRefresh;
1165
+ return this.decompressSync(input);
1122
1166
  }
1123
- /** Reports a source-level failure through the configured callback or the shared logger. */
1124
- reportError(error, message) {
1125
- var _a;
1126
- const normalizedError = normalizeError(error, message);
1127
- const callback = (_a = this.options.core) == null ? void 0 : _a.onError;
1128
- if (callback) {
1129
- callback(normalizedError, this);
1130
- } else {
1131
- log.warn(`${this.constructor.name}: ${normalizedError.message}`)();
1167
+ /** Decompresses batches with a built-in or fflate stream. */
1168
+ async *decompressBatches(inputBatches) {
1169
+ if (this.options.useNative !== false) {
1170
+ const output = decompressBatchesWithNativeDecompressionStream(inputBatches, "gzip");
1171
+ if (output) {
1172
+ yield* output;
1173
+ return;
1174
+ }
1132
1175
  }
1133
- return normalizedError;
1176
+ yield* super.decompressBatches(inputBatches);
1134
1177
  }
1135
1178
  };
1136
1179
  }
1137
1180
  });
1138
1181
 
1139
- // ../loader-utils/src/index.ts
1140
- var init_src = __esm({
1141
- "../loader-utils/src/index.ts"() {
1182
+ // ../compression/src/zstd-decompressor-fzstd.ts
1183
+ var import_fzstd, ZstdFzstdDecompressor;
1184
+ var init_zstd_decompressor_fzstd = __esm({
1185
+ "../compression/src/zstd-decompressor-fzstd.ts"() {
1142
1186
  "use strict";
1143
- init_js_module_utils();
1144
- init_js_module_utils();
1145
- init_async_iteration();
1146
- init_memory_conversion_utils();
1147
- init_data_source();
1187
+ init_compression();
1188
+ import_fzstd = require("fzstd");
1189
+ ZstdFzstdDecompressor = class extends Decompressor {
1190
+ name = "zstd";
1191
+ extensions = ["zst"];
1192
+ contentEncodings = ["zstd"];
1193
+ isSupported = true;
1194
+ constructor(options = {}) {
1195
+ super(options);
1196
+ }
1197
+ /** Decompresses one Zstandard frame synchronously. */
1198
+ decompressSync(input) {
1199
+ return (0, import_fzstd.decompress)(new Uint8Array(input)).slice().buffer;
1200
+ }
1201
+ };
1148
1202
  }
1149
1203
  });
1150
1204
 
1151
- // ../compression/src/lib/compression.ts
1152
- var CompressionTransform, Compressor, Decompressor, Compression;
1153
- var init_compression = __esm({
1154
- "../compression/src/lib/compression.ts"() {
1205
+ // ../compression/src/zstd-fallback.ts
1206
+ var zstd_fallback_exports = {};
1207
+ __export(zstd_fallback_exports, {
1208
+ decompressZstd: () => decompressZstd
1209
+ });
1210
+ function decompressZstd(input) {
1211
+ return (0, import_fzstd2.decompress)(input);
1212
+ }
1213
+ var import_fzstd2;
1214
+ var init_zstd_fallback = __esm({
1215
+ "../compression/src/zstd-fallback.ts"() {
1216
+ "use strict";
1217
+ import_fzstd2 = require("fzstd");
1218
+ }
1219
+ });
1220
+
1221
+ // ../compression/src/lib/zstd-compression.ts
1222
+ var zstd_compression_exports = {};
1223
+ __export(zstd_compression_exports, {
1224
+ ZstdCompression: () => ZstdCompression
1225
+ });
1226
+ var CHUNK_SIZE, zstdPromise, zstd, ZstdCompression;
1227
+ var init_zstd_compression = __esm({
1228
+ "../compression/src/lib/zstd-compression.ts"() {
1155
1229
  "use strict";
1230
+ init_compression();
1156
1231
  init_src();
1157
- CompressionTransform = class {
1158
- /** Preloads any dynamic libraries. May enable sync functions */
1232
+ init_compression_stream();
1233
+ init_decompression_stream();
1234
+ CHUNK_SIZE = 1e6;
1235
+ ZstdCompression = class extends Compression {
1236
+ name = "zstd";
1237
+ extensions = [];
1238
+ contentEncodings = [];
1239
+ isSupported = true;
1240
+ options;
1241
+ /**
1242
+ * zstd-codec is an injectable dependency due to big size
1243
+ * @param options
1244
+ */
1245
+ constructor(options = {}) {
1246
+ super(options);
1247
+ this.options = options;
1248
+ registerJSModules(options == null ? void 0 : options.modules);
1249
+ }
1159
1250
  async preload(modules = {}) {
1160
1251
  registerJSModules(modules);
1161
- return void 0;
1162
- }
1163
- // HELPERS
1164
- concatenate(asyncIterator) {
1165
- return concatenateArrayBuffersAsync(asyncIterator);
1166
- }
1167
- improveError(error) {
1168
- if (!error.message.includes(this.name)) {
1169
- error.message = `${this.name} ${error.message}`;
1252
+ const ZstdCodec = getJSModuleOrNull("zstd-codec");
1253
+ if (!zstdPromise && ZstdCodec) {
1254
+ zstdPromise = new Promise((resolve) => ZstdCodec.run((zstd2) => resolve(zstd2)));
1255
+ }
1256
+ if (zstdPromise) {
1257
+ zstd = await zstdPromise;
1170
1258
  }
1171
- return error;
1172
1259
  }
1173
- };
1174
- Compressor = class extends CompressionTransform {
1175
- constructor(options) {
1176
- super();
1177
- this.compressBatches = this.compressBatches.bind(this);
1260
+ compressSync(input) {
1261
+ getJSModule("zstd-codec", this.name);
1262
+ const simpleZstd = new zstd.Simple();
1263
+ const inputArray = new Uint8Array(input);
1264
+ return simpleZstd.compress(inputArray).buffer;
1178
1265
  }
1179
- /** Asynchronously compresses data. */
1180
1266
  async compress(input) {
1267
+ var _a;
1268
+ if (this.options.useNative !== false && ((_a = this.options.zstd) == null ? void 0 : _a.useNative) !== false) {
1269
+ const nativeOutput = await compressWithNativeCompressionStream(input, "zstd");
1270
+ if (nativeOutput) return nativeOutput;
1271
+ }
1181
1272
  await this.preload();
1182
1273
  return this.compressSync(input);
1183
1274
  }
1184
- /** Synchronously compresses data. */
1185
- compressSync(input) {
1186
- throw new Error(`${this.name}: sync compression not supported`);
1187
- }
1188
- /** Compresses batches. */
1189
- async *compressBatches(asyncIterator) {
1190
- const input = await this.concatenate(asyncIterator);
1191
- yield this.compress(input);
1192
- }
1193
- };
1194
- Decompressor = class extends CompressionTransform {
1195
- constructor(options) {
1196
- super();
1197
- this.decompressBatches = this.decompressBatches.bind(this);
1275
+ decompressSync(input) {
1276
+ getJSModule("zstd-codec", this.name);
1277
+ const simpleZstd = new zstd.Simple();
1278
+ const inputArray = new Uint8Array(input);
1279
+ return simpleZstd.decompress(inputArray).buffer;
1198
1280
  }
1199
- /** Asynchronously decompresses data. */
1200
1281
  async decompress(input, size) {
1282
+ var _a;
1283
+ if (!getJSModuleOrNull("zstd-codec") && this.options.useNative !== false && ((_a = this.options.zstd) == null ? void 0 : _a.useNative) !== false) {
1284
+ const nativeOutput = await decompressWithNativeDecompressionStream(input, "zstd");
1285
+ if (nativeOutput) return nativeOutput;
1286
+ }
1201
1287
  await this.preload();
1202
- return this.decompressSync(input, size);
1203
- }
1204
- /** Synchronously decompresses data. */
1205
- decompressSync(input, size) {
1206
- throw new Error(`${this.name}: sync decompression not supported`);
1207
- }
1208
- /** Decompresses batches. */
1209
- async *decompressBatches(asyncIterator) {
1210
- const input = await this.concatenate(asyncIterator);
1211
- yield this.decompress(input);
1288
+ const inputArray = new Uint8Array(input);
1289
+ if (!zstd) {
1290
+ const { decompressZstd: decompressZstd2 } = await Promise.resolve().then(() => (init_zstd_fallback(), zstd_fallback_exports));
1291
+ return ensureArrayBuffer(decompressZstd2(inputArray));
1292
+ }
1293
+ const simpleZstd = new zstd.Streaming();
1294
+ const chunks = [];
1295
+ for (let i = 0; i <= inputArray.length; i += CHUNK_SIZE) {
1296
+ const chunkView = inputArray.subarray(i, i + CHUNK_SIZE);
1297
+ const chunkArrayBuffer = ensureArrayBuffer(chunkView);
1298
+ chunks.push(new Uint8Array(chunkArrayBuffer));
1299
+ }
1300
+ const decompressResult = await simpleZstd.decompressChunks(chunks);
1301
+ return decompressResult.buffer;
1212
1302
  }
1213
1303
  };
1214
- Compression = class extends Compressor {
1215
- constructor(options) {
1304
+ }
1305
+ });
1306
+
1307
+ // ../compression/src/zstd-decompressor.ts
1308
+ var zstd_decompressor_exports = {};
1309
+ __export(zstd_decompressor_exports, {
1310
+ ZstdDecompressor: () => ZstdDecompressor
1311
+ });
1312
+ var ZstdDecompressor;
1313
+ var init_zstd_decompressor = __esm({
1314
+ "../compression/src/zstd-decompressor.ts"() {
1315
+ "use strict";
1316
+ init_zstd_decompressor_fzstd();
1317
+ init_decompression_stream();
1318
+ init_src();
1319
+ ZstdDecompressor = class extends ZstdFzstdDecompressor {
1320
+ options;
1321
+ compatibility = null;
1322
+ constructor(options = {}) {
1216
1323
  super(options);
1217
- this.decompressBatches = this.decompressBatches.bind(this);
1324
+ this.options = options;
1325
+ registerJSModules(options.modules);
1218
1326
  }
1219
- /** Asynchronously decompresses data. */
1220
- async decompress(input, size) {
1221
- await this.preload();
1222
- return this.decompressSync(input, size);
1327
+ /** Preloads an injected zstd-codec implementation when supplied. */
1328
+ async preload(modules = {}) {
1329
+ registerJSModules(modules);
1330
+ if (getJSModuleOrNull("zstd-codec")) {
1331
+ const { ZstdCompression: ZstdCompression2 } = await Promise.resolve().then(() => (init_zstd_compression(), zstd_compression_exports));
1332
+ this.compatibility ||= new ZstdCompression2(this.options);
1333
+ await this.compatibility.preload(modules);
1334
+ }
1223
1335
  }
1224
- /** Synchronously decompresses data. */
1225
- decompressSync(input, size) {
1226
- throw new Error(`${this.name}: sync decompression not supported`);
1336
+ /** Decompresses with the built-in stream when available, then falls back to fzstd. */
1337
+ async decompress(input) {
1338
+ if (this.options.useNative !== false) {
1339
+ const output = await decompressWithNativeDecompressionStream(input, "zstd");
1340
+ if (output) return output;
1341
+ }
1342
+ if (getJSModuleOrNull("zstd-codec")) {
1343
+ await this.preload(this.options.modules);
1344
+ }
1345
+ return this.decompressSync(input);
1227
1346
  }
1228
- /** Decompresses batches. */
1229
- async *decompressBatches(asyncIterator) {
1230
- const input = await this.concatenate(asyncIterator);
1231
- yield this.decompress(input);
1347
+ /** Decompresses with a preloaded zstd-codec implementation or compact fzstd. */
1348
+ decompressSync(input) {
1349
+ if (this.compatibility) {
1350
+ return this.compatibility.decompressSync(input);
1351
+ }
1352
+ if (getJSModuleOrNull("zstd-codec")) {
1353
+ throw new Error("zstd: call preload() before synchronous decompression with zstd-codec");
1354
+ }
1355
+ return super.decompressSync(input);
1356
+ }
1357
+ /** Decompresses batches with a built-in stream or compact fzstd fallback. */
1358
+ async *decompressBatches(inputBatches) {
1359
+ if (this.options.useNative !== false) {
1360
+ const output = decompressBatchesWithNativeDecompressionStream(inputBatches, "zstd");
1361
+ if (output) {
1362
+ yield* output;
1363
+ return;
1364
+ }
1365
+ }
1366
+ if (getJSModuleOrNull("zstd-codec")) {
1367
+ yield this.decompress(await this.concatenate(inputBatches));
1368
+ return;
1369
+ }
1370
+ yield* super.decompressBatches(inputBatches);
1232
1371
  }
1233
1372
  };
1234
1373
  }
1235
1374
  });
1236
1375
 
1237
- // ../compression/src/lib/compression-stream.ts
1238
- async function compressWithNativeCompressionStream(input, format) {
1239
- const outputBatches = compressBatchesWithNativeCompressionStream([input], format);
1240
- return outputBatches ? await concatenateBatches(outputBatches) : null;
1241
- }
1242
- function compressBatchesWithNativeCompressionStream(inputBatches, format) {
1243
- const compressionStream = createNativeCompressionStream(format);
1244
- return compressionStream ? transformBatches(inputBatches, compressionStream) : null;
1245
- }
1246
- function createNativeCompressionStream(format) {
1247
- if (typeof globalThis.CompressionStream === "undefined") {
1248
- return null;
1376
+ // ../compression/src/default-codecs.ts
1377
+ var GZIP, ZSTD, GZipDecompressor2, ZstdDecompressor2;
1378
+ var init_default_codecs = __esm({
1379
+ "../compression/src/default-codecs.ts"() {
1380
+ "use strict";
1381
+ init_lazy_compression();
1382
+ init_src();
1383
+ GZIP = { name: "gzip", extensions: ["gz"], contentEncodings: ["gzip"] };
1384
+ ZSTD = { name: "zstd", extensions: ["zst"], contentEncodings: ["zstd"] };
1385
+ GZipDecompressor2 = class extends LazyDecompressor {
1386
+ constructor(options = {}) {
1387
+ super(
1388
+ GZIP,
1389
+ async () => (await Promise.resolve().then(() => (init_gzip_decompressor(), gzip_decompressor_exports))).GZipDecompressor,
1390
+ options,
1391
+ "gzip"
1392
+ );
1393
+ }
1394
+ };
1395
+ ZstdDecompressor2 = class extends LazyDecompressor {
1396
+ constructor(options = {}) {
1397
+ super(
1398
+ ZSTD,
1399
+ async () => (await Promise.resolve().then(() => (init_zstd_decompressor(), zstd_decompressor_exports))).ZstdDecompressor,
1400
+ options,
1401
+ "zstd",
1402
+ (preloadOptions) => {
1403
+ var _a;
1404
+ return !((_a = preloadOptions.modules) == null ? void 0 : _a["zstd-codec"]) && !getJSModuleOrNull("zstd-codec");
1405
+ }
1406
+ );
1407
+ }
1408
+ };
1249
1409
  }
1250
- try {
1251
- const CompressionStreamConstructor = globalThis.CompressionStream;
1252
- return new CompressionStreamConstructor(format);
1253
- } catch (error) {
1254
- if (error instanceof TypeError || (error == null ? void 0 : error.name) === "TypeError") {
1255
- return null;
1256
- }
1257
- throw error;
1410
+ });
1411
+
1412
+ // ../compression/src/index.ts
1413
+ var init_src2 = __esm({
1414
+ "../compression/src/index.ts"() {
1415
+ "use strict";
1416
+ init_default_codecs();
1258
1417
  }
1418
+ });
1419
+
1420
+ // dist/lib/splat-utils.js
1421
+ function convertColorByteToSphericalHarmonicDc(colorByte) {
1422
+ return (colorByte / 255 - 0.5) / SH_C0;
1259
1423
  }
1260
- async function* transformBatches(inputBatches, compressionStream) {
1261
- const writer = compressionStream.writable.getWriter();
1262
- const reader = compressionStream.readable.getReader();
1263
- const writePromise = writeBatches(inputBatches, writer);
1264
- writePromise.catch(() => {
1265
- });
1266
- let outputCompleted = false;
1267
- try {
1268
- while (true) {
1269
- const { done, value } = await reader.read();
1270
- if (done) {
1271
- outputCompleted = true;
1272
- break;
1273
- }
1274
- yield new Uint8Array(value).buffer;
1275
- }
1276
- await writePromise;
1277
- } finally {
1278
- if (!outputCompleted) {
1279
- await reader.cancel().catch(() => {
1280
- });
1281
- await writer.abort().catch(() => {
1282
- });
1283
- await writePromise.catch(() => {
1284
- });
1285
- }
1286
- reader.releaseLock();
1287
- }
1424
+ function convertAlphaByteToLinearOpacity(alphaByte) {
1425
+ return Math.min(Math.max(alphaByte / 255, 0), 1);
1288
1426
  }
1289
- async function writeBatches(inputBatches, writer) {
1290
- try {
1291
- for await (const inputBatch of inputBatches) {
1292
- await writer.write(new Uint8Array(inputBatch));
1293
- }
1294
- await writer.close();
1295
- } catch (error) {
1296
- await writer.abort(error).catch(() => {
1297
- });
1298
- throw error;
1427
+ function normalizeQuaternion(w, x, y, z2) {
1428
+ const length = Math.hypot(w, x, y, z2);
1429
+ if (!Number.isFinite(length) || length <= Number.EPSILON) {
1430
+ return [1, 0, 0, 0];
1299
1431
  }
1432
+ return [w / length, x / length, y / length, z2 / length];
1300
1433
  }
1301
- async function concatenateBatches(batches) {
1302
- const output = [];
1303
- let byteLength = 0;
1304
- for await (const batch of batches) {
1305
- const bytes = new Uint8Array(batch);
1306
- output.push(bytes);
1307
- byteLength += bytes.byteLength;
1434
+ function decodeQuaternionByte(byte) {
1435
+ return (byte - 128) / 128;
1436
+ }
1437
+ function decodeFloat16(value) {
1438
+ const sign = value & 32768 ? -1 : 1;
1439
+ const exponent = value >> 10 & 31;
1440
+ const fraction = value & 1023;
1441
+ if (exponent === 0) {
1442
+ return sign * Math.pow(2, -14) * (fraction / 1024);
1308
1443
  }
1309
- const result = new Uint8Array(byteLength);
1310
- let offset = 0;
1311
- for (const batch of output) {
1312
- result.set(batch, offset);
1313
- offset += batch.byteLength;
1444
+ if (exponent === 31) {
1445
+ return fraction ? Number.NaN : sign * Number.POSITIVE_INFINITY;
1314
1446
  }
1315
- return result.buffer;
1447
+ return sign * Math.pow(2, exponent - 15) * (1 + fraction / 1024);
1316
1448
  }
1317
- var init_compression_stream = __esm({
1318
- "../compression/src/lib/compression-stream.ts"() {
1449
+ var SH_C0;
1450
+ var init_splat_utils = __esm({
1451
+ "dist/lib/splat-utils.js"() {
1319
1452
  "use strict";
1453
+ SH_C0 = 0.28209479177387814;
1320
1454
  }
1321
1455
  });
1322
1456
 
1323
- // ../compression/src/lib/decompression-stream.ts
1324
- async function decompressWithNativeDecompressionStream(input, format) {
1325
- const outputBatches = decompressBatchesWithNativeDecompressionStream([input], format);
1326
- return outputBatches ? await concatenateNativeDecompressionBatches(outputBatches) : null;
1327
- }
1328
- function decompressBatchesWithNativeDecompressionStream(inputBatches, format) {
1329
- const decompressionStream = createNativeDecompressionStream(format);
1330
- return decompressionStream ? transformBatchesWithNativeDecompressionStream(inputBatches, decompressionStream) : null;
1331
- }
1332
- function isNativeDecompressionSupported(format) {
1333
- return Boolean(createNativeDecompressionStream(format));
1334
- }
1335
- function createNativeDecompressionStream(format) {
1336
- var _a, _b;
1337
- if (typeof globalThis.DecompressionStream === "undefined") {
1338
- return null;
1339
- }
1340
- if (((_b = (_a = globalThis.process) == null ? void 0 : _a.release) == null ? void 0 : _b.name) === "node" && typeof globalThis.Buffer === "undefined") {
1341
- return null;
1342
- }
1343
- try {
1344
- const DecompressionStreamConstructor = globalThis.DecompressionStream;
1345
- return new DecompressionStreamConstructor(format);
1346
- } catch (error) {
1347
- if (error instanceof TypeError || (error == null ? void 0 : error.name) === "TypeError") {
1348
- return null;
1349
- }
1350
- throw error;
1457
+ // dist/lib/splats-arrow-table.js
1458
+ function makeGaussianSplatsArrowTable(splats) {
1459
+ const columns = {};
1460
+ const fields = [];
1461
+ const schemaFields = [];
1462
+ addColumn(columns, fields, schemaFields, "POSITION", makeFixedSizeListVector(splats.positions, 3), {
1463
+ type: "fixed-size-list",
1464
+ listSize: 3,
1465
+ children: [{ name: "value", type: "float32" }]
1466
+ });
1467
+ const colorCoefficients = getColorCoefficients(splats);
1468
+ addScalarColumn(columns, fields, schemaFields, "f_dc_0", colorCoefficients[0], {
1469
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
1470
+ "loaders_gl.gaussian_splats.component": "0",
1471
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
1472
+ });
1473
+ addScalarColumn(columns, fields, schemaFields, "f_dc_1", colorCoefficients[1], {
1474
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
1475
+ "loaders_gl.gaussian_splats.component": "1",
1476
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
1477
+ });
1478
+ addScalarColumn(columns, fields, schemaFields, "f_dc_2", colorCoefficients[2], {
1479
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
1480
+ "loaders_gl.gaussian_splats.component": "2",
1481
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
1482
+ });
1483
+ addScalarColumn(columns, fields, schemaFields, "opacity", splats.opacities, {
1484
+ "loaders_gl.gaussian_splats.semantic": "opacity",
1485
+ "loaders_gl.gaussian_splats.encoding": "linear"
1486
+ });
1487
+ addVectorComponents(columns, fields, schemaFields, "scale", splats.scales, 3, {
1488
+ "loaders_gl.gaussian_splats.semantic": "scale",
1489
+ "loaders_gl.gaussian_splats.encoding": "linear"
1490
+ });
1491
+ addVectorComponents(columns, fields, schemaFields, "rot", splats.rotations, 4, {
1492
+ "loaders_gl.gaussian_splats.semantic": "rotation",
1493
+ "loaders_gl.gaussian_splats.encoding": "quaternion"
1494
+ });
1495
+ if (splats.sphericalHarmonics && splats.sphericalHarmonicsComponentCount) {
1496
+ addSphericalHarmonicRestColumns(columns, fields, schemaFields, splats.sphericalHarmonics, splats.sphericalHarmonicsComponentCount);
1351
1497
  }
1498
+ const metadata = /* @__PURE__ */ new Map([
1499
+ ["loaders_gl.semantic_type", "gaussian-splats"],
1500
+ ["loaders_gl.gaussian_splats.version", "1"],
1501
+ ["loaders_gl.gaussian_splats.source_format", splats.format],
1502
+ ["topology", "point-list"],
1503
+ ["mode", "0"]
1504
+ ]);
1505
+ const arrowSchema = new arrow.Schema(fields, metadata);
1506
+ const schema = {
1507
+ fields: schemaFields,
1508
+ metadata: Object.fromEntries(metadata)
1509
+ };
1510
+ return {
1511
+ shape: "arrow-table",
1512
+ schema,
1513
+ data: new arrow.Table(arrowSchema, columns),
1514
+ topology: "point-list",
1515
+ loaderData: splats.loaderData
1516
+ };
1352
1517
  }
1353
- async function* transformBatchesWithNativeDecompressionStream(inputBatches, decompressionStream) {
1354
- const writer = decompressionStream.writable.getWriter();
1355
- const reader = decompressionStream.readable.getReader();
1356
- const writePromise = writeBatchesToNativeDecompressionStream(inputBatches, writer);
1357
- writePromise.catch(() => {
1358
- });
1359
- let outputCompleted = false;
1360
- try {
1361
- while (true) {
1362
- const { done, value } = await reader.read();
1363
- if (done) {
1364
- outputCompleted = true;
1365
- break;
1366
- }
1367
- yield copyExactArrayBuffer(value);
1368
- }
1369
- await writePromise;
1370
- } finally {
1371
- if (!outputCompleted) {
1372
- await reader.cancel().catch(() => {
1373
- });
1374
- await writer.abort().catch(() => {
1375
- });
1376
- await writePromise.catch(() => {
1377
- });
1518
+ function addVectorComponents(columns, fields, schemaFields, prefix, values, size, metadata) {
1519
+ for (let component = 0; component < size; component++) {
1520
+ const componentValues = new Float32Array(values.length / size);
1521
+ for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
1522
+ componentValues[rowIndex] = values[rowIndex * size + component];
1378
1523
  }
1379
- reader.releaseLock();
1524
+ addScalarColumn(columns, fields, schemaFields, `${prefix}_${component}`, componentValues, {
1525
+ ...metadata,
1526
+ "loaders_gl.gaussian_splats.component": String(component)
1527
+ });
1380
1528
  }
1381
1529
  }
1382
- async function concatenateNativeDecompressionBatches(outputBatches) {
1383
- const batches = [];
1384
- let byteLength = 0;
1385
- for await (const outputBatch of outputBatches) {
1386
- const bytes = new Uint8Array(outputBatch);
1387
- batches.push(bytes);
1388
- byteLength += bytes.byteLength;
1389
- }
1390
- const output = new Uint8Array(byteLength);
1391
- let byteOffset = 0;
1392
- for (const batch of batches) {
1393
- output.set(batch, byteOffset);
1394
- byteOffset += batch.byteLength;
1530
+ function addSphericalHarmonicRestColumns(columns, fields, schemaFields, sphericalHarmonics, componentCount) {
1531
+ for (let component = 0; component < componentCount; component++) {
1532
+ const componentValues = new Float32Array(sphericalHarmonics.length / componentCount);
1533
+ for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
1534
+ componentValues[rowIndex] = sphericalHarmonics[rowIndex * componentCount + component];
1535
+ }
1536
+ addScalarColumn(columns, fields, schemaFields, `f_rest_${component}`, componentValues, {
1537
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_rest",
1538
+ "loaders_gl.gaussian_splats.component": String(component),
1539
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
1540
+ });
1395
1541
  }
1396
- return output.buffer;
1397
1542
  }
1398
- function copyExactArrayBuffer(value) {
1399
- return new Uint8Array(value).buffer;
1543
+ function addScalarColumn(columns, fields, schemaFields, name, values, metadata) {
1544
+ addColumn(columns, fields, schemaFields, name, arrow.makeVector(values), "float32", metadata);
1400
1545
  }
1401
- async function writeBatchesToNativeDecompressionStream(inputBatches, writer) {
1402
- try {
1403
- for await (const inputBatch of inputBatches) {
1404
- await writer.write(new Uint8Array(inputBatch));
1546
+ function addColumn(columns, fields, schemaFields, name, column, schemaType, metadata = {}) {
1547
+ columns[name] = column;
1548
+ fields.push(new arrow.Field(name, column.type, false, new Map(Object.entries(metadata))));
1549
+ schemaFields.push({ name, type: schemaType, nullable: false, metadata });
1550
+ }
1551
+ function makeFixedSizeListVector(value, size) {
1552
+ const values = arrow.makeVector(value);
1553
+ const child = values.data[0];
1554
+ const type = new arrow.FixedSizeList(size, new arrow.Field("value", child.type, false));
1555
+ const data = new arrow.Data(type, 0, value.length / size, 0, {}, [child]);
1556
+ return new arrow.Vector([data]);
1557
+ }
1558
+ function getColorCoefficients(splats) {
1559
+ const rowCount = splats.splatCount;
1560
+ const fdc0 = new Float32Array(rowCount);
1561
+ const fdc1 = new Float32Array(rowCount);
1562
+ const fdc2 = new Float32Array(rowCount);
1563
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
1564
+ if (splats.sphericalHarmonicDcs) {
1565
+ fdc0[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 0];
1566
+ fdc1[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 1];
1567
+ fdc2[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 2];
1568
+ } else {
1569
+ fdc0[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 0]);
1570
+ fdc1[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 1]);
1571
+ fdc2[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 2]);
1405
1572
  }
1406
- await writer.close();
1407
- } catch (error) {
1408
- await writer.abort(error).catch(() => {
1409
- });
1410
- throw error;
1411
1573
  }
1574
+ return [fdc0, fdc1, fdc2];
1412
1575
  }
1413
- var init_decompression_stream = __esm({
1414
- "../compression/src/lib/decompression-stream.ts"() {
1576
+ var arrow;
1577
+ var init_splats_arrow_table = __esm({
1578
+ "dist/lib/splats-arrow-table.js"() {
1415
1579
  "use strict";
1580
+ arrow = __toESM(require("apache-arrow"), 1);
1581
+ init_splat_utils();
1416
1582
  }
1417
1583
  });
1418
1584
 
1419
- // ../compression/src/lib/native-decompressor.ts
1420
- var native_decompressor_exports = {};
1421
- __export(native_decompressor_exports, {
1422
- NativeDecompressor: () => NativeDecompressor
1423
- });
1424
- var NativeDecompressor;
1425
- var init_native_decompressor = __esm({
1426
- "../compression/src/lib/native-decompressor.ts"() {
1427
- "use strict";
1428
- init_compression();
1429
- init_decompression_stream();
1430
- NativeDecompressor = class extends Decompressor {
1431
- name;
1432
- extensions;
1433
- contentEncodings;
1434
- isSupported = true;
1435
- /** Runtime stream format used for every operation. */
1436
- format;
1437
- constructor(metadata, format, options = {}) {
1438
- super(options);
1439
- this.name = metadata.name;
1440
- this.extensions = [...metadata.extensions];
1441
- this.contentEncodings = [...metadata.contentEncodings];
1442
- this.format = format;
1443
- }
1444
- /** Decompresses one buffer with the runtime-provided stream. */
1445
- async decompress(input) {
1446
- const output = await decompressWithNativeDecompressionStream(input, this.format);
1447
- if (!output) throw new Error(`${this.name}: built-in decompression is no longer available`);
1448
- return output;
1449
- }
1450
- /** Decompresses batches incrementally with the runtime-provided stream. */
1451
- async *decompressBatches(inputBatches) {
1452
- const output = decompressBatchesWithNativeDecompressionStream(inputBatches, this.format);
1453
- if (!output) throw new Error(`${this.name}: built-in decompression is no longer available`);
1454
- yield* output;
1455
- }
1456
- };
1585
+ // dist/lib/parse-spz.js
1586
+ async function parseSPZ(data, options) {
1587
+ return makeGaussianSplatsArrowTable(await parseSPZToGaussianSplats(data, options));
1588
+ }
1589
+ async function parseSPZToGaussianSplats(data, options) {
1590
+ var _a, _b, _c;
1591
+ const version2 = detectSPZVersion(data);
1592
+ if (version2 === 0) {
1593
+ return await parseLegacySPZ(data, options);
1457
1594
  }
1458
- });
1459
-
1460
- // ../compression/src/lib/lazy-compression.ts
1461
- function mergeModules(options, modules) {
1462
- return { ...options, modules: { ...options.modules, ...modules } };
1595
+ if (version2 !== SPZ_VERSION) {
1596
+ throw new Error(`SPZLoader: version ${version2} is not supported.`);
1597
+ }
1598
+ const header = parseSPZHeader(data);
1599
+ const streamInfos = parseSPZStreamInfos(data, header, getSPZStreamByteLengths(header));
1600
+ const compressedStreams = streamInfos.map((streamInfo) => data.slice(streamInfo.compressedOffset, streamInfo.compressedOffset + streamInfo.compressedSize));
1601
+ const decompressor = new ZstdDecompressor2({ modules: options == null ? void 0 : options.modules });
1602
+ const streams = await Promise.all(compressedStreams.map((compressedStream, streamIndex) => decompressor.decompress(compressedStream, streamInfos[streamIndex].uncompressedSize)));
1603
+ validateSPZStreamLengths(streams, streamInfos);
1604
+ return applySPZCoordinateSystem(decodeSPZStreams(header, streams, data), ((_a = options == null ? void 0 : options.splats) == null ? void 0 : _a.sourceCoordinateSystem) ?? "RUB", ((_b = options == null ? void 0 : options.splats) == null ? void 0 : _b.targetCoordinateSystem) ?? ((_c = options == null ? void 0 : options.splats) == null ? void 0 : _c.sourceCoordinateSystem) ?? "RUB");
1463
1605
  }
1464
- var LazyDecompressor;
1465
- var init_lazy_compression = __esm({
1466
- "../compression/src/lib/lazy-compression.ts"() {
1467
- "use strict";
1468
- init_compression();
1469
- init_decompression_stream();
1470
- LazyDecompressor = class extends Decompressor {
1471
- name;
1472
- extensions;
1473
- contentEncodings;
1474
- isSupported = true;
1475
- /** Constructor options retained until a concrete implementation is selected. */
1476
- options;
1477
- /** Built-in stream format to probe, or null when the format has no built-in path. */
1478
- nativeFormat;
1479
- /** Returns whether built-in selection remains eligible for the merged preload options. */
1480
- shouldUseNative;
1481
- /** Dynamically imports the balanced fallback constructor. */
1482
- loadFallback;
1483
- /** Selected concrete implementation after preload completes. */
1484
- implementation = null;
1485
- /** Shared in-flight selection used by concurrent asynchronous calls. */
1486
- implementationPromise = null;
1487
- constructor(metadata, loadFallback, options = {}, nativeFormat = null, shouldUseNative = () => true) {
1488
- super(options);
1489
- this.name = metadata.name;
1490
- this.extensions = [...metadata.extensions];
1491
- this.contentEncodings = [...metadata.contentEncodings];
1492
- this.options = options;
1493
- this.nativeFormat = nativeFormat;
1494
- this.shouldUseNative = shouldUseNative;
1495
- this.loadFallback = loadFallback;
1496
- }
1497
- /** Selects and returns the built-in or dynamically imported fallback decompressor. */
1498
- async preload(modules = {}) {
1499
- if (this.implementation) return this.implementation;
1500
- const options = mergeModules(this.options, modules);
1501
- this.implementationPromise ||= this.loadImplementation(options);
1502
- try {
1503
- this.implementation = await this.implementationPromise;
1504
- return this.implementation;
1505
- } catch (error) {
1506
- this.implementationPromise = null;
1507
- throw error;
1508
- }
1509
- }
1510
- /** Loads the selected concrete decompressor. */
1511
- async loadImplementation(options) {
1512
- if (options.useNative !== false && this.nativeFormat && this.shouldUseNative(options) && isNativeDecompressionSupported(this.nativeFormat)) {
1513
- const { NativeDecompressor: NativeDecompressor2 } = await Promise.resolve().then(() => (init_native_decompressor(), native_decompressor_exports));
1514
- return new NativeDecompressor2(this, this.nativeFormat, options);
1515
- }
1516
- const Decompressor2 = await this.loadFallback();
1517
- const implementation = new Decompressor2({ ...options, useNative: false });
1518
- await implementation.preload(options.modules);
1519
- return implementation;
1520
- }
1521
- /** Decompresses after lazily selecting the default implementation. */
1522
- async decompress(input, size) {
1523
- return (await this.preload()).decompress(input, size);
1524
- }
1525
- /** Decompresses synchronously after an implementation has been preloaded. */
1526
- decompressSync(input, size) {
1527
- if (!this.implementation) {
1528
- throw new Error(`${this.name}: call preload() before decompressSync()`);
1529
- }
1530
- return this.implementation.decompressSync(input, size);
1531
- }
1532
- /** Decompresses batches after lazily selecting the default implementation. */
1533
- async *decompressBatches(inputBatches) {
1534
- yield* (await this.preload()).decompressBatches(inputBatches);
1606
+ function detectSPZVersion(data) {
1607
+ if (data.byteLength < 8) {
1608
+ throw new Error("SPZLoader: file must contain at least an 8-byte header.");
1609
+ }
1610
+ const bytes = new Uint8Array(data);
1611
+ if (bytes[0] === 31 && bytes[1] === 139) {
1612
+ return 0;
1613
+ }
1614
+ if (data.byteLength < SPZ_HEADER_BYTE_LENGTH) {
1615
+ throw new Error("SPZLoader: file must contain a 32-byte header.");
1616
+ }
1617
+ return new DataView(data).getUint32(4, true);
1618
+ }
1619
+ async function parseLegacySPZ(data, options) {
1620
+ var _a, _b, _c;
1621
+ const decompressed = await new GZipDecompressor2({
1622
+ modules: options == null ? void 0 : options.modules,
1623
+ useNative: true
1624
+ }).decompress(data);
1625
+ if (decompressed.byteLength < 16) {
1626
+ throw new Error("SPZLoader: legacy payload must contain a 16-byte header.");
1627
+ }
1628
+ const dataView = new DataView(decompressed);
1629
+ const header = {
1630
+ magic: dataView.getUint32(0, true),
1631
+ version: dataView.getUint32(4, true),
1632
+ numPoints: dataView.getUint32(8, true),
1633
+ shDegree: dataView.getUint8(12),
1634
+ fractionalBits: dataView.getUint8(13),
1635
+ flags: dataView.getUint8(14)
1636
+ };
1637
+ if (header.magic !== SPZ_MAGIC) {
1638
+ throw new Error("SPZLoader: NGSP magic header not found.");
1639
+ }
1640
+ if (header.version !== 2 && header.version !== 3) {
1641
+ throw new Error(`SPZLoader: version ${header.version} is not supported.`);
1642
+ }
1643
+ if (dataView.getUint8(15) !== 0) {
1644
+ throw new Error("SPZLoader: legacy header reserved byte must be zero.");
1645
+ }
1646
+ if (header.shDegree > 3) {
1647
+ throw new Error(`SPZLoader: spherical harmonics degree ${header.shDegree} is not supported.`);
1648
+ }
1649
+ const count = header.numPoints;
1650
+ const shComponentCount = getSphericalHarmonicsComponentCount(header.shDegree);
1651
+ const positionByteLength = count * 9;
1652
+ const alphaByteLength = count;
1653
+ const colorByteLength = count * 3;
1654
+ const scaleByteLength = count * 3;
1655
+ const rotationByteLength = count * (header.version === 2 ? 3 : 4);
1656
+ const shByteLength = count * shComponentCount;
1657
+ const payloadByteLength = positionByteLength + alphaByteLength + colorByteLength + scaleByteLength + rotationByteLength + shByteLength;
1658
+ if (decompressed.byteLength - 16 !== payloadByteLength) {
1659
+ throw new Error(`SPZLoader: legacy payload has ${decompressed.byteLength - 16} bytes, expected ${payloadByteLength}.`);
1660
+ }
1661
+ let offset = 16;
1662
+ const positions = new Float32Array(count * 3);
1663
+ const opacities = new Float32Array(count);
1664
+ const colors = new Uint8Array(count * 3);
1665
+ const scales = new Float32Array(count * 3);
1666
+ const rotations = new Float32Array(count * 4);
1667
+ const sphericalHarmonicDcs = new Float32Array(count * 3);
1668
+ const sphericalHarmonics = shComponentCount ? new Float32Array(count * shComponentCount) : void 0;
1669
+ decodeSPZPositions(new Uint8Array(decompressed, offset, positionByteLength), positions, header.fractionalBits);
1670
+ offset += positionByteLength;
1671
+ decodeSPZOpacities(new Uint8Array(decompressed, offset, alphaByteLength), opacities);
1672
+ offset += alphaByteLength;
1673
+ decodeSPZColors(new Uint8Array(decompressed, offset, colorByteLength), colors, sphericalHarmonicDcs);
1674
+ offset += colorByteLength;
1675
+ decodeSPZScales(new Uint8Array(decompressed, offset, scaleByteLength), scales);
1676
+ offset += scaleByteLength;
1677
+ if (header.version === 2) {
1678
+ decodeLegacySPZRotations(new Uint8Array(decompressed, offset, rotationByteLength), rotations);
1679
+ } else {
1680
+ decodeSPZRotations(new Uint8Array(decompressed, offset, rotationByteLength), rotations);
1681
+ }
1682
+ offset += rotationByteLength;
1683
+ if (sphericalHarmonics) {
1684
+ decodeSPZSphericalHarmonics(new Uint8Array(decompressed, offset, shByteLength), sphericalHarmonics);
1685
+ }
1686
+ return applySPZCoordinateSystem({
1687
+ format: "spz",
1688
+ splatCount: count,
1689
+ positions,
1690
+ scales,
1691
+ rotations,
1692
+ colors,
1693
+ sphericalHarmonicDcs,
1694
+ opacities,
1695
+ sphericalHarmonics,
1696
+ sphericalHarmonicsComponentCount: shComponentCount || void 0,
1697
+ loaderData: { ...header, legacy: true }
1698
+ }, ((_a = options == null ? void 0 : options.splats) == null ? void 0 : _a.sourceCoordinateSystem) ?? "RUB", ((_b = options == null ? void 0 : options.splats) == null ? void 0 : _b.targetCoordinateSystem) ?? ((_c = options == null ? void 0 : options.splats) == null ? void 0 : _c.sourceCoordinateSystem) ?? "RUB");
1699
+ }
1700
+ function decodeLegacySPZRotations(rotationStream, rotations) {
1701
+ for (let splatIndex = 0; splatIndex < rotations.length / 4; splatIndex++) {
1702
+ const byteOffset = splatIndex * 3;
1703
+ const x = signedByte(rotationStream[byteOffset]) / 127;
1704
+ const y = signedByte(rotationStream[byteOffset + 1]) / 127;
1705
+ const z2 = signedByte(rotationStream[byteOffset + 2]) / 127;
1706
+ const w = Math.sqrt(Math.max(0, 1 - x * x - y * y - z2 * z2));
1707
+ const normalized = normalizeQuaternion(w, x, y, z2);
1708
+ rotations.set(normalized, splatIndex * 4);
1709
+ }
1710
+ }
1711
+ function signedByte(value) {
1712
+ return value > 127 ? value - 256 : value;
1713
+ }
1714
+ function applySPZCoordinateSystem(splats, source, target) {
1715
+ if (source === target || source === "UNSPECIFIED" || target === "UNSPECIFIED") {
1716
+ return splats;
1717
+ }
1718
+ if (source === "RUB" && target === "LUF") {
1719
+ for (let index = 0; index < splats.positions.length; index += 3) {
1720
+ splats.positions[index] = -splats.positions[index];
1721
+ splats.positions[index + 2] = -splats.positions[index + 2];
1722
+ }
1723
+ for (let index = 0; index < splats.rotations.length; index += 4) {
1724
+ splats.rotations[index + 1] = -splats.rotations[index + 1];
1725
+ splats.rotations[index + 3] = -splats.rotations[index + 3];
1726
+ }
1727
+ return splats;
1728
+ }
1729
+ if (source === "LUF" && target === "RUB") {
1730
+ return applySPZCoordinateSystem(splats, "RUB", "LUF");
1731
+ }
1732
+ throw new Error(`SPZLoader: coordinate conversion ${source} -> ${target} is not supported.`);
1733
+ }
1734
+ function parseSPZHeader(data) {
1735
+ if (data.byteLength < SPZ_HEADER_BYTE_LENGTH) {
1736
+ throw new Error(`SPZLoader: file must contain a ${SPZ_HEADER_BYTE_LENGTH}-byte header.`);
1737
+ }
1738
+ const dataView = new DataView(data);
1739
+ const header = {
1740
+ magic: dataView.getUint32(0, true),
1741
+ version: dataView.getUint32(4, true),
1742
+ numPoints: dataView.getUint32(8, true),
1743
+ shDegree: dataView.getUint8(12),
1744
+ fractionalBits: dataView.getUint8(13),
1745
+ flags: dataView.getUint8(14),
1746
+ numStreams: dataView.getUint8(15),
1747
+ tocByteOffset: dataView.getUint32(16, true)
1748
+ };
1749
+ if (header.magic !== SPZ_MAGIC) {
1750
+ throw new Error("SPZLoader: NGSP magic header not found.");
1751
+ }
1752
+ if (header.version !== SPZ_VERSION) {
1753
+ throw new Error(`SPZLoader: version ${header.version} is not supported.`);
1754
+ }
1755
+ if (header.shDegree > 4) {
1756
+ throw new Error(`SPZLoader: spherical harmonics degree ${header.shDegree} is not supported.`);
1757
+ }
1758
+ if (header.tocByteOffset < SPZ_HEADER_BYTE_LENGTH || header.tocByteOffset > data.byteLength) {
1759
+ throw new Error("SPZLoader: invalid table of contents byte offset.");
1760
+ }
1761
+ return header;
1762
+ }
1763
+ function parseSPZStreamInfos(data, header, expectedUncompressedSizes) {
1764
+ if (header.numStreams !== expectedUncompressedSizes.length) {
1765
+ throw new Error(`SPZLoader: expected ${expectedUncompressedSizes.length} streams, found ${header.numStreams}.`);
1766
+ }
1767
+ const tocByteLength = header.numStreams * 16;
1768
+ const tocEnd = header.tocByteOffset + tocByteLength;
1769
+ if (tocEnd > data.byteLength) {
1770
+ throw new Error("SPZLoader: table of contents exceeds file byte length.");
1771
+ }
1772
+ const dataView = new DataView(data);
1773
+ let compressedOffset = tocEnd;
1774
+ const streamInfos = [];
1775
+ for (let streamIndex = 0; streamIndex < header.numStreams; streamIndex++) {
1776
+ const tocOffset = header.tocByteOffset + streamIndex * 16;
1777
+ const compressedSize = readSafeUint64(dataView, tocOffset);
1778
+ const uncompressedSize = readSafeUint64(dataView, tocOffset + 8);
1779
+ const expectedUncompressedSize = expectedUncompressedSizes[streamIndex];
1780
+ if (uncompressedSize !== expectedUncompressedSize) {
1781
+ throw new Error(`SPZLoader: stream ${streamIndex} has ${uncompressedSize} uncompressed bytes, expected ${expectedUncompressedSize}.`);
1782
+ }
1783
+ if (compressedOffset + compressedSize > data.byteLength) {
1784
+ throw new Error(`SPZLoader: stream ${streamIndex} exceeds file byte length.`);
1785
+ }
1786
+ streamInfos.push({ compressedSize, uncompressedSize, compressedOffset });
1787
+ compressedOffset += compressedSize;
1788
+ }
1789
+ if (compressedOffset !== data.byteLength) {
1790
+ throw new Error("SPZLoader: compressed stream byte lengths do not match file byte length.");
1791
+ }
1792
+ return streamInfos;
1793
+ }
1794
+ function readSafeUint64(dataView, byteOffset) {
1795
+ const value = dataView.getBigUint64(byteOffset, true);
1796
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
1797
+ throw new Error("SPZLoader: stream byte length exceeds Number.MAX_SAFE_INTEGER.");
1798
+ }
1799
+ return Number(value);
1800
+ }
1801
+ function getSPZStreamByteLengths(header) {
1802
+ return [
1803
+ header.numPoints * 9,
1804
+ header.numPoints,
1805
+ header.numPoints * 3,
1806
+ header.numPoints * 3,
1807
+ header.numPoints * 4,
1808
+ header.numPoints * getSphericalHarmonicsComponentCount(header.shDegree)
1809
+ ].filter((byteLength) => byteLength > 0);
1810
+ }
1811
+ function validateSPZStreamLengths(streams, streamInfos) {
1812
+ for (let streamIndex = 0; streamIndex < streams.length; streamIndex++) {
1813
+ if (streams[streamIndex].byteLength !== streamInfos[streamIndex].uncompressedSize) {
1814
+ throw new Error(`SPZLoader: decompressed stream ${streamIndex} has unexpected byte length.`);
1815
+ }
1816
+ }
1817
+ }
1818
+ function decodeSPZStreams(header, streams, sourceData) {
1819
+ const splatCount = header.numPoints;
1820
+ const positions = new Float32Array(splatCount * 3);
1821
+ const scales = new Float32Array(splatCount * 3);
1822
+ const rotations = new Float32Array(splatCount * 4);
1823
+ const colors = new Uint8Array(splatCount * 3);
1824
+ const sphericalHarmonicDcs = new Float32Array(splatCount * 3);
1825
+ const opacities = new Float32Array(splatCount);
1826
+ const sphericalHarmonicsComponentCount = getSphericalHarmonicsComponentCount(header.shDegree);
1827
+ const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
1828
+ const [positionStream, alphaStream, colorStream, scaleStream, rotationStream, sphericalHarmonicsStream] = streams.map((stream) => new Uint8Array(stream));
1829
+ decodeSPZPositions(positionStream, positions, header.fractionalBits);
1830
+ decodeSPZScales(scaleStream, scales);
1831
+ decodeSPZRotations(rotationStream, rotations);
1832
+ decodeSPZColors(colorStream, colors, sphericalHarmonicDcs);
1833
+ decodeSPZOpacities(alphaStream, opacities);
1834
+ if (sphericalHarmonics && sphericalHarmonicsStream) {
1835
+ decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics);
1836
+ }
1837
+ return {
1838
+ format: "spz",
1839
+ splatCount,
1840
+ positions,
1841
+ scales,
1842
+ rotations,
1843
+ colors,
1844
+ sphericalHarmonicDcs,
1845
+ opacities,
1846
+ sphericalHarmonics,
1847
+ sphericalHarmonicsComponentCount,
1848
+ loaderData: {
1849
+ format: "spz",
1850
+ ...header,
1851
+ antialiased: Boolean(header.flags & 1),
1852
+ extensionByteLength: getSPZExtensionByteLength(header),
1853
+ extensionBytes: getSPZExtensionBytes(sourceData, header)
1854
+ }
1855
+ };
1856
+ }
1857
+ function decodeSPZPositions(positionStream, positions, fractionalBits) {
1858
+ const scale = 1 / 2 ** fractionalBits;
1859
+ for (let componentIndex = 0; componentIndex < positions.length; componentIndex++) {
1860
+ const byteOffset = componentIndex * 3;
1861
+ let fixed32 = positionStream[byteOffset] | positionStream[byteOffset + 1] << 8 | positionStream[byteOffset + 2] << 16;
1862
+ fixed32 |= fixed32 & 8388608 ? 4278190080 : 0;
1863
+ positions[componentIndex] = fixed32 * scale;
1864
+ }
1865
+ }
1866
+ function decodeSPZScales(scaleStream, scales) {
1867
+ for (let componentIndex = 0; componentIndex < scales.length; componentIndex++) {
1868
+ scales[componentIndex] = Math.exp(scaleStream[componentIndex] / 16 - 10);
1869
+ }
1870
+ }
1871
+ function decodeSPZRotations(rotationStream, rotations) {
1872
+ for (let splatIndex = 0; splatIndex < rotations.length / 4; splatIndex++) {
1873
+ const byteOffset = splatIndex * 4;
1874
+ const component = rotationStream[byteOffset] | rotationStream[byteOffset + 1] << 8 | rotationStream[byteOffset + 2] << 16 | rotationStream[byteOffset + 3] << 24;
1875
+ const xyzw = decodeSPZQuaternion(component >>> 0);
1876
+ const [w, x, y, z2] = normalizeQuaternion(xyzw[3], xyzw[0], xyzw[1], xyzw[2]);
1877
+ const rotationOffset = splatIndex * 4;
1878
+ rotations[rotationOffset + 0] = w;
1879
+ rotations[rotationOffset + 1] = x;
1880
+ rotations[rotationOffset + 2] = y;
1881
+ rotations[rotationOffset + 3] = z2;
1882
+ }
1883
+ }
1884
+ function decodeSPZQuaternion(component) {
1885
+ const rotation = [0, 0, 0, 0];
1886
+ const largestComponent = component >>> 30;
1887
+ let remainingBits = component;
1888
+ let sumSquares = 0;
1889
+ for (let componentIndex = 3; componentIndex >= 0; componentIndex--) {
1890
+ if (componentIndex !== largestComponent) {
1891
+ const magnitude = remainingBits & SPZ_ROTATION_COMPONENT_MASK;
1892
+ const isNegative = remainingBits >>> 9 & 1;
1893
+ remainingBits >>>= 10;
1894
+ let value = SPZ_ROTATION_COMPONENT_SCALE * magnitude / SPZ_ROTATION_COMPONENT_MASK;
1895
+ if (isNegative) {
1896
+ value = -value;
1535
1897
  }
1536
- };
1898
+ rotation[componentIndex] = value;
1899
+ sumSquares += value * value;
1900
+ }
1537
1901
  }
1538
- });
1539
-
1540
- // ../compression/src/zstd-decompressor-fzstd.ts
1541
- var import_fzstd, ZstdFzstdDecompressor;
1542
- var init_zstd_decompressor_fzstd = __esm({
1543
- "../compression/src/zstd-decompressor-fzstd.ts"() {
1902
+ rotation[largestComponent] = Math.sqrt(Math.max(0, 1 - sumSquares));
1903
+ return rotation;
1904
+ }
1905
+ function decodeSPZColors(colorStream, colors, sphericalHarmonicDcs) {
1906
+ for (let componentIndex = 0; componentIndex < colors.length; componentIndex++) {
1907
+ sphericalHarmonicDcs[componentIndex] = (colorStream[componentIndex] / 255 - 0.5) / SPZ_COLOR_SCALE;
1908
+ colors[componentIndex] = normalizeColorByte(sphericalHarmonicDcs[componentIndex]);
1909
+ }
1910
+ }
1911
+ function decodeSPZOpacities(alphaStream, opacities) {
1912
+ for (let splatIndex = 0; splatIndex < opacities.length; splatIndex++) {
1913
+ opacities[splatIndex] = alphaStream[splatIndex] / 255;
1914
+ }
1915
+ }
1916
+ function decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics) {
1917
+ for (let componentIndex = 0; componentIndex < sphericalHarmonics.length; componentIndex++) {
1918
+ sphericalHarmonics[componentIndex] = (sphericalHarmonicsStream[componentIndex] - 128) / 128;
1919
+ }
1920
+ }
1921
+ function normalizeColorByte(sphericalHarmonicDc) {
1922
+ return Math.min(Math.max(Math.round((sphericalHarmonicDc * SPZ_COLOR_SCALE + 0.5) * 255), 0), 255);
1923
+ }
1924
+ function getSphericalHarmonicsComponentCount(shDegree) {
1925
+ switch (shDegree) {
1926
+ case 0:
1927
+ return 0;
1928
+ case 1:
1929
+ return 9;
1930
+ case 2:
1931
+ return 24;
1932
+ case 3:
1933
+ return 45;
1934
+ case 4:
1935
+ return 72;
1936
+ default:
1937
+ throw new Error(`SPZLoader: spherical harmonics degree ${shDegree} is not supported.`);
1938
+ }
1939
+ }
1940
+ function getSPZExtensionByteLength(header) {
1941
+ return header.flags & SPZ_EXTENSION_FLAG ? header.tocByteOffset - SPZ_HEADER_BYTE_LENGTH : 0;
1942
+ }
1943
+ function getSPZExtensionBytes(data, header) {
1944
+ const extensionByteLength = getSPZExtensionByteLength(header);
1945
+ return extensionByteLength ? new Uint8Array(data.slice(SPZ_HEADER_BYTE_LENGTH, header.tocByteOffset)) : void 0;
1946
+ }
1947
+ var SPZ_HEADER_BYTE_LENGTH, SPZ_MAGIC, SPZ_VERSION, SPZ_EXTENSION_FLAG, SPZ_COLOR_SCALE, SPZ_ROTATION_COMPONENT_SCALE, SPZ_ROTATION_COMPONENT_MASK;
1948
+ var init_parse_spz = __esm({
1949
+ "dist/lib/parse-spz.js"() {
1544
1950
  "use strict";
1545
- init_compression();
1546
- import_fzstd = require("fzstd");
1547
- ZstdFzstdDecompressor = class extends Decompressor {
1548
- name = "zstd";
1549
- extensions = ["zst"];
1550
- contentEncodings = ["zstd"];
1551
- isSupported = true;
1552
- constructor(options = {}) {
1553
- super(options);
1554
- }
1555
- /** Decompresses one Zstandard frame synchronously. */
1556
- decompressSync(input) {
1557
- return (0, import_fzstd.decompress)(new Uint8Array(input)).slice().buffer;
1558
- }
1559
- };
1951
+ init_src2();
1952
+ init_splats_arrow_table();
1953
+ init_splat_utils();
1954
+ SPZ_HEADER_BYTE_LENGTH = 32;
1955
+ SPZ_MAGIC = 1347635022;
1956
+ SPZ_VERSION = 4;
1957
+ SPZ_EXTENSION_FLAG = 2;
1958
+ SPZ_COLOR_SCALE = 0.15;
1959
+ SPZ_ROTATION_COMPONENT_SCALE = Math.SQRT1_2;
1960
+ SPZ_ROTATION_COMPONENT_MASK = (1 << 9) - 1;
1560
1961
  }
1561
1962
  });
1562
1963
 
1563
- // ../compression/src/zstd-fallback.ts
1564
- var zstd_fallback_exports = {};
1565
- __export(zstd_fallback_exports, {
1566
- decompressZstd: () => decompressZstd
1567
- });
1568
- function decompressZstd(input) {
1569
- return (0, import_fzstd2.decompress)(input);
1964
+ // dist/lib/parse-splat.js
1965
+ function parseSPLAT(data) {
1966
+ return makeGaussianSplatsArrowTable(parseSPLATToGaussianSplats(data));
1570
1967
  }
1571
- var import_fzstd2;
1572
- var init_zstd_fallback = __esm({
1573
- "../compression/src/zstd-fallback.ts"() {
1574
- "use strict";
1575
- import_fzstd2 = require("fzstd");
1968
+ function parseSPLATToGaussianSplats(data) {
1969
+ if (data.byteLength % SPLAT_ROW_BYTE_LENGTH !== 0) {
1970
+ throw new Error(`SPLATLoader: byte length must be a multiple of ${SPLAT_ROW_BYTE_LENGTH}.`);
1576
1971
  }
1577
- });
1578
-
1579
- // ../compression/src/lib/zstd-compression.ts
1580
- var zstd_compression_exports = {};
1581
- __export(zstd_compression_exports, {
1582
- ZstdCompression: () => ZstdCompression
1583
- });
1584
- var CHUNK_SIZE, zstdPromise, zstd, ZstdCompression;
1585
- var init_zstd_compression = __esm({
1586
- "../compression/src/lib/zstd-compression.ts"() {
1587
- "use strict";
1588
- init_compression();
1589
- init_src();
1590
- init_compression_stream();
1591
- init_decompression_stream();
1592
- CHUNK_SIZE = 1e6;
1593
- ZstdCompression = class extends Compression {
1594
- name = "zstd";
1595
- extensions = [];
1596
- contentEncodings = [];
1597
- isSupported = true;
1598
- options;
1599
- /**
1600
- * zstd-codec is an injectable dependency due to big size
1601
- * @param options
1602
- */
1603
- constructor(options = {}) {
1604
- super(options);
1605
- this.options = options;
1606
- registerJSModules(options == null ? void 0 : options.modules);
1607
- }
1608
- async preload(modules = {}) {
1609
- registerJSModules(modules);
1610
- const ZstdCodec = getJSModuleOrNull("zstd-codec");
1611
- if (!zstdPromise && ZstdCodec) {
1612
- zstdPromise = new Promise((resolve) => ZstdCodec.run((zstd2) => resolve(zstd2)));
1613
- }
1614
- if (zstdPromise) {
1615
- zstd = await zstdPromise;
1616
- }
1617
- }
1618
- compressSync(input) {
1619
- getJSModule("zstd-codec", this.name);
1620
- const simpleZstd = new zstd.Simple();
1621
- const inputArray = new Uint8Array(input);
1622
- return simpleZstd.compress(inputArray).buffer;
1623
- }
1624
- async compress(input) {
1625
- var _a;
1626
- if (this.options.useNative !== false && ((_a = this.options.zstd) == null ? void 0 : _a.useNative) !== false) {
1627
- const nativeOutput = await compressWithNativeCompressionStream(input, "zstd");
1628
- if (nativeOutput) return nativeOutput;
1629
- }
1630
- await this.preload();
1631
- return this.compressSync(input);
1632
- }
1633
- decompressSync(input) {
1634
- getJSModule("zstd-codec", this.name);
1635
- const simpleZstd = new zstd.Simple();
1636
- const inputArray = new Uint8Array(input);
1637
- return simpleZstd.decompress(inputArray).buffer;
1638
- }
1639
- async decompress(input, size) {
1640
- var _a;
1641
- if (!getJSModuleOrNull("zstd-codec") && this.options.useNative !== false && ((_a = this.options.zstd) == null ? void 0 : _a.useNative) !== false) {
1642
- const nativeOutput = await decompressWithNativeDecompressionStream(input, "zstd");
1643
- if (nativeOutput) return nativeOutput;
1644
- }
1645
- await this.preload();
1646
- const inputArray = new Uint8Array(input);
1647
- if (!zstd) {
1648
- const { decompressZstd: decompressZstd2 } = await Promise.resolve().then(() => (init_zstd_fallback(), zstd_fallback_exports));
1649
- return ensureArrayBuffer(decompressZstd2(inputArray));
1650
- }
1651
- const simpleZstd = new zstd.Streaming();
1652
- const chunks = [];
1653
- for (let i = 0; i <= inputArray.length; i += CHUNK_SIZE) {
1654
- const chunkView = inputArray.subarray(i, i + CHUNK_SIZE);
1655
- const chunkArrayBuffer = ensureArrayBuffer(chunkView);
1656
- chunks.push(new Uint8Array(chunkArrayBuffer));
1657
- }
1658
- const decompressResult = await simpleZstd.decompressChunks(chunks);
1659
- return decompressResult.buffer;
1660
- }
1661
- };
1972
+ const splatCount = data.byteLength / SPLAT_ROW_BYTE_LENGTH;
1973
+ const dataView = new DataView(data);
1974
+ const positions = new Float32Array(splatCount * 3);
1975
+ const scales = new Float32Array(splatCount * 3);
1976
+ const rotations = new Float32Array(splatCount * 4);
1977
+ const colors = new Uint8Array(splatCount * 3);
1978
+ const opacities = new Float32Array(splatCount);
1979
+ for (let splatIndex = 0; splatIndex < splatCount; splatIndex++) {
1980
+ const byteOffset = splatIndex * SPLAT_ROW_BYTE_LENGTH;
1981
+ const positionOffset = splatIndex * 3;
1982
+ const rotationOffset = splatIndex * 4;
1983
+ positions[positionOffset + 0] = dataView.getFloat32(byteOffset + 0, true);
1984
+ positions[positionOffset + 1] = dataView.getFloat32(byteOffset + 4, true);
1985
+ positions[positionOffset + 2] = dataView.getFloat32(byteOffset + 8, true);
1986
+ scales[positionOffset + 0] = dataView.getFloat32(byteOffset + 12, true);
1987
+ scales[positionOffset + 1] = dataView.getFloat32(byteOffset + 16, true);
1988
+ scales[positionOffset + 2] = dataView.getFloat32(byteOffset + 20, true);
1989
+ colors[positionOffset + 0] = dataView.getUint8(byteOffset + 24);
1990
+ colors[positionOffset + 1] = dataView.getUint8(byteOffset + 25);
1991
+ colors[positionOffset + 2] = dataView.getUint8(byteOffset + 26);
1992
+ opacities[splatIndex] = convertAlphaByteToLinearOpacity(dataView.getUint8(byteOffset + 27));
1993
+ const [w, x, y, z2] = normalizeQuaternion(decodeQuaternionByte(dataView.getUint8(byteOffset + 28)), decodeQuaternionByte(dataView.getUint8(byteOffset + 29)), decodeQuaternionByte(dataView.getUint8(byteOffset + 30)), decodeQuaternionByte(dataView.getUint8(byteOffset + 31)));
1994
+ rotations[rotationOffset + 0] = w;
1995
+ rotations[rotationOffset + 1] = x;
1996
+ rotations[rotationOffset + 2] = y;
1997
+ rotations[rotationOffset + 3] = z2;
1662
1998
  }
1663
- });
1664
-
1665
- // ../compression/src/zstd-decompressor.ts
1666
- var zstd_decompressor_exports = {};
1667
- __export(zstd_decompressor_exports, {
1668
- ZstdDecompressor: () => ZstdDecompressor
1669
- });
1670
- var ZstdDecompressor;
1671
- var init_zstd_decompressor = __esm({
1672
- "../compression/src/zstd-decompressor.ts"() {
1999
+ return {
2000
+ format: "splat",
2001
+ splatCount,
2002
+ positions,
2003
+ scales,
2004
+ rotations,
2005
+ colors,
2006
+ opacities,
2007
+ loaderData: {
2008
+ format: "splat",
2009
+ splatCount,
2010
+ rowByteLength: SPLAT_ROW_BYTE_LENGTH
2011
+ }
2012
+ };
2013
+ }
2014
+ var SPLAT_ROW_BYTE_LENGTH;
2015
+ var init_parse_splat = __esm({
2016
+ "dist/lib/parse-splat.js"() {
1673
2017
  "use strict";
1674
- init_zstd_decompressor_fzstd();
1675
- init_decompression_stream();
1676
- init_src();
1677
- ZstdDecompressor = class extends ZstdFzstdDecompressor {
1678
- options;
1679
- compatibility = null;
1680
- constructor(options = {}) {
1681
- super(options);
1682
- this.options = options;
1683
- registerJSModules(options.modules);
1684
- }
1685
- /** Preloads an injected zstd-codec implementation when supplied. */
1686
- async preload(modules = {}) {
1687
- registerJSModules(modules);
1688
- if (getJSModuleOrNull("zstd-codec")) {
1689
- const { ZstdCompression: ZstdCompression2 } = await Promise.resolve().then(() => (init_zstd_compression(), zstd_compression_exports));
1690
- this.compatibility ||= new ZstdCompression2(this.options);
1691
- await this.compatibility.preload(modules);
1692
- }
1693
- }
1694
- /** Decompresses with the built-in stream when available, then falls back to fzstd. */
1695
- async decompress(input) {
1696
- if (this.options.useNative !== false) {
1697
- const output = await decompressWithNativeDecompressionStream(input, "zstd");
1698
- if (output) return output;
1699
- }
1700
- if (getJSModuleOrNull("zstd-codec")) {
1701
- await this.preload(this.options.modules);
1702
- }
1703
- return this.decompressSync(input);
1704
- }
1705
- /** Decompresses with a preloaded zstd-codec implementation or compact fzstd. */
1706
- decompressSync(input) {
1707
- if (this.compatibility) {
1708
- return this.compatibility.decompressSync(input);
1709
- }
1710
- if (getJSModuleOrNull("zstd-codec")) {
1711
- throw new Error("zstd: call preload() before synchronous decompression with zstd-codec");
1712
- }
1713
- return super.decompressSync(input);
1714
- }
1715
- /** Decompresses batches with a built-in stream or compact fzstd fallback. */
1716
- async *decompressBatches(inputBatches) {
1717
- if (this.options.useNative !== false) {
1718
- const output = decompressBatchesWithNativeDecompressionStream(inputBatches, "zstd");
1719
- if (output) {
1720
- yield* output;
1721
- return;
1722
- }
1723
- }
1724
- if (getJSModuleOrNull("zstd-codec")) {
1725
- yield this.decompress(await this.concatenate(inputBatches));
1726
- return;
1727
- }
1728
- yield* super.decompressBatches(inputBatches);
1729
- }
1730
- };
2018
+ init_splats_arrow_table();
2019
+ init_splat_utils();
2020
+ SPLAT_ROW_BYTE_LENGTH = 32;
1731
2021
  }
1732
2022
  });
1733
2023
 
1734
- // ../compression/src/default-codecs.ts
1735
- var ZSTD, ZstdDecompressor2;
1736
- var init_default_codecs = __esm({
1737
- "../compression/src/default-codecs.ts"() {
1738
- "use strict";
1739
- init_lazy_compression();
1740
- init_src();
1741
- ZSTD = { name: "zstd", extensions: ["zst"], contentEncodings: ["zstd"] };
1742
- ZstdDecompressor2 = class extends LazyDecompressor {
1743
- constructor(options = {}) {
1744
- super(
1745
- ZSTD,
1746
- async () => (await Promise.resolve().then(() => (init_zstd_decompressor(), zstd_decompressor_exports))).ZstdDecompressor,
1747
- options,
1748
- "zstd",
1749
- (preloadOptions) => {
1750
- var _a;
1751
- return !((_a = preloadOptions.modules) == null ? void 0 : _a["zstd-codec"]) && !getJSModuleOrNull("zstd-codec");
1752
- }
1753
- );
1754
- }
1755
- };
1756
- }
2024
+ // dist/splat-loader.js
2025
+ var splat_loader_exports = {};
2026
+ __export(splat_loader_exports, {
2027
+ SPLATLoaderWithParser: () => SPLATLoaderWithParser
1757
2028
  });
1758
-
1759
- // ../compression/src/index.ts
1760
- var init_src2 = __esm({
1761
- "../compression/src/index.ts"() {
2029
+ var _SPLATLoaderPreload, SPLATLoaderMetadataWithoutPreload, SPLATLoaderWithParser;
2030
+ var init_splat_loader = __esm({
2031
+ "dist/splat-loader.js"() {
1762
2032
  "use strict";
1763
- init_default_codecs();
2033
+ init_parse_splat();
2034
+ init_splat_loader_types();
2035
+ ({ preload: _SPLATLoaderPreload, ...SPLATLoaderMetadataWithoutPreload } = SPLATLoader);
2036
+ SPLATLoaderWithParser = {
2037
+ ...SPLATLoaderMetadataWithoutPreload,
2038
+ parse: async (arrayBuffer) => parseSPLAT(arrayBuffer),
2039
+ parseSync: (arrayBuffer) => parseSPLAT(arrayBuffer)
2040
+ };
1764
2041
  }
1765
2042
  });
1766
2043
 
1767
- // dist/lib/parse-spz.js
1768
- async function parseSPZ(data, options) {
1769
- return makeGaussianSplatsArrowTable(await parseSPZToGaussianSplats(data, options));
1770
- }
1771
- async function parseSPZToGaussianSplats(data, options) {
1772
- const header = parseSPZHeader(data);
1773
- const streamInfos = parseSPZStreamInfos(data, header, getSPZStreamByteLengths(header));
1774
- const compressedStreams = streamInfos.map((streamInfo) => data.slice(streamInfo.compressedOffset, streamInfo.compressedOffset + streamInfo.compressedSize));
1775
- const decompressor = new ZstdDecompressor2({ modules: options == null ? void 0 : options.modules });
1776
- const streams = await Promise.all(compressedStreams.map((compressedStream, streamIndex) => decompressor.decompress(compressedStream, streamInfos[streamIndex].uncompressedSize)));
1777
- validateSPZStreamLengths(streams, streamInfos);
1778
- return decodeSPZStreams(header, streams, data);
2044
+ // dist/splat-loader-types.js
2045
+ async function preload() {
2046
+ const { SPLATLoaderWithParser: SPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_splat_loader(), splat_loader_exports));
2047
+ return SPLATLoaderWithParser2;
1779
2048
  }
1780
- function parseSPZHeader(data) {
1781
- if (data.byteLength < SPZ_HEADER_BYTE_LENGTH) {
1782
- throw new Error(`SPZLoader: file must contain a ${SPZ_HEADER_BYTE_LENGTH}-byte header.`);
1783
- }
1784
- const dataView = new DataView(data);
1785
- const header = {
1786
- magic: dataView.getUint32(0, true),
1787
- version: dataView.getUint32(4, true),
1788
- numPoints: dataView.getUint32(8, true),
1789
- shDegree: dataView.getUint8(12),
1790
- fractionalBits: dataView.getUint8(13),
1791
- flags: dataView.getUint8(14),
1792
- numStreams: dataView.getUint8(15),
1793
- tocByteOffset: dataView.getUint32(16, true)
1794
- };
1795
- if (header.magic !== SPZ_MAGIC) {
1796
- throw new Error("SPZLoader: NGSP magic header not found.");
1797
- }
1798
- if (header.version !== SPZ_VERSION) {
1799
- throw new Error(`SPZLoader: version ${header.version} is not supported.`);
1800
- }
1801
- if (header.shDegree > 4) {
1802
- throw new Error(`SPZLoader: spherical harmonics degree ${header.shDegree} is not supported.`);
1803
- }
1804
- if (header.tocByteOffset < SPZ_HEADER_BYTE_LENGTH || header.tocByteOffset > data.byteLength) {
1805
- throw new Error("SPZLoader: invalid table of contents byte offset.");
2049
+ var VERSION2, SPLATLoader;
2050
+ var init_splat_loader_types = __esm({
2051
+ "dist/splat-loader-types.js"() {
2052
+ "use strict";
2053
+ init_splats_format();
2054
+ VERSION2 = true ? "5.0.0-alpha.8" : "latest";
2055
+ SPLATLoader = {
2056
+ dataType: null,
2057
+ batchType: null,
2058
+ ...SPLATFormat,
2059
+ version: VERSION2,
2060
+ options: {
2061
+ splats: {
2062
+ shape: "arrow-table"
2063
+ }
2064
+ },
2065
+ preload
2066
+ };
1806
2067
  }
1807
- return header;
2068
+ });
2069
+
2070
+ // dist/lib/parse-ksplat.js
2071
+ function parseKSPLAT(data) {
2072
+ return makeGaussianSplatsArrowTable(parseKSPLATToGaussianSplats(data));
1808
2073
  }
1809
- function parseSPZStreamInfos(data, header, expectedUncompressedSizes) {
1810
- if (header.numStreams !== expectedUncompressedSizes.length) {
1811
- throw new Error(`SPZLoader: expected ${expectedUncompressedSizes.length} streams, found ${header.numStreams}.`);
1812
- }
1813
- const tocByteLength = header.numStreams * 16;
1814
- const tocEnd = header.tocByteOffset + tocByteLength;
1815
- if (tocEnd > data.byteLength) {
1816
- throw new Error("SPZLoader: table of contents exceeds file byte length.");
2074
+ function parseKSPLATToGaussianSplats(data) {
2075
+ if (data.byteLength < HEADER_BYTE_LENGTH) {
2076
+ throw new Error(`KSPLATLoader: file must contain a ${HEADER_BYTE_LENGTH}-byte header.`);
1817
2077
  }
1818
- const dataView = new DataView(data);
1819
- let compressedOffset = tocEnd;
1820
- const streamInfos = [];
1821
- for (let streamIndex = 0; streamIndex < header.numStreams; streamIndex++) {
1822
- const tocOffset = header.tocByteOffset + streamIndex * 16;
1823
- const compressedSize = readSafeUint64(dataView, tocOffset);
1824
- const uncompressedSize = readSafeUint64(dataView, tocOffset + 8);
1825
- const expectedUncompressedSize = expectedUncompressedSizes[streamIndex];
1826
- if (uncompressedSize !== expectedUncompressedSize) {
1827
- throw new Error(`SPZLoader: stream ${streamIndex} has ${uncompressedSize} uncompressed bytes, expected ${expectedUncompressedSize}.`);
1828
- }
1829
- if (compressedOffset + compressedSize > data.byteLength) {
1830
- throw new Error(`SPZLoader: stream ${streamIndex} exceeds file byte length.`);
2078
+ const header = parseKSPLATHeader(data);
2079
+ checkKSPLATVersion(header);
2080
+ const sections = parseKSPLATSections(data, header);
2081
+ const splatCount = getTotalSplatCount(header, sections);
2082
+ const sphericalHarmonicsComponentCount = Math.max(0, ...sections.slice(0, getActiveSectionCount(header)).map((section) => getSphericalHarmonicsComponentCount2(section.sphericalHarmonicsDegree)));
2083
+ const positions = new Float32Array(splatCount * 3);
2084
+ const scales = new Float32Array(splatCount * 3);
2085
+ const rotations = new Float32Array(splatCount * 4);
2086
+ const colors = new Uint8Array(splatCount * 3);
2087
+ const opacities = new Float32Array(splatCount);
2088
+ const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
2089
+ let outputSplatIndex = 0;
2090
+ for (const section of sections.slice(0, getActiveSectionCount(header))) {
2091
+ validateSectionBounds(data, section);
2092
+ for (let localSplatIndex = 0; localSplatIndex < section.splatCount && outputSplatIndex < splatCount; localSplatIndex++) {
2093
+ decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount);
2094
+ outputSplatIndex++;
1831
2095
  }
1832
- streamInfos.push({ compressedSize, uncompressedSize, compressedOffset });
1833
- compressedOffset += compressedSize;
1834
2096
  }
1835
- if (compressedOffset !== data.byteLength) {
1836
- throw new Error("SPZLoader: compressed stream byte lengths do not match file byte length.");
1837
- }
1838
- return streamInfos;
2097
+ return {
2098
+ format: "ksplat",
2099
+ splatCount,
2100
+ positions,
2101
+ scales,
2102
+ rotations,
2103
+ colors,
2104
+ opacities,
2105
+ sphericalHarmonics,
2106
+ sphericalHarmonicsComponentCount,
2107
+ loaderData: {
2108
+ format: "ksplat",
2109
+ ...header,
2110
+ sections: sections.slice(0, getActiveSectionCount(header)).map((section) => ({
2111
+ splatCount: section.splatCount,
2112
+ maxSplatCount: section.maxSplatCount,
2113
+ sphericalHarmonicsDegree: section.sphericalHarmonicsDegree
2114
+ }))
2115
+ }
2116
+ };
1839
2117
  }
1840
- function readSafeUint64(dataView, byteOffset) {
1841
- const value = dataView.getBigUint64(byteOffset, true);
1842
- if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
1843
- throw new Error("SPZLoader: stream byte length exceeds Number.MAX_SAFE_INTEGER.");
2118
+ function decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount) {
2119
+ const layout = COMPRESSION_LAYOUTS[header.compressionLevel];
2120
+ const splatBase = section.dataBase + section.bytesPerSplat * localSplatIndex;
2121
+ const positionOffset = outputSplatIndex * 3;
2122
+ const rotationOffset = outputSplatIndex * 4;
2123
+ const bucketCenter = getBucketCenter(data, section, localSplatIndex);
2124
+ positions[positionOffset + 0] = decodeKSPLATCenterComponent(data, splatBase, 0, header, section, bucketCenter[0]);
2125
+ positions[positionOffset + 1] = decodeKSPLATCenterComponent(data, splatBase, 1, header, section, bucketCenter[1]);
2126
+ positions[positionOffset + 2] = decodeKSPLATCenterComponent(data, splatBase, 2, header, section, bucketCenter[2]);
2127
+ scales[positionOffset + 0] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 0, header.compressionLevel);
2128
+ scales[positionOffset + 1] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 1, header.compressionLevel);
2129
+ scales[positionOffset + 2] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 2, header.compressionLevel);
2130
+ const [w, x, y, z2] = normalizeQuaternion(readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 3, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 4, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 5, header.compressionLevel), readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 6, header.compressionLevel));
2131
+ rotations[rotationOffset + 0] = w;
2132
+ rotations[rotationOffset + 1] = x;
2133
+ rotations[rotationOffset + 2] = y;
2134
+ rotations[rotationOffset + 3] = z2;
2135
+ const colorBase = splatBase + layout.colorOffsetBytes;
2136
+ const colorView = new Uint8Array(data, colorBase, 4);
2137
+ colors[positionOffset + 0] = colorView[0];
2138
+ colors[positionOffset + 1] = colorView[1];
2139
+ colors[positionOffset + 2] = colorView[2];
2140
+ opacities[outputSplatIndex] = convertAlphaByteToLinearOpacity(colorView[3]);
2141
+ if (sphericalHarmonics && sphericalHarmonicsComponentCount) {
2142
+ decodeSphericalHarmonics(data, splatBase + layout.sphericalHarmonicsOffsetBytes, header, section, outputSplatIndex, sphericalHarmonics, sphericalHarmonicsComponentCount);
1844
2143
  }
1845
- return Number(value);
1846
2144
  }
1847
- function getSPZStreamByteLengths(header) {
1848
- return [
1849
- header.numPoints * 9,
1850
- header.numPoints,
1851
- header.numPoints * 3,
1852
- header.numPoints * 3,
1853
- header.numPoints * 4,
1854
- header.numPoints * getSphericalHarmonicsComponentCount2(header.shDegree)
1855
- ].filter((byteLength) => byteLength > 0);
2145
+ function parseKSPLATHeader(data) {
2146
+ const dataView = new DataView(data, 0, HEADER_BYTE_LENGTH);
2147
+ const compressionLevel = dataView.getUint16(20, true);
2148
+ if (compressionLevel !== 0 && compressionLevel !== 1 && compressionLevel !== 2) {
2149
+ throw new Error(`KSPLATLoader: unsupported compression level ${compressionLevel}.`);
2150
+ }
2151
+ return {
2152
+ versionMajor: dataView.getUint8(0),
2153
+ versionMinor: dataView.getUint8(1),
2154
+ maxSectionCount: dataView.getUint32(4, true),
2155
+ sectionCount: dataView.getUint32(8, true),
2156
+ maxSplatCount: dataView.getUint32(12, true),
2157
+ splatCount: dataView.getUint32(16, true),
2158
+ compressionLevel,
2159
+ minSphericalHarmonicsCoeff: dataView.getFloat32(36, true) || -DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE,
2160
+ maxSphericalHarmonicsCoeff: dataView.getFloat32(40, true) || DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE
2161
+ };
1856
2162
  }
1857
- function validateSPZStreamLengths(streams, streamInfos) {
1858
- for (let streamIndex = 0; streamIndex < streams.length; streamIndex++) {
1859
- if (streams[streamIndex].byteLength !== streamInfos[streamIndex].uncompressedSize) {
1860
- throw new Error(`SPZLoader: decompressed stream ${streamIndex} has unexpected byte length.`);
1861
- }
2163
+ function checkKSPLATVersion(header) {
2164
+ if (header.versionMajor === CURRENT_MAJOR_VERSION ? header.versionMinor >= CURRENT_MINOR_VERSION : header.versionMajor > CURRENT_MAJOR_VERSION) {
2165
+ return;
1862
2166
  }
2167
+ throw new Error(`KSPLATLoader: version ${header.versionMajor}.${header.versionMinor} is not supported.`);
1863
2168
  }
1864
- function decodeSPZStreams(header, streams, sourceData) {
1865
- const splatCount = header.numPoints;
1866
- const positions = new Float32Array(splatCount * 3);
1867
- const scales = new Float32Array(splatCount * 3);
1868
- const rotations = new Float32Array(splatCount * 4);
1869
- const colors = new Uint8Array(splatCount * 3);
1870
- const sphericalHarmonicDcs = new Float32Array(splatCount * 3);
1871
- const opacities = new Float32Array(splatCount);
1872
- const sphericalHarmonicsComponentCount = getSphericalHarmonicsComponentCount2(header.shDegree);
1873
- const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
1874
- const [positionStream, alphaStream, colorStream, scaleStream, rotationStream, sphericalHarmonicsStream] = streams.map((stream) => new Uint8Array(stream));
1875
- decodeSPZPositions(positionStream, positions, header.fractionalBits);
1876
- decodeSPZScales(scaleStream, scales);
1877
- decodeSPZRotations(rotationStream, rotations);
1878
- decodeSPZColors(colorStream, colors, sphericalHarmonicDcs);
1879
- decodeSPZOpacities(alphaStream, opacities);
1880
- if (sphericalHarmonics && sphericalHarmonicsStream) {
1881
- decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics);
2169
+ function parseKSPLATSections(data, header) {
2170
+ if (data.byteLength < HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH) {
2171
+ throw new Error("KSPLATLoader: file does not contain all section headers.");
2172
+ }
2173
+ const sections = [];
2174
+ let sectionBase = HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH;
2175
+ let splatCountOffset = 0;
2176
+ for (let sectionIndex = 0; sectionIndex < header.maxSectionCount; sectionIndex++) {
2177
+ const sectionHeaderBase = HEADER_BYTE_LENGTH + sectionIndex * SECTION_HEADER_BYTE_LENGTH;
2178
+ const dataView = new DataView(data, sectionHeaderBase, SECTION_HEADER_BYTE_LENGTH);
2179
+ const splatCount = dataView.getUint32(0, true);
2180
+ const maxSplatCount = dataView.getUint32(4, true);
2181
+ const bucketSize = dataView.getUint32(8, true);
2182
+ const bucketCount = dataView.getUint32(12, true);
2183
+ const bucketBlockSize = dataView.getFloat32(16, true);
2184
+ const bucketStorageSizeBytes = dataView.getUint16(20, true);
2185
+ const compressionScaleRange = dataView.getUint32(24, true) || COMPRESSION_LAYOUTS[header.compressionLevel].scaleRange;
2186
+ const fullBucketCount = dataView.getUint32(32, true);
2187
+ const partiallyFilledBucketCount = dataView.getUint32(36, true);
2188
+ const sphericalHarmonicsDegree = dataView.getUint16(40, true);
2189
+ const bytesPerSplat = getBytesPerSplat(header.compressionLevel, sphericalHarmonicsDegree);
2190
+ const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;
2191
+ const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;
2192
+ const storageSizeBytes = bytesPerSplat * maxSplatCount + bucketsStorageSizeBytes;
2193
+ sections.push({
2194
+ bytesPerSplat,
2195
+ splatCountOffset,
2196
+ splatCount: splatCount || maxSplatCount,
2197
+ maxSplatCount,
2198
+ bucketSize,
2199
+ bucketCount,
2200
+ bucketStorageSizeBytes,
2201
+ bucketsStorageSizeBytes,
2202
+ compressionScaleRange,
2203
+ compressionScaleFactor: bucketBlockSize / 2 / compressionScaleRange,
2204
+ base: sectionBase,
2205
+ bucketsBase: sectionBase + bucketsMetaDataSizeBytes,
2206
+ dataBase: sectionBase + bucketsStorageSizeBytes,
2207
+ fullBucketCount,
2208
+ partiallyFilledBucketCount,
2209
+ sphericalHarmonicsDegree
2210
+ });
2211
+ sectionBase += storageSizeBytes;
2212
+ splatCountOffset += maxSplatCount;
1882
2213
  }
1883
- return {
1884
- format: "spz",
1885
- splatCount,
1886
- positions,
1887
- scales,
1888
- rotations,
1889
- colors,
1890
- sphericalHarmonicDcs,
1891
- opacities,
1892
- sphericalHarmonics,
1893
- sphericalHarmonicsComponentCount,
1894
- loaderData: {
1895
- format: "spz",
1896
- ...header,
1897
- antialiased: Boolean(header.flags & 1),
1898
- extensionByteLength: getSPZExtensionByteLength(header),
1899
- extensionBytes: getSPZExtensionBytes(sourceData, header)
1900
- }
1901
- };
2214
+ return sections;
1902
2215
  }
1903
- function decodeSPZPositions(positionStream, positions, fractionalBits) {
1904
- const scale = 1 / 2 ** fractionalBits;
1905
- for (let componentIndex = 0; componentIndex < positions.length; componentIndex++) {
1906
- const byteOffset = componentIndex * 3;
1907
- let fixed32 = positionStream[byteOffset] | positionStream[byteOffset + 1] << 8 | positionStream[byteOffset + 2] << 16;
1908
- fixed32 |= fixed32 & 8388608 ? 4278190080 : 0;
1909
- positions[componentIndex] = fixed32 * scale;
1910
- }
2216
+ function decodeKSPLATCenterComponent(data, splatBase, component, header, section, bucketCenter) {
2217
+ const value = readCompressedCenterValue(data, splatBase, component, header.compressionLevel);
2218
+ return header.compressionLevel >= 1 ? (value - section.compressionScaleRange) * section.compressionScaleFactor + bucketCenter : value;
1911
2219
  }
1912
- function decodeSPZScales(scaleStream, scales) {
1913
- for (let componentIndex = 0; componentIndex < scales.length; componentIndex++) {
1914
- scales[componentIndex] = Math.exp(scaleStream[componentIndex] / 16 - 10);
1915
- }
2220
+ function readCompressedCenterValue(data, byteOffset, component, compressionLevel) {
2221
+ const dataView = new DataView(data);
2222
+ return compressionLevel === 0 ? dataView.getFloat32(byteOffset + component * 4, true) : dataView.getUint16(byteOffset + component * 2, true);
1916
2223
  }
1917
- function decodeSPZRotations(rotationStream, rotations) {
1918
- for (let splatIndex = 0; splatIndex < rotations.length / 4; splatIndex++) {
1919
- const byteOffset = splatIndex * 4;
1920
- const component = rotationStream[byteOffset] | rotationStream[byteOffset + 1] << 8 | rotationStream[byteOffset + 2] << 16 | rotationStream[byteOffset + 3] << 24;
1921
- const xyzw = decodeSPZQuaternion(component >>> 0);
1922
- const [w, x, y, z2] = normalizeQuaternion(xyzw[3], xyzw[0], xyzw[1], xyzw[2]);
1923
- const rotationOffset = splatIndex * 4;
1924
- rotations[rotationOffset + 0] = w;
1925
- rotations[rotationOffset + 1] = x;
1926
- rotations[rotationOffset + 2] = y;
1927
- rotations[rotationOffset + 3] = z2;
2224
+ function getBucketCenter(data, section, localSplatIndex) {
2225
+ if (!section.bucketCount) {
2226
+ return [0, 0, 0];
1928
2227
  }
2228
+ const bucketIndex = getBucketIndex(data, section, localSplatIndex);
2229
+ const bucketBase = section.bucketsBase + bucketIndex * section.bucketStorageSizeBytes;
2230
+ const dataView = new DataView(data, bucketBase, 12);
2231
+ return [dataView.getFloat32(0, true), dataView.getFloat32(4, true), dataView.getFloat32(8, true)];
1929
2232
  }
1930
- function decodeSPZQuaternion(component) {
1931
- const rotation = [0, 0, 0, 0];
1932
- const largestComponent = component >>> 30;
1933
- let remainingBits = component;
1934
- let sumSquares = 0;
1935
- for (let componentIndex = 3; componentIndex >= 0; componentIndex--) {
1936
- if (componentIndex !== largestComponent) {
1937
- const magnitude = remainingBits & SPZ_ROTATION_COMPONENT_MASK;
1938
- const isNegative = remainingBits >>> 9 & 1;
1939
- remainingBits >>>= 10;
1940
- let value = SPZ_ROTATION_COMPONENT_SCALE * magnitude / SPZ_ROTATION_COMPONENT_MASK;
1941
- if (isNegative) {
1942
- value = -value;
1943
- }
1944
- rotation[componentIndex] = value;
1945
- sumSquares += value * value;
2233
+ function getBucketIndex(data, section, localSplatIndex) {
2234
+ const maxSplatIndexInFullBuckets = section.fullBucketCount * section.bucketSize;
2235
+ if (localSplatIndex < maxSplatIndexInFullBuckets) {
2236
+ return Math.floor(localSplatIndex / section.bucketSize);
2237
+ }
2238
+ let bucketSplatIndex = maxSplatIndexInFullBuckets;
2239
+ let bucketIndex = section.fullBucketCount;
2240
+ for (let partiallyFilledBucketIndex = 0; partiallyFilledBucketIndex < section.partiallyFilledBucketCount; partiallyFilledBucketIndex++) {
2241
+ const bucketLength = new DataView(data, section.base + partiallyFilledBucketIndex * 4, 4).getUint32(0, true);
2242
+ if (localSplatIndex < bucketSplatIndex + bucketLength) {
2243
+ return bucketIndex;
1946
2244
  }
2245
+ bucketSplatIndex += bucketLength;
2246
+ bucketIndex++;
1947
2247
  }
1948
- rotation[largestComponent] = Math.sqrt(Math.max(0, 1 - sumSquares));
1949
- return rotation;
2248
+ return Math.max(bucketIndex - 1, 0);
1950
2249
  }
1951
- function decodeSPZColors(colorStream, colors, sphericalHarmonicDcs) {
1952
- for (let componentIndex = 0; componentIndex < colors.length; componentIndex++) {
1953
- sphericalHarmonicDcs[componentIndex] = (colorStream[componentIndex] / 255 - 0.5) / SPZ_COLOR_SCALE;
1954
- colors[componentIndex] = normalizeColorByte(sphericalHarmonicDcs[componentIndex]);
2250
+ function decodeSphericalHarmonics(data, byteOffset, header, section, outputSplatIndex, output, outputComponentCount) {
2251
+ const componentCount = getSphericalHarmonicsComponentCount2(section.sphericalHarmonicsDegree);
2252
+ const componentBase = outputSplatIndex * outputComponentCount;
2253
+ for (let component = 0; component < componentCount; component++) {
2254
+ output[componentBase + component] = readCompressedFloat(data, byteOffset, component, header.compressionLevel, true, header.minSphericalHarmonicsCoeff, header.maxSphericalHarmonicsCoeff);
1955
2255
  }
1956
2256
  }
1957
- function decodeSPZOpacities(alphaStream, opacities) {
1958
- for (let splatIndex = 0; splatIndex < opacities.length; splatIndex++) {
1959
- opacities[splatIndex] = alphaStream[splatIndex] / 255;
2257
+ function readCompressedFloat(data, byteOffset, component, compressionLevel, sphericalHarmonic = false, sphericalHarmonicRangeMin = 0, sphericalHarmonicRangeMax = 0) {
2258
+ const dataView = new DataView(data);
2259
+ if (compressionLevel === 0) {
2260
+ return dataView.getFloat32(byteOffset + component * 4, true);
1960
2261
  }
1961
- }
1962
- function decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics) {
1963
- for (let componentIndex = 0; componentIndex < sphericalHarmonics.length; componentIndex++) {
1964
- sphericalHarmonics[componentIndex] = (sphericalHarmonicsStream[componentIndex] - 128) / 128;
2262
+ if (compressionLevel === 1 || !sphericalHarmonic) {
2263
+ return decodeFloat16(dataView.getUint16(byteOffset + component * 2, true));
1965
2264
  }
2265
+ const value = dataView.getUint8(byteOffset + component);
2266
+ return value / 255 * (sphericalHarmonicRangeMax - sphericalHarmonicRangeMin) + sphericalHarmonicRangeMin;
1966
2267
  }
1967
- function normalizeColorByte(sphericalHarmonicDc) {
1968
- return Math.min(Math.max(Math.round((sphericalHarmonicDc * SPZ_COLOR_SCALE + 0.5) * 255), 0), 255);
2268
+ function getBytesPerSplat(compressionLevel, sphericalHarmonicsDegree) {
2269
+ const layout = COMPRESSION_LAYOUTS[compressionLevel];
2270
+ return layout.bytesPerCenter + layout.bytesPerScale + layout.bytesPerRotation + layout.bytesPerColor + layout.bytesPerSphericalHarmonicsComponent * getSphericalHarmonicsComponentCount2(sphericalHarmonicsDegree);
1969
2271
  }
1970
- function getSphericalHarmonicsComponentCount2(shDegree) {
1971
- switch (shDegree) {
2272
+ function getSphericalHarmonicsComponentCount2(sphericalHarmonicsDegree) {
2273
+ switch (sphericalHarmonicsDegree) {
1972
2274
  case 0:
1973
2275
  return 0;
1974
2276
  case 1:
@@ -1977,33 +2279,116 @@ function getSphericalHarmonicsComponentCount2(shDegree) {
1977
2279
  return 24;
1978
2280
  case 3:
1979
2281
  return 45;
1980
- case 4:
1981
- return 72;
1982
2282
  default:
1983
- throw new Error(`SPZLoader: spherical harmonics degree ${shDegree} is not supported.`);
2283
+ throw new Error(`KSPLATLoader: unsupported spherical harmonics degree ${sphericalHarmonicsDegree}.`);
1984
2284
  }
1985
2285
  }
1986
- function getSPZExtensionByteLength(header) {
1987
- return header.flags & SPZ_EXTENSION_FLAG ? header.tocByteOffset - SPZ_HEADER_BYTE_LENGTH : 0;
2286
+ function getActiveSectionCount(header) {
2287
+ return header.sectionCount || header.maxSectionCount;
1988
2288
  }
1989
- function getSPZExtensionBytes(data, header) {
1990
- const extensionByteLength = getSPZExtensionByteLength(header);
1991
- return extensionByteLength ? new Uint8Array(data.slice(SPZ_HEADER_BYTE_LENGTH, header.tocByteOffset)) : void 0;
2289
+ function getTotalSplatCount(header, sections) {
2290
+ const sectionSplatCount = sections.slice(0, getActiveSectionCount(header)).reduce((splatCount, section) => splatCount + section.splatCount, 0);
2291
+ return header.splatCount ? Math.min(header.splatCount, sectionSplatCount || header.splatCount) : sectionSplatCount;
1992
2292
  }
1993
- var SPZ_HEADER_BYTE_LENGTH, SPZ_MAGIC, SPZ_VERSION, SPZ_EXTENSION_FLAG, SPZ_COLOR_SCALE, SPZ_ROTATION_COMPONENT_SCALE, SPZ_ROTATION_COMPONENT_MASK;
1994
- var init_parse_spz = __esm({
1995
- "dist/lib/parse-spz.js"() {
2293
+ function validateSectionBounds(data, section) {
2294
+ const requiredByteLength = section.dataBase + section.bytesPerSplat * section.splatCount;
2295
+ if (requiredByteLength > data.byteLength) {
2296
+ throw new Error("KSPLATLoader: section data extends beyond the file length.");
2297
+ }
2298
+ }
2299
+ var CURRENT_MAJOR_VERSION, CURRENT_MINOR_VERSION, HEADER_BYTE_LENGTH, SECTION_HEADER_BYTE_LENGTH, DEFAULT_SH_8BIT_COMPRESSION_RANGE, DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE, COMPRESSION_LAYOUTS;
2300
+ var init_parse_ksplat = __esm({
2301
+ "dist/lib/parse-ksplat.js"() {
1996
2302
  "use strict";
1997
- init_src2();
1998
2303
  init_splats_arrow_table();
1999
2304
  init_splat_utils();
2000
- SPZ_HEADER_BYTE_LENGTH = 32;
2001
- SPZ_MAGIC = 1347635022;
2002
- SPZ_VERSION = 4;
2003
- SPZ_EXTENSION_FLAG = 2;
2004
- SPZ_COLOR_SCALE = 0.15;
2005
- SPZ_ROTATION_COMPONENT_SCALE = Math.SQRT1_2;
2006
- SPZ_ROTATION_COMPONENT_MASK = (1 << 9) - 1;
2305
+ CURRENT_MAJOR_VERSION = 0;
2306
+ CURRENT_MINOR_VERSION = 1;
2307
+ HEADER_BYTE_LENGTH = 4096;
2308
+ SECTION_HEADER_BYTE_LENGTH = 1024;
2309
+ DEFAULT_SH_8BIT_COMPRESSION_RANGE = 3;
2310
+ DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE = DEFAULT_SH_8BIT_COMPRESSION_RANGE / 2;
2311
+ COMPRESSION_LAYOUTS = {
2312
+ 0: {
2313
+ bytesPerCenter: 12,
2314
+ bytesPerScale: 12,
2315
+ bytesPerRotation: 16,
2316
+ bytesPerColor: 4,
2317
+ scaleOffsetBytes: 12,
2318
+ colorOffsetBytes: 40,
2319
+ sphericalHarmonicsOffsetBytes: 44,
2320
+ scaleRange: 1,
2321
+ bytesPerSphericalHarmonicsComponent: 4
2322
+ },
2323
+ 1: {
2324
+ bytesPerCenter: 6,
2325
+ bytesPerScale: 6,
2326
+ bytesPerRotation: 8,
2327
+ bytesPerColor: 4,
2328
+ scaleOffsetBytes: 6,
2329
+ colorOffsetBytes: 20,
2330
+ sphericalHarmonicsOffsetBytes: 24,
2331
+ scaleRange: 32767,
2332
+ bytesPerSphericalHarmonicsComponent: 2
2333
+ },
2334
+ 2: {
2335
+ bytesPerCenter: 6,
2336
+ bytesPerScale: 6,
2337
+ bytesPerRotation: 8,
2338
+ bytesPerColor: 4,
2339
+ scaleOffsetBytes: 6,
2340
+ colorOffsetBytes: 20,
2341
+ sphericalHarmonicsOffsetBytes: 24,
2342
+ scaleRange: 32767,
2343
+ bytesPerSphericalHarmonicsComponent: 1
2344
+ }
2345
+ };
2346
+ }
2347
+ });
2348
+
2349
+ // dist/ksplat-loader.js
2350
+ var ksplat_loader_exports = {};
2351
+ __export(ksplat_loader_exports, {
2352
+ KSPLATLoaderWithParser: () => KSPLATLoaderWithParser
2353
+ });
2354
+ var _KSPLATLoaderPreload, KSPLATLoaderMetadataWithoutPreload, KSPLATLoaderWithParser;
2355
+ var init_ksplat_loader = __esm({
2356
+ "dist/ksplat-loader.js"() {
2357
+ "use strict";
2358
+ init_parse_ksplat();
2359
+ init_ksplat_loader_types();
2360
+ ({ preload: _KSPLATLoaderPreload, ...KSPLATLoaderMetadataWithoutPreload } = KSPLATLoader);
2361
+ KSPLATLoaderWithParser = {
2362
+ ...KSPLATLoaderMetadataWithoutPreload,
2363
+ parse: async (arrayBuffer) => parseKSPLAT(arrayBuffer),
2364
+ parseSync: (arrayBuffer) => parseKSPLAT(arrayBuffer)
2365
+ };
2366
+ }
2367
+ });
2368
+
2369
+ // dist/ksplat-loader-types.js
2370
+ async function preload2() {
2371
+ const { KSPLATLoaderWithParser: KSPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_ksplat_loader(), ksplat_loader_exports));
2372
+ return KSPLATLoaderWithParser2;
2373
+ }
2374
+ var VERSION3, KSPLATLoader;
2375
+ var init_ksplat_loader_types = __esm({
2376
+ "dist/ksplat-loader-types.js"() {
2377
+ "use strict";
2378
+ init_splats_format();
2379
+ VERSION3 = true ? "5.0.0-alpha.8" : "latest";
2380
+ KSPLATLoader = {
2381
+ dataType: null,
2382
+ batchType: null,
2383
+ ...KSPLATFormat,
2384
+ version: VERSION3,
2385
+ options: {
2386
+ splats: {
2387
+ shape: "arrow-table"
2388
+ }
2389
+ },
2390
+ preload: preload2
2391
+ };
2007
2392
  }
2008
2393
  });
2009
2394
 
@@ -2036,7 +2421,7 @@ var init_spz_loader_types = __esm({
2036
2421
  "dist/spz-loader-types.js"() {
2037
2422
  "use strict";
2038
2423
  init_splats_format();
2039
- VERSION4 = true ? "5.0.0-alpha.6" : "latest";
2424
+ VERSION4 = true ? "5.0.0-alpha.8" : "latest";
2040
2425
  SPZLoader = {
2041
2426
  dataType: null,
2042
2427
  batchType: null,
@@ -2210,31 +2595,12 @@ var init_parse_rad = __esm({
2210
2595
  }
2211
2596
  });
2212
2597
 
2213
- // ../compression/src/lib/fflate-stream.ts
2214
- async function* transformFflateBatches(processor, inputBatches) {
2215
- const chunks = [];
2216
- processor.ondata = (data) => {
2217
- chunks.push(data.slice().buffer);
2218
- };
2219
- for await (const batch of inputBatches) {
2220
- processor.push(new Uint8Array(batch), false);
2221
- yield* chunks.splice(0);
2222
- }
2223
- processor.push(new Uint8Array(0), true);
2224
- yield* chunks;
2225
- }
2226
- var init_fflate_stream = __esm({
2227
- "../compression/src/lib/fflate-stream.ts"() {
2228
- "use strict";
2229
- }
2230
- });
2231
-
2232
2598
  // ../compression/src/deflate-decompressor-fflate.ts
2233
- var import_fflate, DeflateFflateDecompressor;
2599
+ var import_fflate2, DeflateFflateDecompressor;
2234
2600
  var init_deflate_decompressor_fflate = __esm({
2235
2601
  "../compression/src/deflate-decompressor-fflate.ts"() {
2236
2602
  "use strict";
2237
- import_fflate = require("fflate");
2603
+ import_fflate2 = require("fflate");
2238
2604
  init_compression();
2239
2605
  init_fflate_stream();
2240
2606
  DeflateFflateDecompressor = class extends Decompressor {
@@ -2250,12 +2616,12 @@ var init_deflate_decompressor_fflate = __esm({
2250
2616
  /** Decompresses one zlib-wrapped DEFLATE payload synchronously. */
2251
2617
  decompressSync(input) {
2252
2618
  const bytes = new Uint8Array(input);
2253
- const output = this.options.raw ? (0, import_fflate.inflateSync)(bytes) : (0, import_fflate.unzlibSync)(bytes);
2619
+ const output = this.options.raw ? (0, import_fflate2.inflateSync)(bytes) : (0, import_fflate2.unzlibSync)(bytes);
2254
2620
  return output.slice().buffer;
2255
2621
  }
2256
2622
  /** Decompresses DEFLATE batches incrementally. */
2257
2623
  async *decompressBatches(inputBatches) {
2258
- const processor = this.options.raw ? new import_fflate.Inflate() : new import_fflate.Unzlib();
2624
+ const processor = this.options.raw ? new import_fflate2.Inflate() : new import_fflate2.Unzlib();
2259
2625
  yield* transformFflateBatches(processor, inputBatches);
2260
2626
  }
2261
2627
  };
@@ -2806,7 +3172,7 @@ var init_rad_loader_types = __esm({
2806
3172
  "dist/rad-loader-types.js"() {
2807
3173
  "use strict";
2808
3174
  init_splats_format();
2809
- VERSION5 = true ? "5.0.0-alpha.6" : "latest";
3175
+ VERSION5 = true ? "5.0.0-alpha.8" : "latest";
2810
3176
  RADLoader = {
2811
3177
  dataType: null,
2812
3178
  batchType: null,
@@ -2831,10 +3197,13 @@ __export(index_exports, {
2831
3197
  SPLATLoader: () => SPLATLoader,
2832
3198
  SPZFormat: () => SPZFormat,
2833
3199
  SPZLoader: () => SPZLoader,
3200
+ parseSPZ: () => parseSPZ,
3201
+ parseSPZToGaussianSplats: () => parseSPZToGaussianSplats,
2834
3202
  resolveRADChunkUrl: () => resolveRADChunkUrl
2835
3203
  });
2836
3204
  module.exports = __toCommonJS(index_exports);
2837
3205
  init_splats_format();
3206
+ init_parse_spz();
2838
3207
  init_splat_loader_types();
2839
3208
  init_ksplat_loader_types();
2840
3209
  init_spz_loader_types();
@@ -2848,7 +3217,7 @@ init_parse_rad_chunk();
2848
3217
  init_splats_arrow_table();
2849
3218
  var DEFAULT_RAD_HEADER_BYTE_LENGTHS = [64 * 1024, 256 * 1024, 1024 * 1024];
2850
3219
  var DEFAULT_RAD_MAX_CONCURRENT_CHUNK_REQUESTS = 4;
2851
- var VERSION6 = true ? "5.0.0-alpha.6" : "latest";
3220
+ var VERSION6 = true ? "5.0.0-alpha.8" : "latest";
2852
3221
  var RADSourceLoader = {
2853
3222
  dataType: null,
2854
3223
  batchType: null,