@loaders.gl/splats 5.0.0-alpha.1

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.
Files changed (112) hide show
  1. package/LICENSE +41 -0
  2. package/README.md +3 -0
  3. package/dist/bundled.d.ts +2 -0
  4. package/dist/bundled.d.ts.map +1 -0
  5. package/dist/bundled.js +5 -0
  6. package/dist/bundled.js.map +1 -0
  7. package/dist/dist.dev.js +20876 -0
  8. package/dist/dist.min.js +18 -0
  9. package/dist/index.cjs +2046 -0
  10. package/dist/index.cjs.map +7 -0
  11. package/dist/index.d.ts +10 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +10 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/ksplat-loader-types.d.ts +42 -0
  16. package/dist/ksplat-loader-types.d.ts.map +1 -0
  17. package/dist/ksplat-loader-types.js +26 -0
  18. package/dist/ksplat-loader-types.js.map +1 -0
  19. package/dist/ksplat-loader.d.ts +22 -0
  20. package/dist/ksplat-loader.d.ts.map +1 -0
  21. package/dist/ksplat-loader.js +13 -0
  22. package/dist/ksplat-loader.js.map +1 -0
  23. package/dist/lib/parse-ksplat.d.ts +7 -0
  24. package/dist/lib/parse-ksplat.d.ts.map +1 -0
  25. package/dist/lib/parse-ksplat.js +312 -0
  26. package/dist/lib/parse-ksplat.js.map +1 -0
  27. package/dist/lib/parse-rad-chunk.d.ts +19 -0
  28. package/dist/lib/parse-rad-chunk.d.ts.map +1 -0
  29. package/dist/lib/parse-rad-chunk.js +514 -0
  30. package/dist/lib/parse-rad-chunk.js.map +1 -0
  31. package/dist/lib/parse-rad.d.ts +120 -0
  32. package/dist/lib/parse-rad.d.ts.map +1 -0
  33. package/dist/lib/parse-rad.js +235 -0
  34. package/dist/lib/parse-rad.js.map +1 -0
  35. package/dist/lib/parse-splat.d.ts +7 -0
  36. package/dist/lib/parse-splat.d.ts.map +1 -0
  37. package/dist/lib/parse-splat.js +58 -0
  38. package/dist/lib/parse-splat.js.map +1 -0
  39. package/dist/lib/parse-spz.d.ts +7 -0
  40. package/dist/lib/parse-spz.d.ts.map +1 -0
  41. package/dist/lib/parse-spz.js +268 -0
  42. package/dist/lib/parse-spz.js.map +1 -0
  43. package/dist/lib/splat-utils.d.ts +12 -0
  44. package/dist/lib/splat-utils.d.ts.map +1 -0
  45. package/dist/lib/splat-utils.js +38 -0
  46. package/dist/lib/splat-utils.js.map +1 -0
  47. package/dist/lib/splats-arrow-table.d.ts +5 -0
  48. package/dist/lib/splats-arrow-table.d.ts.map +1 -0
  49. package/dist/lib/splats-arrow-table.js +132 -0
  50. package/dist/lib/splats-arrow-table.js.map +1 -0
  51. package/dist/rad-loader-types.d.ts +36 -0
  52. package/dist/rad-loader-types.d.ts.map +1 -0
  53. package/dist/rad-loader-types.js +22 -0
  54. package/dist/rad-loader-types.js.map +1 -0
  55. package/dist/rad-loader.d.ts +21 -0
  56. package/dist/rad-loader.d.ts.map +1 -0
  57. package/dist/rad-loader.js +15 -0
  58. package/dist/rad-loader.js.map +1 -0
  59. package/dist/rad-source-loader.d.ts +115 -0
  60. package/dist/rad-source-loader.d.ts.map +1 -0
  61. package/dist/rad-source-loader.js +338 -0
  62. package/dist/rad-source-loader.js.map +1 -0
  63. package/dist/splat-loader-types.d.ts +42 -0
  64. package/dist/splat-loader-types.d.ts.map +1 -0
  65. package/dist/splat-loader-types.js +26 -0
  66. package/dist/splat-loader-types.js.map +1 -0
  67. package/dist/splat-loader.d.ts +22 -0
  68. package/dist/splat-loader.d.ts.map +1 -0
  69. package/dist/splat-loader.js +13 -0
  70. package/dist/splat-loader.js.map +1 -0
  71. package/dist/splats-format.d.ts +43 -0
  72. package/dist/splats-format.d.ts.map +1 -0
  73. package/dist/splats-format.js +46 -0
  74. package/dist/splats-format.js.map +1 -0
  75. package/dist/spz-loader-types.d.ts +44 -0
  76. package/dist/spz-loader-types.d.ts.map +1 -0
  77. package/dist/spz-loader-types.js +26 -0
  78. package/dist/spz-loader-types.js.map +1 -0
  79. package/dist/spz-loader.d.ts +23 -0
  80. package/dist/spz-loader.d.ts.map +1 -0
  81. package/dist/spz-loader.js +12 -0
  82. package/dist/spz-loader.js.map +1 -0
  83. package/dist/types.d.ts +34 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +5 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/unbundled.d.ts +2 -0
  88. package/dist/unbundled.d.ts.map +1 -0
  89. package/dist/unbundled.js +5 -0
  90. package/dist/unbundled.js.map +1 -0
  91. package/package.json +85 -0
  92. package/src/bundled.ts +5 -0
  93. package/src/index.ts +26 -0
  94. package/src/ksplat-loader-types.ts +32 -0
  95. package/src/ksplat-loader.ts +18 -0
  96. package/src/lib/parse-ksplat.ts +538 -0
  97. package/src/lib/parse-rad-chunk.ts +721 -0
  98. package/src/lib/parse-rad.ts +439 -0
  99. package/src/lib/parse-splat.ts +77 -0
  100. package/src/lib/parse-spz.ts +368 -0
  101. package/src/lib/splat-utils.ts +49 -0
  102. package/src/lib/splats-arrow-table.ts +188 -0
  103. package/src/rad-loader-types.ts +27 -0
  104. package/src/rad-loader.ts +24 -0
  105. package/src/rad-source-loader.ts +504 -0
  106. package/src/splat-loader-types.ts +32 -0
  107. package/src/splat-loader.ts +18 -0
  108. package/src/splats-format.ts +51 -0
  109. package/src/spz-loader-types.ts +32 -0
  110. package/src/spz-loader.ts +18 -0
  111. package/src/types.ts +39 -0
  112. package/src/unbundled.ts +5 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2046 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // dist/splats-format.js
34
+ var SPLATFormat, KSPLATFormat, SPZFormat, RADFormat;
35
+ var init_splats_format = __esm({
36
+ "dist/splats-format.js"() {
37
+ "use strict";
38
+ SPLATFormat = {
39
+ name: "SPLAT",
40
+ id: "splat",
41
+ module: "splats",
42
+ format: "splat",
43
+ extensions: ["splat"],
44
+ mimeTypes: ["application/octet-stream"],
45
+ binary: true
46
+ };
47
+ KSPLATFormat = {
48
+ name: "KSPLAT",
49
+ id: "ksplat",
50
+ module: "splats",
51
+ format: "ksplat",
52
+ extensions: ["ksplat"],
53
+ mimeTypes: ["application/octet-stream"],
54
+ binary: true
55
+ };
56
+ SPZFormat = {
57
+ name: "SPZ",
58
+ id: "spz",
59
+ module: "splats",
60
+ format: "spz",
61
+ extensions: ["spz"],
62
+ mimeTypes: ["application/octet-stream"],
63
+ binary: true,
64
+ tests: [new Uint8Array([78, 71, 83, 80]).buffer]
65
+ };
66
+ RADFormat = {
67
+ name: "RAD",
68
+ id: "rad",
69
+ module: "splats",
70
+ format: "rad",
71
+ extensions: ["rad"],
72
+ mimeTypes: ["application/octet-stream"],
73
+ binary: true,
74
+ tests: [new Uint8Array([82, 65, 68, 48]).buffer]
75
+ };
76
+ }
77
+ });
78
+
79
+ // dist/lib/splat-utils.js
80
+ function convertColorByteToSphericalHarmonicDc(colorByte) {
81
+ return (colorByte / 255 - 0.5) / SH_C0;
82
+ }
83
+ function convertAlphaByteToLinearOpacity(alphaByte) {
84
+ return Math.min(Math.max(alphaByte / 255, 0), 1);
85
+ }
86
+ function normalizeQuaternion(w, x, y, z) {
87
+ const length = Math.hypot(w, x, y, z);
88
+ if (!Number.isFinite(length) || length <= Number.EPSILON) {
89
+ return [1, 0, 0, 0];
90
+ }
91
+ return [w / length, x / length, y / length, z / length];
92
+ }
93
+ function decodeQuaternionByte(byte) {
94
+ return (byte - 128) / 128;
95
+ }
96
+ function decodeFloat16(value) {
97
+ const sign = value & 32768 ? -1 : 1;
98
+ const exponent = value >> 10 & 31;
99
+ const fraction = value & 1023;
100
+ if (exponent === 0) {
101
+ return sign * Math.pow(2, -14) * (fraction / 1024);
102
+ }
103
+ if (exponent === 31) {
104
+ return fraction ? Number.NaN : sign * Number.POSITIVE_INFINITY;
105
+ }
106
+ return sign * Math.pow(2, exponent - 15) * (1 + fraction / 1024);
107
+ }
108
+ var SH_C0;
109
+ var init_splat_utils = __esm({
110
+ "dist/lib/splat-utils.js"() {
111
+ "use strict";
112
+ SH_C0 = 0.28209479177387814;
113
+ }
114
+ });
115
+
116
+ // dist/lib/splats-arrow-table.js
117
+ function makeGaussianSplatsArrowTable(splats) {
118
+ const columns = {};
119
+ const fields = [];
120
+ const schemaFields = [];
121
+ addColumn(columns, fields, schemaFields, "POSITION", makeFixedSizeListVector(splats.positions, 3), {
122
+ type: "fixed-size-list",
123
+ listSize: 3,
124
+ children: [{ name: "value", type: "float32" }]
125
+ });
126
+ const colorCoefficients = getColorCoefficients(splats);
127
+ addScalarColumn(columns, fields, schemaFields, "f_dc_0", colorCoefficients[0], {
128
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
129
+ "loaders_gl.gaussian_splats.component": "0",
130
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
131
+ });
132
+ addScalarColumn(columns, fields, schemaFields, "f_dc_1", colorCoefficients[1], {
133
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
134
+ "loaders_gl.gaussian_splats.component": "1",
135
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
136
+ });
137
+ addScalarColumn(columns, fields, schemaFields, "f_dc_2", colorCoefficients[2], {
138
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_dc",
139
+ "loaders_gl.gaussian_splats.component": "2",
140
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
141
+ });
142
+ addScalarColumn(columns, fields, schemaFields, "opacity", splats.opacities, {
143
+ "loaders_gl.gaussian_splats.semantic": "opacity",
144
+ "loaders_gl.gaussian_splats.encoding": "linear"
145
+ });
146
+ addVectorComponents(columns, fields, schemaFields, "scale", splats.scales, 3, {
147
+ "loaders_gl.gaussian_splats.semantic": "scale",
148
+ "loaders_gl.gaussian_splats.encoding": "linear"
149
+ });
150
+ addVectorComponents(columns, fields, schemaFields, "rot", splats.rotations, 4, {
151
+ "loaders_gl.gaussian_splats.semantic": "rotation",
152
+ "loaders_gl.gaussian_splats.encoding": "quaternion"
153
+ });
154
+ if (splats.sphericalHarmonics && splats.sphericalHarmonicsComponentCount) {
155
+ addSphericalHarmonicRestColumns(columns, fields, schemaFields, splats.sphericalHarmonics, splats.sphericalHarmonicsComponentCount);
156
+ }
157
+ const metadata = /* @__PURE__ */ new Map([
158
+ ["loaders_gl.semantic_type", "gaussian-splats"],
159
+ ["loaders_gl.gaussian_splats.version", "1"],
160
+ ["loaders_gl.gaussian_splats.source_format", splats.format],
161
+ ["topology", "point-list"],
162
+ ["mode", "0"]
163
+ ]);
164
+ const arrowSchema = new arrow.Schema(fields, metadata);
165
+ const schema = {
166
+ fields: schemaFields,
167
+ metadata: Object.fromEntries(metadata)
168
+ };
169
+ return {
170
+ shape: "arrow-table",
171
+ schema,
172
+ data: new arrow.Table(arrowSchema, columns),
173
+ topology: "point-list",
174
+ loaderData: splats.loaderData
175
+ };
176
+ }
177
+ function addVectorComponents(columns, fields, schemaFields, prefix, values, size, metadata) {
178
+ for (let component = 0; component < size; component++) {
179
+ const componentValues = new Float32Array(values.length / size);
180
+ for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
181
+ componentValues[rowIndex] = values[rowIndex * size + component];
182
+ }
183
+ addScalarColumn(columns, fields, schemaFields, `${prefix}_${component}`, componentValues, {
184
+ ...metadata,
185
+ "loaders_gl.gaussian_splats.component": String(component)
186
+ });
187
+ }
188
+ }
189
+ function addSphericalHarmonicRestColumns(columns, fields, schemaFields, sphericalHarmonics, componentCount) {
190
+ for (let component = 0; component < componentCount; component++) {
191
+ const componentValues = new Float32Array(sphericalHarmonics.length / componentCount);
192
+ for (let rowIndex = 0; rowIndex < componentValues.length; rowIndex++) {
193
+ componentValues[rowIndex] = sphericalHarmonics[rowIndex * componentCount + component];
194
+ }
195
+ addScalarColumn(columns, fields, schemaFields, `f_rest_${component}`, componentValues, {
196
+ "loaders_gl.gaussian_splats.semantic": "spherical_harmonic_rest",
197
+ "loaders_gl.gaussian_splats.component": String(component),
198
+ "loaders_gl.gaussian_splats.encoding": "coefficient"
199
+ });
200
+ }
201
+ }
202
+ function addScalarColumn(columns, fields, schemaFields, name, values, metadata) {
203
+ addColumn(columns, fields, schemaFields, name, arrow.makeVector(values), "float32", metadata);
204
+ }
205
+ function addColumn(columns, fields, schemaFields, name, column, schemaType, metadata = {}) {
206
+ columns[name] = column;
207
+ fields.push(new arrow.Field(name, column.type, false, new Map(Object.entries(metadata))));
208
+ schemaFields.push({ name, type: schemaType, nullable: false, metadata });
209
+ }
210
+ function makeFixedSizeListVector(value, size) {
211
+ const values = arrow.makeVector(value);
212
+ const child = values.data[0];
213
+ const type = new arrow.FixedSizeList(size, new arrow.Field("value", child.type, false));
214
+ const data = new arrow.Data(type, 0, value.length / size, 0, {}, [child]);
215
+ return new arrow.Vector([data]);
216
+ }
217
+ function getColorCoefficients(splats) {
218
+ const rowCount = splats.splatCount;
219
+ const fdc0 = new Float32Array(rowCount);
220
+ const fdc1 = new Float32Array(rowCount);
221
+ const fdc2 = new Float32Array(rowCount);
222
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
223
+ if (splats.sphericalHarmonicDcs) {
224
+ fdc0[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 0];
225
+ fdc1[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 1];
226
+ fdc2[rowIndex] = splats.sphericalHarmonicDcs[rowIndex * 3 + 2];
227
+ } else {
228
+ fdc0[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 0]);
229
+ fdc1[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 1]);
230
+ fdc2[rowIndex] = convertColorByteToSphericalHarmonicDc(splats.colors[rowIndex * 3 + 2]);
231
+ }
232
+ }
233
+ return [fdc0, fdc1, fdc2];
234
+ }
235
+ var arrow;
236
+ var init_splats_arrow_table = __esm({
237
+ "dist/lib/splats-arrow-table.js"() {
238
+ "use strict";
239
+ arrow = __toESM(require("apache-arrow"), 1);
240
+ init_splat_utils();
241
+ }
242
+ });
243
+
244
+ // dist/lib/parse-splat.js
245
+ function parseSPLAT(data) {
246
+ return makeGaussianSplatsArrowTable(parseSPLATToGaussianSplats(data));
247
+ }
248
+ function parseSPLATToGaussianSplats(data) {
249
+ if (data.byteLength % SPLAT_ROW_BYTE_LENGTH !== 0) {
250
+ throw new Error(`SPLATLoader: byte length must be a multiple of ${SPLAT_ROW_BYTE_LENGTH}.`);
251
+ }
252
+ const splatCount = data.byteLength / SPLAT_ROW_BYTE_LENGTH;
253
+ const dataView = new DataView(data);
254
+ const positions = new Float32Array(splatCount * 3);
255
+ const scales = new Float32Array(splatCount * 3);
256
+ const rotations = new Float32Array(splatCount * 4);
257
+ const colors = new Uint8Array(splatCount * 3);
258
+ const opacities = new Float32Array(splatCount);
259
+ for (let splatIndex = 0; splatIndex < splatCount; splatIndex++) {
260
+ const byteOffset = splatIndex * SPLAT_ROW_BYTE_LENGTH;
261
+ const positionOffset = splatIndex * 3;
262
+ const rotationOffset = splatIndex * 4;
263
+ positions[positionOffset + 0] = dataView.getFloat32(byteOffset + 0, true);
264
+ positions[positionOffset + 1] = dataView.getFloat32(byteOffset + 4, true);
265
+ positions[positionOffset + 2] = dataView.getFloat32(byteOffset + 8, true);
266
+ scales[positionOffset + 0] = dataView.getFloat32(byteOffset + 12, true);
267
+ scales[positionOffset + 1] = dataView.getFloat32(byteOffset + 16, true);
268
+ scales[positionOffset + 2] = dataView.getFloat32(byteOffset + 20, true);
269
+ colors[positionOffset + 0] = dataView.getUint8(byteOffset + 24);
270
+ colors[positionOffset + 1] = dataView.getUint8(byteOffset + 25);
271
+ colors[positionOffset + 2] = dataView.getUint8(byteOffset + 26);
272
+ opacities[splatIndex] = convertAlphaByteToLinearOpacity(dataView.getUint8(byteOffset + 27));
273
+ const [w, x, y, z] = normalizeQuaternion(decodeQuaternionByte(dataView.getUint8(byteOffset + 28)), decodeQuaternionByte(dataView.getUint8(byteOffset + 29)), decodeQuaternionByte(dataView.getUint8(byteOffset + 30)), decodeQuaternionByte(dataView.getUint8(byteOffset + 31)));
274
+ rotations[rotationOffset + 0] = w;
275
+ rotations[rotationOffset + 1] = x;
276
+ rotations[rotationOffset + 2] = y;
277
+ rotations[rotationOffset + 3] = z;
278
+ }
279
+ return {
280
+ format: "splat",
281
+ splatCount,
282
+ positions,
283
+ scales,
284
+ rotations,
285
+ colors,
286
+ opacities,
287
+ loaderData: {
288
+ format: "splat",
289
+ splatCount,
290
+ rowByteLength: SPLAT_ROW_BYTE_LENGTH
291
+ }
292
+ };
293
+ }
294
+ var SPLAT_ROW_BYTE_LENGTH;
295
+ var init_parse_splat = __esm({
296
+ "dist/lib/parse-splat.js"() {
297
+ "use strict";
298
+ init_splats_arrow_table();
299
+ init_splat_utils();
300
+ SPLAT_ROW_BYTE_LENGTH = 32;
301
+ }
302
+ });
303
+
304
+ // dist/splat-loader.js
305
+ var splat_loader_exports = {};
306
+ __export(splat_loader_exports, {
307
+ SPLATLoaderWithParser: () => SPLATLoaderWithParser
308
+ });
309
+ var _SPLATLoaderPreload, SPLATLoaderMetadataWithoutPreload, SPLATLoaderWithParser;
310
+ var init_splat_loader = __esm({
311
+ "dist/splat-loader.js"() {
312
+ "use strict";
313
+ init_parse_splat();
314
+ init_splat_loader_types();
315
+ ({ preload: _SPLATLoaderPreload, ...SPLATLoaderMetadataWithoutPreload } = SPLATLoader);
316
+ SPLATLoaderWithParser = {
317
+ ...SPLATLoaderMetadataWithoutPreload,
318
+ parse: async (arrayBuffer) => parseSPLAT(arrayBuffer),
319
+ parseSync: (arrayBuffer) => parseSPLAT(arrayBuffer)
320
+ };
321
+ }
322
+ });
323
+
324
+ // dist/splat-loader-types.js
325
+ async function preload() {
326
+ const { SPLATLoaderWithParser: SPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_splat_loader(), splat_loader_exports));
327
+ return SPLATLoaderWithParser2;
328
+ }
329
+ var VERSION, SPLATLoader;
330
+ var init_splat_loader_types = __esm({
331
+ "dist/splat-loader-types.js"() {
332
+ "use strict";
333
+ init_splats_format();
334
+ VERSION = true ? "5.0.0-alpha.1" : "latest";
335
+ SPLATLoader = {
336
+ dataType: null,
337
+ batchType: null,
338
+ ...SPLATFormat,
339
+ version: VERSION,
340
+ options: {
341
+ splats: {
342
+ shape: "arrow-table"
343
+ }
344
+ },
345
+ preload
346
+ };
347
+ }
348
+ });
349
+
350
+ // dist/lib/parse-ksplat.js
351
+ function parseKSPLAT(data) {
352
+ return makeGaussianSplatsArrowTable(parseKSPLATToGaussianSplats(data));
353
+ }
354
+ function parseKSPLATToGaussianSplats(data) {
355
+ if (data.byteLength < HEADER_BYTE_LENGTH) {
356
+ throw new Error(`KSPLATLoader: file must contain a ${HEADER_BYTE_LENGTH}-byte header.`);
357
+ }
358
+ const header = parseKSPLATHeader(data);
359
+ checkKSPLATVersion(header);
360
+ const sections = parseKSPLATSections(data, header);
361
+ const splatCount = getTotalSplatCount(header, sections);
362
+ const sphericalHarmonicsComponentCount = Math.max(0, ...sections.slice(0, getActiveSectionCount(header)).map((section) => getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree)));
363
+ const positions = new Float32Array(splatCount * 3);
364
+ const scales = new Float32Array(splatCount * 3);
365
+ const rotations = new Float32Array(splatCount * 4);
366
+ const colors = new Uint8Array(splatCount * 3);
367
+ const opacities = new Float32Array(splatCount);
368
+ const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
369
+ let outputSplatIndex = 0;
370
+ for (const section of sections.slice(0, getActiveSectionCount(header))) {
371
+ validateSectionBounds(data, section);
372
+ for (let localSplatIndex = 0; localSplatIndex < section.splatCount && outputSplatIndex < splatCount; localSplatIndex++) {
373
+ decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount);
374
+ outputSplatIndex++;
375
+ }
376
+ }
377
+ return {
378
+ format: "ksplat",
379
+ splatCount,
380
+ positions,
381
+ scales,
382
+ rotations,
383
+ colors,
384
+ opacities,
385
+ sphericalHarmonics,
386
+ sphericalHarmonicsComponentCount,
387
+ loaderData: {
388
+ format: "ksplat",
389
+ ...header,
390
+ sections: sections.slice(0, getActiveSectionCount(header)).map((section) => ({
391
+ splatCount: section.splatCount,
392
+ maxSplatCount: section.maxSplatCount,
393
+ sphericalHarmonicsDegree: section.sphericalHarmonicsDegree
394
+ }))
395
+ }
396
+ };
397
+ }
398
+ function decodeKSPLATSplat(data, header, section, localSplatIndex, outputSplatIndex, positions, scales, rotations, colors, opacities, sphericalHarmonics, sphericalHarmonicsComponentCount) {
399
+ const layout = COMPRESSION_LAYOUTS[header.compressionLevel];
400
+ const splatBase = section.dataBase + section.bytesPerSplat * localSplatIndex;
401
+ const positionOffset = outputSplatIndex * 3;
402
+ const rotationOffset = outputSplatIndex * 4;
403
+ const bucketCenter = getBucketCenter(data, section, localSplatIndex);
404
+ positions[positionOffset + 0] = decodeKSPLATCenterComponent(data, splatBase, 0, header, section, bucketCenter[0]);
405
+ positions[positionOffset + 1] = decodeKSPLATCenterComponent(data, splatBase, 1, header, section, bucketCenter[1]);
406
+ positions[positionOffset + 2] = decodeKSPLATCenterComponent(data, splatBase, 2, header, section, bucketCenter[2]);
407
+ scales[positionOffset + 0] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 0, header.compressionLevel);
408
+ scales[positionOffset + 1] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 1, header.compressionLevel);
409
+ scales[positionOffset + 2] = readCompressedFloat(data, splatBase + layout.scaleOffsetBytes, 2, header.compressionLevel);
410
+ const [w, x, y, z] = 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));
411
+ rotations[rotationOffset + 0] = w;
412
+ rotations[rotationOffset + 1] = x;
413
+ rotations[rotationOffset + 2] = y;
414
+ rotations[rotationOffset + 3] = z;
415
+ const colorBase = splatBase + layout.colorOffsetBytes;
416
+ const colorView = new Uint8Array(data, colorBase, 4);
417
+ colors[positionOffset + 0] = colorView[0];
418
+ colors[positionOffset + 1] = colorView[1];
419
+ colors[positionOffset + 2] = colorView[2];
420
+ opacities[outputSplatIndex] = convertAlphaByteToLinearOpacity(colorView[3]);
421
+ if (sphericalHarmonics && sphericalHarmonicsComponentCount) {
422
+ decodeSphericalHarmonics(data, splatBase + layout.sphericalHarmonicsOffsetBytes, header, section, outputSplatIndex, sphericalHarmonics, sphericalHarmonicsComponentCount);
423
+ }
424
+ }
425
+ function parseKSPLATHeader(data) {
426
+ const dataView = new DataView(data, 0, HEADER_BYTE_LENGTH);
427
+ const compressionLevel = dataView.getUint16(20, true);
428
+ if (compressionLevel !== 0 && compressionLevel !== 1 && compressionLevel !== 2) {
429
+ throw new Error(`KSPLATLoader: unsupported compression level ${compressionLevel}.`);
430
+ }
431
+ return {
432
+ versionMajor: dataView.getUint8(0),
433
+ versionMinor: dataView.getUint8(1),
434
+ maxSectionCount: dataView.getUint32(4, true),
435
+ sectionCount: dataView.getUint32(8, true),
436
+ maxSplatCount: dataView.getUint32(12, true),
437
+ splatCount: dataView.getUint32(16, true),
438
+ compressionLevel,
439
+ minSphericalHarmonicsCoeff: dataView.getFloat32(36, true) || -DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE,
440
+ maxSphericalHarmonicsCoeff: dataView.getFloat32(40, true) || DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE
441
+ };
442
+ }
443
+ function checkKSPLATVersion(header) {
444
+ if (header.versionMajor === CURRENT_MAJOR_VERSION ? header.versionMinor >= CURRENT_MINOR_VERSION : header.versionMajor > CURRENT_MAJOR_VERSION) {
445
+ return;
446
+ }
447
+ throw new Error(`KSPLATLoader: version ${header.versionMajor}.${header.versionMinor} is not supported.`);
448
+ }
449
+ function parseKSPLATSections(data, header) {
450
+ if (data.byteLength < HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH) {
451
+ throw new Error("KSPLATLoader: file does not contain all section headers.");
452
+ }
453
+ const sections = [];
454
+ let sectionBase = HEADER_BYTE_LENGTH + header.maxSectionCount * SECTION_HEADER_BYTE_LENGTH;
455
+ let splatCountOffset = 0;
456
+ for (let sectionIndex = 0; sectionIndex < header.maxSectionCount; sectionIndex++) {
457
+ const sectionHeaderBase = HEADER_BYTE_LENGTH + sectionIndex * SECTION_HEADER_BYTE_LENGTH;
458
+ const dataView = new DataView(data, sectionHeaderBase, SECTION_HEADER_BYTE_LENGTH);
459
+ const splatCount = dataView.getUint32(0, true);
460
+ const maxSplatCount = dataView.getUint32(4, true);
461
+ const bucketSize = dataView.getUint32(8, true);
462
+ const bucketCount = dataView.getUint32(12, true);
463
+ const bucketBlockSize = dataView.getFloat32(16, true);
464
+ const bucketStorageSizeBytes = dataView.getUint16(20, true);
465
+ const compressionScaleRange = dataView.getUint32(24, true) || COMPRESSION_LAYOUTS[header.compressionLevel].scaleRange;
466
+ const fullBucketCount = dataView.getUint32(32, true);
467
+ const partiallyFilledBucketCount = dataView.getUint32(36, true);
468
+ const sphericalHarmonicsDegree = dataView.getUint16(40, true);
469
+ const bytesPerSplat = getBytesPerSplat(header.compressionLevel, sphericalHarmonicsDegree);
470
+ const bucketsMetaDataSizeBytes = partiallyFilledBucketCount * 4;
471
+ const bucketsStorageSizeBytes = bucketStorageSizeBytes * bucketCount + bucketsMetaDataSizeBytes;
472
+ const storageSizeBytes = bytesPerSplat * maxSplatCount + bucketsStorageSizeBytes;
473
+ sections.push({
474
+ bytesPerSplat,
475
+ splatCountOffset,
476
+ splatCount: splatCount || maxSplatCount,
477
+ maxSplatCount,
478
+ bucketSize,
479
+ bucketCount,
480
+ bucketStorageSizeBytes,
481
+ bucketsStorageSizeBytes,
482
+ compressionScaleRange,
483
+ compressionScaleFactor: bucketBlockSize / 2 / compressionScaleRange,
484
+ base: sectionBase,
485
+ bucketsBase: sectionBase + bucketsMetaDataSizeBytes,
486
+ dataBase: sectionBase + bucketsStorageSizeBytes,
487
+ fullBucketCount,
488
+ partiallyFilledBucketCount,
489
+ sphericalHarmonicsDegree
490
+ });
491
+ sectionBase += storageSizeBytes;
492
+ splatCountOffset += maxSplatCount;
493
+ }
494
+ return sections;
495
+ }
496
+ function decodeKSPLATCenterComponent(data, splatBase, component, header, section, bucketCenter) {
497
+ const value = readCompressedCenterValue(data, splatBase, component, header.compressionLevel);
498
+ return header.compressionLevel >= 1 ? (value - section.compressionScaleRange) * section.compressionScaleFactor + bucketCenter : value;
499
+ }
500
+ function readCompressedCenterValue(data, byteOffset, component, compressionLevel) {
501
+ const dataView = new DataView(data);
502
+ return compressionLevel === 0 ? dataView.getFloat32(byteOffset + component * 4, true) : dataView.getUint16(byteOffset + component * 2, true);
503
+ }
504
+ function getBucketCenter(data, section, localSplatIndex) {
505
+ if (!section.bucketCount) {
506
+ return [0, 0, 0];
507
+ }
508
+ const bucketIndex = getBucketIndex(data, section, localSplatIndex);
509
+ const bucketBase = section.bucketsBase + bucketIndex * section.bucketStorageSizeBytes;
510
+ const dataView = new DataView(data, bucketBase, 12);
511
+ return [dataView.getFloat32(0, true), dataView.getFloat32(4, true), dataView.getFloat32(8, true)];
512
+ }
513
+ function getBucketIndex(data, section, localSplatIndex) {
514
+ const maxSplatIndexInFullBuckets = section.fullBucketCount * section.bucketSize;
515
+ if (localSplatIndex < maxSplatIndexInFullBuckets) {
516
+ return Math.floor(localSplatIndex / section.bucketSize);
517
+ }
518
+ let bucketSplatIndex = maxSplatIndexInFullBuckets;
519
+ let bucketIndex = section.fullBucketCount;
520
+ for (let partiallyFilledBucketIndex = 0; partiallyFilledBucketIndex < section.partiallyFilledBucketCount; partiallyFilledBucketIndex++) {
521
+ const bucketLength = new DataView(data, section.base + partiallyFilledBucketIndex * 4, 4).getUint32(0, true);
522
+ if (localSplatIndex < bucketSplatIndex + bucketLength) {
523
+ return bucketIndex;
524
+ }
525
+ bucketSplatIndex += bucketLength;
526
+ bucketIndex++;
527
+ }
528
+ return Math.max(bucketIndex - 1, 0);
529
+ }
530
+ function decodeSphericalHarmonics(data, byteOffset, header, section, outputSplatIndex, output, outputComponentCount) {
531
+ const componentCount = getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree);
532
+ const componentBase = outputSplatIndex * outputComponentCount;
533
+ for (let component = 0; component < componentCount; component++) {
534
+ output[componentBase + component] = readCompressedFloat(data, byteOffset, component, header.compressionLevel, true, header.minSphericalHarmonicsCoeff, header.maxSphericalHarmonicsCoeff);
535
+ }
536
+ }
537
+ function readCompressedFloat(data, byteOffset, component, compressionLevel, sphericalHarmonic = false, sphericalHarmonicRangeMin = 0, sphericalHarmonicRangeMax = 0) {
538
+ const dataView = new DataView(data);
539
+ if (compressionLevel === 0) {
540
+ return dataView.getFloat32(byteOffset + component * 4, true);
541
+ }
542
+ if (compressionLevel === 1 || !sphericalHarmonic) {
543
+ return decodeFloat16(dataView.getUint16(byteOffset + component * 2, true));
544
+ }
545
+ const value = dataView.getUint8(byteOffset + component);
546
+ return value / 255 * (sphericalHarmonicRangeMax - sphericalHarmonicRangeMin) + sphericalHarmonicRangeMin;
547
+ }
548
+ function getBytesPerSplat(compressionLevel, sphericalHarmonicsDegree) {
549
+ const layout = COMPRESSION_LAYOUTS[compressionLevel];
550
+ return layout.bytesPerCenter + layout.bytesPerScale + layout.bytesPerRotation + layout.bytesPerColor + layout.bytesPerSphericalHarmonicsComponent * getSphericalHarmonicsComponentCount(sphericalHarmonicsDegree);
551
+ }
552
+ function getSphericalHarmonicsComponentCount(sphericalHarmonicsDegree) {
553
+ switch (sphericalHarmonicsDegree) {
554
+ case 0:
555
+ return 0;
556
+ case 1:
557
+ return 9;
558
+ case 2:
559
+ return 24;
560
+ case 3:
561
+ return 45;
562
+ default:
563
+ throw new Error(`KSPLATLoader: unsupported spherical harmonics degree ${sphericalHarmonicsDegree}.`);
564
+ }
565
+ }
566
+ function getActiveSectionCount(header) {
567
+ return header.sectionCount || header.maxSectionCount;
568
+ }
569
+ function getTotalSplatCount(header, sections) {
570
+ const sectionSplatCount = sections.slice(0, getActiveSectionCount(header)).reduce((splatCount, section) => splatCount + section.splatCount, 0);
571
+ return header.splatCount ? Math.min(header.splatCount, sectionSplatCount || header.splatCount) : sectionSplatCount;
572
+ }
573
+ function validateSectionBounds(data, section) {
574
+ const requiredByteLength = section.dataBase + section.bytesPerSplat * section.splatCount;
575
+ if (requiredByteLength > data.byteLength) {
576
+ throw new Error("KSPLATLoader: section data extends beyond the file length.");
577
+ }
578
+ }
579
+ 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;
580
+ var init_parse_ksplat = __esm({
581
+ "dist/lib/parse-ksplat.js"() {
582
+ "use strict";
583
+ init_splats_arrow_table();
584
+ init_splat_utils();
585
+ CURRENT_MAJOR_VERSION = 0;
586
+ CURRENT_MINOR_VERSION = 1;
587
+ HEADER_BYTE_LENGTH = 4096;
588
+ SECTION_HEADER_BYTE_LENGTH = 1024;
589
+ DEFAULT_SH_8BIT_COMPRESSION_RANGE = 3;
590
+ DEFAULT_SH_8BIT_COMPRESSION_HALF_RANGE = DEFAULT_SH_8BIT_COMPRESSION_RANGE / 2;
591
+ COMPRESSION_LAYOUTS = {
592
+ 0: {
593
+ bytesPerCenter: 12,
594
+ bytesPerScale: 12,
595
+ bytesPerRotation: 16,
596
+ bytesPerColor: 4,
597
+ scaleOffsetBytes: 12,
598
+ colorOffsetBytes: 40,
599
+ sphericalHarmonicsOffsetBytes: 44,
600
+ scaleRange: 1,
601
+ bytesPerSphericalHarmonicsComponent: 4
602
+ },
603
+ 1: {
604
+ bytesPerCenter: 6,
605
+ bytesPerScale: 6,
606
+ bytesPerRotation: 8,
607
+ bytesPerColor: 4,
608
+ scaleOffsetBytes: 6,
609
+ colorOffsetBytes: 20,
610
+ sphericalHarmonicsOffsetBytes: 24,
611
+ scaleRange: 32767,
612
+ bytesPerSphericalHarmonicsComponent: 2
613
+ },
614
+ 2: {
615
+ bytesPerCenter: 6,
616
+ bytesPerScale: 6,
617
+ bytesPerRotation: 8,
618
+ bytesPerColor: 4,
619
+ scaleOffsetBytes: 6,
620
+ colorOffsetBytes: 20,
621
+ sphericalHarmonicsOffsetBytes: 24,
622
+ scaleRange: 32767,
623
+ bytesPerSphericalHarmonicsComponent: 1
624
+ }
625
+ };
626
+ }
627
+ });
628
+
629
+ // dist/ksplat-loader.js
630
+ var ksplat_loader_exports = {};
631
+ __export(ksplat_loader_exports, {
632
+ KSPLATLoaderWithParser: () => KSPLATLoaderWithParser
633
+ });
634
+ var _KSPLATLoaderPreload, KSPLATLoaderMetadataWithoutPreload, KSPLATLoaderWithParser;
635
+ var init_ksplat_loader = __esm({
636
+ "dist/ksplat-loader.js"() {
637
+ "use strict";
638
+ init_parse_ksplat();
639
+ init_ksplat_loader_types();
640
+ ({ preload: _KSPLATLoaderPreload, ...KSPLATLoaderMetadataWithoutPreload } = KSPLATLoader);
641
+ KSPLATLoaderWithParser = {
642
+ ...KSPLATLoaderMetadataWithoutPreload,
643
+ parse: async (arrayBuffer) => parseKSPLAT(arrayBuffer),
644
+ parseSync: (arrayBuffer) => parseKSPLAT(arrayBuffer)
645
+ };
646
+ }
647
+ });
648
+
649
+ // dist/ksplat-loader-types.js
650
+ async function preload2() {
651
+ const { KSPLATLoaderWithParser: KSPLATLoaderWithParser2 } = await Promise.resolve().then(() => (init_ksplat_loader(), ksplat_loader_exports));
652
+ return KSPLATLoaderWithParser2;
653
+ }
654
+ var VERSION2, KSPLATLoader;
655
+ var init_ksplat_loader_types = __esm({
656
+ "dist/ksplat-loader-types.js"() {
657
+ "use strict";
658
+ init_splats_format();
659
+ VERSION2 = true ? "5.0.0-alpha.1" : "latest";
660
+ KSPLATLoader = {
661
+ dataType: null,
662
+ batchType: null,
663
+ ...KSPLATFormat,
664
+ version: VERSION2,
665
+ options: {
666
+ splats: {
667
+ shape: "arrow-table"
668
+ }
669
+ },
670
+ preload: preload2
671
+ };
672
+ }
673
+ });
674
+
675
+ // dist/lib/parse-spz.js
676
+ async function parseSPZ(data, options) {
677
+ return makeGaussianSplatsArrowTable(await parseSPZToGaussianSplats(data, options));
678
+ }
679
+ async function parseSPZToGaussianSplats(data, options) {
680
+ const header = parseSPZHeader(data);
681
+ const streamInfos = parseSPZStreamInfos(data, header, getSPZStreamByteLengths(header));
682
+ const compressedStreams = streamInfos.map((streamInfo) => data.slice(streamInfo.compressedOffset, streamInfo.compressedOffset + streamInfo.compressedSize));
683
+ const compression = new import_compression.ZstdCompression({ modules: options == null ? void 0 : options.modules });
684
+ const streams = await Promise.all(compressedStreams.map((compressedStream, streamIndex) => compression.decompress(compressedStream, streamInfos[streamIndex].uncompressedSize)));
685
+ validateSPZStreamLengths(streams, streamInfos);
686
+ return decodeSPZStreams(header, streams, data);
687
+ }
688
+ function parseSPZHeader(data) {
689
+ if (data.byteLength < SPZ_HEADER_BYTE_LENGTH) {
690
+ throw new Error(`SPZLoader: file must contain a ${SPZ_HEADER_BYTE_LENGTH}-byte header.`);
691
+ }
692
+ const dataView = new DataView(data);
693
+ const header = {
694
+ magic: dataView.getUint32(0, true),
695
+ version: dataView.getUint32(4, true),
696
+ numPoints: dataView.getUint32(8, true),
697
+ shDegree: dataView.getUint8(12),
698
+ fractionalBits: dataView.getUint8(13),
699
+ flags: dataView.getUint8(14),
700
+ numStreams: dataView.getUint8(15),
701
+ tocByteOffset: dataView.getUint32(16, true)
702
+ };
703
+ if (header.magic !== SPZ_MAGIC) {
704
+ throw new Error("SPZLoader: NGSP magic header not found.");
705
+ }
706
+ if (header.version !== SPZ_VERSION) {
707
+ throw new Error(`SPZLoader: version ${header.version} is not supported.`);
708
+ }
709
+ if (header.shDegree > 4) {
710
+ throw new Error(`SPZLoader: spherical harmonics degree ${header.shDegree} is not supported.`);
711
+ }
712
+ if (header.tocByteOffset < SPZ_HEADER_BYTE_LENGTH || header.tocByteOffset > data.byteLength) {
713
+ throw new Error("SPZLoader: invalid table of contents byte offset.");
714
+ }
715
+ return header;
716
+ }
717
+ function parseSPZStreamInfos(data, header, expectedUncompressedSizes) {
718
+ if (header.numStreams !== expectedUncompressedSizes.length) {
719
+ throw new Error(`SPZLoader: expected ${expectedUncompressedSizes.length} streams, found ${header.numStreams}.`);
720
+ }
721
+ const tocByteLength = header.numStreams * 16;
722
+ const tocEnd = header.tocByteOffset + tocByteLength;
723
+ if (tocEnd > data.byteLength) {
724
+ throw new Error("SPZLoader: table of contents exceeds file byte length.");
725
+ }
726
+ const dataView = new DataView(data);
727
+ let compressedOffset = tocEnd;
728
+ const streamInfos = [];
729
+ for (let streamIndex = 0; streamIndex < header.numStreams; streamIndex++) {
730
+ const tocOffset = header.tocByteOffset + streamIndex * 16;
731
+ const compressedSize = readSafeUint64(dataView, tocOffset);
732
+ const uncompressedSize = readSafeUint64(dataView, tocOffset + 8);
733
+ const expectedUncompressedSize = expectedUncompressedSizes[streamIndex];
734
+ if (uncompressedSize !== expectedUncompressedSize) {
735
+ throw new Error(`SPZLoader: stream ${streamIndex} has ${uncompressedSize} uncompressed bytes, expected ${expectedUncompressedSize}.`);
736
+ }
737
+ if (compressedOffset + compressedSize > data.byteLength) {
738
+ throw new Error(`SPZLoader: stream ${streamIndex} exceeds file byte length.`);
739
+ }
740
+ streamInfos.push({ compressedSize, uncompressedSize, compressedOffset });
741
+ compressedOffset += compressedSize;
742
+ }
743
+ if (compressedOffset !== data.byteLength) {
744
+ throw new Error("SPZLoader: compressed stream byte lengths do not match file byte length.");
745
+ }
746
+ return streamInfos;
747
+ }
748
+ function readSafeUint64(dataView, byteOffset) {
749
+ const value = dataView.getBigUint64(byteOffset, true);
750
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
751
+ throw new Error("SPZLoader: stream byte length exceeds Number.MAX_SAFE_INTEGER.");
752
+ }
753
+ return Number(value);
754
+ }
755
+ function getSPZStreamByteLengths(header) {
756
+ return [
757
+ header.numPoints * 9,
758
+ header.numPoints,
759
+ header.numPoints * 3,
760
+ header.numPoints * 3,
761
+ header.numPoints * 4,
762
+ header.numPoints * getSphericalHarmonicsComponentCount2(header.shDegree)
763
+ ].filter((byteLength) => byteLength > 0);
764
+ }
765
+ function validateSPZStreamLengths(streams, streamInfos) {
766
+ for (let streamIndex = 0; streamIndex < streams.length; streamIndex++) {
767
+ if (streams[streamIndex].byteLength !== streamInfos[streamIndex].uncompressedSize) {
768
+ throw new Error(`SPZLoader: decompressed stream ${streamIndex} has unexpected byte length.`);
769
+ }
770
+ }
771
+ }
772
+ function decodeSPZStreams(header, streams, sourceData) {
773
+ const splatCount = header.numPoints;
774
+ const positions = new Float32Array(splatCount * 3);
775
+ const scales = new Float32Array(splatCount * 3);
776
+ const rotations = new Float32Array(splatCount * 4);
777
+ const colors = new Uint8Array(splatCount * 3);
778
+ const sphericalHarmonicDcs = new Float32Array(splatCount * 3);
779
+ const opacities = new Float32Array(splatCount);
780
+ const sphericalHarmonicsComponentCount = getSphericalHarmonicsComponentCount2(header.shDegree);
781
+ const sphericalHarmonics = sphericalHarmonicsComponentCount ? new Float32Array(splatCount * sphericalHarmonicsComponentCount) : void 0;
782
+ const [positionStream, alphaStream, colorStream, scaleStream, rotationStream, sphericalHarmonicsStream] = streams.map((stream) => new Uint8Array(stream));
783
+ decodeSPZPositions(positionStream, positions, header.fractionalBits);
784
+ decodeSPZScales(scaleStream, scales);
785
+ decodeSPZRotations(rotationStream, rotations);
786
+ decodeSPZColors(colorStream, colors, sphericalHarmonicDcs);
787
+ decodeSPZOpacities(alphaStream, opacities);
788
+ if (sphericalHarmonics && sphericalHarmonicsStream) {
789
+ decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics);
790
+ }
791
+ return {
792
+ format: "spz",
793
+ splatCount,
794
+ positions,
795
+ scales,
796
+ rotations,
797
+ colors,
798
+ sphericalHarmonicDcs,
799
+ opacities,
800
+ sphericalHarmonics,
801
+ sphericalHarmonicsComponentCount,
802
+ loaderData: {
803
+ format: "spz",
804
+ ...header,
805
+ antialiased: Boolean(header.flags & 1),
806
+ extensionByteLength: getSPZExtensionByteLength(header),
807
+ extensionBytes: getSPZExtensionBytes(sourceData, header)
808
+ }
809
+ };
810
+ }
811
+ function decodeSPZPositions(positionStream, positions, fractionalBits) {
812
+ const scale = 1 / 2 ** fractionalBits;
813
+ for (let componentIndex = 0; componentIndex < positions.length; componentIndex++) {
814
+ const byteOffset = componentIndex * 3;
815
+ let fixed32 = positionStream[byteOffset] | positionStream[byteOffset + 1] << 8 | positionStream[byteOffset + 2] << 16;
816
+ fixed32 |= fixed32 & 8388608 ? 4278190080 : 0;
817
+ positions[componentIndex] = fixed32 * scale;
818
+ }
819
+ }
820
+ function decodeSPZScales(scaleStream, scales) {
821
+ for (let componentIndex = 0; componentIndex < scales.length; componentIndex++) {
822
+ scales[componentIndex] = Math.exp(scaleStream[componentIndex] / 16 - 10);
823
+ }
824
+ }
825
+ function decodeSPZRotations(rotationStream, rotations) {
826
+ for (let splatIndex = 0; splatIndex < rotations.length / 4; splatIndex++) {
827
+ const byteOffset = splatIndex * 4;
828
+ const component = rotationStream[byteOffset] | rotationStream[byteOffset + 1] << 8 | rotationStream[byteOffset + 2] << 16 | rotationStream[byteOffset + 3] << 24;
829
+ const xyzw = decodeSPZQuaternion(component >>> 0);
830
+ const [w, x, y, z] = normalizeQuaternion(xyzw[3], xyzw[0], xyzw[1], xyzw[2]);
831
+ const rotationOffset = splatIndex * 4;
832
+ rotations[rotationOffset + 0] = w;
833
+ rotations[rotationOffset + 1] = x;
834
+ rotations[rotationOffset + 2] = y;
835
+ rotations[rotationOffset + 3] = z;
836
+ }
837
+ }
838
+ function decodeSPZQuaternion(component) {
839
+ const rotation = [0, 0, 0, 0];
840
+ const largestComponent = component >>> 30;
841
+ let remainingBits = component;
842
+ let sumSquares = 0;
843
+ for (let componentIndex = 3; componentIndex >= 0; componentIndex--) {
844
+ if (componentIndex !== largestComponent) {
845
+ const magnitude = remainingBits & SPZ_ROTATION_COMPONENT_MASK;
846
+ const isNegative = remainingBits >>> 9 & 1;
847
+ remainingBits >>>= 10;
848
+ let value = SPZ_ROTATION_COMPONENT_SCALE * magnitude / SPZ_ROTATION_COMPONENT_MASK;
849
+ if (isNegative) {
850
+ value = -value;
851
+ }
852
+ rotation[componentIndex] = value;
853
+ sumSquares += value * value;
854
+ }
855
+ }
856
+ rotation[largestComponent] = Math.sqrt(Math.max(0, 1 - sumSquares));
857
+ return rotation;
858
+ }
859
+ function decodeSPZColors(colorStream, colors, sphericalHarmonicDcs) {
860
+ for (let componentIndex = 0; componentIndex < colors.length; componentIndex++) {
861
+ sphericalHarmonicDcs[componentIndex] = (colorStream[componentIndex] / 255 - 0.5) / SPZ_COLOR_SCALE;
862
+ colors[componentIndex] = normalizeColorByte(sphericalHarmonicDcs[componentIndex]);
863
+ }
864
+ }
865
+ function decodeSPZOpacities(alphaStream, opacities) {
866
+ for (let splatIndex = 0; splatIndex < opacities.length; splatIndex++) {
867
+ opacities[splatIndex] = alphaStream[splatIndex] / 255;
868
+ }
869
+ }
870
+ function decodeSPZSphericalHarmonics(sphericalHarmonicsStream, sphericalHarmonics) {
871
+ for (let componentIndex = 0; componentIndex < sphericalHarmonics.length; componentIndex++) {
872
+ sphericalHarmonics[componentIndex] = (sphericalHarmonicsStream[componentIndex] - 128) / 128;
873
+ }
874
+ }
875
+ function normalizeColorByte(sphericalHarmonicDc) {
876
+ return Math.min(Math.max(Math.round((sphericalHarmonicDc * SPZ_COLOR_SCALE + 0.5) * 255), 0), 255);
877
+ }
878
+ function getSphericalHarmonicsComponentCount2(shDegree) {
879
+ switch (shDegree) {
880
+ case 0:
881
+ return 0;
882
+ case 1:
883
+ return 9;
884
+ case 2:
885
+ return 24;
886
+ case 3:
887
+ return 45;
888
+ case 4:
889
+ return 72;
890
+ default:
891
+ throw new Error(`SPZLoader: spherical harmonics degree ${shDegree} is not supported.`);
892
+ }
893
+ }
894
+ function getSPZExtensionByteLength(header) {
895
+ return header.flags & SPZ_EXTENSION_FLAG ? header.tocByteOffset - SPZ_HEADER_BYTE_LENGTH : 0;
896
+ }
897
+ function getSPZExtensionBytes(data, header) {
898
+ const extensionByteLength = getSPZExtensionByteLength(header);
899
+ return extensionByteLength ? new Uint8Array(data.slice(SPZ_HEADER_BYTE_LENGTH, header.tocByteOffset)) : void 0;
900
+ }
901
+ var import_compression, SPZ_HEADER_BYTE_LENGTH, SPZ_MAGIC, SPZ_VERSION, SPZ_EXTENSION_FLAG, SPZ_COLOR_SCALE, SPZ_ROTATION_COMPONENT_SCALE, SPZ_ROTATION_COMPONENT_MASK;
902
+ var init_parse_spz = __esm({
903
+ "dist/lib/parse-spz.js"() {
904
+ "use strict";
905
+ import_compression = require("@loaders.gl/compression");
906
+ init_splats_arrow_table();
907
+ init_splat_utils();
908
+ SPZ_HEADER_BYTE_LENGTH = 32;
909
+ SPZ_MAGIC = 1347635022;
910
+ SPZ_VERSION = 4;
911
+ SPZ_EXTENSION_FLAG = 2;
912
+ SPZ_COLOR_SCALE = 0.15;
913
+ SPZ_ROTATION_COMPONENT_SCALE = Math.SQRT1_2;
914
+ SPZ_ROTATION_COMPONENT_MASK = (1 << 9) - 1;
915
+ }
916
+ });
917
+
918
+ // dist/spz-loader.js
919
+ var spz_loader_exports = {};
920
+ __export(spz_loader_exports, {
921
+ SPZLoaderWithParser: () => SPZLoaderWithParser
922
+ });
923
+ var _SPZLoaderPreload, SPZLoaderMetadataWithoutPreload, SPZLoaderWithParser;
924
+ var init_spz_loader = __esm({
925
+ "dist/spz-loader.js"() {
926
+ "use strict";
927
+ init_parse_spz();
928
+ init_spz_loader_types();
929
+ ({ preload: _SPZLoaderPreload, ...SPZLoaderMetadataWithoutPreload } = SPZLoader);
930
+ SPZLoaderWithParser = {
931
+ ...SPZLoaderMetadataWithoutPreload,
932
+ parse: async (arrayBuffer, options) => parseSPZ(arrayBuffer, options)
933
+ };
934
+ }
935
+ });
936
+
937
+ // dist/spz-loader-types.js
938
+ async function preload3() {
939
+ const { SPZLoaderWithParser: SPZLoaderWithParser2 } = await Promise.resolve().then(() => (init_spz_loader(), spz_loader_exports));
940
+ return SPZLoaderWithParser2;
941
+ }
942
+ var VERSION3, SPZLoader;
943
+ var init_spz_loader_types = __esm({
944
+ "dist/spz-loader-types.js"() {
945
+ "use strict";
946
+ init_splats_format();
947
+ VERSION3 = true ? "5.0.0-alpha.1" : "latest";
948
+ SPZLoader = {
949
+ dataType: null,
950
+ batchType: null,
951
+ ...SPZFormat,
952
+ version: VERSION3,
953
+ options: {
954
+ splats: {
955
+ shape: "arrow-table"
956
+ }
957
+ },
958
+ preload: preload3
959
+ };
960
+ }
961
+ });
962
+
963
+ // dist/lib/parse-rad.js
964
+ function parseRADHeader(data) {
965
+ const metadata = tryParseRADHeader(data);
966
+ if (!metadata) {
967
+ throw new Error("RADLoader: file must contain a complete RAD metadata header.");
968
+ }
969
+ return metadata;
970
+ }
971
+ function tryParseRADHeader(data) {
972
+ const bytes = getUint8Array(data);
973
+ if (bytes.byteLength < RAD_HEADER_BYTE_LENGTH) {
974
+ return null;
975
+ }
976
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
977
+ const magic = dataView.getUint32(0, true);
978
+ if (magic !== RAD_MAGIC) {
979
+ throw new Error(`RADLoader: RAD0 magic header not found, received 0x${magic.toString(16)}.`);
980
+ }
981
+ const headerJsonByteLength = dataView.getUint32(4, true);
982
+ const headerJsonEnd = RAD_HEADER_BYTE_LENGTH + headerJsonByteLength;
983
+ if (bytes.byteLength < headerJsonEnd) {
984
+ return null;
985
+ }
986
+ const rawMetadata = parseJSONRecord(bytes.subarray(RAD_HEADER_BYTE_LENGTH, headerJsonEnd), "RADLoader: failed to parse RAD metadata JSON.");
987
+ return normalizeRADMetadata(rawMetadata, headerJsonByteLength);
988
+ }
989
+ function parseRADChunkHeader(data) {
990
+ const bytes = getUint8Array(data);
991
+ if (bytes.byteLength < RAD_HEADER_BYTE_LENGTH) {
992
+ throw new Error("RADLoader: RADC chunk must contain an 8-byte metadata header.");
993
+ }
994
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
995
+ const magic = dataView.getUint32(0, true);
996
+ if (magic !== RAD_CHUNK_MAGIC) {
997
+ throw new Error(`RADLoader: RADC magic header not found, received 0x${magic.toString(16)}.`);
998
+ }
999
+ const headerJsonByteLength = dataView.getUint32(4, true);
1000
+ const headerJsonEnd = RAD_HEADER_BYTE_LENGTH + headerJsonByteLength;
1001
+ const payloadByteLengthOffset = RAD_HEADER_BYTE_LENGTH + roundUpToEight(headerJsonByteLength);
1002
+ const payloadByteOffset = payloadByteLengthOffset + RAD_CHUNK_PAYLOAD_LENGTH_BYTE_LENGTH;
1003
+ if (bytes.byteLength < payloadByteOffset) {
1004
+ throw new Error("RADLoader: RADC chunk must contain a complete metadata header.");
1005
+ }
1006
+ const rawMetadata = parseJSONRecord(bytes.subarray(RAD_HEADER_BYTE_LENGTH, headerJsonEnd), "RADLoader: failed to parse RADC metadata JSON.");
1007
+ const payloadBytes = readSafeUint642(dataView, payloadByteLengthOffset, "RADC payload byte length");
1008
+ return normalizeRADChunkMetadata(rawMetadata, headerJsonByteLength, payloadByteOffset, payloadBytes);
1009
+ }
1010
+ function roundUpToEight(byteLength) {
1011
+ return byteLength + 7 & ~7;
1012
+ }
1013
+ function normalizeRADMetadata(rawMetadata, headerJsonByteLength) {
1014
+ const version = requireSafeInteger(rawMetadata.version, "RAD version");
1015
+ if (version !== 1) {
1016
+ throw new Error(`RADLoader: version ${version} is not supported.`);
1017
+ }
1018
+ const type = requireString(rawMetadata.type, "RAD type");
1019
+ if (type !== "gsplat") {
1020
+ throw new Error(`RADLoader: RAD type ${type} is not supported.`);
1021
+ }
1022
+ const chunks = requireArray(rawMetadata.chunks, "RAD chunks").map((chunk, chunkIndex) => normalizeRADChunkRange(chunk, chunkIndex));
1023
+ const metadata = {
1024
+ version,
1025
+ type,
1026
+ count: requireSafeInteger(rawMetadata.count, "RAD count"),
1027
+ maxSh: optionalSafeInteger(rawMetadata.maxSh, "RAD maxSh"),
1028
+ lodTree: optionalBoolean(rawMetadata.lodTree, "RAD lodTree"),
1029
+ chunkSize: optionalSafeInteger(rawMetadata.chunkSize, "RAD chunkSize"),
1030
+ allChunkBytes: optionalSafeInteger(rawMetadata.allChunkBytes, "RAD allChunkBytes"),
1031
+ chunks,
1032
+ splatEncoding: optionalSplatEncoding(rawMetadata.splatEncoding, "RAD splatEncoding"),
1033
+ shCodeCount: optionalSafeInteger(rawMetadata.shCodeCount, "RAD shCodeCount"),
1034
+ comment: optionalString(rawMetadata.comment, "RAD comment"),
1035
+ headerJsonByteLength,
1036
+ chunksByteOffset: RAD_HEADER_BYTE_LENGTH + roundUpToEight(headerJsonByteLength)
1037
+ };
1038
+ return metadata;
1039
+ }
1040
+ function normalizeRADChunkRange(rawChunk, chunkIndex) {
1041
+ const chunk = requireRecord(rawChunk, `RAD chunk ${chunkIndex}`);
1042
+ return {
1043
+ offset: requireSafeInteger(chunk.offset, `RAD chunk ${chunkIndex} offset`),
1044
+ bytes: requireSafeInteger(chunk.bytes, `RAD chunk ${chunkIndex} bytes`),
1045
+ base: optionalSafeInteger(chunk.base, `RAD chunk ${chunkIndex} base`),
1046
+ count: optionalSafeInteger(chunk.count, `RAD chunk ${chunkIndex} count`),
1047
+ filename: optionalString(chunk.filename, `RAD chunk ${chunkIndex} filename`)
1048
+ };
1049
+ }
1050
+ function normalizeRADChunkMetadata(rawMetadata, headerJsonByteLength, payloadByteOffset, payloadBytes) {
1051
+ const version = requireSafeInteger(rawMetadata.version, "RADC version");
1052
+ if (version !== 1) {
1053
+ throw new Error(`RADLoader: RADC version ${version} is not supported.`);
1054
+ }
1055
+ const metadataPayloadBytes = requireSafeInteger(rawMetadata.payloadBytes, "RADC payloadBytes");
1056
+ if (metadataPayloadBytes !== payloadBytes) {
1057
+ throw new Error("RADLoader: RADC metadata payload byte length does not match binary header.");
1058
+ }
1059
+ return {
1060
+ version,
1061
+ base: requireSafeInteger(rawMetadata.base, "RADC base"),
1062
+ count: requireSafeInteger(rawMetadata.count, "RADC count"),
1063
+ payloadBytes,
1064
+ maxSh: optionalSafeInteger(rawMetadata.maxSh, "RADC maxSh"),
1065
+ lodTree: optionalBoolean(rawMetadata.lodTree, "RADC lodTree"),
1066
+ splatEncoding: optionalSplatEncoding(rawMetadata.splatEncoding, "RADC splatEncoding"),
1067
+ properties: requireArray(rawMetadata.properties, "RADC properties").map((property, index) => normalizeRADChunkProperty(property, index)),
1068
+ headerJsonByteLength,
1069
+ payloadByteOffset,
1070
+ chunkByteLength: payloadByteOffset + payloadBytes
1071
+ };
1072
+ }
1073
+ function normalizeRADChunkProperty(rawProperty, propertyIndex) {
1074
+ const property = requireRecord(rawProperty, `RADC property ${propertyIndex}`);
1075
+ return {
1076
+ offset: requireSafeInteger(property.offset, `RADC property ${propertyIndex} offset`),
1077
+ bytes: requireSafeInteger(property.bytes, `RADC property ${propertyIndex} bytes`),
1078
+ property: requireString(property.property, `RADC property ${propertyIndex} name`),
1079
+ encoding: requireString(property.encoding, `RADC property ${propertyIndex} encoding`),
1080
+ compression: optionalString(property.compression, `RADC property ${propertyIndex} compression`),
1081
+ min: optionalFiniteNumber(property.min, `RADC property ${propertyIndex} min`),
1082
+ max: optionalFiniteNumber(property.max, `RADC property ${propertyIndex} max`)
1083
+ };
1084
+ }
1085
+ function optionalSplatEncoding(value, fieldName) {
1086
+ if (value === void 0) {
1087
+ return void 0;
1088
+ }
1089
+ const encoding = requireRecord(value, fieldName);
1090
+ return {
1091
+ rgbMin: optionalFiniteNumber(encoding.rgbMin, `${fieldName}.rgbMin`),
1092
+ rgbMax: optionalFiniteNumber(encoding.rgbMax, `${fieldName}.rgbMax`),
1093
+ lnScaleMin: optionalFiniteNumber(encoding.lnScaleMin, `${fieldName}.lnScaleMin`),
1094
+ lnScaleMax: optionalFiniteNumber(encoding.lnScaleMax, `${fieldName}.lnScaleMax`),
1095
+ sh1Max: optionalFiniteNumber(encoding.sh1Max, `${fieldName}.sh1Max`),
1096
+ sh2Max: optionalFiniteNumber(encoding.sh2Max, `${fieldName}.sh2Max`),
1097
+ sh3Max: optionalFiniteNumber(encoding.sh3Max, `${fieldName}.sh3Max`),
1098
+ lodOpacity: optionalBoolean(encoding.lodOpacity, `${fieldName}.lodOpacity`)
1099
+ };
1100
+ }
1101
+ function parseJSONRecord(bytes, message) {
1102
+ try {
1103
+ return requireRecord(JSON.parse(TEXT_DECODER.decode(bytes)), message);
1104
+ } catch (error) {
1105
+ if (error instanceof Error && error.message.startsWith("RADLoader:")) {
1106
+ throw error;
1107
+ }
1108
+ throw new Error(message);
1109
+ }
1110
+ }
1111
+ function requireRecord(value, fieldName) {
1112
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1113
+ throw new Error(`RADLoader: ${fieldName} must be an object.`);
1114
+ }
1115
+ return value;
1116
+ }
1117
+ function requireArray(value, fieldName) {
1118
+ if (!Array.isArray(value)) {
1119
+ throw new Error(`RADLoader: ${fieldName} must be an array.`);
1120
+ }
1121
+ return value;
1122
+ }
1123
+ function requireString(value, fieldName) {
1124
+ if (typeof value !== "string") {
1125
+ throw new Error(`RADLoader: ${fieldName} must be a string.`);
1126
+ }
1127
+ return value;
1128
+ }
1129
+ function optionalString(value, fieldName) {
1130
+ if (value === void 0) {
1131
+ return void 0;
1132
+ }
1133
+ return requireString(value, fieldName);
1134
+ }
1135
+ function optionalBoolean(value, fieldName) {
1136
+ if (value === void 0) {
1137
+ return void 0;
1138
+ }
1139
+ if (typeof value !== "boolean") {
1140
+ throw new Error(`RADLoader: ${fieldName} must be a boolean.`);
1141
+ }
1142
+ return value;
1143
+ }
1144
+ function requireSafeInteger(value, fieldName) {
1145
+ if (!Number.isSafeInteger(value) || Number(value) < 0) {
1146
+ throw new Error(`RADLoader: ${fieldName} must be a non-negative safe integer.`);
1147
+ }
1148
+ return Number(value);
1149
+ }
1150
+ function optionalSafeInteger(value, fieldName) {
1151
+ if (value === void 0) {
1152
+ return void 0;
1153
+ }
1154
+ return requireSafeInteger(value, fieldName);
1155
+ }
1156
+ function optionalFiniteNumber(value, fieldName) {
1157
+ if (value === void 0) {
1158
+ return void 0;
1159
+ }
1160
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1161
+ throw new Error(`RADLoader: ${fieldName} must be a finite number.`);
1162
+ }
1163
+ return value;
1164
+ }
1165
+ function readSafeUint642(dataView, byteOffset, fieldName) {
1166
+ const value = dataView.getBigUint64(byteOffset, true);
1167
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
1168
+ throw new Error(`RADLoader: ${fieldName} exceeds Number.MAX_SAFE_INTEGER.`);
1169
+ }
1170
+ return Number(value);
1171
+ }
1172
+ function getUint8Array(data) {
1173
+ return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1174
+ }
1175
+ var RAD_MAGIC, RAD_CHUNK_MAGIC, RAD_HEADER_BYTE_LENGTH, RAD_CHUNK_PAYLOAD_LENGTH_BYTE_LENGTH, TEXT_DECODER;
1176
+ var init_parse_rad = __esm({
1177
+ "dist/lib/parse-rad.js"() {
1178
+ "use strict";
1179
+ RAD_MAGIC = 809779538;
1180
+ RAD_CHUNK_MAGIC = 1128546642;
1181
+ RAD_HEADER_BYTE_LENGTH = 8;
1182
+ RAD_CHUNK_PAYLOAD_LENGTH_BYTE_LENGTH = 8;
1183
+ TEXT_DECODER = new TextDecoder();
1184
+ }
1185
+ });
1186
+
1187
+ // dist/lib/parse-rad-chunk.js
1188
+ function parseRADChunk(data, options) {
1189
+ return makeGaussianSplatsArrowTable(parseRADChunkToGaussianSplats(data, options));
1190
+ }
1191
+ function parseRADChunkToGaussianSplats(data, options) {
1192
+ var _a, _b;
1193
+ const bytes = getUint8Array2(data);
1194
+ const metadata = getRADChunkDecodeMetadata(parseRADChunkHeader(bytes), options);
1195
+ if (bytes.byteLength < metadata.chunkByteLength) {
1196
+ throw new Error("RADLoader: RADC chunk payload is incomplete.");
1197
+ }
1198
+ const splatCount = metadata.count;
1199
+ const positions = decodeRADFloatProperty(bytes, metadata, requireRADProperty(metadata, "center"), 3);
1200
+ const opacities = decodeRADAlpha(bytes, metadata, splatCount);
1201
+ const rgb = decodeRADRgb(bytes, metadata, splatCount);
1202
+ const scales = decodeRADScales(bytes, metadata, splatCount);
1203
+ const rotations = decodeRADRotations(bytes, metadata, splatCount);
1204
+ const { colors, sphericalHarmonicDcs } = convertRgbToColorColumns(rgb);
1205
+ const includeLoDTree = ((_a = options == null ? void 0 : options.radChunk) == null ? void 0 : _a.includeLoDTree) ?? true;
1206
+ const childCounts = includeLoDTree ? decodeOptionalRADUint16(bytes, metadata, "child_count") : null;
1207
+ const childStarts = includeLoDTree ? decodeOptionalRADUint32(bytes, metadata, "child_start") : null;
1208
+ const includeSphericalHarmonics = ((_b = options == null ? void 0 : options.radChunk) == null ? void 0 : _b.includeSphericalHarmonics) ?? false;
1209
+ const sphericalHarmonics = includeSphericalHarmonics ? decodeRADSphericalHarmonics(bytes, metadata) : null;
1210
+ return {
1211
+ format: "rad",
1212
+ splatCount,
1213
+ positions,
1214
+ scales,
1215
+ rotations,
1216
+ colors,
1217
+ sphericalHarmonicDcs,
1218
+ opacities,
1219
+ sphericalHarmonics: sphericalHarmonics == null ? void 0 : sphericalHarmonics.values,
1220
+ sphericalHarmonicsComponentCount: sphericalHarmonics == null ? void 0 : sphericalHarmonics.componentCount,
1221
+ loaderData: {
1222
+ format: "rad",
1223
+ base: metadata.base,
1224
+ count: metadata.count,
1225
+ maxSh: metadata.maxSh ?? 0,
1226
+ lodTree: metadata.lodTree ?? false,
1227
+ splatEncoding: metadata.splatEncoding,
1228
+ childCounts: childCounts ?? void 0,
1229
+ childStarts: childStarts ?? void 0
1230
+ }
1231
+ };
1232
+ }
1233
+ function decodeRADAlpha(bytes, metadata, splatCount) {
1234
+ const property = findRADProperty(metadata, "alpha");
1235
+ if (!property) {
1236
+ return new Float32Array(splatCount).fill(1);
1237
+ }
1238
+ const opacities = decodeRADFloatProperty(bytes, metadata, property, 1);
1239
+ for (let splatIndex = 0; splatIndex < opacities.length; splatIndex++) {
1240
+ opacities[splatIndex] = decodeRADOpacity(opacities[splatIndex], metadata, property);
1241
+ }
1242
+ return opacities;
1243
+ }
1244
+ function decodeRADOpacity(opacity, metadata, property) {
1245
+ var _a;
1246
+ const normalizedOpacity = Math.max(opacity, 0);
1247
+ if (!((_a = metadata.splatEncoding) == null ? void 0 : _a.lodOpacity) || property.encoding !== "r8" && property.encoding !== "r8_delta") {
1248
+ return normalizedOpacity;
1249
+ }
1250
+ return normalizedOpacity * 2;
1251
+ }
1252
+ function decodeRADRgb(bytes, metadata, splatCount) {
1253
+ const property = findRADProperty(metadata, "rgb");
1254
+ if (!property) {
1255
+ return new Float32Array(splatCount * 3).fill(1);
1256
+ }
1257
+ return decodeRADFloatProperty(bytes, metadata, property, 3);
1258
+ }
1259
+ function decodeRADScales(bytes, metadata, splatCount) {
1260
+ const property = findRADProperty(metadata, "scales");
1261
+ if (!property) {
1262
+ return new Float32Array(splatCount * 3).fill(1);
1263
+ }
1264
+ return decodeRADFloatProperty(bytes, metadata, property, 3);
1265
+ }
1266
+ function decodeRADRotations(bytes, metadata, splatCount) {
1267
+ const property = findRADProperty(metadata, "orientation");
1268
+ if (!property) {
1269
+ return makeIdentityRotations(splatCount);
1270
+ }
1271
+ const propertyBytes = getRADPropertyBytes(bytes, metadata, property);
1272
+ switch (property.encoding) {
1273
+ case "oct88r8":
1274
+ return decodeRADOct88R8Rotations(propertyBytes, splatCount);
1275
+ case "f32":
1276
+ case "f16": {
1277
+ const xyz = decodeRADFloatProperty(bytes, metadata, property, 3);
1278
+ const rotations = new Float32Array(splatCount * 4);
1279
+ for (let splatIndex = 0; splatIndex < splatCount; splatIndex++) {
1280
+ const xyzOffset = splatIndex * 3;
1281
+ const rotationOffset = splatIndex * 4;
1282
+ const x = xyz[xyzOffset + 0];
1283
+ const y = xyz[xyzOffset + 1];
1284
+ const z = xyz[xyzOffset + 2];
1285
+ const w = Math.sqrt(Math.max(0, 1 - x * x - y * y - z * z));
1286
+ const normalized = normalizeQuaternion(w, x, y, z);
1287
+ rotations.set(normalized, rotationOffset);
1288
+ }
1289
+ return rotations;
1290
+ }
1291
+ default:
1292
+ throw new Error(`RADLoader: unsupported orientation encoding ${property.encoding}.`);
1293
+ }
1294
+ }
1295
+ function decodeRADSphericalHarmonics(bytes, metadata) {
1296
+ const shProperties = [
1297
+ { property: findRADProperty(metadata, "sh1"), dimensions: 9 },
1298
+ { property: findRADProperty(metadata, "sh2"), dimensions: 15 },
1299
+ { property: findRADProperty(metadata, "sh3"), dimensions: 21 }
1300
+ ].filter((entry) => entry.property !== void 0);
1301
+ if (shProperties.length === 0) {
1302
+ return null;
1303
+ }
1304
+ const decodedProperties = shProperties.map((entry) => ({
1305
+ values: decodeRADFloatProperty(bytes, metadata, entry.property, entry.dimensions),
1306
+ dimensions: entry.dimensions
1307
+ }));
1308
+ const componentCount = decodedProperties.reduce((total, entry) => total + entry.dimensions, 0);
1309
+ const values = new Float32Array(metadata.count * componentCount);
1310
+ for (let splatIndex = 0; splatIndex < metadata.count; splatIndex++) {
1311
+ let outputOffset = splatIndex * componentCount;
1312
+ for (const decodedProperty of decodedProperties) {
1313
+ const inputOffset = splatIndex * decodedProperty.dimensions;
1314
+ values.set(decodedProperty.values.subarray(inputOffset, inputOffset + decodedProperty.dimensions), outputOffset);
1315
+ outputOffset += decodedProperty.dimensions;
1316
+ }
1317
+ }
1318
+ return { values, componentCount };
1319
+ }
1320
+ function decodeRADFloatProperty(bytes, metadata, property, dimensions) {
1321
+ const propertyBytes = getRADPropertyBytes(bytes, metadata, property);
1322
+ switch (property.encoding) {
1323
+ case "f32":
1324
+ return decodePlanarFloat32(propertyBytes, dimensions, metadata.count);
1325
+ case "f16":
1326
+ return decodePlanarFloat16(propertyBytes, dimensions, metadata.count);
1327
+ case "f32_lebytes":
1328
+ return decodeLeBytesFloat32(propertyBytes, dimensions, metadata.count);
1329
+ case "f16_lebytes":
1330
+ return decodeLeBytesFloat16(propertyBytes, dimensions, metadata.count);
1331
+ case "r8":
1332
+ return decodeR8(propertyBytes, dimensions, metadata.count, getPropertyMin(metadata, property), getPropertyMax(metadata, property));
1333
+ case "r8_delta":
1334
+ return decodeR8Delta(propertyBytes, dimensions, metadata.count, getPropertyMin(metadata, property), getPropertyMax(metadata, property));
1335
+ case "s8":
1336
+ return decodeS8(propertyBytes, dimensions, metadata.count, getPropertyMax(metadata, property));
1337
+ case "s8_delta":
1338
+ return decodeS8Delta(propertyBytes, dimensions, metadata.count, getPropertyMax(metadata, property));
1339
+ case "ln_0r8":
1340
+ return decodeScaleR8(propertyBytes, dimensions, metadata.count, getPropertyMin(metadata, property), getPropertyMax(metadata, property));
1341
+ case "ln_f16":
1342
+ return decodeLogFloat16(propertyBytes, dimensions, metadata.count);
1343
+ default:
1344
+ throw new Error(`RADLoader: unsupported ${property.property} encoding ${property.encoding}.`);
1345
+ }
1346
+ }
1347
+ function decodeOptionalRADUint16(bytes, metadata, propertyName) {
1348
+ const property = findRADProperty(metadata, propertyName);
1349
+ if (!property) {
1350
+ return null;
1351
+ }
1352
+ if (property.encoding !== "u16") {
1353
+ throw new Error(`RADLoader: unsupported ${propertyName} encoding ${property.encoding}.`);
1354
+ }
1355
+ const propertyBytes = getRADPropertyBytes(bytes, metadata, property);
1356
+ const values = new Uint16Array(metadata.count);
1357
+ for (let splatIndex = 0; splatIndex < metadata.count; splatIndex++) {
1358
+ values[splatIndex] = propertyBytes[splatIndex * 2] | propertyBytes[splatIndex * 2 + 1] << 8;
1359
+ }
1360
+ return values;
1361
+ }
1362
+ function decodeOptionalRADUint32(bytes, metadata, propertyName) {
1363
+ const property = findRADProperty(metadata, propertyName);
1364
+ if (!property) {
1365
+ return null;
1366
+ }
1367
+ if (property.encoding !== "u32") {
1368
+ throw new Error(`RADLoader: unsupported ${propertyName} encoding ${property.encoding}.`);
1369
+ }
1370
+ const propertyBytes = getRADPropertyBytes(bytes, metadata, property);
1371
+ const dataView = new DataView(propertyBytes.buffer, propertyBytes.byteOffset, propertyBytes.byteLength);
1372
+ const values = new Uint32Array(metadata.count);
1373
+ for (let splatIndex = 0; splatIndex < metadata.count; splatIndex++) {
1374
+ values[splatIndex] = dataView.getUint32(splatIndex * 4, true);
1375
+ }
1376
+ return values;
1377
+ }
1378
+ function getRADPropertyBytes(bytes, metadata, property) {
1379
+ const paddedByteLength = roundUpToEight(property.bytes);
1380
+ const byteOffset = metadata.payloadByteOffset + property.offset;
1381
+ const byteEnd = byteOffset + paddedByteLength;
1382
+ if (byteEnd > bytes.byteLength || property.offset + paddedByteLength > metadata.payloadBytes) {
1383
+ throw new Error(`RADLoader: property ${property.property} exceeds RADC payload byte length.`);
1384
+ }
1385
+ const propertyBytes = bytes.subarray(byteOffset, byteOffset + property.bytes);
1386
+ if (!property.compression) {
1387
+ return propertyBytes;
1388
+ }
1389
+ if (property.compression !== "gz") {
1390
+ throw new Error(`RADLoader: unsupported property compression ${property.compression}.`);
1391
+ }
1392
+ return decompressRADProperty(propertyBytes, property.property);
1393
+ }
1394
+ function decompressRADProperty(bytes, propertyName) {
1395
+ const arrayBuffer = copyToArrayBuffer(bytes);
1396
+ try {
1397
+ return new Uint8Array(RAD_PROPERTY_DEFLATE.decompressSync(arrayBuffer));
1398
+ } catch {
1399
+ try {
1400
+ return new Uint8Array(RAD_PROPERTY_RAW_DEFLATE.decompressSync(arrayBuffer));
1401
+ } catch {
1402
+ throw new Error(`RADLoader: failed to decompress RADC property ${propertyName}.`);
1403
+ }
1404
+ }
1405
+ }
1406
+ function decodePlanarFloat32(bytes, dimensions, count) {
1407
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1408
+ const values = new Float32Array(count * dimensions);
1409
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1410
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1411
+ values[rowIndex * dimensions + dimension] = dataView.getFloat32((dimension * count + rowIndex) * 4, true);
1412
+ }
1413
+ }
1414
+ return values;
1415
+ }
1416
+ function decodePlanarFloat16(bytes, dimensions, count) {
1417
+ const values = new Float32Array(count * dimensions);
1418
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1419
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1420
+ const byteOffset = (dimension * count + rowIndex) * 2;
1421
+ values[rowIndex * dimensions + dimension] = decodeFloat16(bytes[byteOffset] | bytes[byteOffset + 1] << 8);
1422
+ }
1423
+ }
1424
+ return values;
1425
+ }
1426
+ function decodeLeBytesFloat32(bytes, dimensions, count) {
1427
+ const values = new Float32Array(count * dimensions);
1428
+ const stride = count * dimensions;
1429
+ const scratch = new Uint8Array(4);
1430
+ const scratchView = new DataView(scratch.buffer);
1431
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1432
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1433
+ const byteOffset = dimension * count + rowIndex;
1434
+ for (let byteIndex = 0; byteIndex < 4; byteIndex++) {
1435
+ scratch[byteIndex] = bytes[byteOffset + stride * byteIndex];
1436
+ }
1437
+ values[rowIndex * dimensions + dimension] = scratchView.getFloat32(0, true);
1438
+ }
1439
+ }
1440
+ return values;
1441
+ }
1442
+ function decodeLeBytesFloat16(bytes, dimensions, count) {
1443
+ const values = new Float32Array(count * dimensions);
1444
+ const stride = count * dimensions;
1445
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1446
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1447
+ const byteOffset = dimension * count + rowIndex;
1448
+ values[rowIndex * dimensions + dimension] = decodeFloat16(bytes[byteOffset] | bytes[byteOffset + stride] << 8);
1449
+ }
1450
+ }
1451
+ return values;
1452
+ }
1453
+ function decodeR8(bytes, dimensions, count, min, max) {
1454
+ const values = new Float32Array(count * dimensions);
1455
+ const range = max - min;
1456
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1457
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1458
+ values[rowIndex * dimensions + dimension] = bytes[dimension * count + rowIndex] / 255 * range + min;
1459
+ }
1460
+ }
1461
+ return values;
1462
+ }
1463
+ function decodeR8Delta(bytes, dimensions, count, min, max) {
1464
+ const values = new Float32Array(count * dimensions);
1465
+ const range = max - min;
1466
+ const last = new Uint8Array(dimensions);
1467
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1468
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1469
+ const byteOffset = dimension * count + rowIndex;
1470
+ const value = last[dimension] + bytes[byteOffset] & 255;
1471
+ last[dimension] = value;
1472
+ values[rowIndex * dimensions + dimension] = value / 255 * range + min;
1473
+ }
1474
+ }
1475
+ return values;
1476
+ }
1477
+ function decodeS8(bytes, dimensions, count, max) {
1478
+ const values = new Float32Array(count * dimensions);
1479
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1480
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1481
+ const byte = bytes[dimension * count + rowIndex];
1482
+ values[rowIndex * dimensions + dimension] = (byte << 24 >> 24) / 127 * max;
1483
+ }
1484
+ }
1485
+ return values;
1486
+ }
1487
+ function decodeS8Delta(bytes, dimensions, count, max) {
1488
+ const values = new Float32Array(count * dimensions);
1489
+ const last = new Uint8Array(dimensions);
1490
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1491
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1492
+ const byteOffset = dimension * count + rowIndex;
1493
+ const value = last[dimension] + bytes[byteOffset] & 255;
1494
+ last[dimension] = value;
1495
+ values[rowIndex * dimensions + dimension] = (value << 24 >> 24) / 127 * max;
1496
+ }
1497
+ }
1498
+ return values;
1499
+ }
1500
+ function decodeScaleR8(bytes, dimensions, count, min, max) {
1501
+ const values = new Float32Array(count * dimensions);
1502
+ for (let rowIndex = 0; rowIndex < count; rowIndex++) {
1503
+ for (let dimension = 0; dimension < dimensions; dimension++) {
1504
+ values[rowIndex * dimensions + dimension] = decodeScale8(bytes[dimension * count + rowIndex], min, max);
1505
+ }
1506
+ }
1507
+ return values;
1508
+ }
1509
+ function decodeLogFloat16(bytes, dimensions, count) {
1510
+ const logValues = decodePlanarFloat16(bytes, dimensions, count);
1511
+ for (let valueIndex = 0; valueIndex < logValues.length; valueIndex++) {
1512
+ logValues[valueIndex] = Math.exp(logValues[valueIndex]);
1513
+ }
1514
+ return logValues;
1515
+ }
1516
+ function decodeRADOct88R8Rotations(bytes, count) {
1517
+ const rotations = new Float32Array(count * 4);
1518
+ for (let splatIndex = 0; splatIndex < count; splatIndex++) {
1519
+ const byteOffset = splatIndex * 3;
1520
+ const [x, y, z, w] = decodeQuatOct888(bytes[byteOffset], bytes[byteOffset + 1], bytes[byteOffset + 2]);
1521
+ rotations.set(normalizeQuaternion(w, x, y, z), splatIndex * 4);
1522
+ }
1523
+ return rotations;
1524
+ }
1525
+ function convertRgbToColorColumns(rgb) {
1526
+ const colors = new Uint8Array(rgb.length);
1527
+ const sphericalHarmonicDcs = new Float32Array(rgb.length);
1528
+ for (let componentIndex = 0; componentIndex < rgb.length; componentIndex++) {
1529
+ const component = rgb[componentIndex];
1530
+ colors[componentIndex] = normalizeColorByte2(component);
1531
+ sphericalHarmonicDcs[componentIndex] = (component - 0.5) / SH_C0;
1532
+ }
1533
+ return { colors, sphericalHarmonicDcs };
1534
+ }
1535
+ function makeIdentityRotations(count) {
1536
+ const rotations = new Float32Array(count * 4);
1537
+ for (let splatIndex = 0; splatIndex < count; splatIndex++) {
1538
+ rotations[splatIndex * 4] = 1;
1539
+ }
1540
+ return rotations;
1541
+ }
1542
+ function decodeScale8(scale, min, max) {
1543
+ if (scale === 0) {
1544
+ return 0;
1545
+ }
1546
+ const logScaleStep = (max - min) / 254;
1547
+ return Math.exp(min + (scale - 1) * logScaleStep);
1548
+ }
1549
+ function decodeQuatOct888(u, v, r) {
1550
+ let x = u / 255 * 2 - 1;
1551
+ let y = v / 255 * 2 - 1;
1552
+ const z = 1 - Math.abs(x) - Math.abs(y);
1553
+ const t = Math.max(-z, 0);
1554
+ x = x >= 0 ? x - t : x + t;
1555
+ y = y >= 0 ? y - t : y + t;
1556
+ const length = Math.hypot(x, y, z);
1557
+ const axisX = length > Number.EPSILON ? x / length : 1;
1558
+ const axisY = length > Number.EPSILON ? y / length : 0;
1559
+ const axisZ = length > Number.EPSILON ? z / length : 0;
1560
+ const halfTheta = r / 255 * 0.5 * Math.PI;
1561
+ const sinHalfTheta = Math.sin(halfTheta);
1562
+ return [axisX * sinHalfTheta, axisY * sinHalfTheta, axisZ * sinHalfTheta, Math.cos(halfTheta)];
1563
+ }
1564
+ function requireRADProperty(metadata, propertyName) {
1565
+ const property = findRADProperty(metadata, propertyName);
1566
+ if (!property) {
1567
+ throw new Error(`RADLoader: RADC chunk is missing ${propertyName} property.`);
1568
+ }
1569
+ return property;
1570
+ }
1571
+ function findRADProperty(metadata, propertyName) {
1572
+ return metadata.properties.find((property) => property.property === propertyName);
1573
+ }
1574
+ function getRADChunkDecodeMetadata(metadata, options) {
1575
+ var _a;
1576
+ const splatEncoding = (_a = options == null ? void 0 : options.radChunk) == null ? void 0 : _a.splatEncoding;
1577
+ if (!splatEncoding) {
1578
+ return metadata;
1579
+ }
1580
+ return {
1581
+ ...metadata,
1582
+ splatEncoding: {
1583
+ ...splatEncoding,
1584
+ ...metadata.splatEncoding
1585
+ }
1586
+ };
1587
+ }
1588
+ function getPropertyMin(metadata, property) {
1589
+ if (property.min === void 0) {
1590
+ const fallback = getSplatEncodingMinimum(metadata.splatEncoding, property.property);
1591
+ if (fallback !== void 0) {
1592
+ return fallback;
1593
+ }
1594
+ throw new Error(`RADLoader: RADC property ${property.property} is missing min.`);
1595
+ }
1596
+ return property.min;
1597
+ }
1598
+ function getPropertyMax(metadata, property) {
1599
+ if (property.max === void 0) {
1600
+ const fallback = getSplatEncodingMaximum(metadata.splatEncoding, property.property);
1601
+ if (fallback !== void 0) {
1602
+ return fallback;
1603
+ }
1604
+ throw new Error(`RADLoader: RADC property ${property.property} is missing max.`);
1605
+ }
1606
+ return property.max;
1607
+ }
1608
+ function getSplatEncodingMinimum(splatEncoding, propertyName) {
1609
+ switch (propertyName) {
1610
+ case "rgb":
1611
+ return splatEncoding == null ? void 0 : splatEncoding.rgbMin;
1612
+ case "scales":
1613
+ return splatEncoding == null ? void 0 : splatEncoding.lnScaleMin;
1614
+ default:
1615
+ return void 0;
1616
+ }
1617
+ }
1618
+ function getSplatEncodingMaximum(splatEncoding, propertyName) {
1619
+ switch (propertyName) {
1620
+ case "rgb":
1621
+ return splatEncoding == null ? void 0 : splatEncoding.rgbMax;
1622
+ case "scales":
1623
+ return splatEncoding == null ? void 0 : splatEncoding.lnScaleMax;
1624
+ case "sh1":
1625
+ return splatEncoding == null ? void 0 : splatEncoding.sh1Max;
1626
+ case "sh2":
1627
+ return splatEncoding == null ? void 0 : splatEncoding.sh2Max;
1628
+ case "sh3":
1629
+ return splatEncoding == null ? void 0 : splatEncoding.sh3Max;
1630
+ default:
1631
+ return void 0;
1632
+ }
1633
+ }
1634
+ function normalizeColorByte2(value) {
1635
+ return Math.round(Math.min(Math.max(value, 0), 1) * 255);
1636
+ }
1637
+ function copyToArrayBuffer(bytes) {
1638
+ const copy = new Uint8Array(bytes.byteLength);
1639
+ copy.set(bytes);
1640
+ return copy.buffer;
1641
+ }
1642
+ function getUint8Array2(data) {
1643
+ return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
1644
+ }
1645
+ var import_compression2, RAD_PROPERTY_DEFLATE, RAD_PROPERTY_RAW_DEFLATE;
1646
+ var init_parse_rad_chunk = __esm({
1647
+ "dist/lib/parse-rad-chunk.js"() {
1648
+ "use strict";
1649
+ import_compression2 = require("@loaders.gl/compression");
1650
+ init_parse_rad();
1651
+ init_splats_arrow_table();
1652
+ init_splat_utils();
1653
+ RAD_PROPERTY_DEFLATE = new import_compression2.DeflateCompression();
1654
+ RAD_PROPERTY_RAW_DEFLATE = new import_compression2.DeflateCompression({ raw: true });
1655
+ }
1656
+ });
1657
+
1658
+ // dist/rad-loader.js
1659
+ var rad_loader_exports = {};
1660
+ __export(rad_loader_exports, {
1661
+ RADLoaderWithParser: () => RADLoaderWithParser,
1662
+ parseRADChunk: () => parseRADChunk,
1663
+ parseRADChunkHeader: () => parseRADChunkHeader,
1664
+ parseRADChunkToGaussianSplats: () => parseRADChunkToGaussianSplats,
1665
+ parseRADHeader: () => parseRADHeader,
1666
+ tryParseRADHeader: () => tryParseRADHeader
1667
+ });
1668
+ var _RADLoaderPreload, RADLoaderMetadataWithoutPreload, RADLoaderWithParser;
1669
+ var init_rad_loader = __esm({
1670
+ "dist/rad-loader.js"() {
1671
+ "use strict";
1672
+ init_parse_rad();
1673
+ init_rad_loader_types();
1674
+ init_parse_rad();
1675
+ init_parse_rad_chunk();
1676
+ ({ preload: _RADLoaderPreload, ...RADLoaderMetadataWithoutPreload } = RADLoader);
1677
+ RADLoaderWithParser = {
1678
+ ...RADLoaderMetadataWithoutPreload,
1679
+ parse: async (arrayBuffer) => parseRADHeader(arrayBuffer),
1680
+ parseSync: (arrayBuffer) => parseRADHeader(arrayBuffer)
1681
+ };
1682
+ }
1683
+ });
1684
+
1685
+ // dist/rad-loader-types.js
1686
+ async function preload4() {
1687
+ const { RADLoaderWithParser: RADLoaderWithParser2 } = await Promise.resolve().then(() => (init_rad_loader(), rad_loader_exports));
1688
+ return RADLoaderWithParser2;
1689
+ }
1690
+ var VERSION4, RADLoader;
1691
+ var init_rad_loader_types = __esm({
1692
+ "dist/rad-loader-types.js"() {
1693
+ "use strict";
1694
+ init_splats_format();
1695
+ VERSION4 = true ? "5.0.0-alpha.1" : "latest";
1696
+ RADLoader = {
1697
+ dataType: null,
1698
+ batchType: null,
1699
+ ...RADFormat,
1700
+ version: VERSION4,
1701
+ options: {},
1702
+ preload: preload4
1703
+ };
1704
+ }
1705
+ });
1706
+
1707
+ // dist/index.js
1708
+ var dist_exports = {};
1709
+ __export(dist_exports, {
1710
+ KSPLATFormat: () => KSPLATFormat,
1711
+ KSPLATLoader: () => KSPLATLoader,
1712
+ RADFormat: () => RADFormat,
1713
+ RADLoader: () => RADLoader,
1714
+ RADSource: () => RADSource,
1715
+ RADSourceLoader: () => RADSourceLoader,
1716
+ SPLATFormat: () => SPLATFormat,
1717
+ SPLATLoader: () => SPLATLoader,
1718
+ SPZFormat: () => SPZFormat,
1719
+ SPZLoader: () => SPZLoader,
1720
+ resolveRADChunkUrl: () => resolveRADChunkUrl
1721
+ });
1722
+ module.exports = __toCommonJS(dist_exports);
1723
+ init_splats_format();
1724
+ init_splat_loader_types();
1725
+ init_ksplat_loader_types();
1726
+ init_spz_loader_types();
1727
+ init_rad_loader_types();
1728
+
1729
+ // dist/rad-source-loader.js
1730
+ var import_loader_utils = require("@loaders.gl/loader-utils");
1731
+ init_splats_format();
1732
+ init_parse_rad();
1733
+ init_parse_rad_chunk();
1734
+ init_splats_arrow_table();
1735
+ var DEFAULT_RAD_HEADER_BYTE_LENGTHS = [64 * 1024, 256 * 1024, 1024 * 1024];
1736
+ var DEFAULT_RAD_MAX_CONCURRENT_CHUNK_REQUESTS = 4;
1737
+ var VERSION5 = true ? "5.0.0-alpha.1" : "latest";
1738
+ var RADSourceLoader = {
1739
+ dataType: null,
1740
+ batchType: null,
1741
+ ...RADFormat,
1742
+ name: "RADSourceLoader",
1743
+ version: VERSION5,
1744
+ type: "rad",
1745
+ fromUrl: true,
1746
+ fromBlob: true,
1747
+ options: {
1748
+ rad: {
1749
+ headers: void 0,
1750
+ withCredentials: false,
1751
+ headerByteLengths: void 0
1752
+ }
1753
+ },
1754
+ defaultOptions: {
1755
+ rad: {
1756
+ headers: void 0,
1757
+ withCredentials: false,
1758
+ headerByteLengths: void 0
1759
+ }
1760
+ },
1761
+ testURL: (url) => /\.rad(?:$|[?#])/i.test(url),
1762
+ createDataSource: (data, options, coreApi) => new RADSource(data, options, coreApi)
1763
+ };
1764
+ var RADSource = class extends import_loader_utils.DataSource {
1765
+ /** Shared metadata promise exposed for source-style integrations. */
1766
+ metadata;
1767
+ /** Lazily initialized RAD header promise. */
1768
+ _metadataPromise = null;
1769
+ /** Lazily initialized per-chunk metadata promises. */
1770
+ _chunkMetadataPromises = /* @__PURE__ */ new Map();
1771
+ constructor(data, options, coreApi) {
1772
+ super(data, options, RADSourceLoader.defaultOptions, coreApi);
1773
+ this.metadata = this.getMetadata();
1774
+ }
1775
+ /** Ensures the RAD header metadata has been loaded. */
1776
+ async initialize() {
1777
+ await this.getMetadata();
1778
+ }
1779
+ /** Returns parsed Spark RAD top-level metadata. */
1780
+ async getMetadata() {
1781
+ if (!this._metadataPromise) {
1782
+ this._metadataPromise = this._loadMetadata();
1783
+ }
1784
+ return await this._metadataPromise;
1785
+ }
1786
+ /** Returns the number of chunks declared by the RAD metadata. */
1787
+ async getChunkCount() {
1788
+ const metadata = await this.getMetadata();
1789
+ return metadata.chunks.length;
1790
+ }
1791
+ /** Returns the URL used for a chunk, or `null` for Blob-backed inline chunks. */
1792
+ async getChunkUrl(chunkIndex) {
1793
+ const metadata = await this.getMetadata();
1794
+ const chunk = this._getChunkRange(metadata, chunkIndex);
1795
+ if (chunk.filename) {
1796
+ return resolveRADChunkUrl(this.url, chunk.filename);
1797
+ }
1798
+ return typeof this.data === "string" ? this.url : null;
1799
+ }
1800
+ /** Fetches one raw RADC chunk by index. */
1801
+ async getChunk(chunkIndex, options = {}) {
1802
+ const metadata = await this.getMetadata();
1803
+ const chunk = this._getChunkRange(metadata, chunkIndex);
1804
+ if (chunk.filename) {
1805
+ if (typeof this.data !== "string") {
1806
+ throw new Error("RADSource: sidecar RADC chunks require a URL-backed RAD source.");
1807
+ }
1808
+ return await this._fetchArrayBuffer(resolveRADChunkUrl(this.url, chunk.filename), void 0, {
1809
+ signal: options.signal
1810
+ });
1811
+ }
1812
+ if (chunk.bytes === 0) {
1813
+ return new ArrayBuffer(0);
1814
+ }
1815
+ const byteOffset = metadata.chunksByteOffset + chunk.offset;
1816
+ if (typeof this.data !== "string") {
1817
+ return await this.data.slice(byteOffset, byteOffset + chunk.bytes).arrayBuffer();
1818
+ }
1819
+ return await this._fetchArrayBuffer(this.url, { offset: byteOffset, bytes: chunk.bytes }, { signal: options.signal });
1820
+ }
1821
+ /** Fetches and parses metadata for one RADC chunk. */
1822
+ async getChunkMetadata(chunkIndex, options = {}) {
1823
+ let chunkMetadataPromise = this._chunkMetadataPromises.get(chunkIndex);
1824
+ if (!chunkMetadataPromise) {
1825
+ chunkMetadataPromise = this.getChunk(chunkIndex, options).then((chunk) => parseRADChunkHeader(chunk));
1826
+ this._chunkMetadataPromises.set(chunkIndex, chunkMetadataPromise);
1827
+ }
1828
+ return await chunkMetadataPromise;
1829
+ }
1830
+ /** Fetches and decodes one RADC chunk into raw Gaussian splat arrays. */
1831
+ async getChunkSplats(chunkIndex, options = {}) {
1832
+ const metadata = await this.getMetadata();
1833
+ return parseRADChunkToGaussianSplats(await this.getChunk(chunkIndex, options), this._getChunkDecodeOptions(metadata, options));
1834
+ }
1835
+ /** Fetches and decodes one RADC chunk into a Mesh Arrow table. */
1836
+ async getChunkTable(chunkIndex, options = {}) {
1837
+ const metadata = await this.getMetadata();
1838
+ return parseRADChunk(await this.getChunk(chunkIndex, options), this._getChunkDecodeOptions(metadata, options));
1839
+ }
1840
+ /** Iterates decoded RADC chunks as Mesh Arrow tables. */
1841
+ async *getChunkTables(options = {}) {
1842
+ const metadata = await this.getMetadata();
1843
+ const startChunkIndex = options.startChunkIndex ?? 0;
1844
+ const maxChunks = options.maxChunks ?? Number.POSITIVE_INFINITY;
1845
+ const maxSplats = options.maxSplats ?? Number.POSITIVE_INFINITY;
1846
+ let chunkCount = 0;
1847
+ let splatCount = 0;
1848
+ if (options.pruneLoadedLoDParents) {
1849
+ const chunkIndices = getRADChunkTableIteratorIndices(metadata, startChunkIndex, maxChunks, maxSplats);
1850
+ const splatChunks = await this._getChunkSplatsConcurrently(chunkIndices, options);
1851
+ let loadedGlobalSplatEnd = 0;
1852
+ for (const splats of splatChunks) {
1853
+ chunkCount++;
1854
+ splatCount += splats.splatCount;
1855
+ const base = getRADChunkSplatBase(splats);
1856
+ loadedGlobalSplatEnd = Math.max(loadedGlobalSplatEnd, base + splats.splatCount);
1857
+ }
1858
+ for (const splats of splatChunks) {
1859
+ yield makeGaussianSplatsArrowTable(pruneLoadedLoDParents(splats, loadedGlobalSplatEnd));
1860
+ }
1861
+ return;
1862
+ }
1863
+ for (let chunkIndex = startChunkIndex; chunkIndex < metadata.chunks.length && chunkCount < maxChunks && splatCount < maxSplats; chunkIndex++) {
1864
+ const table = await this.getChunkTable(chunkIndex, options);
1865
+ chunkCount++;
1866
+ splatCount += table.data.numRows;
1867
+ yield table;
1868
+ }
1869
+ }
1870
+ /** Fetches and decodes RAD chunks with bounded concurrency while preserving chunk order. */
1871
+ async _getChunkSplatsConcurrently(chunkIndices, options) {
1872
+ const splatChunks = new Array(chunkIndices.length);
1873
+ const maxConcurrentChunkRequests = getRADMaxConcurrentChunkRequests(options.maxConcurrentChunkRequests);
1874
+ let nextResultIndex = 0;
1875
+ async function loadNextChunk(source) {
1876
+ while (nextResultIndex < chunkIndices.length) {
1877
+ const resultIndex = nextResultIndex++;
1878
+ const chunkIndex = chunkIndices[resultIndex];
1879
+ splatChunks[resultIndex] = await source.getChunkSplats(chunkIndex, options);
1880
+ }
1881
+ }
1882
+ const workerCount = Math.min(maxConcurrentChunkRequests, chunkIndices.length);
1883
+ await Promise.all(Array.from({ length: workerCount }, () => loadNextChunk(this)));
1884
+ return splatChunks;
1885
+ }
1886
+ /** Adds source-level RAD decode metadata to chunk decode options. */
1887
+ _getChunkDecodeOptions(metadata, options) {
1888
+ return {
1889
+ ...options,
1890
+ radChunk: {
1891
+ splatEncoding: metadata.splatEncoding,
1892
+ ...options.radChunk
1893
+ }
1894
+ };
1895
+ }
1896
+ /** Loads and parses the top-level RAD metadata. */
1897
+ async _loadMetadata() {
1898
+ var _a, _b;
1899
+ const headerByteLengths = ((_b = (_a = this.options.rad) == null ? void 0 : _a.headerByteLengths) == null ? void 0 : _b.length) ? this.options.rad.headerByteLengths : DEFAULT_RAD_HEADER_BYTE_LENGTHS;
1900
+ if (typeof this.data !== "string") {
1901
+ const byteLength = Math.min(this.data.size, Math.max(...headerByteLengths));
1902
+ const metadata = tryParseRADHeader(await this.data.slice(0, byteLength).arrayBuffer());
1903
+ if (metadata) {
1904
+ return metadata;
1905
+ }
1906
+ throw new Error("RADSource: Blob does not contain a complete RAD metadata header.");
1907
+ }
1908
+ for (const byteLength of headerByteLengths) {
1909
+ const metadata = tryParseRADHeader(await this._fetchArrayBuffer(this.url, { offset: 0, bytes: byteLength }));
1910
+ if (metadata) {
1911
+ return metadata;
1912
+ }
1913
+ }
1914
+ throw new Error("RADSource: failed to load a complete RAD metadata header.");
1915
+ }
1916
+ /** Returns a validated chunk table entry. */
1917
+ _getChunkRange(metadata, chunkIndex) {
1918
+ if (!Number.isInteger(chunkIndex) || chunkIndex < 0 || chunkIndex >= metadata.chunks.length) {
1919
+ throw new Error(`RADSource: chunk index ${chunkIndex} is outside 0-${metadata.chunks.length - 1}.`);
1920
+ }
1921
+ return metadata.chunks[chunkIndex];
1922
+ }
1923
+ /** Fetches a full or ranged ArrayBuffer while tolerating non-206 range fallbacks. */
1924
+ async _fetchArrayBuffer(url, range, options = {}) {
1925
+ const response = await this._fetchResponse(url, this._getRequestInit(range, options));
1926
+ if (!response.ok) {
1927
+ throw new Error(`RADSource: failed to fetch ${url}: ${response.status} ${response.statusText}`);
1928
+ }
1929
+ const arrayBuffer = await response.arrayBuffer();
1930
+ if (range && response.status !== 206 && arrayBuffer.byteLength >= range.offset + range.bytes) {
1931
+ return arrayBuffer.slice(range.offset, range.offset + range.bytes);
1932
+ }
1933
+ if (range && arrayBuffer.byteLength > range.bytes) {
1934
+ return arrayBuffer.slice(0, range.bytes);
1935
+ }
1936
+ return arrayBuffer;
1937
+ }
1938
+ /** Fetches through custom source fetch hooks or the injected core fetchFile helper. */
1939
+ async _fetchResponse(url, requestInit) {
1940
+ if (this._hasCustomFetch()) {
1941
+ return await this.fetch(url, requestInit);
1942
+ }
1943
+ return this.hasCoreApi ? await this.coreApi.fetchFile(url, requestInit) : await this.fetch(url, requestInit);
1944
+ }
1945
+ /** Returns true when source options supplied an explicit fetch override. */
1946
+ _hasCustomFetch() {
1947
+ var _a, _b, _c;
1948
+ return Boolean(((_b = (_a = this.loadOptions) == null ? void 0 : _a.core) == null ? void 0 : _b.fetch) || ((_c = this.loadOptions) == null ? void 0 : _c.fetch));
1949
+ }
1950
+ /** Builds request options for RAD fetches. */
1951
+ _getRequestInit(range, options = {}) {
1952
+ var _a, _b;
1953
+ const headers = new Headers((_a = this.options.rad) == null ? void 0 : _a.headers);
1954
+ if (range && range.bytes > 0) {
1955
+ headers.set("Range", `bytes=${range.offset}-${range.offset + range.bytes - 1}`);
1956
+ }
1957
+ return {
1958
+ headers,
1959
+ credentials: ((_b = this.options.rad) == null ? void 0 : _b.withCredentials) ? "include" : "same-origin",
1960
+ signal: options.signal
1961
+ };
1962
+ }
1963
+ };
1964
+ function getRADChunkTableIteratorIndices(metadata, startChunkIndex, maxChunks, maxSplats) {
1965
+ const chunkIndices = [];
1966
+ let estimatedSplatCount = 0;
1967
+ for (let chunkIndex = startChunkIndex; chunkIndex < metadata.chunks.length && chunkIndices.length < maxChunks && estimatedSplatCount < maxSplats; chunkIndex++) {
1968
+ const chunk = metadata.chunks[chunkIndex];
1969
+ chunkIndices.push(chunkIndex);
1970
+ estimatedSplatCount += (chunk == null ? void 0 : chunk.count) ?? metadata.chunkSize ?? 0;
1971
+ }
1972
+ return chunkIndices;
1973
+ }
1974
+ function getRADMaxConcurrentChunkRequests(maxConcurrentChunkRequests) {
1975
+ return Number.isFinite(maxConcurrentChunkRequests) && maxConcurrentChunkRequests > 0 ? Math.floor(maxConcurrentChunkRequests) : DEFAULT_RAD_MAX_CONCURRENT_CHUNK_REQUESTS;
1976
+ }
1977
+ function getRADChunkSplatBase(splats) {
1978
+ var _a;
1979
+ return typeof ((_a = splats.loaderData) == null ? void 0 : _a.base) === "number" ? splats.loaderData.base : 0;
1980
+ }
1981
+ function pruneLoadedLoDParents(splats, loadedGlobalSplatEnd) {
1982
+ var _a, _b;
1983
+ const childCounts = (_a = splats.loaderData) == null ? void 0 : _a.childCounts;
1984
+ const childStarts = (_b = splats.loaderData) == null ? void 0 : _b.childStarts;
1985
+ if (!(childCounts instanceof Uint16Array) || !(childStarts instanceof Uint32Array)) {
1986
+ return splats;
1987
+ }
1988
+ const keepRows = new Uint32Array(splats.splatCount);
1989
+ let keepCount = 0;
1990
+ for (let rowIndex = 0; rowIndex < splats.splatCount; rowIndex++) {
1991
+ const childCount = childCounts[rowIndex];
1992
+ const childStart = childStarts[rowIndex];
1993
+ if (childCount > 0 && childStart < loadedGlobalSplatEnd) {
1994
+ continue;
1995
+ }
1996
+ keepRows[keepCount++] = rowIndex;
1997
+ }
1998
+ if (keepCount === splats.splatCount) {
1999
+ return splats;
2000
+ }
2001
+ const keptRows = keepRows.subarray(0, keepCount);
2002
+ const sphericalHarmonicsComponentCount = splats.sphericalHarmonicsComponentCount ?? 0;
2003
+ return {
2004
+ ...splats,
2005
+ splatCount: keepCount,
2006
+ positions: copyInterleavedRows(splats.positions, 3, keptRows),
2007
+ scales: copyInterleavedRows(splats.scales, 3, keptRows),
2008
+ rotations: copyInterleavedRows(splats.rotations, 4, keptRows),
2009
+ colors: copyInterleavedRows(splats.colors, 3, keptRows),
2010
+ sphericalHarmonicDcs: splats.sphericalHarmonicDcs ? copyInterleavedRows(splats.sphericalHarmonicDcs, 3, keptRows) : void 0,
2011
+ opacities: copyInterleavedRows(splats.opacities, 1, keptRows),
2012
+ sphericalHarmonics: splats.sphericalHarmonics && sphericalHarmonicsComponentCount ? copyInterleavedRows(splats.sphericalHarmonics, sphericalHarmonicsComponentCount, keptRows) : void 0,
2013
+ loaderData: {
2014
+ ...splats.loaderData,
2015
+ count: keepCount,
2016
+ childCounts: copyInterleavedRows(childCounts, 1, keptRows),
2017
+ childStarts: copyInterleavedRows(childStarts, 1, keptRows)
2018
+ }
2019
+ };
2020
+ }
2021
+ function copyInterleavedRows(values, itemSize, rows) {
2022
+ const copiedValues = new values.constructor(rows.length * itemSize);
2023
+ for (let outputRowIndex = 0; outputRowIndex < rows.length; outputRowIndex++) {
2024
+ const inputOffset = rows[outputRowIndex] * itemSize;
2025
+ const outputOffset = outputRowIndex * itemSize;
2026
+ copiedValues.set(values.subarray(inputOffset, inputOffset + itemSize), outputOffset);
2027
+ }
2028
+ return copiedValues;
2029
+ }
2030
+ function resolveRADChunkUrl(rootUrl, chunkFilename) {
2031
+ if (/^[a-z][a-z0-9+.-]*:/i.test(chunkFilename) || chunkFilename.startsWith("/")) {
2032
+ return chunkFilename;
2033
+ }
2034
+ if (!rootUrl) {
2035
+ throw new Error("RADSource: cannot resolve a sidecar RADC chunk without a RAD URL.");
2036
+ }
2037
+ try {
2038
+ return new URL(chunkFilename, rootUrl).toString();
2039
+ } catch {
2040
+ const [rootPath, suffix = ""] = rootUrl.split(/([?#].*)/, 2);
2041
+ const lastSlashIndex = Math.max(rootPath.lastIndexOf("/"), rootPath.lastIndexOf("\\"));
2042
+ const rootDirectory = lastSlashIndex >= 0 ? rootPath.slice(0, lastSlashIndex + 1) : "";
2043
+ return `${rootDirectory}${chunkFilename}${suffix}`;
2044
+ }
2045
+ }
2046
+ //# sourceMappingURL=index.cjs.map